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:
madresebanoo
2026-09-02 11:17:20 +04:30
parent 81332abdb0
commit e10cfba09d
12 changed files with 349 additions and 105 deletions
+22 -4
View File
@@ -2,31 +2,49 @@ import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import { tokenService } from '@/services/api/token-service'
import { syncAuthStatusCookie, clearAuthStatusCookie } from '@/services/wp-sync/auth-status-cookie'
export const useAuthStore = defineStore('auth', () => {
const user = ref(tokenService.getUserInfo())
const isAuthenticated = computed(() => !!tokenService.getToken() && !!user.value)
const role = computed(() => {
// Full set of roles this user holds — access should be additive across all
// of them, never just their first/"primary" one.
const roles = computed(() => {
const u = user.value
if (!u) return null
if (Array.isArray(u.roles) && u.roles.length > 0) return u.roles[0]
return u.role || u.roleName || null
if (!u) return []
if (Array.isArray(u.roles) && u.roles.length > 0) return u.roles
if (u.role) return [u.role]
if (u.roleName) return [u.roleName]
return []
})
// Primary role, used only where a single default is needed (e.g. the
// landing route right after login) — never for access control.
const role = computed(() => roles.value[0] || null)
const setUser = (userData) => {
user.value = userData
tokenService.saveUserInfo(userData)
// Only a real, token-backed session should tell WordPress "logged in" —
// setUser is also used to stash a phone number mid-signup, before any
// token exists, so gate the display-state cookie on the actual token.
if (tokenService.hasToken()) {
syncAuthStatusCookie(role.value)
} else {
clearAuthStatusCookie()
}
}
const clearUser = () => {
user.value = null
tokenService.clearAll()
clearAuthStatusCookie()
}
return {
user,
role,
roles,
isAuthenticated,
setUser,
clearUser,