import React, { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { TrashIcon, PlusIcon, PencilIcon } from '@heroicons/react/24/outline'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { toast } from 'sonner'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import type { Category, CategoryBundle } from '../types'; import PageHeader from '../components/ui/PageHeader'; import DataTable, { Column } from '../components/ui/DataTable'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import Modal from '../components/ui/Modal'; const TABS: { key: CategoryBundle; label: string }[] = [ { key: 'state', label: 'استان‌ها' }, { key: 'city', label: 'شهرها' }, { key: 'specialty', label: 'تخصص‌ها' }, { key: 'doctor_service', label: 'خدمات پزشک' }, { key: 'insurance_type', label: 'نوع بیمه' }, { key: 'supplementary_insurance', label: 'بیمه تکمیلی' }, { key: 'tag', label: 'تگ‌های بلاگ' }, ]; const schema = z.object({ name: z.string().min(1, 'نام الزامی است'), code: z.string().optional(), parent_uuid: z.string().optional(), }); type FormData = z.infer; export default function CategoriesPage() { const qc = useQueryClient(); const [activeTab, setActiveTab] = useState('state'); const [search, setSearch] = useState(''); const [addOpen, setAddOpen] = useState(false); const [editTarget, setEditTarget] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const { data, isLoading } = useQuery({ queryKey: ['categories', activeTab], queryFn: () => api.get>(`/api/v1/categorys/${activeTab}`), }); const { register, handleSubmit, reset, setValue, formState: { errors, isSubmitting } } = useForm({ resolver: zodResolver(schema), }); const createMutation = useMutation({ mutationFn: (d: FormData) => api.post>('/api/v1/category', { ...d, bundle: activeTab }), onSuccess: () => { toast.success('دسته‌بندی اضافه شد'); setAddOpen(false); reset(); qc.invalidateQueries({ queryKey: ['categories', activeTab] }); }, onError: (err: Error) => toast.error(err.message), }); const updateMutation = useMutation({ mutationFn: ({ uuid, d }: { uuid: string; d: FormData }) => api.patch>(`/api/v1/category/${uuid}`, d), onSuccess: () => { toast.success('دسته‌بندی بروزرسانی شد'); setEditTarget(null); reset(); qc.invalidateQueries({ queryKey: ['categories', activeTab] }); }, onError: (err: Error) => toast.error(err.message), }); const deleteMutation = useMutation({ mutationFn: (c: Category) => api.delete>(`/api/v1/category/${c.uuid}`), onSuccess: () => { toast.success('دسته‌بندی حذف شد'); setDeleteTarget(null); qc.invalidateQueries({ queryKey: ['categories', activeTab] }); }, onError: (err: Error) => toast.error(err.message), }); const openEdit = (c: Category) => { setEditTarget(c); setValue('name', c.name); setValue('code', c.code ?? ''); setValue('parent_uuid', c.parent_uuid ?? ''); }; const allItems = data?.data ?? []; const filtered = search ? allItems.filter((c) => c.name.includes(search)) : allItems; const columns: Column[] = [ { key: 'name', header: 'نام', render: (c) => {c.name} }, { key: 'code', header: 'کد', render: (c) => c.code ? {c.code} : '—' }, { key: 'parent_name', header: 'والد', render: (c) => c.parent_name ?? '—' }, ]; const handleTabChange = (tab: CategoryBundle) => { setActiveTab(tab); setSearch(''); }; return (
setAddOpen(true)} className="flex items-center gap-2 px-4 py-2 bg-primary-600 text-white text-sm rounded-[10px] hover:bg-primary-700 transition-colors"> افزودن } />
{TABS.map((t) => ( ))}
columns={columns} data={filtered} loading={isLoading} searchValue={search} onSearchChange={setSearch} searchPlaceholder="جستجو..." emptyMessage="هیچ موردی یافت نشد" actions={(cat) => ( <> )} />
t.key === activeTab)?.label}`} onClose={() => { setAddOpen(false); reset(); }} footer={ <> } >
createMutation.mutate(d))} className="space-y-4">
{errors.name &&

{errors.name.message}

}
{(activeTab === 'city') && (
)}
{ setEditTarget(null); reset(); }} footer={ <> } >
editTarget && updateMutation.mutate({ uuid: editTarget.uuid, d }))} className="space-y-4">
{errors.name &&

{errors.name.message}

}
deleteTarget && deleteMutation.mutate(deleteTarget)} onCancel={() => setDeleteTarget(null)} />
); }