fix(secretary): route «نوبت‌دهی» settings to the scope-correct variant

A clinic-scoped secretary opening «مدیریت نوبت دهی» hit 404s
(/api/v1/doctor/{clinicUuid}, available-locations, weekly-schedule): the
permission-only secretary filter ignored each item's `roles`, so BOTH
appointment-settings variants (doctor → /admin/appointment-settings,
clinic → /admin/settings/appointment-settings) showed. Clicking the doctor
variant landed on the personal page, which has no doctor uuid for a clinic
secretary and fell back to the clinic uuid — not a doctor → 404.

Make the secretary settings filter scope-aware in both navs
(PurchaseSubscriptionSidebar + menuForRole): a role-variant item is kept only
when its `roles` matches the secretary's context scope (clinic→'clinic',
else 'doctor'). The clinic page already threads clinic_uuid through
ScheduleSection, so once routed correctly the flow works end-to-end.

Test: appointment variant resolves to the clinic route under clinic scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-23 18:11:41 +03:30
co-authored by Claude Opus 4.8
parent d986cff255
commit 221dce29c3
4 changed files with 35 additions and 9 deletions
@@ -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 (