import React, { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { TrashIcon, PencilIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { toast } from 'sonner'; import { api } from '../lib/api'; import type { ApiResponse, PaginatedResponse } from '../lib/api'; import type { Secretary, SecretaryPermissions } from '../types'; import { formatDate, maskMobile } from '../lib/utils'; import DataTable, { Column } from '../components/ui/DataTable'; import { ActiveBadge } from '../components/ui/StatusBadge'; import Pagination from '../components/ui/Pagination'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import Modal from '../components/ui/Modal'; const DEFAULT_PERMISSIONS: SecretaryPermissions = { appointments: { view: true, create: false, cancel: false, update_status: false }, patients: { view: true, create: false, update: false, delete: false }, payments: { view: true, create: false, update: false, delete: false }, insurances: { view: true, create: false, update: false, delete: false }, addresses: { view: true, create: false, update: false, delete: false }, clinic_info: { view: true, update: false }, }; type PermSection = keyof SecretaryPermissions; const PERMISSION_LABELS: Record = { appointments: { label: 'نوبت‌ها', actions: [ { key: 'view', label: 'مشاهده' }, { key: 'create', label: 'ایجاد' }, { key: 'cancel', label: 'لغو' }, { key: 'update_status', label: 'تغییر وضعیت' }, ], }, patients: { label: 'پرونده بیماران', actions: [ { key: 'view', label: 'مشاهده' }, { key: 'create', label: 'ایجاد' }, { key: 'update', label: 'ویرایش' }, { key: 'delete', label: 'حذف' }, ], }, payments: { label: 'پرداخت‌ها', actions: [ { key: 'view', label: 'مشاهده' }, { key: 'create', label: 'ایجاد' }, { key: 'update', label: 'ویرایش' }, { key: 'delete', label: 'حذف' }, ], }, addresses: { label: 'آدرس‌ها', actions: [ { key: 'view', label: 'مشاهده' }, { key: 'create', label: 'ایجاد' }, { key: 'update', label: 'ویرایش' }, { key: 'delete', label: 'حذف' }, ], }, clinic_info: { label: 'اطلاعات کلینیک', actions: [ { key: 'view', label: 'مشاهده' }, { key: 'update', label: 'ویرایش' }, ], }, insurances: { label: 'بیمه‌ها', actions: [ { key: 'view', label: 'مشاهده' }, { key: 'create', label: 'ایجاد' }, { key: 'update', label: 'ویرایش' }, { key: 'delete', label: 'حذف' }, ], }, }; function PermissionsMatrix({ permissions, onChange, }: { permissions: SecretaryPermissions; onChange: (p: SecretaryPermissions) => void; }) { const toggle = (section: PermSection, action: string) => { const current = (permissions[section] as Record)[action]; onChange({ ...permissions, [section]: { ...(permissions[section] as Record), [action]: !current }, }); }; const allActions = ['view', 'create', 'update', 'delete', 'cancel', 'update_status']; const actionHeaders = ['مشاهده', 'ایجاد', 'ویرایش', 'حذف', 'لغو', 'تغییر وضعیت']; return (
{actionHeaders.map((h) => ( ))} {(Object.keys(PERMISSION_LABELS) as PermSection[]).map((section) => { const config = PERMISSION_LABELS[section]; const sectionPerms = permissions[section] as Record; return ( {allActions.map((action) => { const actionConfig = config.actions.find((a) => a.key === action); if (!actionConfig) { return ; } return ( ); })} ); })}
بخش{h}
{config.label} toggle(section, action)} style={{ width: 16, height: 16, accentColor: 'var(--primary)', cursor: 'pointer' }} />
); } export default function SecretariesPage() { const qc = useQueryClient(); const [page, setPage] = useState(1); const [search, setSearch] = useState(''); const [editTarget, setEditTarget] = useState(null); const [editPerms, setEditPerms] = useState(DEFAULT_PERMISSIONS); const [deleteTarget, setDeleteTarget] = useState(null); const limit = 15; const { data, isLoading } = useQuery({ queryKey: ['secretaries', page, search], queryFn: () => { const params = new URLSearchParams({ page: String(page), limit: String(limit) }); if (search) params.set('search', search); return api.get>(`/api/v1/admin/secretaries?${params}`); }, }); const updatePermsMutation = useMutation({ mutationFn: ({ uuid, permissions }: { uuid: string; permissions: SecretaryPermissions }) => api.patch>(`/api/v1/secretary/${uuid}`, { permissions }), onSuccess: () => { toast.success('دسترسی‌ها بروزرسانی شد'); setEditTarget(null); qc.invalidateQueries({ queryKey: ['secretaries'] }); }, onError: (err: Error) => toast.error(err.message), }); const deleteMutation = useMutation({ mutationFn: (s: Secretary) => api.delete>(`/api/v1/secretary/${s.uuid}`), onSuccess: () => { toast.success('منشی حذف شد'); setDeleteTarget(null); qc.invalidateQueries({ queryKey: ['secretaries'] }); }, onError: (err: Error) => toast.error(err.message), }); const openEdit = (s: Secretary) => { setEditTarget(s); setEditPerms(s.permissions ?? DEFAULT_PERMISSIONS); }; const columns: Column[] = [ { key: 'user_name', header: 'نام', render: (s) => {s.user_name} }, { key: 'mobile_number', header: 'موبایل', render: (s) => {maskMobile(s.mobile_number)} }, { key: 'doctor_name', header: 'پزشک', render: (s) => s.doctor_name }, { key: 'is_active', header: 'وضعیت', render: (s) => }, { key: 'created_at', header: 'تاریخ ثبت', render: (s) => formatDate(s.created_at) }, ]; const items = data?.data ?? []; const total = data?.meta?.totalRecords ?? 0; return (

منشی‌ها

{total} منشی ثبت‌شده
{ setSearch(e.target.value); setPage(1); }} placeholder="جستجو بر اساس نام یا پزشک..." />
columns={columns} data={items} loading={isLoading} emptyMessage="هیچ منشی‌ای یافت نشد" actions={(sec) => ( <> )} />
setEditTarget(null)} footer={ <> } > deleteTarget && deleteMutation.mutate(deleteTarget)} onCancel={() => setDeleteTarget(null)} />
); }