diff --git a/assets/admin/components/layout/PurchaseSubscriptionSidebar.test.tsx b/assets/admin/components/layout/PurchaseSubscriptionSidebar.test.tsx
index 46e47a38..885bdb5b 100644
--- a/assets/admin/components/layout/PurchaseSubscriptionSidebar.test.tsx
+++ b/assets/admin/components/layout/PurchaseSubscriptionSidebar.test.tsx
@@ -38,6 +38,20 @@ describe('PurchaseSubscriptionSidebar — settings menu', () => {
useAuthStore.setState({ primaryRole: null, context: null } as any);
});
+ it('«مدیریت نوبت دهی» را با scope منشی به واریانتِ درست لینک میکند', () => {
+ // منشیِ کلینیک → صفحهٔ کلینیک (نه صفحهٔ پزشکِ مستقل که uuid کلینیک را
+ // بهجای doctor میفرستد و ۴۰۴ میگرفت).
+ useAuthStore.setState({
+ primaryRole: 'secretary',
+ context: { scope: 'clinic', permissions: { resources: { appointment_settings: { view: true } } } },
+ } as any);
+ renderWithProviders(, { route: '/admin/settings/appointment-settings' });
+
+ const link = screen.getByRole('link', { name: 'مدیریت نوبت دهی' });
+ expect(link).toHaveAttribute('href', '/admin/settings/appointment-settings');
+ useAuthStore.setState({ primaryRole: null, context: null } as any);
+ });
+
// regression: the settings menu must stay visible on mobile (was `hidden lg:block`,
// which dropped the whole menu below the lg breakpoint → no settings nav on phones).
it('is not hidden on mobile', () => {
diff --git a/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx b/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx
index 21dbf7a6..92648774 100644
--- a/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx
+++ b/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx
@@ -49,17 +49,24 @@ const NAV_ITEMS: NavItem[] = [
export default function PurchaseSubscriptionSidebar({ active }: { active: string }) {
const [query, setQuery] = useState('');
const primaryRole = useAuthStore((s) => s.primaryRole);
+ const scope = useAuthStore((s) => s.context?.scope);
const { can } = usePermissions();
const items = useMemo(
() => NAV_ITEMS
- // منشی: بر اساس مجوز، نه نقش. آیتمِ بدونِ perm/alwaysOpen برای منشی پنهان است.
- .filter((i) =>
- primaryRole === 'secretary'
- ? (i.alwaysOpen || (i.perm ? can(i.perm[0], i.perm[1]) : false))
- : (!i.roles || (primaryRole != null && i.roles.includes(primaryRole))),
- )
+ // منشی: بر اساس مجوز، نه نقش. آیتمِ بدونِ perm/alwaysOpen پنهان است. برای
+ // آیتمهایی که واریانتِ نقشی دارند (مثلِ «نوبتدهی» با doctor vs clinic)، با
+ // scope منشی تطبیق داده میشود تا واریانتِ درست انتخاب شود.
+ .filter((i) => {
+ if (primaryRole !== 'secretary') {
+ return !i.roles || (primaryRole != null && i.roles.includes(primaryRole));
+ }
+ if (i.alwaysOpen) return true;
+ if (!i.perm || !can(i.perm[0], i.perm[1])) return false;
+ if (i.roles) return i.roles.includes(scope === 'clinic' ? 'clinic' : 'doctor');
+ return true;
+ })
.filter((i) => i.label.includes(query.trim())),
- [query, primaryRole, can],
+ [query, primaryRole, scope, can],
);
return (
diff --git a/assets/admin/components/layout/SettingsLayout.tsx b/assets/admin/components/layout/SettingsLayout.tsx
index fd5725bd..fd986793 100644
--- a/assets/admin/components/layout/SettingsLayout.tsx
+++ b/assets/admin/components/layout/SettingsLayout.tsx
@@ -46,11 +46,15 @@ export const SETTINGS_MENU: SettingsMenuItem[] = [
export function menuForRole(
role: string | null | undefined,
can?: (resource: string, action: string) => boolean,
+ scope?: string | null,
): SettingsMenuItem[] {
return SETTINGS_MENU.filter((i) => {
if (role === 'secretary') {
if (i.alwaysOpen) return true;
- return i.perm && can ? can(i.perm[0], i.perm[1]) : false;
+ if (!i.perm || !can || !can(i.perm[0], i.perm[1])) return false;
+ // واریانتِ نقشی (نوبتدهی/پزشکان کلینیک) را با scope منشی تطبیق بده.
+ if (i.roles) return i.roles.includes(scope === 'clinic' ? 'clinic' : 'doctor');
+ return true;
}
return !i.roles || (role != null && i.roles.includes(role));
});
diff --git a/assets/admin/pages/SettingsMenuPage.tsx b/assets/admin/pages/SettingsMenuPage.tsx
index e543eb38..3f2b2e15 100644
--- a/assets/admin/pages/SettingsMenuPage.tsx
+++ b/assets/admin/pages/SettingsMenuPage.tsx
@@ -13,8 +13,9 @@ import { usePermissions } from '../hooks/usePermissions';
*/
export default function SettingsMenuPage() {
const primaryRole = useAuthStore((s) => s.primaryRole);
+ const scope = useAuthStore((s) => s.context?.scope);
const { can } = usePermissions();
- const items = menuForRole(primaryRole, can);
+ const items = menuForRole(primaryRole, can, scope);
return (