| import { InfiniteData, QueryClient } from '@tanstack/react-query'; |
|
|
| export const addData = <TCollection, TData>( |
| data: InfiniteData<TCollection>, |
| collectionName: string, |
| newData: TData, |
| findIndex: (page: TCollection) => number, |
| ) => { |
| const dataJson = JSON.parse(JSON.stringify(data)) as InfiniteData<TCollection>; |
| const { pageIndex, index } = findPage<TCollection>(data, findIndex); |
|
|
| if (pageIndex !== -1 && index !== -1) { |
| return updateData(data, collectionName, newData, findIndex); |
| } |
| dataJson.pages[0][collectionName].unshift({ |
| ...newData, |
| updatedAt: new Date().toISOString(), |
| }); |
|
|
| return dataJson; |
| }; |
|
|
| export const getRecordByProperty = <TCollection, TData>( |
| data: InfiniteData<TCollection>, |
| collectionName: string, |
| findProperty: (item: TData) => boolean, |
| ): TData | undefined => { |
| |
| const { pageIndex, index } = findPage<TCollection>(data, (page) => |
| page[collectionName].findIndex(findProperty), |
| ); |
|
|
| |
| if (pageIndex !== -1 && index !== -1) { |
| return data.pages[pageIndex][collectionName][index]; |
| } |
|
|
| |
| return undefined; |
| }; |
|
|
| export function findPage<TData>(data: InfiniteData<TData>, findIndex: (page: TData) => number) { |
| for (let pageIndex = 0; pageIndex < data.pages.length; pageIndex++) { |
| const page = data.pages[pageIndex]; |
| const index = findIndex(page); |
| if (index !== -1) { |
| return { pageIndex, index }; |
| } |
| } |
| return { pageIndex: -1, index: -1 }; |
| } |
|
|
| export const updateData = <TCollection, TData>( |
| data: InfiniteData<TCollection>, |
| collectionName: string, |
| updatedData: TData, |
| findIndex: (page: TCollection) => number, |
| ) => { |
| const newData = JSON.parse(JSON.stringify(data)) as InfiniteData<TCollection>; |
| const { pageIndex, index } = findPage<TCollection>(data, findIndex); |
|
|
| if (pageIndex !== -1 && index !== -1) { |
| |
| newData.pages[pageIndex][collectionName].splice(index, 1); |
| |
| newData.pages[0][collectionName].unshift({ |
| ...updatedData, |
| updatedAt: new Date().toISOString(), |
| }); |
| } |
|
|
| return newData; |
| }; |
|
|
| export const deleteData = <TCollection, TData>( |
| data: TData, |
| collectionName: string, |
| findIndex: (page: TCollection) => number, |
| ): TData => { |
| const newData = JSON.parse(JSON.stringify(data)); |
| const { pageIndex, index } = findPage<TCollection>(newData, findIndex); |
|
|
| if (pageIndex !== -1 && index !== -1) { |
| |
| newData.pages[pageIndex][collectionName].splice(index, 1); |
| } |
| return newData; |
| }; |
|
|
| |
| |
| |
| export const normalizeData = <TCollection, TData>( |
| data: InfiniteData<TCollection>, |
| collectionName: string, |
| pageSize: number, |
| uniqueProperty?: keyof TData, |
| ): InfiniteData<TCollection> => { |
| const infiniteData = JSON.parse(JSON.stringify(data)) as InfiniteData<TCollection>; |
| const pageCount = infiniteData.pages.length; |
| if (pageCount === 0) { |
| return infiniteData; |
| } |
|
|
| const pageParams = infiniteData.pageParams; |
|
|
| |
| let collection = infiniteData.pages.flatMap((page) => page[collectionName]); |
|
|
| if (collection.length === 0) { |
| return infiniteData; |
| } |
|
|
| if (uniqueProperty) { |
| const seen = new Set<TData>(); |
| collection = collection.filter((item) => { |
| const value = item[uniqueProperty]; |
| if (seen.has(value)) { |
| return false; |
| } |
| seen.add(value); |
| return true; |
| }); |
| } |
|
|
| |
| const restructuredPages = Array.from({ length: pageCount }, (_, i) => ({ |
| ...infiniteData.pages[i], |
| [collectionName]: collection.slice(i * pageSize, (i + 1) * pageSize), |
| })).filter((page) => page[collectionName].length > 0); |
|
|
| return { |
| pageParams: pageParams.slice(0, restructuredPages.length), |
| pages: restructuredPages, |
| }; |
| }; |
|
|
| export const updateFields = <TCollection, TData>( |
| data: InfiniteData<TCollection>, |
| updatedItem: Partial<TData>, |
| collectionName: string, |
| identifierField: keyof TData, |
| callback?: (newItem: TData) => void, |
| ): InfiniteData<TCollection> => { |
| const newData = JSON.parse(JSON.stringify(data)) as InfiniteData<TCollection>; |
| const { pageIndex, index } = findPage<TCollection>(newData, (page) => |
| page[collectionName].findIndex( |
| (item: TData) => item[identifierField] === updatedItem[identifierField], |
| ), |
| ); |
|
|
| if (pageIndex !== -1 && index !== -1) { |
| const deleted = newData.pages[pageIndex][collectionName].splice(index, 1); |
| const oldItem = deleted[0]; |
| const newItem = { |
| ...oldItem, |
| ...updatedItem, |
| updatedAt: new Date().toISOString(), |
| }; |
| if (callback) { |
| callback(newItem); |
| } |
| newData.pages[0][collectionName].unshift(newItem); |
| } |
|
|
| return newData; |
| }; |
|
|
| type UpdateCacheListOptions<TData> = { |
| queryClient: QueryClient; |
| queryKey: unknown[]; |
| searchProperty: keyof TData; |
| updateData: Partial<TData>; |
| searchValue: unknown; |
| }; |
|
|
| export function updateCacheList<TData>({ |
| queryClient, |
| queryKey, |
| searchProperty, |
| updateData, |
| searchValue, |
| }: UpdateCacheListOptions<TData>) { |
| queryClient.setQueryData<TData[]>(queryKey, (oldData) => { |
| if (!oldData) { |
| return oldData; |
| } |
|
|
| return oldData.map((item) => |
| item[searchProperty] === searchValue ? { ...item, ...updateData } : item, |
| ); |
| }); |
| } |
|
|
| export function addToCacheList<TData>( |
| queryClient: QueryClient, |
| queryKey: unknown[], |
| newItem: TData, |
| ) { |
| queryClient.setQueryData<TData[]>(queryKey, (oldData) => { |
| if (!oldData) { |
| return [newItem]; |
| } |
| return [...oldData, newItem]; |
| }); |
| } |
|
|
| export function removeFromCacheList<TData>( |
| queryClient: QueryClient, |
| queryKey: unknown[], |
| searchProperty: keyof TData, |
| searchValue: unknown, |
| ) { |
| queryClient.setQueryData<TData[]>(queryKey, (oldData) => { |
| if (!oldData) { |
| return oldData; |
| } |
| return oldData.filter((item) => item[searchProperty] !== searchValue); |
| }); |
| } |
|
|