TorbatYar/frontend/modules/workspace/components/CommentThread.tsx
Mortezakoohjani a483b47369 feat(workspace): complete production workspace and content operations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-12 11:54:17 +03:30

82 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Button, Textarea } from "@/components/ds";
import { workspaceApi } from "@/modules/workspace/services/workspace-api";
import { displayPerson, formatWhen } from "@/modules/workspace/labels";
import { WorkspacePageError, WorkspacePageLoader } from "@/modules/workspace/pages/shared";
export function CommentThread({
tenantId,
workHubId,
subjectType,
subjectId,
}: {
tenantId: string;
workHubId: string;
subjectType: "project" | "task" | "content" | "team";
subjectId: string;
}) {
const queryClient = useQueryClient();
const [body, setBody] = useState("");
const comments = useQuery({
queryKey: ["workspace", tenantId, "comments", subjectType, subjectId],
queryFn: () =>
workspaceApi.comments.list(tenantId, {
work_hub_id: workHubId,
subject_type: subjectType,
subject_id: subjectId,
}),
});
const create = useMutation({
mutationFn: () =>
workspaceApi.comments.create(tenantId, {
work_hub_id: workHubId,
subject_type: subjectType,
subject_id: subjectId,
body,
}),
onSuccess: () => {
setBody("");
toast.success("نظر ثبت شد");
void queryClient.invalidateQueries({ queryKey: ["workspace", tenantId, "comments"] });
void queryClient.invalidateQueries({ queryKey: ["workspace", tenantId, "activity"] });
},
onError: (error) => toast.error(error instanceof Error ? error.message : "ثبت نظر ناموفق بود"),
});
if (comments.isLoading) return <WorkspacePageLoader label="در حال بارگذاری گفتگو…" />;
if (comments.error) return <WorkspacePageError error={comments.error} onRetry={() => comments.refetch()} />;
return (
<div className="space-y-3">
<h3 className="text-sm font-semibold text-secondary">گفتگو</h3>
<div className="space-y-2">
{(comments.data ?? []).length === 0 ? (
<p className="text-sm text-[var(--muted)]">هنوز نظری ثبت نشده است. برای اشاره به فرد از @نام استفاده کنید.</p>
) : (
(comments.data ?? []).map((item) => (
<div key={String(item.id)} className="rounded-xl border border-[var(--border)] bg-[var(--surface)] p-3">
<p className="text-xs text-[var(--muted)]">
{displayPerson(String(item.author_user_id || ""))} · {formatWhen(String(item.created_at || ""))}
</p>
<p className="mt-1 text-sm text-secondary">{String(item.body || "")}</p>
</div>
))
)}
</div>
<Textarea
value={body}
onChange={(event) => setBody(event.target.value)}
placeholder="نظر خود را بنویسید…"
rows={3}
/>
<Button type="button" disabled={!body.trim() || create.isPending} onClick={() => create.mutate()}>
ثبت نظر
</Button>
</div>
);
}