feat(batch-1): multi-role sidebar, video display, certificate layout, upload progress, counselor access
- roleMenuItems.js: merged menu builder that unions items from all user roles (student + missionary, student + counselor, etc.) additively - auth store: expose `roles` array in addition to singular `role`; wire in WordPress auth-status cookie sync so the public site can show/hide the account button - router guards: use roles.includes() instead of role === for multi-role access - layouts (Student/Counselor/Missionary): delegate menuItems to buildMergedMenuItems so dual-role users see sections from both roles - StudentSessionDetailsPage: contentKind now returns 'video' (not 'link') when session.videoUrl is set; adds embed iframe branch for online sessions - CertificateItem.vue: fix CSS order/alignment for desktop + mobile layout - StudentCertificatesPage.vue: map backend payload fields to component props with Jalaali date formatting - SessionFormPage: upload progress bar (%) during video uploads; embed_code textarea for online sessions (frontend-only; dormant until batch-2 backend migration is deployed) - wp-sync/auth-status-cookie.js: cookie helper for WordPress login-state sync [batch-1-low-risk]
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
// Per-role sidebar sections, kept as plain builder functions so any layout
|
||||
// can request the union of sections for every role a user holds — additive
|
||||
// multi-role access without each layout hardcoding its own single-role list.
|
||||
// Only roles with a registered builder participate in the merge; a role
|
||||
// without one (e.g. admin) contributes nothing and keeps its own standalone
|
||||
// menu untouched.
|
||||
|
||||
export const buildStudentMenuItems = (route) => [
|
||||
{
|
||||
title: 'داشبورد',
|
||||
icon: 'monitor',
|
||||
to: { name: 'student-dashboard' },
|
||||
active: route.name === 'student-dashboard',
|
||||
},
|
||||
{
|
||||
title: 'آموزش',
|
||||
icon: 'graduation-cap',
|
||||
to: { name: 'student-terms' },
|
||||
active: [
|
||||
'student-terms',
|
||||
'student-term-details',
|
||||
'student-lesson-details',
|
||||
'student-session-details',
|
||||
'student-exam',
|
||||
'student-courses',
|
||||
'student-course-details',
|
||||
].includes(route.name),
|
||||
},
|
||||
{
|
||||
title: 'خدمات',
|
||||
icon: 'folder-simple-star',
|
||||
to: { name: 'student-services' },
|
||||
active: route.name === 'student-services',
|
||||
},
|
||||
{
|
||||
title: 'مشاوره',
|
||||
icon: 'chat-teardrop-text',
|
||||
to: { name: 'student-consultants' },
|
||||
active: route.name === 'student-consultants',
|
||||
},
|
||||
{
|
||||
title: 'گواهینامه',
|
||||
icon: 'certificate',
|
||||
to: { name: 'student-certificates' },
|
||||
active: route.name === 'student-certificates',
|
||||
},
|
||||
{
|
||||
title: 'ویرایش پروفایل',
|
||||
icon: 'user-circle-check',
|
||||
to: { name: 'student-profile' },
|
||||
active: route.name === 'student-profile',
|
||||
},
|
||||
{
|
||||
title: 'تیکت',
|
||||
icon: 'envelope-open',
|
||||
to: { name: 'student-tickets' },
|
||||
active: route.name === 'student-tickets',
|
||||
},
|
||||
]
|
||||
|
||||
export const buildMissionaryMenuItems = (route) => [
|
||||
{
|
||||
title: 'پیشخوان',
|
||||
icon: 'menu',
|
||||
to: { name: 'missionary-dashboard' },
|
||||
active: route.name === 'missionary-dashboard',
|
||||
},
|
||||
{
|
||||
title: 'سامانه اعزام',
|
||||
icon: 'user-sound',
|
||||
to: { name: 'missionary-requests' },
|
||||
active: route.name === 'missionary-requests',
|
||||
},
|
||||
{
|
||||
title: 'آموزش من',
|
||||
icon: 'graduation-cap',
|
||||
to: { name: 'missionary-education' },
|
||||
active: route.name?.startsWith('missionary-education'),
|
||||
},
|
||||
{
|
||||
title: 'تیکت',
|
||||
icon: 'envelope-open',
|
||||
to: { name: 'missionary-tickets' },
|
||||
active: route.name === 'missionary-tickets',
|
||||
},
|
||||
]
|
||||
|
||||
export const buildCounselorMenuItems = (route) => [
|
||||
{
|
||||
title: 'پیشخوان',
|
||||
icon: 'menu',
|
||||
to: { name: 'counselor-dashboard' },
|
||||
active: route.name === 'counselor-dashboard',
|
||||
},
|
||||
{
|
||||
title: 'مشاوره',
|
||||
icon: 'chat',
|
||||
to: { name: 'counselor-consultations' },
|
||||
active: route.name === 'counselor-consultations',
|
||||
},
|
||||
]
|
||||
|
||||
const MENU_BUILDERS = {
|
||||
student: buildStudentMenuItems,
|
||||
missionary: buildMissionaryMenuItems,
|
||||
counselor: buildCounselorMenuItems,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
export const buildMergedMenuItems = (roles, route) => {
|
||||
const seen = 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))
|
||||
}
|
||||
return items
|
||||
}
|
||||
Reference in New Issue
Block a user