import { create } from 'zustand'; import type { Post } from '../../types'; import { CacheEntry, createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache'; export interface PostManagerState { listsMap: Map>; detailsMap: Map>; loadingListKeys: Set; loadingDetailIds: Set; pendingRequests: Map>; } export interface PostManagerActions { getPostsList: (type: string, page: number, pageSize: number) => Post[] | null; getPostDetail: (postId: string) => Post | null; isListExpired: (type: string, page: number, pageSize: number) => boolean; isDetailExpired: (postId: string) => boolean; isLoadingList: (type: string, page: number, pageSize: number) => boolean; isLoadingDetail: (postId: string) => boolean; setPostsList: (type: string, page: number, pageSize: number, posts: Post[]) => void; setPostDetail: (postId: string, post: Post | null) => void; setLoadingList: (type: string, page: number, pageSize: number, loading: boolean) => void; setLoadingDetail: (postId: string, loading: boolean) => void; invalidateList: (type?: string, page?: number, pageSize?: number) => void; invalidateDetail: (postId: string) => void; invalidateAll: () => void; getPendingRequest: (key: string) => Promise | undefined; setPendingRequest: (key: string, request: Promise) => void; deletePendingRequest: (key: string) => void; clearPendingRequests: () => void; reset: () => void; } function buildListKey(type: string, page: number, pageSize: number): string { return `list:${type}:${page}:${pageSize}`; } const initialState: PostManagerState = { listsMap: new Map(), detailsMap: new Map(), loadingListKeys: new Set(), loadingDetailIds: new Set(), pendingRequests: new Map(), }; export type PostManagerStore = PostManagerState & PostManagerActions; export const usePostManagerStore = create((set, get) => ({ ...initialState, getPostsList: (type: string, page: number, pageSize: number) => { const key = buildListKey(type, page, pageSize); const entry = get().listsMap.get(key); if (!entry) return null; if (isCacheExpired(entry)) return null; return entry.data; }, getPostDetail: (postId: string) => { const entry = get().detailsMap.get(postId); if (!entry) return null; if (isCacheExpired(entry)) return null; return entry.data; }, isListExpired: (type: string, page: number, pageSize: number) => { const key = buildListKey(type, page, pageSize); const entry = get().listsMap.get(key); if (!entry) return true; return isCacheExpired(entry); }, isDetailExpired: (postId: string) => { const entry = get().detailsMap.get(postId); if (!entry) return true; return isCacheExpired(entry); }, isLoadingList: (type: string, page: number, pageSize: number) => { const key = buildListKey(type, page, pageSize); return get().loadingListKeys.has(key); }, isLoadingDetail: (postId: string) => { return get().loadingDetailIds.has(postId); }, setPostsList: (type: string, page: number, pageSize: number, posts: Post[]) => { const key = buildListKey(type, page, pageSize); set(state => { const newListsMap = new Map(state.listsMap); newListsMap.set(key, createCacheEntry(posts, DEFAULT_TTL.POST_LIST)); return { listsMap: newListsMap }; }); }, setPostDetail: (postId: string, post: Post | null) => { set(state => { const newDetailsMap = new Map(state.detailsMap); newDetailsMap.set(postId, createCacheEntry(post, DEFAULT_TTL.POST_DETAIL)); return { detailsMap: newDetailsMap }; }); }, setLoadingList: (type: string, page: number, pageSize: number, loading: boolean) => { const key = buildListKey(type, page, pageSize); set(state => { const newLoadingListKeys = new Set(state.loadingListKeys); if (loading) { newLoadingListKeys.add(key); } else { newLoadingListKeys.delete(key); } return { loadingListKeys: newLoadingListKeys }; }); }, setLoadingDetail: (postId: string, loading: boolean) => { set(state => { const newLoadingDetailIds = new Set(state.loadingDetailIds); if (loading) { newLoadingDetailIds.add(postId); } else { newLoadingDetailIds.delete(postId); } return { loadingDetailIds: newLoadingDetailIds }; }); }, invalidateList: (type?: string, page?: number, pageSize?: number) => { if (type !== undefined && page !== undefined && pageSize !== undefined) { const key = buildListKey(type, page, pageSize); set(state => { const newListsMap = new Map(state.listsMap); newListsMap.delete(key); return { listsMap: newListsMap }; }); } else { set({ listsMap: new Map() }); } }, invalidateDetail: (postId: string) => { set(state => { const newDetailsMap = new Map(state.detailsMap); newDetailsMap.delete(postId); return { detailsMap: newDetailsMap }; }); }, invalidateAll: () => { set({ listsMap: new Map(), detailsMap: new Map(), pendingRequests: new Map(), }); }, getPendingRequest: (key: string) => { return get().pendingRequests.get(key) as Promise | undefined; }, setPendingRequest: (key: string, request: Promise) => { set(state => { const newPendingRequests = new Map(state.pendingRequests); newPendingRequests.set(key, request); return { pendingRequests: newPendingRequests }; }); }, deletePendingRequest: (key: string) => { set(state => { const newPendingRequests = new Map(state.pendingRequests); newPendingRequests.delete(key); return { pendingRequests: newPendingRequests }; }); }, clearPendingRequests: () => { set({ pendingRequests: new Map() }); }, reset: () => { set({ ...initialState, listsMap: new Map(), detailsMap: new Map(), loadingListKeys: new Set(), loadingDetailIds: new Set(), pendingRequests: new Map(), }); }, }));