- Replace ProcessPostUseCase with new PostSyncService in src/services/post/ - Add postListStore for state management in src/stores/post/ - Remove deprecated ProcessPostUseCase and ProcessMessageUseCase files - Delete architecture documentation files (ARCHITECTURE_REFACTOR_PLAN.md, architecture-comparison-report.md) - Update all consumers (HomeScreen, PostDetailScreen, SearchScreen, useUserProfile, useDifferentialPosts) - Simplify postService to only contain API layer methods - Remove unused type exports from message stores BREAKING CHANGE: ProcessPostUseCase and ProcessMessageUseCase have been removed. Use postSyncService for post operations instead.
193 lines
6.0 KiB
TypeScript
193 lines
6.0 KiB
TypeScript
import { create } from 'zustand';
|
|
import type { Post } from '../../types';
|
|
import { CacheEntry, createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache';
|
|
|
|
export interface PostManagerState {
|
|
listsMap: Map<string, CacheEntry<Post[]>>;
|
|
detailsMap: Map<string, CacheEntry<Post | null>>;
|
|
loadingListKeys: Set<string>;
|
|
loadingDetailIds: Set<string>;
|
|
pendingRequests: Map<string, Promise<any>>;
|
|
}
|
|
|
|
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: <T>(key: string) => Promise<T> | undefined;
|
|
setPendingRequest: <T>(key: string, request: Promise<T>) => 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<PostManagerStore>((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: <T>(key: string) => {
|
|
return get().pendingRequests.get(key) as Promise<T> | undefined;
|
|
},
|
|
|
|
setPendingRequest: <T>(key: string, request: Promise<T>) => {
|
|
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(),
|
|
});
|
|
},
|
|
})); |