80 lines
2.5 KiB
TypeScript
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),
|
|
},
|
|
});
|
|
},
|
|
}));
|