- Introduced hrefProfileChatSettings() for navigation to chat settings. - Updated SettingsScreen to include new settings items for chat settings, language selection, data storage, terms, and privacy policy. - Enhanced user experience by providing alerts for language and data storage options. This update improves the profile settings interface by adding more customization options for users.
287 lines
8.4 KiB
TypeScript
287 lines
8.4 KiB
TypeScript
/**
|
|
* 群组状态 Zustand Store
|
|
*/
|
|
|
|
import { create } from 'zustand';
|
|
import type {
|
|
GroupResponse,
|
|
GroupMemberResponse,
|
|
} from '../../types/dto';
|
|
import { CacheEntry, createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache';
|
|
|
|
// ==================== 状态接口 ====================
|
|
|
|
export interface GroupManagerState {
|
|
// 群组列表缓存
|
|
groupsListEntry: CacheEntry<GroupResponse[]> | null;
|
|
|
|
// 群组详情缓存
|
|
groupsMap: Map<string, CacheEntry<GroupResponse>>;
|
|
|
|
// 群组成员缓存 (key: members:groupId:page:pageSize)
|
|
membersMap: Map<string, CacheEntry<GroupMemberResponse[]>>;
|
|
|
|
// 加载状态
|
|
isLoadingGroups: boolean;
|
|
loadingGroupIds: Set<string>;
|
|
loadingMemberKeys: Set<string>;
|
|
|
|
// 待处理请求(去重)
|
|
pendingRequests: Map<string, Promise<any>>;
|
|
}
|
|
|
|
export interface GroupManagerActions {
|
|
// 获取状态
|
|
getGroupsList: () => GroupResponse[] | null;
|
|
getGroup: (groupId: string) => GroupResponse | null;
|
|
getMembers: (groupId: string, page?: number, pageSize?: number) => GroupMemberResponse[] | null;
|
|
isGroupsListExpired: () => boolean;
|
|
isGroupExpired: (groupId: string) => boolean;
|
|
isMembersExpired: (groupId: string, page?: number, pageSize?: number) => boolean;
|
|
isLoadingGroup: (groupId: string) => boolean;
|
|
isLoadingMembers: (groupId: string, page?: number, pageSize?: number) => boolean;
|
|
|
|
// 设置状态
|
|
setGroupsList: (groups: GroupResponse[]) => void;
|
|
setGroupsListEntry: (entry: CacheEntry<GroupResponse[]>) => void;
|
|
setGroup: (groupId: string, group: GroupResponse) => void;
|
|
setMembers: (groupId: string, members: GroupMemberResponse[], page?: number, pageSize?: number) => void;
|
|
setLoadingGroups: (loading: boolean) => void;
|
|
setLoadingGroup: (groupId: string, loading: boolean) => void;
|
|
setLoadingMembers: (groupId: string, loading: boolean, page?: number, pageSize?: number) => void;
|
|
|
|
// 缓存管理
|
|
invalidateGroupsList: () => void;
|
|
invalidateGroup: (groupId: string) => void;
|
|
invalidateMembers: (groupId: 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 buildMembersKey(groupId: string, page: number = 1, pageSize: number = 20): string {
|
|
return `members:${groupId}:${page}:${pageSize}`;
|
|
}
|
|
|
|
// ==================== 初始状态 ====================
|
|
|
|
const initialState: GroupManagerState = {
|
|
groupsListEntry: null,
|
|
groupsMap: new Map(),
|
|
membersMap: new Map(),
|
|
isLoadingGroups: false,
|
|
loadingGroupIds: new Set(),
|
|
loadingMemberKeys: new Set(),
|
|
pendingRequests: new Map(),
|
|
};
|
|
|
|
// ==================== Store 创建 ====================
|
|
|
|
export type GroupManagerStore = GroupManagerState & GroupManagerActions;
|
|
|
|
export const useGroupManagerStore = create<GroupManagerStore>((set, get) => ({
|
|
// ==================== 初始状态 ====================
|
|
...initialState,
|
|
|
|
// ==================== 获取状态 ====================
|
|
|
|
getGroupsList: () => {
|
|
const entry = get().groupsListEntry;
|
|
if (!entry) return null;
|
|
if (isCacheExpired(entry)) return null;
|
|
return entry.data;
|
|
},
|
|
|
|
getGroup: (groupId: string) => {
|
|
const entry = get().groupsMap.get(groupId);
|
|
if (!entry) return null;
|
|
if (isCacheExpired(entry)) return null;
|
|
return entry.data;
|
|
},
|
|
|
|
getMembers: (groupId: string, page = 1, pageSize = 20) => {
|
|
const key = buildMembersKey(groupId, page, pageSize);
|
|
const entry = get().membersMap.get(key);
|
|
if (!entry) return null;
|
|
if (isCacheExpired(entry)) return null;
|
|
return entry.data;
|
|
},
|
|
|
|
isGroupsListExpired: () => {
|
|
const entry = get().groupsListEntry;
|
|
if (!entry) return true;
|
|
return isCacheExpired(entry);
|
|
},
|
|
|
|
isGroupExpired: (groupId: string) => {
|
|
const entry = get().groupsMap.get(groupId);
|
|
if (!entry) return true;
|
|
return isCacheExpired(entry);
|
|
},
|
|
|
|
isMembersExpired: (groupId: string, page = 1, pageSize = 20) => {
|
|
const key = buildMembersKey(groupId, page, pageSize);
|
|
const entry = get().membersMap.get(key);
|
|
if (!entry) return true;
|
|
return isCacheExpired(entry);
|
|
},
|
|
|
|
isLoadingGroup: (groupId: string) => {
|
|
return get().loadingGroupIds.has(groupId);
|
|
},
|
|
|
|
isLoadingMembers: (groupId: string, page = 1, pageSize = 20) => {
|
|
const key = buildMembersKey(groupId, page, pageSize);
|
|
return get().loadingMemberKeys.has(key);
|
|
},
|
|
|
|
// ==================== 设置状态 ====================
|
|
|
|
setGroupsList: (groups: GroupResponse[]) => {
|
|
set({
|
|
groupsListEntry: createCacheEntry(groups, DEFAULT_TTL.GROUP),
|
|
});
|
|
},
|
|
|
|
setGroupsListEntry: (entry: CacheEntry<GroupResponse[]>) => {
|
|
set({ groupsListEntry: entry });
|
|
},
|
|
|
|
setGroup: (groupId: string, group: GroupResponse) => {
|
|
set(state => {
|
|
const newGroupsMap = new Map(state.groupsMap);
|
|
newGroupsMap.set(groupId, createCacheEntry(group, DEFAULT_TTL.GROUP));
|
|
return { groupsMap: newGroupsMap };
|
|
});
|
|
},
|
|
|
|
setMembers: (groupId: string, members: GroupMemberResponse[], page = 1, pageSize = 20) => {
|
|
const key = buildMembersKey(groupId, page, pageSize);
|
|
set(state => {
|
|
const newMembersMap = new Map(state.membersMap);
|
|
newMembersMap.set(key, createCacheEntry(members, DEFAULT_TTL.GROUP_MEMBERS));
|
|
return { membersMap: newMembersMap };
|
|
});
|
|
},
|
|
|
|
setLoadingGroups: (loading: boolean) => {
|
|
set({ isLoadingGroups: loading });
|
|
},
|
|
|
|
setLoadingGroup: (groupId: string, loading: boolean) => {
|
|
set(state => {
|
|
const newLoadingGroupIds = new Set(state.loadingGroupIds);
|
|
if (loading) {
|
|
newLoadingGroupIds.add(groupId);
|
|
} else {
|
|
newLoadingGroupIds.delete(groupId);
|
|
}
|
|
return { loadingGroupIds: newLoadingGroupIds };
|
|
});
|
|
},
|
|
|
|
setLoadingMembers: (groupId: string, loading: boolean, page = 1, pageSize = 20) => {
|
|
const key = buildMembersKey(groupId, page, pageSize);
|
|
set(state => {
|
|
const newLoadingMemberKeys = new Set(state.loadingMemberKeys);
|
|
if (loading) {
|
|
newLoadingMemberKeys.add(key);
|
|
} else {
|
|
newLoadingMemberKeys.delete(key);
|
|
}
|
|
return { loadingMemberKeys: newLoadingMemberKeys };
|
|
});
|
|
},
|
|
|
|
// ==================== 缓存管理 ====================
|
|
|
|
invalidateGroupsList: () => {
|
|
set({ groupsListEntry: null });
|
|
},
|
|
|
|
invalidateGroup: (groupId: string) => {
|
|
set(state => {
|
|
const newGroupsMap = new Map(state.groupsMap);
|
|
newGroupsMap.delete(groupId);
|
|
|
|
// 删除相关的成员缓存
|
|
const newMembersMap = new Map(state.membersMap);
|
|
for (const key of newMembersMap.keys()) {
|
|
if (key.startsWith(`members:${groupId}:`)) {
|
|
newMembersMap.delete(key);
|
|
}
|
|
}
|
|
|
|
return { groupsMap: newGroupsMap, membersMap: newMembersMap };
|
|
});
|
|
},
|
|
|
|
invalidateMembers: (groupId: string) => {
|
|
set(state => {
|
|
const newMembersMap = new Map(state.membersMap);
|
|
for (const key of newMembersMap.keys()) {
|
|
if (key.startsWith(`members:${groupId}:`)) {
|
|
newMembersMap.delete(key);
|
|
}
|
|
}
|
|
return { membersMap: newMembersMap };
|
|
});
|
|
},
|
|
|
|
invalidateAll: () => {
|
|
set({
|
|
groupsListEntry: null,
|
|
groupsMap: new Map(),
|
|
membersMap: 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,
|
|
groupsMap: new Map(),
|
|
membersMap: new Map(),
|
|
loadingGroupIds: new Set(),
|
|
loadingMemberKeys: new Set(),
|
|
pendingRequests: new Map(),
|
|
});
|
|
},
|
|
})); |