import React, { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { PlusIcon, PencilIcon, TrashIcon } 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 { Secretary, SecretaryPermissions } from '../types'; import { formatDate, maskMobile } from '../lib/utils'; import { ActiveBadge } from '../components/ui/StatusBadge'; import Modal from '../components/ui/Modal'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import PageHeader from '../components/ui/PageHeader'; import { useAuthStore } from '../stores/authStore'; // ── Default permissions & labels ────────────────────────────────────────── const DEFAULT_PERMISSIONS: SecretaryPermissions = { appointments: { view: true, create: false, cancel: false, update_status: false }, addresses: { view: true, create: false, update: false, delete: false }, clinic_info: { view: true, update: false }, insurances: { view: true, create: false, update: false, delete: 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: 'تغییر وضعیت' }, ], }, 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: 'حذف' }, ], }, }; const ALL_ACTIONS = ['view', 'create', 'update', 'delete', 'cancel', 'update_status']; const ACTION_HEADERS = ['مشاهده', 'ایجاد', 'ویرایش', 'حذف', 'لغو', 'تغییر وضعیت']; function PermissionsMatrix({ permissions, onChange, }: { permissions: SecretaryPermissions; onChange: (p: SecretaryPermissions) => void; }) { const toggle = (section: PermSection, action: string) => { const cur = (permissions[section] as Record)[action]; onChange({ ...permissions, [section]: { ...(permissions[section] as Record), [action]: !cur }, }); }; return (
{ACTION_HEADERS.map((h) => ( ))} {(Object.keys(PERMISSION_LABELS) as PermSection[]).map((section) => { const config = PERMISSION_LABELS[section]; const sectionPrm = permissions[section] as Record; return ( {ALL_ACTIONS.map((action) => { const ac = config.actions.find((a) => a.key === action); if (!ac) return ; return ( ); })} ); })}
بخش{h}
{config.label} toggle(section, action)} style={{ width: 16, height: 16, accentColor: 'var(--primary)', cursor: 'pointer' }} />
); } // ── Create form schema ───────────────────────────────────────────────────── const createSchema = z.object({ mobile_number: z.string().min(10, 'شماره موبایل معتبر نیست'), }); type CreateForm = z.infer; // ── Main component ───────────────────────────────────────────────────────── export default function MySecretariesPage() { const qc = useQueryClient(); const { doctorUuid } = useAuthStore(); const [createOpen, setCreateOpen] = useState(false); const [editTarget, setEditTarget] = useState(null); const [editPerms, setEditPerms] = useState(DEFAULT_PERMISSIONS); const [deleteTarget, setDeleteTarget] = useState(null); const { data, isLoading } = useQuery>({ queryKey: ['my-secretaries', doctorUuid], queryFn: () => api.get(`/api/v1/secretaries/${doctorUuid}`), enabled: !!doctorUuid, }); const secretaries = data?.data ?? []; const createForm = useForm({ resolver: zodResolver(createSchema) }); const createMutation = useMutation({ mutationFn: (body: CreateForm) => api.post('/api/v1/secretary', { ...body, doctor_uuid: doctorUuid }), onSuccess: () => { toast.success('منشی اضافه شد'); setCreateOpen(false); createForm.reset(); qc.invalidateQueries({ queryKey: ['my-secretaries'] }); }, onError: (e: any) => toast.error(e.message), }); 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: ['my-secretaries'] }); }, onError: (e: any) => toast.error(e.message), }); const deleteMutation = useMutation({ mutationFn: (uuid: string) => api.delete(`/api/v1/secretary/${uuid}`), onSuccess: () => { toast.success('منشی غیرفعال شد'); setDeleteTarget(null); qc.invalidateQueries({ queryKey: ['my-secretaries'] }); }, onError: (e: any) => toast.error(e.message), }); const openEdit = (s: Secretary) => { setEditTarget(s); setEditPerms(s.permissions ?? DEFAULT_PERMISSIONS); }; return ( <> setCreateOpen(true)}> افزودن منشی } /> {!doctorUuid ? (
پروفایل پزشک یافت نشد
) : isLoading ? (
در حال بارگذاری...
) : secretaries.length === 0 ? (
هنوز منشی‌ای ثبت نشده است
) : (
{secretaries.map((s, i) => ( ))}
نام موبایل وضعیت تاریخ ثبت عملیات
{s.user_name} {maskMobile(s.mobile_number)} {formatDate(Number(s.created_at))}
)} {/* Modal افزودن منشی */} setCreateOpen(false)} title="افزودن منشی جدید">
createMutation.mutate(d))}>
{createForm.formState.errors.mobile_number && ( {createForm.formState.errors.mobile_number.message} )}

کاربری با این شماره در سیستم جستجو شده و به عنوان منشی اضافه می‌شود.

{/* Modal ویرایش دسترسی‌ها */} setEditTarget(null)} title={`دسترسی‌های ${editTarget?.user_name ?? ''}`} size="lg" footer={ <> } > {/* Confirm غیرفعال‌سازی */} deleteTarget && deleteMutation.mutate(deleteTarget.uuid)} onCancel={() => setDeleteTarget(null)} /> ); }