feat: refactor clinic management into a dedicated settings tab

- Removed MyClinicPage and redirected its functionality to a new ClinicDoctorsPage.
- Created ClinicDoctorsManager component for managing doctors and invitations within the settings layout.
- Updated backend permissions to allow clinic owners to detach doctors, alongside admins.
- Adjusted API documentation to reflect new permission structure.
- Updated tests to cover new functionality and permissions.
- Modified sidebar and settings menu to reflect the new structure and role-based visibility.
This commit is contained in:
hamed
2026-07-17 21:56:27 +03:30
parent 385b81fae0
commit 6ab7ed38b8
15 changed files with 731 additions and 318 deletions
+15 -3
View File
@@ -341,7 +341,7 @@ class ClinicController extends BaseController
#[OA\Delete(
path: '/api/v1/admin/clinic/{clinicUuid}/doctor/{doctorUuid}',
summary: 'Detach a doctor from a clinic (admin only)',
summary: 'Detach a doctor from a clinic (admin or the clinic owner)',
security: [['bearerAuth' => []]],
parameters: [
new OA\Parameter(name: 'clinicUuid', in: 'path', required: true, schema: new OA\Schema(type: 'string', format: 'uuid')),
@@ -349,18 +349,23 @@ class ClinicController extends BaseController
],
responses: [
new OA\Response(response: 200, description: 'Doctor detached from clinic'),
new OA\Response(response: 403, description: 'Not the clinic owner'),
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
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function detachDoctor(string $clinicUuid, string $doctorUuid, #[CurrentUser] User $user): JsonResponse
{
$clinic = $this->clinicRepo->findByUuid($clinicUuid);
if ($clinic === null) {
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'کلینیک یافت نشد', 404);
}
if (!$this->canManageClinic($clinic, $user)) {
return $this->error(ErrorCodes::ERR_ACCESS_DENIED, 'دسترسی مجاز نیست', 403);
}
$doctor = $this->doctorRepo->findByUuid($doctorUuid);
if ($doctor === null) {
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'پزشک یافت نشد', 404);
@@ -376,6 +381,13 @@ class ClinicController extends BaseController
return $this->success(['message' => 'پزشک از کلینیک جدا شد']);
}
/** ادمین یا مالکِ همان کلینیک اجازه‌ی مدیریت پزشکان را دارد. */
private function canManageClinic(Clinic $clinic, User $user): bool
{
return $user->hasRole('ROLE_ADMIN')
|| ($user->hasRole('ROLE_CLINIC') && $clinic->getUser()->getId() === $user->getId());
}
#[OA\Post(
path: '/file/upload/clinic_pro/clinic/field_image_clinic',
summary: 'Upload a clinic gallery image',