Files
frontend/src/stores/group/groupStore.ts
lafay 5614b4078a
All checks were successful
Frontend CI / ota-android (push) Successful in 13m7s
Frontend CI / build-and-push-web (push) Successful in 16m58s
Frontend CI / build-android-apk (push) Successful in 1h4m18s
feat(profile): add chat settings and language options to profile settings
- 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.
2026-04-01 02:17:36 +08:00

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