Files
frontend/src/stores/post/postStore.ts
lafay 2adc9360a5
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 3m28s
Frontend CI / ota-android (push) Successful in 10m25s
Frontend CI / build-android-apk (push) Successful in 55m22s
refactor(post): consolidate post sync to PostSyncService and remove ProcessPostUseCase
- 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.
2026-04-13 00:26:05 +08:00

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(),
});
},
}));