fix(sidebar): deduplicate menu items for multi-role users
Deploy banu-front / deploy (push) Successful in 1m50s
Deploy banu-front / deploy (push) Successful in 1m50s
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 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ export const buildStudentMenuItems = (route) => [
|
|||||||
icon: 'monitor',
|
icon: 'monitor',
|
||||||
to: { name: 'student-dashboard' },
|
to: { name: 'student-dashboard' },
|
||||||
active: route.name === 'student-dashboard',
|
active: route.name === 'student-dashboard',
|
||||||
|
dedupeKey: 'dashboard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'آموزش',
|
title: 'آموزش',
|
||||||
@@ -25,6 +26,7 @@ export const buildStudentMenuItems = (route) => [
|
|||||||
'student-courses',
|
'student-courses',
|
||||||
'student-course-details',
|
'student-course-details',
|
||||||
].includes(route.name),
|
].includes(route.name),
|
||||||
|
dedupeKey: 'education',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'خدمات',
|
title: 'خدمات',
|
||||||
@@ -55,6 +57,7 @@ export const buildStudentMenuItems = (route) => [
|
|||||||
icon: 'envelope-open',
|
icon: 'envelope-open',
|
||||||
to: { name: 'student-tickets' },
|
to: { name: 'student-tickets' },
|
||||||
active: route.name === 'student-tickets',
|
active: route.name === 'student-tickets',
|
||||||
|
dedupeKey: 'ticket',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -64,6 +67,7 @@ export const buildMissionaryMenuItems = (route) => [
|
|||||||
icon: 'menu',
|
icon: 'menu',
|
||||||
to: { name: 'missionary-dashboard' },
|
to: { name: 'missionary-dashboard' },
|
||||||
active: route.name === 'missionary-dashboard',
|
active: route.name === 'missionary-dashboard',
|
||||||
|
dedupeKey: 'dashboard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'سامانه اعزام',
|
title: 'سامانه اعزام',
|
||||||
@@ -76,12 +80,14 @@ export const buildMissionaryMenuItems = (route) => [
|
|||||||
icon: 'graduation-cap',
|
icon: 'graduation-cap',
|
||||||
to: { name: 'missionary-education' },
|
to: { name: 'missionary-education' },
|
||||||
active: route.name?.startsWith('missionary-education'),
|
active: route.name?.startsWith('missionary-education'),
|
||||||
|
dedupeKey: 'education',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'تیکت',
|
title: 'تیکت',
|
||||||
icon: 'envelope-open',
|
icon: 'envelope-open',
|
||||||
to: { name: 'missionary-tickets' },
|
to: { name: 'missionary-tickets' },
|
||||||
active: route.name === 'missionary-tickets',
|
active: route.name === 'missionary-tickets',
|
||||||
|
dedupeKey: 'ticket',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -91,12 +97,14 @@ export const buildCounselorMenuItems = (route) => [
|
|||||||
icon: 'menu',
|
icon: 'menu',
|
||||||
to: { name: 'counselor-dashboard' },
|
to: { name: 'counselor-dashboard' },
|
||||||
active: route.name === 'counselor-dashboard',
|
active: route.name === 'counselor-dashboard',
|
||||||
|
dedupeKey: 'dashboard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'مشاوره',
|
title: 'مشاوره',
|
||||||
icon: 'chat',
|
icon: 'chat',
|
||||||
to: { name: 'counselor-consultations' },
|
to: { name: 'counselor-consultations' },
|
||||||
active: route.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
|
* 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
|
* 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).
|
* 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) => {
|
export const buildMergedMenuItems = (roles, route) => {
|
||||||
const seen = new Set()
|
const seenRoles = new Set()
|
||||||
|
const seenKeys = new Set()
|
||||||
const items = []
|
const items = []
|
||||||
for (const roleName of roles ?? []) {
|
for (const roleName of roles ?? []) {
|
||||||
const builder = MENU_BUILDERS[roleName]
|
const builder = MENU_BUILDERS[roleName]
|
||||||
if (!builder || seen.has(roleName)) continue
|
if (!builder || seenRoles.has(roleName)) continue
|
||||||
seen.add(roleName)
|
seenRoles.add(roleName)
|
||||||
items.push(...builder(route))
|
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
|
return items
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user