feat: add doctor_uuid support in authStore and update DoctorDetailPage to prioritize doctorUuid
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
# رفع باگ پروفایل دکتر در context کلینیک — doctor_uuid با clinic_uuid اشتباه گرفته میشود
|
||||
|
||||
## زمینه
|
||||
|
||||
دکتری که عضو چند کلینیک است، در صفحه «انتخاب محیط کاری» میتواند به context کلینیک سوئیچ کند. بعد از سوئیچ، `dbUuid` در authStore برابر **uuid کلینیک** میشود. وقتی دکتر به `/admin/profile` میرود، `DoctorProfilePage` از `dbUuid` به عنوان uuid دکتر استفاده میکند و همه API callها با uuid اشتباه صدا زده میشوند:
|
||||
|
||||
- `GET /api/v1/doctor/c9c6a393-...` (uuid کلینیک) → 404
|
||||
- `GET /api/v1/appointment-slots?doctor_uuid=c9c6a393-...` → 404
|
||||
|
||||
کاربر تست: `09123456783` — دکتر `8b066a5e-3742-4bf7-8087-0b1f8d98de08` (uuid دکتر) که عضو کلینیک `c9c6a393-9182-4388-8cdc-6423026eeb54` است.
|
||||
|
||||
## مشکل / هدف
|
||||
|
||||
`dbUuid` دو معنی متفاوت دارد:
|
||||
- در context مطب شخصی: uuid دکتر ✓
|
||||
- در context کلینیک: uuid کلینیک ✗ (اما `DoctorProfilePage` آن را uuid دکتر فرض میکند)
|
||||
|
||||
راهحل: `doctor_uuid` را به عنوان فیلد جداگانه در `userinfo` و `switch-context` response اضافه کن و در store ذخیره کن. `DoctorProfilePage` باید از `doctorUuid` استفاده کند نه `dbUuid`.
|
||||
|
||||
## فایلهای مرتبط
|
||||
|
||||
| فایل | نقش |
|
||||
|------|-----|
|
||||
| `src/Auth/Controller/AuthController.php` | `userInfo()` خط 516، `switchContext()` خط 571 |
|
||||
| `assets/admin/stores/authStore.ts` | `fetchMe()` و `switchContext()` — خط 86 و 105 |
|
||||
| `assets/admin/pages/DoctorDetailPage.tsx` | `uuid = isOwnProfile ? (dbUuid ?? undefined) : paramUuid` — خط 2162 |
|
||||
| `assets/admin/pages/DoctorProfilePage.tsx` | wrapper که `isOwnProfile` را به DoctorDetailPage پاس میدهد |
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
### Backend — `userInfo()` response (خط 536-548)
|
||||
|
||||
```php
|
||||
return $this->success([
|
||||
'uuid' => $user->getUuid(),
|
||||
'primary_role' => $primaryRole,
|
||||
'db_uuid' => $dbUuid, // ← وقتی context کلینیک است، این uuid کلینیک است
|
||||
'context' => $context,
|
||||
'available_contexts' => $availableContexts,
|
||||
// ← doctor_uuid وجود ندارد
|
||||
]);
|
||||
```
|
||||
|
||||
### Backend — `buildAvailableContexts()` (خط 614-661)
|
||||
|
||||
```php
|
||||
if ($doctor = $this->doctorRepo->findByUser($user)) {
|
||||
$contexts[] = [
|
||||
'type' => 'doctor',
|
||||
'db_uuid' => $doctor->getUuid(), // ← uuid دکتر در این context
|
||||
'role' => 'doctor',
|
||||
];
|
||||
foreach ($this->clinicRepo->findByDoctor($doctor) as $clinic) {
|
||||
$contexts[] = [
|
||||
'type' => 'clinic',
|
||||
'db_uuid' => $clinic->getUuid(), // ← uuid کلینیک در این context
|
||||
'role' => 'clinic',
|
||||
// ← doctor_uuid ندارد
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Frontend — `authStore.ts` (خط 19، 94-95)
|
||||
|
||||
```ts
|
||||
interface AuthState {
|
||||
dbUuid: string | null; // ← فقط یک uuid — در context کلینیک، uuid کلینیک است
|
||||
// ← doctorUuid وجود ندارد
|
||||
}
|
||||
|
||||
// fetchMe:
|
||||
set({
|
||||
dbUuid: d.db_uuid ?? null, // ← uuid کلینیک یا دکتر بسته به context
|
||||
// ← doctorUuid set نمیشود
|
||||
});
|
||||
```
|
||||
|
||||
### Frontend — `DoctorDetailPage.tsx` (خط 2162)
|
||||
|
||||
```tsx
|
||||
const uuid = isOwnProfile ? (dbUuid ?? undefined) : paramUuid;
|
||||
// ← وقتی context کلینیک است: uuid = uuid کلینیک → همه API ها با uuid اشتباه صدا زده میشوند
|
||||
```
|
||||
|
||||
## وظایف
|
||||
|
||||
### ۱. Backend — اضافه کردن `doctor_uuid` به response های auth
|
||||
|
||||
در `src/Auth/Controller/AuthController.php`:
|
||||
|
||||
**الف) `userInfo()` (خط 536):** فیلد `doctor_uuid` را اضافه کن:
|
||||
|
||||
```php
|
||||
$doctor = $this->doctorRepo->findByUser($user);
|
||||
|
||||
return $this->success([
|
||||
'id' => $user->getId(),
|
||||
'uuid' => $user->getUuid(),
|
||||
'mobile_number' => $user->getMobileNumber(),
|
||||
'realName' => $user->getRealName(),
|
||||
'status' => $user->getStatus(),
|
||||
'roles' => $user->getRoles(),
|
||||
'primary_role' => $primaryRole,
|
||||
'db_uuid' => $dbUuid,
|
||||
'db_key' => $dbKey,
|
||||
'doctor_uuid' => $doctor?->getUuid(), // ← اضافه شود
|
||||
'context' => $context,
|
||||
'available_contexts' => $availableContexts,
|
||||
]);
|
||||
```
|
||||
|
||||
**ب) `buildAvailableContexts()` (خط 626):** `doctor_uuid` را به context های کلینیک اضافه کن:
|
||||
|
||||
```php
|
||||
foreach ($this->clinicRepo->findByDoctor($doctor) as $clinic) {
|
||||
$contexts[] = [
|
||||
'type' => 'clinic',
|
||||
'db_uuid' => $clinic->getUuid(),
|
||||
'name' => $clinic->getName() ?? '',
|
||||
'role' => 'clinic',
|
||||
'doctor_uuid' => $doctor->getUuid(), // ← اضافه شود
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
**ج) `switchContext()` response (خط 595):** بدون تغییر — `context` کامل برمیگردد و شامل `doctor_uuid` خواهد بود.
|
||||
|
||||
### ۲. Frontend — اضافه کردن `doctorUuid` به authStore
|
||||
|
||||
در `assets/admin/stores/authStore.ts`:
|
||||
|
||||
**الف) `ContextItem` interface (خط 4):**
|
||||
|
||||
```ts
|
||||
export interface ContextItem {
|
||||
type: 'doctor' | 'clinic';
|
||||
db_uuid: string;
|
||||
name: string;
|
||||
role: 'admin' | 'clinic' | 'doctor' | 'secretary' | 'user';
|
||||
doctor_uuid?: string; // ← اضافه شود — فقط در context های کلینیک
|
||||
permissions?: Record<string, any>;
|
||||
}
|
||||
```
|
||||
|
||||
**ب) `AuthState` interface (خط 12):**
|
||||
|
||||
```ts
|
||||
interface AuthState {
|
||||
// ...
|
||||
dbUuid: string | null;
|
||||
doctorUuid: string | null; // ← اضافه شود — همیشه uuid دکتر، بدون توجه به context
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**ج) مقدار اولیه (خط 62):**
|
||||
|
||||
```ts
|
||||
dbUuid: null,
|
||||
doctorUuid: null, // ← اضافه شود
|
||||
```
|
||||
|
||||
**د) `logout` (خط 72):**
|
||||
|
||||
```ts
|
||||
doctorUuid: null, // ← اضافه شود
|
||||
```
|
||||
|
||||
**ه) `fetchMe` (خط 91):**
|
||||
|
||||
```ts
|
||||
set({
|
||||
dbUuid: d.db_uuid ?? null,
|
||||
doctorUuid: d.doctor_uuid ?? null, // ← اضافه شود
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
**و) `switchContext` (خط 111):**
|
||||
|
||||
```ts
|
||||
set({
|
||||
dbUuid: res.data.db_uuid,
|
||||
doctorUuid: res.data.context?.doctor_uuid ?? get().doctorUuid, // ← context کلینیک doctor_uuid دارد، بقیه همان قبلی
|
||||
dbKey: res.data.db_key,
|
||||
context: res.data.context,
|
||||
primaryRole: res.data.context?.role ?? null,
|
||||
});
|
||||
```
|
||||
|
||||
**ز) `partialize` (خط 121):**
|
||||
|
||||
```ts
|
||||
partialize: (s) => ({
|
||||
// ...
|
||||
doctorUuid: s.doctorUuid, // ← اضافه شود
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
### ۳. Frontend — استفاده از `doctorUuid` در `DoctorDetailPage`
|
||||
|
||||
در `assets/admin/pages/DoctorDetailPage.tsx` خط 2160-2162:
|
||||
|
||||
```tsx
|
||||
const primaryRole = useAuthStore(s => s.primaryRole);
|
||||
const dbUuid = useAuthStore(s => s.dbUuid);
|
||||
const doctorUuid = useAuthStore(s => s.doctorUuid); // ← اضافه شود
|
||||
|
||||
// تغییر خط 2162:
|
||||
const uuid = isOwnProfile
|
||||
? (doctorUuid ?? dbUuid ?? undefined) // ← doctorUuid اولویت دارد
|
||||
: paramUuid;
|
||||
```
|
||||
|
||||
این تضمین میکند که حتی در context کلینیک، uuid دکتر برای همه API callها استفاده شود.
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- **migration لازم نیست** — هیچ entity تغییر نمیکند
|
||||
- `doctorUuid` فقط برای کاربرانی که role دکتر دارند پر میشود — برای admin و clinic-owner خالص `null` است
|
||||
- `get().doctorUuid` در `switchContext` — اگر context جدید `doctor_uuid` نداشت (مثلاً مطب شخصی که `db_uuid` خودش uuid دکتر است)، مقدار قبلی حفظ شود
|
||||
- وقتی context مطب شخصی دکتر است (`type: 'doctor'`)، `db_uuid` خودش uuid دکتر است — `doctor_uuid` جداگانه نیاز نیست اما خوب است همان مقدار ست شود
|
||||
- بعد از تغییر backend: `cache:clear`
|
||||
- بعد از تغییر frontend: `yarn dev` و TypeScript check
|
||||
- مستندات: `docs/api/auth.md` را با فیلد `doctor_uuid` در response های `userinfo` و `switch-context` بهروزرسانی کن
|
||||
- کاربر تست: `09123456783` — doctor_uuid: `8b066a5e-3742-4bf7-8087-0b1f8d98de08`
|
||||
Reference in New Issue
Block a user