From a967479c9fe4394dca67665aa48386fea7aad804 Mon Sep 17 00:00:00 2001 From: madresebanoo Date: Sat, 5 Sep 2026 16:08:59 +0430 Subject: [PATCH] fix(sidebar): deduplicate menu items for multi-role users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a user has both student and missionary roles, common items (dashboard, education, ticket) appeared twice. Added dedupeKey to each item; buildMergedMenuItems now skips items whose key was already added by an earlier role — the primary role's version always wins. Co-Authored-By: Claude Sonnet 4.6 --- src/layouts/roleMenuItems.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/layouts/roleMenuItems.js b/src/layouts/roleMenuItems.js index 0bcd2dd..39f395f 100644 --- a/src/layouts/roleMenuItems.js +++ b/src/layouts/roleMenuItems.js @@ -11,6 +11,7 @@ export const buildStudentMenuItems = (route) => [ icon: 'monitor', to: { name: 'student-dashboard' }, active: route.name === 'student-dashboard', + dedupeKey: 'dashboard', }, { title: 'آموزش', @@ -25,6 +26,7 @@ export const buildStudentMenuItems = (route) => [ 'student-courses', 'student-course-details', ].includes(route.name), + dedupeKey: 'education', }, { title: 'خدمات', @@ -55,6 +57,7 @@ export const buildStudentMenuItems = (route) => [ icon: 'envelope-open', to: { name: 'student-tickets' }, active: route.name === 'student-tickets', + dedupeKey: 'ticket', }, ] @@ -64,6 +67,7 @@ export const buildMissionaryMenuItems = (route) => [ icon: 'menu', to: { name: 'missionary-dashboard' }, active: route.name === 'missionary-dashboard', + dedupeKey: 'dashboard', }, { title: 'سامانه اعزام', @@ -76,12 +80,14 @@ export const buildMissionaryMenuItems = (route) => [ icon: 'graduation-cap', to: { name: 'missionary-education' }, active: route.name?.startsWith('missionary-education'), + dedupeKey: 'education', }, { title: 'تیکت', icon: 'envelope-open', to: { name: 'missionary-tickets' }, active: route.name === 'missionary-tickets', + dedupeKey: 'ticket', }, ] @@ -91,12 +97,14 @@ export const buildCounselorMenuItems = (route) => [ icon: 'menu', to: { name: 'counselor-dashboard' }, active: route.name === 'counselor-dashboard', + dedupeKey: 'dashboard', }, { title: 'مشاوره', icon: 'chat', to: { name: 'counselor-consultations' }, active: route.name === 'counselor-consultations', + dedupeKey: 'consultation', }, ] @@ -110,15 +118,22 @@ const MENU_BUILDERS = { * Union of every panel section unlocked by `roles`, in role order (roles * come back from the API ordered by role id, so a user's base role's * sections lead and each additional role's sections are appended after). + * Items sharing a dedupeKey across roles are merged — only the first + * occurrence is kept (the primary role's version wins). */ export const buildMergedMenuItems = (roles, route) => { - const seen = new Set() + const seenRoles = new Set() + const seenKeys = new Set() const items = [] for (const roleName of roles ?? []) { const builder = MENU_BUILDERS[roleName] - if (!builder || seen.has(roleName)) continue - seen.add(roleName) - items.push(...builder(route)) + if (!builder || seenRoles.has(roleName)) continue + seenRoles.add(roleName) + for (const item of builder(route)) { + if (item.dedupeKey && seenKeys.has(item.dedupeKey)) continue + if (item.dedupeKey) seenKeys.add(item.dedupeKey) + items.push(item) + } } return items }