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: 'specially_doctor', label: 'تخصص‌ها' }, { key: 'doctor_services', label: 'خدمات پزشک' }, { key: 'insurance_type', label: 'نوع بیمه' }, { key: 'supplementary_insurance', label: 'بیمه تکمیلی' }, { key: 'tag', label: 'تگ‌های بلاگ' }, ]; const schema = z.object({ label: z.string().min(1, 'نام الزامی است'), parent_id: 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', { label: d.label, bundle: activeTab, ...(d.parent_id ? { parent_id: parseInt(d.parent_id) } : {}), }), onSuccess: () => { toast.success('دسته‌بندی اضافه شد'); setAddOpen(false); reset(); qc.invalidateQueries({ queryKey: ['categories', activeTab] }); }, onError: (err: Error) => toast.error(err.message), }); const updateMutation = useMutation({ mutationFn: ({ id, d }: { id: number; d: FormData }) => api.patch>(`/api/v1/category/${id}`, { label: d.label }), 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.id}`), onSuccess: () => { toast.success('دسته‌بندی حذف شد'); setDeleteTarget(null); qc.invalidateQueries({ queryKey: ['categories', activeTab] }); }, onError: (err: Error) => toast.error(err.message), }); const openEdit = (c: Category) => { setEditTarget(c); setValue('label', c.label); }; const allItems = data?.data?.data ?? []; const filtered = search ? allItems.filter((c) => c.label.includes(search)) : allItems; const columns: Column[] = [ { key: 'label', header: 'نام', render: (c) => {c.label} }, { key: 'bundle', header: 'نوع', render: (c) => ( {c.bundle} ), }, { key: 'status', header: 'وضعیت', render: (c) => ( {c.status === 1 ? 'فعال' : 'غیرفعال'} ), }, ]; 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) => ( <> )} />
{/* Add Modal */} t.key === activeTab)?.label}`} onClose={() => { setAddOpen(false); reset(); }} footer={ <> } >
createMutation.mutate(d))} className="space-y-4">
{errors.label &&

{errors.label.message}

}
{activeTab === 'city' && (
)}
{/* Edit Modal */} { setEditTarget(null); reset(); }} footer={ <> } >
editTarget && updateMutation.mutate({ id: editTarget.id, d }))} className="space-y-4">
{errors.label &&

{errors.label.message}

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