diff --git a/assets/admin/pages/ClinicDetailPage.tsx b/assets/admin/pages/ClinicDetailPage.tsx index 2295551b..44563675 100644 --- a/assets/admin/pages/ClinicDetailPage.tsx +++ b/assets/admin/pages/ClinicDetailPage.tsx @@ -480,6 +480,7 @@ export default function ClinicDetailPage() { const [editingClinicAddr, setEditingClinicAddr] = useState(null); const [deleteAddrConfirm, setDeleteAddrConfirm] = useState(null); const [deleteImageConfirm, setDeleteImageConfirm] = useState(null); + const [detachDoctorConfirm, setDetachDoctorConfirm] = useState(null); const emptyAddrForm = { name: '', address: '', telephone: '', province_id: null as number | null, city_id: null as number | null, latitude: null as number | null, longitude: null as number | null }; const [addrForm, setAddrForm] = useState(emptyAddrForm); @@ -587,6 +588,17 @@ export default function ClinicDetailPage() { onError: (e: Error) => toast.error(e.message), }); + const detachDoctorMut = useMutation({ + mutationFn: (doctorUuid: string) => + api.delete>(`/api/v1/admin/clinic/${uuid}/doctor/${doctorUuid}`), + onSuccess: () => { + toast.success('پزشک از کلینیک جدا شد'); + qc.invalidateQueries({ queryKey: ['clinic-doctors', uuid] }); + qc.invalidateQueries({ queryKey: ['clinic-detail', uuid] }); + }, + onError: (e: Error) => toast.error(e.message), + }); + const handleLogoUpload = async (file: File) => { setLogoUploading(true); try { @@ -825,6 +837,13 @@ export default function ClinicDetailPage() { > + ); @@ -1195,6 +1214,21 @@ export default function ClinicDetailPage() { onCancel={() => setDeleteImageConfirm(null)} /> + {/* Detach Doctor From Clinic Confirm */} + { + if (detachDoctorConfirm) detachDoctorMut.mutate(detachDoctorConfirm.uuid); + setDetachDoctorConfirm(null); + }} + onCancel={() => setDetachDoctorConfirm(null)} + /> + {/* Edit modal — portal to escape Leaflet transform context */} {editOpen && createPortal( []]], + parameters: [ + new OA\Parameter(name: 'clinicUuid', in: 'path', required: true, schema: new OA\Schema(type: 'string', format: 'uuid')), + new OA\Parameter(name: 'doctorUuid', in: 'path', required: true, schema: new OA\Schema(type: 'string', format: 'uuid')), + ], + responses: [ + new OA\Response(response: 200, description: 'Doctor detached from clinic'), + new OA\Response(response: 404, description: 'Clinic or doctor not found'), + ] + )] + #[Route('/api/v1/admin/clinic/{clinicUuid}/doctor/{doctorUuid}', methods: ['DELETE'])] + #[IsGranted('ROLE_ADMIN')] + public function detachDoctor(string $clinicUuid, string $doctorUuid): JsonResponse + { + $clinic = $this->clinicRepo->findByUuid($clinicUuid); + if ($clinic === null) { + return $this->error(ErrorCodes::ERR_VALIDATION_002, 'کلینیک یافت نشد', 404); + } + + $doctor = $this->doctorRepo->findByUuid($doctorUuid); + if ($doctor === null) { + return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'پزشک یافت نشد', 404); + } + + if (!$clinic->hasDoctor($doctor)) { + return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'این پزشک به کلینیک متصل نیست', 404); + } + + $clinic->removeDoctor($doctor); + $this->clinicRepo->save($clinic); + + return $this->success(['message' => 'پزشک از کلینیک جدا شد']); + } + #[OA\Post( path: '/file/upload/clinic_pro/clinic/field_image_clinic', summary: 'Upload a clinic gallery image', diff --git a/src/Clinic/Entity/Clinic.php b/src/Clinic/Entity/Clinic.php index cc7d024d..12e93773 100644 --- a/src/Clinic/Entity/Clinic.php +++ b/src/Clinic/Entity/Clinic.php @@ -147,6 +147,16 @@ class Clinic public function getCreatedAt(): int { return $this->createdAt; } public function getUpdatedAt(): int { return $this->updatedAt; } public function getDoctors(): Collection { return $this->doctors; } + + public function hasDoctor(Doctor $doctor): bool { return $this->doctors->contains($doctor); } + + public function removeDoctor(Doctor $doctor): self + { + $this->doctors->removeElement($doctor); + $this->touch(); + return $this; + } + public function getSpecialties(): Collection { return $this->specialties; } public function getServices(): Collection { return $this->services; } public function getInsurances(): Collection { return $this->insurances; }