feat: add per-doctor permissions management in clinics

- Implement DoctorPermissionsModal for managing doctor permissions in clinics.
- Create usePermissions hook to handle user permissions context.
- Add migration for clinic_doctor_permissions table with default permissions.
- Develop ClinicDoctorPermissionController for handling permissions API.
- Create ClinicDoctorPermission entity to manage permissions data.
- Implement ClinicDoctorPermissionRepository for database interactions.
- Add ClinicDoctorPermissionChecker for permission validation logic.
- Write tests for clinic doctor permissions functionality.
This commit is contained in:
hamed
2026-07-18 09:44:13 +03:30
parent 3a23aa242e
commit e4ddd38f0c
17 changed files with 1504 additions and 44 deletions
@@ -2,7 +2,7 @@ import { useState, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
TrashIcon, EnvelopeIcon, ArrowPathIcon, NoSymbolIcon, EyeIcon,
TrashIcon, EnvelopeIcon, ArrowPathIcon, NoSymbolIcon, EyeIcon, ShieldCheckIcon,
} from '@heroicons/react/24/outline';
import { toast } from 'sonner';
import { api } from '../lib/api';
@@ -10,6 +10,7 @@ import type { ApiResponse, PaginatedResponse } from '../lib/api';
import { formatNumber } from '../lib/utils';
import ConfirmDialog from './ui/ConfirmDialog';
import InviteDoctorModal from './ui/InviteDoctorModal';
import DoctorPermissionsModal from './ui/DoctorPermissionsModal';
const HUES_LIST = [256, 205, 162, 295, 272];
@@ -58,6 +59,7 @@ export default function ClinicDoctorsManager({ clinicUuid, readOnly = false }: {
const [doctorsTab, setDoctorsTab] = useState<'doctors' | 'invitations'>('doctors');
const [inviteOpen, setInviteOpen] = useState(false);
const [detachDoctorConfirm, setDetachDoctorConfirm] = useState<ClinicDoctorItem | null>(null);
const [permissionsFor, setPermissionsFor] = useState<ClinicDoctorItem | null>(null);
const doctorsQ = useQuery({
queryKey: ['clinic-doctors', clinicUuid],
@@ -166,13 +168,22 @@ export default function ClinicDoctorsManager({ clinicUuid, readOnly = false }: {
<EyeIcon style={{ width: 14, height: 14 }} />
</button>
{!readOnly && (
<button
className="mini-btn danger"
title="جداسازی از کلینیک"
onClick={() => setDetachDoctorConfirm(doc)}
>
<TrashIcon style={{ width: 14, height: 14 }} />
</button>
<>
<button
className="mini-btn"
title="مدیریت دسترسی‌ها"
onClick={() => setPermissionsFor(doc)}
>
<ShieldCheckIcon style={{ width: 14, height: 14 }} />
</button>
<button
className="mini-btn danger"
title="جداسازی از کلینیک"
onClick={() => setDetachDoctorConfirm(doc)}
>
<TrashIcon style={{ width: 14, height: 14 }} />
</button>
</>
)}
</div>
</div>
@@ -274,6 +285,16 @@ export default function ClinicDoctorsManager({ clinicUuid, readOnly = false }: {
onCancel={() => setDetachDoctorConfirm(null)}
/>
{/* Per-doctor clinic permissions */}
{permissionsFor && (
<DoctorPermissionsModal
clinicUuid={clinicUuid}
doctorUuid={permissionsFor.uuid}
doctorName={permissionsFor.name}
onClose={() => setPermissionsFor(null)}
/>
)}
{/* Invite doctor modal */}
{inviteOpen && clinicUuid && (
<InviteDoctorModal