diff --git a/app/dashboard/chat-topics/page.tsx b/app/dashboard/chat-topics/page.tsx new file mode 100644 index 0000000..749e761 --- /dev/null +++ b/app/dashboard/chat-topics/page.tsx @@ -0,0 +1,238 @@ +"use client"; + +import { useState } from "react"; +import { apiFetch, ApiError } from "@/lib/api"; +import { useList } from "@/lib/useResource"; +import { useToast } from "@/components/toast"; +import { DataTable, type Column } from "@/components/DataTable"; +import { + Badge, + Button, + ConfirmDialog, + Field, + Input, + Textarea, + Switch, + Modal, + PageHeader, +} from "@/components/ui"; +import { EditIcon, PlusIcon, TrashIcon } from "@/components/icons"; +import { toFa } from "@/lib/utils"; + +interface ChatTopic { + id: number; + title?: string; + description?: string | null; + order?: number | null; + is_active?: boolean; +} + +export default function ChatTopicsPage() { + const { data, loading, error, reload } = useList("/chat-topics"); + const toast = useToast(); + + const [editing, setEditing] = useState(null); + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [order, setOrder] = useState(""); + const [isActive, setIsActive] = useState(true); + + const [deleting, setDeleting] = useState(null); + const [removing, setRemoving] = useState(false); + + function openCreate() { + setEditing(null); + setTitle(""); + setDescription(""); + setOrder(""); + setIsActive(true); + setOpen(true); + } + function openEdit(row: ChatTopic) { + setEditing(row); + setTitle(row.title ?? ""); + setDescription(row.description ?? ""); + setOrder(row.order != null ? String(row.order) : ""); + setIsActive(row.is_active ?? true); + setOpen(true); + } + + async function save(e: React.FormEvent) { + e.preventDefault(); + setSaving(true); + try { + // chat-topics is a JSON apiResource (no files). + const payload = { + title, + description: description || null, + order: order === "" ? null : Number(order), + is_active: isActive, + }; + if (editing) { + await apiFetch(`/chat-topics/${editing.id}`, { + method: "PUT", + body: payload, + }); + toast.success("موضوع ویرایش شد."); + } else { + await apiFetch("/chat-topics", { method: "POST", body: payload }); + toast.success("موضوع افزوده شد."); + } + setOpen(false); + reload(); + } catch (err) { + toast.error(err instanceof ApiError ? err.message : "خطا در ذخیره‌سازی"); + } finally { + setSaving(false); + } + } + + async function confirmDelete() { + if (!deleting) return; + setRemoving(true); + try { + await apiFetch(`/chat-topics/${deleting.id}`, { method: "DELETE" }); + toast.success("موضوع حذف شد."); + setDeleting(null); + reload(); + } catch (err) { + toast.error(err instanceof ApiError ? err.message : "خطا در حذف"); + } finally { + setRemoving(false); + } + } + + const columns: Column[] = [ + { key: "id", header: "شناسه", render: (r) => toFa(r.id), className: "w-20" }, + { key: "title", header: "عنوان", render: (r) => r.title ?? "—" }, + { + key: "description", + header: "توضیحات", + render: (r) => r.description || "—", + }, + { + key: "order", + header: "ترتیب", + render: (r) => toFa(r.order ?? "—"), + className: "w-20", + }, + { + key: "is_active", + header: "وضعیت", + render: (r) => + r.is_active ? ( + فعال + ) : ( + غیرفعال + ), + }, + ]; + + return ( +
+ } onClick={openCreate}> + موضوع جدید + + } + /> + + } onClick={openCreate}> + موضوع جدید + + } + actions={(row) => ( + <> + + + + )} + /> + + setOpen(false)} + title={editing ? "ویرایش موضوع" : "موضوع جدید"} + footer={ + <> + + + + } + > +
+ + setTitle(e.target.value)} + placeholder="مثلاً هیچ راه واحدی برای مدیتیشن وجود ندارد" + required + autoFocus + /> + + + +