feat(web): role groups, last seen and unread markers in members, channels and spaces; lock channels without keys
This commit is contained in:
1 parent
5043c798ff
commit
d1ff8bab7d
23 files changed
+381
-34
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
/** 每个频道「读到哪里」,只存在这台设备的浏览器里(只是便利功能,取不到就当全读过) */
|
||||
const STORAGE_KEY = 'wd.readState';
|
||||
|
||||
type Reads = Record<string, number>;
|
||||
|
||||
function load(): Reads {
|
||||
try {
|
||||
const parsed: unknown = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '{}');
|
||||
return parsed && typeof parsed === 'object' ? parsed as Reads : {};
|
||||
} catch { return {}; }
|
||||
}
|
||||
function save(reads: Reads) {
|
||||
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(reads)); } catch { /* 隐私模式等:这次会话内仍然有效 */ }
|
||||
}
|
||||
|
||||
/** 空间级别读到的日志序号:别的空间 last_seq 超过它,就说明有新动静 */
|
||||
export const spaceSeqKey = (spaceId: string) => `seq:${spaceId}`;
|
||||
export const readKey =(spaceId: string, threadId: string) => `${spaceId}:${threadId}`;
|
||||
|
||||
interface ReadState {
|
||||
reads: Reads;
|
||||
/** 把频道标记为读到 ts;只前进不后退 */
|
||||
markRead: (key: string, ts: number) => void;
|
||||
/** 第一次见到的频道:以此刻为基线,不把历史消息算成未读 */
|
||||
baseline: (key: string, value?: number) => void;
|
||||
}
|
||||
|
||||
export const useReadState = create<ReadState>((set, get) => ({
|
||||
reads: load(),
|
||||
markRead: (key, ts) => {
|
||||
const current = get().reads[key];
|
||||
if (current !== undefined && current >= ts) return;
|
||||
const reads = { ...get().reads, [key]: ts };
|
||||
save(reads); set({ reads });
|
||||
},
|
||||
baseline: (key, value = Date.now()) => {
|
||||
if (get().reads[key] !== undefined) return;
|
||||
const reads = { ...get().reads, [key]: value };
|
||||
save(reads); set({ reads });
|
||||
},
|
||||
}));
|
||||
@@ -16,6 +16,8 @@ export interface WorkspaceData {
|
||||
connection: ConnectionState;
|
||||
channel: ChannelInfo | null;
|
||||
threads: ThreadInfo[];
|
||||
/** 没有密钥、不能读写的频道 id */
|
||||
lockedThreads: string[];
|
||||
groups: ChannelGroupInfo[];
|
||||
roles: RoleInfo[];
|
||||
folders: FolderInfo[];
|
||||
@@ -35,6 +37,7 @@ export const initialData: WorkspaceData = {
|
||||
connection: 'offline',
|
||||
channel: null,
|
||||
threads: [],
|
||||
lockedThreads: [],
|
||||
groups: [],
|
||||
roles: [],
|
||||
folders: [],
|
||||
@@ -81,6 +84,8 @@ export function reduce(s: WorkspaceData, e: WorkspaceEvent): WorkspaceData {
|
||||
return { ...s, people: profiles, threads: e.state.channels.map(c => ({ ...c, groupId: c.groupId ?? undefined })), groups: e.state.groups, roles: e.state.roles ?? [],
|
||||
folders: e.state.folders.map(f => ({ ...f, parentId: f.parentId ?? undefined })), locations, authors, byId };
|
||||
}
|
||||
case 'access':
|
||||
return { ...s, lockedThreads: e.locked };
|
||||
case 'reset':
|
||||
return { ...initialData, connection: s.connection };
|
||||
case 'error':
|
||||
|
||||
Reference in new issue
Block a user