feat: implement OTP login flow and enhance role-based access control
- Added OTP login functionality in driver.mjs to handle user authentication with a fixed code in dev environment. - Enhanced RoleRoute component in App.tsx to support clinic-scoped doctor roles and permissions. - Updated ClinicDoctorsManager component to include pagination and search functionality for better user experience. - Refactored tests for ClinicDoctorsManager to cover new features and ensure proper API mocking. - Adjusted permissions in settingsMenu.ts and PracticeDomainSettingsPage.tsx to align with updated backend requirements. - Created RoleRoute.test.tsx to validate role-based access logic for different user scenarios.
This commit is contained in:
+22
-3
@@ -144,7 +144,7 @@ function PublicRoute({ children }: { children: React.ReactNode }) {
|
||||
return isAuthenticated ? <Navigate to="/admin/dashboard" replace /> : <>{children}</>;
|
||||
}
|
||||
|
||||
function RoleRoute({ roles, blockClinicScope, permission, children }: {
|
||||
export function RoleRoute({ roles, blockClinicScope, permission, children }: {
|
||||
roles: string[];
|
||||
blockClinicScope?: boolean;
|
||||
/**
|
||||
@@ -159,7 +159,23 @@ function RoleRoute({ roles, blockClinicScope, permission, children }: {
|
||||
const context = useAuthStore((s) => s.context);
|
||||
const { can } = usePermissions();
|
||||
if (!primaryRole) return <div style={{ padding: 40, textAlign: 'center' }}>در حال بارگذاری...</div>;
|
||||
if (!roles.includes(primaryRole)) return <Navigate to="/admin/dashboard" replace />;
|
||||
|
||||
/**
|
||||
* پزشکِ عضو در محیط کلینیک برای گِیتِ نقشی همان «clinic» حساب میشود — ولی **فقط**
|
||||
* وقتی صفحه مجوزی اعلام کرده و کلینیک آن مجوز را به او داده باشد.
|
||||
*
|
||||
* بدون این، منو و route با هم نمیخواندند: `settingsMenu` واریانتِ نقشیِ همین پزشک را
|
||||
* با `clinic` تطبیق میداد و آیتم را نشان میداد، ولی اینجا `primaryRole` او `doctor`
|
||||
* بود و کلیک به داشبورد میپرید — یعنی منویی که کار نمیکرد.
|
||||
*
|
||||
* قید «مجوز الزامی» عمدی است: بدون آن، هر صفحهٔ مخصوصِ مالک برای هر پزشکِ عضو باز
|
||||
* میشد. با آن، دسترسی همان چیزی میماند که مالک کلینیک صراحتاً داده است.
|
||||
*/
|
||||
const clinicScopedDoctor = primaryRole === 'doctor' && context?.scope === 'clinic';
|
||||
const roleOk = roles.includes(primaryRole)
|
||||
|| (clinicScopedDoctor && roles.includes('clinic') && !!permission && can(permission[0], permission[1]));
|
||||
|
||||
if (!roleOk) return <Navigate to="/admin/dashboard" replace />;
|
||||
// منشیِ بدون مجوزِ این صفحه نباید با ورود مستقیم URL هم بازش کند.
|
||||
if (primaryRole === 'secretary' && permission && !can(permission[0], permission[1])) {
|
||||
return <Navigate to="/admin/dashboard" replace />;
|
||||
@@ -297,7 +313,10 @@ export default function App() {
|
||||
<Route path="clinic-services/:uuid" element={<RoleRoute roles={['doctor', 'clinic', 'secretary']} blockClinicScope permission={['services', 'view']}><ServiceDetailPage /></RoleRoute>} />
|
||||
<Route path="inventory" element={<RoleRoute roles={['doctor', 'clinic', 'secretary']} blockClinicScope permission={['inventory', 'view']}><InventoryPage /></RoleRoute>} />
|
||||
<Route path="treatment-cases" element={<RoleRoute roles={['doctor', 'clinic', 'secretary']} permission={['treatment', 'view']}><TreatmentCasesPage /></RoleRoute>} />
|
||||
<Route path="settings/practice-domain" element={<RoleRoute roles={['clinic']} permission={['appointment_settings', 'view']}><PracticeDomainSettingsPage /></RoleRoute>} />
|
||||
{/* مجوزش `clinic_info` است نه `appointment_settings`: صفحه حوزهٔ فعالیت را با
|
||||
PATCH /api/v1/clinic/{uuid} ذخیره میکند و backend همانجا `clinic_info.update`
|
||||
را میسنجد. گِیتِ قبلی منبع دیگری را میپرسید و با اجبارِ واقعی نمیخواند. */}
|
||||
<Route path="settings/practice-domain" element={<RoleRoute roles={['clinic']} permission={['clinic_info', 'view']}><PracticeDomainSettingsPage /></RoleRoute>} />
|
||||
<Route path="practice-domains" element={<RoleRoute roles={['admin']}><AdminPracticeDomainsPage /></RoleRoute>} />
|
||||
<Route path="service-categories" element={<RoleRoute roles={['doctor', 'clinic', 'secretary']} blockClinicScope permission={['services', 'view']}><CatalogCategoriesPage /></RoleRoute>} />
|
||||
<Route path="resources" element={<RoleRoute roles={['doctor', 'clinic', 'secretary']} blockClinicScope permission={['resources', 'view']}><ResourcesPage /></RoleRoute>} />
|
||||
|
||||
Reference in New Issue
Block a user