import React, { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { PencilIcon, EyeIcon, EyeSlashIcon, PlusIcon, UserGroupIcon } 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 { ClinicStaff } from '../types'; import { formatDate } from '../lib/utils'; import DataTable, { type Column } from '../components/ui/DataTable'; import Modal from '../components/ui/Modal'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import PageHeader from '../components/ui/PageHeader'; import SettingsLayout from '../components/layout/SettingsLayout'; import { ActiveBadge } from '../components/ui/StatusBadge'; import { numericField } from '../lib/forms'; const schema = z.object({ full_name: z.string().min(2, 'نام حداقل ۲ کاراکتر باید باشد'), phone: z.string().optional(), job_title: z.string().optional(), address: z.string().optional(), national_code: z.string().optional(), }); type StaffFormData = z.infer; const EMPTY: ClinicStaff[] = []; export default function StaffPage() { const qc = useQueryClient(); const [createOpen, setCreateOpen] = useState(false); const [editTarget, setEditTarget] = useState(null); const [toggleTarget, setToggleTarget] = useState(null); const { data, isLoading } = useQuery>({ queryKey: ['staff'], queryFn: () => api.get('/api/v1/staff'), }); const staff = data?.data ?? EMPTY; const total = staff.length; const active = staff.filter((s) => s.active).length; const inactive = total - active; const createForm = useForm({ resolver: zodResolver(schema) }); const editForm = useForm({ resolver: zodResolver(schema) }); const createMutation = useMutation({ mutationFn: (body: StaffFormData) => api.post('/api/v1/staff', body), onSuccess: () => { qc.invalidateQueries({ queryKey: ['staff'] }); setCreateOpen(false); createForm.reset(); toast.success('پرسنل ایجاد شد'); }, onError: (err: any) => toast.error(err.message), }); const editMutation = useMutation({ mutationFn: ({ uuid, body }: { uuid: string; body: StaffFormData }) => api.patch(`/api/v1/staff/${uuid}`, body), onSuccess: () => { qc.invalidateQueries({ queryKey: ['staff'] }); setEditTarget(null); toast.success('اطلاعات پرسنل ویرایش شد'); }, onError: (err: any) => toast.error(err.message), }); const toggleMutation = useMutation({ mutationFn: (uuid: string) => api.patch(`/api/v1/staff/${uuid}/toggle`, {}), onSuccess: () => { qc.invalidateQueries({ queryKey: ['staff'] }); setToggleTarget(null); toast.success('وضعیت پرسنل تغییر کرد'); }, onError: (err: any) => toast.error(err.message), }); const openEdit = (s: ClinicStaff) => { editForm.reset({ full_name: s.full_name, phone: s.phone ?? '', job_title: s.job_title ?? '', address: s.address ?? '', national_code: s.national_code ?? '', }); setEditTarget(s); }; const columns: Column[] = [ { key: 'full_name', header: 'پرسنل', render: (s) => (
{s.full_name}
{s.job_title && (
{s.job_title}
)}
), }, { key: 'phone', header: 'تلفن', render: (s) => ( {s.phone ?? '—'} ), }, { key: 'national_code', header: 'کد ملی', render: (s) => ( {s.national_code ?? '—'} ), }, { key: 'active', header: 'وضعیت', render: (s) => , }, { key: 'created_at', header: 'تاریخ ثبت', render: (s) => ( {formatDate(s.created_at)} ), }, { key: 'uuid', header: 'عملیات', render: (s) => (
), }, ]; return ( setCreateOpen(true)}> افزودن پرسنل } /> {/* KPI bar */} {!isLoading && (
{total}
کل پرسنل
{active}
فعال
{inactive}
غیرفعال
)}
{staff.length === 0 && !isLoading ? (
هنوز پرسنلی ثبت نشده
اولین عضو تیم خود را اضافه کنید
) : ( )}
{/* Modal ایجاد */} setCreateOpen(false)} title="افزودن پرسنل جدید">
createMutation.mutate(d))}>
{/* Modal ویرایش */} setEditTarget(null)} title="ویرایش پرسنل">
editTarget && editMutation.mutate({ uuid: editTarget.uuid, body: d }) )} >
{/* Confirm toggle */} toggleTarget && toggleMutation.mutate(toggleTarget.uuid)} onCancel={() => setToggleTarget(null)} loading={toggleMutation.isPending} />
); } function StaffFormFields({ form }: { form: ReturnType> }) { const { register, formState: { errors } } = form; return (
{errors.full_name && {errors.full_name.message}}
); }