Files
ftb-project-management/apps/web/stores/useCommentStore.ts

80 lines
2.5 KiB
TypeScript

'use client';
import { create } from 'zustand';
import { api } from '@/lib/api';
import type { CommentEntityType } from '@/components/comment/CommentPanel';
export interface CommentRecord {
id: string;
entityType: CommentEntityType;
entityId: string;
entityVersionId?: string | null;
authorId: string;
content: string;
mentionedMemberIds?: string[];
createdAt: string;
deletedAt?: string | null;
}
interface CreateCommentInput {
actorId: string;
entityType: CommentEntityType;
entityId: string;
entityVersionId?: string | null;
productId?: string | null;
projectId?: string | null;
versionId?: string | null;
content: string;
mentionMemberIds?: string[];
}
interface CommentState {
commentsByKey: Record<string, CommentRecord[]>;
loadingKeys: string[];
fetchComments: (entityType: CommentEntityType, entityId: string) => Promise<void>;
createComment: (input: CreateCommentInput) => Promise<void>;
deleteComment: (entityType: CommentEntityType, entityId: string, id: string, actorId: string) => Promise<void>;
}
export function commentKey(entityType: CommentEntityType, entityId: string) {
return `${entityType}:${entityId}`;
}
export const useCommentStore = create<CommentState>((set, get) => ({
commentsByKey: {},
loadingKeys: [],
fetchComments: async (entityType, entityId) => {
const key = commentKey(entityType, entityId);
set({ loadingKeys: [...get().loadingKeys.filter((item) => item !== key), key] });
const params = new URLSearchParams({ entityType, entityId });
const rows = await api.get<CommentRecord[]>(`/comments?${params.toString()}`);
set({
commentsByKey: { ...get().commentsByKey, [key]: rows },
loadingKeys: get().loadingKeys.filter((item) => item !== key),
});
},
createComment: async (input) => {
const row = await api.post<CommentRecord>('/comments', input);
const key = commentKey(input.entityType, input.entityId);
set({
commentsByKey: {
...get().commentsByKey,
[key]: [...(get().commentsByKey[key] ?? []), row],
},
});
},
deleteComment: async (entityType, entityId, id, actorId) => {
const row = await api.deleteWithBody<CommentRecord>(`/comments/${id}`, { actorId });
const key = commentKey(entityType, entityId);
set({
commentsByKey: {
...get().commentsByKey,
[key]: (get().commentsByKey[key] ?? []).map((item) => item.id === id ? row : item).filter((item) => !item.deletedAt),
},
});
},
}));