feat: add doctor invitation modal and appointment creation API
- Implemented InviteDoctorModal component for inviting doctors to clinics. - Updated ClinicDashboard to include a button for inviting doctors and handle modal state. - Added createAppointment API endpoint in AdminApiController for scheduling appointments. - Enhanced ClinicInvitationController to check user access when inviting doctors. - Updated MyAppointmentsController to ensure unique appointment records. - Added seed_test_data.php for populating test data including doctors, clinics, and appointments. - Refactored styles to include new appointment status badges and updated font imports.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\ClinicInvitation\Controller;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\ClinicInvitation\Repository\ClinicDoctorInvitationRepository;
|
||||
use App\ClinicInvitation\Service\ClinicInvitationService;
|
||||
use App\Clinic\Repository\ClinicRepository;
|
||||
@@ -10,6 +11,7 @@ use App\Shared\Exception\AppException;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class ClinicInvitationController extends BaseController
|
||||
@@ -23,14 +25,16 @@ class ClinicInvitationController extends BaseController
|
||||
// ── Admin endpoints ──────────────────────────────────────────────────────
|
||||
|
||||
#[Route('/api/v1/admin/clinic/{uuid}/invite-doctor', methods: ['POST'])]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function inviteDoctor(string $uuid, Request $request): JsonResponse
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function inviteDoctor(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$clinic = $this->clinicRepo->findByUuid($uuid);
|
||||
if (!$clinic) {
|
||||
throw new AppException('ERR_NOT_FOUND_001', 'کلینیک یافت نشد', 404);
|
||||
}
|
||||
|
||||
$this->assertClinicAccess($clinic, $user);
|
||||
|
||||
$body = json_decode($request->getContent(), true) ?? [];
|
||||
$mobile = trim($body['mobile'] ?? '');
|
||||
$name = !empty($body['name']) ? trim($body['name']) : null;
|
||||
@@ -40,20 +44,22 @@ class ClinicInvitationController extends BaseController
|
||||
throw new AppException('ERR_VALIDATION_001', 'شماره موبایل نامعتبر است', 422, 'mobile');
|
||||
}
|
||||
|
||||
$inv = $this->invitationService->invite($clinic, $this->getUser(), $mobile, $name, $specialty);
|
||||
$inv = $this->invitationService->invite($clinic, $user, $mobile, $name, $specialty);
|
||||
|
||||
return $this->success($inv->toArray(), 201);
|
||||
}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/{uuid}/invitations', methods: ['GET'])]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function listInvitations(string $uuid, Request $request): JsonResponse
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function listInvitations(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$clinic = $this->clinicRepo->findByUuid($uuid);
|
||||
if (!$clinic) {
|
||||
throw new AppException('ERR_NOT_FOUND_001', 'کلینیک یافت نشد', 404);
|
||||
}
|
||||
|
||||
$this->assertClinicAccess($clinic, $user);
|
||||
|
||||
$page = max(1, (int) $request->query->get('page', 1));
|
||||
$limit = min(50, max(1, (int) $request->query->get('limit', 20)));
|
||||
|
||||
@@ -76,28 +82,31 @@ class ClinicInvitationController extends BaseController
|
||||
}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/invitation/{invUuid}/resend', methods: ['POST'])]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function resendInvitation(string $invUuid): JsonResponse
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function resendInvitation(string $invUuid, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$inv = $this->invRepo->findOneBy(['uuid' => $invUuid]);
|
||||
if (!$inv) {
|
||||
throw new AppException('ERR_NOT_FOUND_001', 'دعوتنامه یافت نشد', 404);
|
||||
}
|
||||
|
||||
$this->assertClinicAccess($inv->getClinic(), $user);
|
||||
$this->invitationService->resend($inv);
|
||||
|
||||
return $this->success(['message' => 'پیامک مجدداً ارسال شد']);
|
||||
}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/invitation/{invUuid}/status', methods: ['PATCH'])]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function changeInvitationStatus(string $invUuid, Request $request): JsonResponse
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function changeInvitationStatus(string $invUuid, Request $request, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$inv = $this->invRepo->findOneBy(['uuid' => $invUuid]);
|
||||
if (!$inv) {
|
||||
throw new AppException('ERR_NOT_FOUND_001', 'دعوتنامه یافت نشد', 404);
|
||||
}
|
||||
|
||||
$this->assertClinicAccess($inv->getClinic(), $user);
|
||||
|
||||
$body = json_decode($request->getContent(), true) ?? [];
|
||||
$status = $body['status'] ?? '';
|
||||
|
||||
@@ -107,19 +116,31 @@ class ClinicInvitationController extends BaseController
|
||||
}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/invitation/{invUuid}', methods: ['DELETE'])]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function deleteInvitation(string $invUuid): JsonResponse
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function deleteInvitation(string $invUuid, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$inv = $this->invRepo->findOneBy(['uuid' => $invUuid]);
|
||||
if (!$inv) {
|
||||
throw new AppException('ERR_NOT_FOUND_001', 'دعوتنامه یافت نشد', 404);
|
||||
}
|
||||
|
||||
$this->assertClinicAccess($inv->getClinic(), $user);
|
||||
$this->invitationService->delete($inv);
|
||||
|
||||
return $this->success(null, 204);
|
||||
}
|
||||
|
||||
private function assertClinicAccess(\App\Clinic\Entity\Clinic $clinic, User $user): void
|
||||
{
|
||||
if ($user->hasRole('ROLE_ADMIN')) {
|
||||
return;
|
||||
}
|
||||
if ($user->hasRole('ROLE_CLINIC') && $clinic->getUser()->getId() === $user->getId()) {
|
||||
return;
|
||||
}
|
||||
throw new AppException('ERR_ACCESS_DENIED', 'دسترسی ندارید', 403);
|
||||
}
|
||||
|
||||
// ── Public endpoints ──────────────────────────────────────────────────────
|
||||
|
||||
#[Route('/api/v1/clinic-invitation/{token}', methods: ['GET'])]
|
||||
|
||||
Reference in New Issue
Block a user