feat: enhance ClinicDetailPage with dynamic tab management in EditModal

- Added initialTab prop to EditModal for setting the active tab on open.
- Updated state management in ClinicDetailPage to handle initial tab for editing.
- Refactored openEdit function to set the initial tab before opening the edit modal.
- Combined specialties, insurances, and services sections in the sidebar for better organization.
- Improved modal rendering using createPortal for better context handling.

style: increase z-index for modal overlay

- Updated the z-index of the overlay class in styles.css to ensure modals appear above other elements.

feat: implement multi-role dashboard functionality

- Created a new prompt for multi-role dashboard implementation.
- Defined roles and their access levels in the admin panel.
- Updated backend to support user role identification and context retrieval.
- Enhanced frontend to dynamically render components based on user roles.
- Added new routes and components for role-specific dashboards.

chore: add skills for admin endpoint and page creation

- Created SKILL.md files for adding admin endpoints and pages.
- Provided templates and guidelines for implementing new admin features.

chore: sync database after entity changes

- Added a new skill for syncing the database after any entity modifications.
This commit is contained in:
hamed
2026-06-11 09:28:51 +03:30
parent af0ae51987
commit e88ae9bf9c
7 changed files with 1475 additions and 955 deletions
@@ -0,0 +1,69 @@
---
name: add-admin-endpoint
description: Add a new paginated admin API endpoint to AdminApiController. Use when the user wants to add a backend admin list, stats, or action endpoint — things like "add an endpoint for X", "create an admin API for Y", "I need a route that lists Z".
---
## Target file
`src/Admin/Controller/AdminApiController.php`
All admin endpoints live here. The class already has `#[IsGranted('ROLE_ADMIN')]` and injects `EntityManagerInterface $em`.
## Checklist
1. **Stats endpoint** (optional but standard): a separate `#[Route('/api/v1/admin/{entity}/stats')]` method that returns counts via raw SQL (`$this->em->getConnection()->fetchOne()`). Return with `$this->success([...])`.
2. **List endpoint**: use QueryBuilder with `->getArrayResult()` — never load full entities for list queries (entity getters may not exist for all fields). Pattern:
```php
#[Route('/api/v1/admin/{entities}', methods: ['GET'])]
public function list{Entity}(Request $request): JsonResponse
{
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(100, max(1, (int) $request->query->get('limit', 15)));
$search = trim((string) $request->query->get('search', ''));
$qb = $this->em->createQueryBuilder()
->select('e.id, e.uuid, e.someField, e.createdAt')
->from(SomeEntity::class, 'e');
if ($search !== '') {
$qb->andWhere('e.name LIKE :s')->setParameter('s', "%$search%");
}
$total = (clone $qb)->select('COUNT(e.id)')->getQuery()->getSingleScalarResult();
$items = $qb
->orderBy('e.id', 'DESC')
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit)
->getQuery()
->getArrayResult();
return $this->paginated($items, (int) $total, $page, $limit);
}
```
3. **Action endpoints** (toggle status, etc.) follow this shape:
```php
#[Route('/api/v1/admin/{entities}/{uuid}/status', methods: ['POST'])]
public function toggle{Entity}Status(string $uuid): JsonResponse
{
$entity = $this->em->getRepository(SomeEntity::class)->findOneBy(['uuid' => $uuid]);
if (!$entity) return $this->error('NOT_FOUND', 'Entity not found', 404);
$entity->setIsActive(!$entity->getIsActive());
$this->em->flush();
return $this->success(['is_active' => $entity->getIsActive()]);
}
```
## Critical rules
- **Always use `getArrayResult()`** for list queries. Never call entity getters inside admin list methods.
- `createdAt` and `updatedAt` are Unix integer timestamps — do not format them in PHP, let the frontend handle it.
- For JOINs to categories (city, state, specialty), use LEFT JOIN in DQL and select the name field directly into the array result.
- Response shape for lists: `$this->paginated($items, $total, $page, $limit)` — frontend reads `data?.data` for items and `data?.meta?.totalRecords` for count.
- Add `use` imports for any new entity class at the top of the file.
- Run `/sync-db` only if a new entity or column was added as part of this change.