fix signin signout and apply the new style

This commit is contained in:
root
2026-05-24 23:58:54 -04:00
parent bf97a072dd
commit 9bd0938951
68 changed files with 851 additions and 200 deletions
+78 -42
View File
@@ -49,6 +49,15 @@ type FleetDict = {
manual: string
automatic: string
fuelType: string
pickupLocations: string
pickupLocationsPlaceholder: string
dropoffLocations: string
dropoffLocationsPlaceholder: string
locationHint: string
allowDifferentDropoff: string
dropoffLocationsRequired: string
sameDropoffOnly: string
differentDropoffAvailable: string
photosLabel: string
clickToAddPhotos: string
addMorePhotos: string
@@ -323,20 +332,20 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
settings: 'Settings',
},
titles: {
'/dashboard': 'Dashboard',
'/dashboard/fleet': 'Fleet Management',
'/dashboard/reservations': 'Booking',
'/dashboard/reservations/new': 'Book Car',
'/dashboard/online-reservations': 'Online Reservations',
'/dashboard/customers': 'Customers',
'/dashboard/offers': 'Offers',
'/dashboard/team': 'Team',
'/dashboard/reports': 'Reports',
'/dashboard/subscription': 'Subscription',
'/dashboard/billing': 'Customer Billing',
'/dashboard/contracts': 'Contracts',
'/dashboard/notifications': 'Notifications',
'/dashboard/settings': 'Settings',
'/': 'Dashboard',
'/fleet': 'Fleet Management',
'/reservations': 'Booking',
'/reservations/new': 'Book Car',
'/online-reservations': 'Online Reservations',
'/customers': 'Customers',
'/offers': 'Offers',
'/team': 'Team',
'/reports': 'Reports',
'/subscription': 'Subscription',
'/billing': 'Customer Billing',
'/contracts': 'Contracts',
'/notifications': 'Notifications',
'/settings': 'Settings',
},
notifications: 'Notifications',
noNewNotifications: 'No new notifications',
@@ -390,6 +399,15 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
manual: 'Manual',
automatic: 'Automatic',
fuelType: 'Fuel Type',
pickupLocations: 'Pick-up locations',
pickupLocationsPlaceholder: 'e.g. Casablanca Airport, Casablanca Downtown',
dropoffLocations: 'Drop-off locations',
dropoffLocationsPlaceholder: 'e.g. Rabat Downtown, Marrakech Center',
locationHint: 'Separate multiple locations with commas.',
allowDifferentDropoff: 'Allow different drop-off location',
dropoffLocationsRequired: 'Please add at least one drop-off location when different drop-off is enabled.',
sameDropoffOnly: 'Same drop-off only',
differentDropoffAvailable: 'Different drop-off available',
photosLabel: 'Photos (up to 10)',
clickToAddPhotos: 'Click to add photos',
addMorePhotos: 'Add more photos',
@@ -666,20 +684,20 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
settings: 'Paramètres',
},
titles: {
'/dashboard': 'Tableau de bord',
'/dashboard/fleet': 'Gestion de flotte',
'/dashboard/reservations': 'Réservations',
'/dashboard/reservations/new': 'Réserver une voiture',
'/dashboard/online-reservations': 'Réservations en ligne',
'/dashboard/customers': 'Clients',
'/dashboard/offers': 'Offres',
'/dashboard/team': 'Équipe',
'/dashboard/reports': 'Rapports',
'/dashboard/subscription': 'Abonnement',
'/dashboard/billing': 'Facturation clients',
'/dashboard/contracts': 'Contrats',
'/dashboard/notifications': 'Notifications',
'/dashboard/settings': 'Paramètres',
'/': 'Tableau de bord',
'/fleet': 'Gestion de flotte',
'/reservations': 'Réservations',
'/reservations/new': 'Réserver une voiture',
'/online-reservations': 'Réservations en ligne',
'/customers': 'Clients',
'/offers': 'Offres',
'/team': 'Équipe',
'/reports': 'Rapports',
'/subscription': 'Abonnement',
'/billing': 'Facturation clients',
'/contracts': 'Contrats',
'/notifications': 'Notifications',
'/settings': 'Paramètres',
},
notifications: 'Notifications',
noNewNotifications: 'Aucune nouvelle notification',
@@ -733,6 +751,15 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
manual: 'Manuelle',
automatic: 'Automatique',
fuelType: 'Carburant',
pickupLocations: 'Lieux de départ',
pickupLocationsPlaceholder: 'ex. Aéroport de Casablanca, Centre-ville de Casablanca',
dropoffLocations: 'Lieux de retour',
dropoffLocationsPlaceholder: 'ex. Centre-ville de Rabat, Centre de Marrakech',
locationHint: 'Séparez plusieurs lieux par des virgules.',
allowDifferentDropoff: 'Autoriser un lieu de retour différent',
dropoffLocationsRequired: 'Ajoutez au moins un lieu de retour lorsque le retour différent est activé.',
sameDropoffOnly: 'Retour au même lieu uniquement',
differentDropoffAvailable: 'Retour différent disponible',
photosLabel: "Photos (jusqu'à 10)",
clickToAddPhotos: 'Cliquer pour ajouter des photos',
addMorePhotos: "Ajouter d'autres photos",
@@ -1009,20 +1036,20 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
settings: 'الإعدادات',
},
titles: {
'/dashboard': 'لوحة التحكم',
'/dashboard/fleet': 'إدارة الأسطول',
'/dashboard/reservations': 'الحجوزات',
'/dashboard/reservations/new': 'حجز سيارة',
'/dashboard/online-reservations': 'الحجوزات الإلكترونية',
'/dashboard/customers': 'العملاء',
'/dashboard/offers': 'العروض',
'/dashboard/team': 'الفريق',
'/dashboard/reports': 'التقارير',
'/dashboard/subscription': 'الاشتراك',
'/dashboard/billing': 'فوترة العملاء',
'/dashboard/contracts': 'العقود',
'/dashboard/notifications': 'الإشعارات',
'/dashboard/settings': 'الإعدادات',
'/': 'لوحة التحكم',
'/fleet': 'إدارة الأسطول',
'/reservations': 'الحجوزات',
'/reservations/new': 'حجز سيارة',
'/online-reservations': 'الحجوزات الإلكترونية',
'/customers': 'العملاء',
'/offers': 'العروض',
'/team': 'الفريق',
'/reports': 'التقارير',
'/subscription': 'الاشتراك',
'/billing': 'فوترة العملاء',
'/contracts': 'العقود',
'/notifications': 'الإشعارات',
'/settings': 'الإعدادات',
},
notifications: 'الإشعارات',
noNewNotifications: 'لا توجد إشعارات جديدة',
@@ -1076,6 +1103,15 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
manual: 'يدوي',
automatic: 'أوتوماتيكي',
fuelType: 'نوع الوقود',
pickupLocations: 'مواقع الاستلام',
pickupLocationsPlaceholder: 'مثال: مطار الدار البيضاء، وسط الدار البيضاء',
dropoffLocations: 'مواقع الإرجاع',
dropoffLocationsPlaceholder: 'مثال: وسط الرباط، مركز مراكش',
locationHint: 'افصل بين المواقع المتعددة بفواصل.',
allowDifferentDropoff: 'السماح بموقع إرجاع مختلف',
dropoffLocationsRequired: 'أضف موقع إرجاع واحداً على الأقل عند تفعيل الإرجاع المختلف.',
sameDropoffOnly: 'الإرجاع في نفس الموقع فقط',
differentDropoffAvailable: 'الإرجاع المختلف متاح',
photosLabel: 'الصور (حتى 10)',
clickToAddPhotos: 'انقر لإضافة صور',
addMorePhotos: 'إضافة المزيد من الصور',
@@ -23,6 +23,7 @@ import {
import { useDashboardI18n } from '@/components/I18nProvider'
import { marketplaceUrl } from '@/lib/urls'
import { EMPLOYEE_PROFILE_KEY, EMPLOYEE_TOKEN_KEY, apiFetch } from '@/lib/api'
import { toDashboardAppPath } from '@/lib/dashboardPaths'
import { SHARED_LANGUAGE_KEY, readCurrentUserScopedPreference } from '@/lib/preferences'
interface BrandSettings {
@@ -61,19 +62,19 @@ function toSidebarUser(profile: Partial<EmployeeProfile>, fallbackName: string,
}
const NAV_ITEMS = [
{ href: '/dashboard', key: 'dashboard', icon: LayoutDashboard, exact: true, minRole: 'AGENT' },
{ href: '/dashboard/fleet', key: 'fleet', icon: Car, minRole: 'AGENT' },
{ href: '/dashboard/reservations', key: 'reservations', icon: Calendar, minRole: 'AGENT' },
{ href: '/dashboard/online-reservations', key: 'onlineReservations', icon: Globe, minRole: 'AGENT' },
{ href: '/dashboard/customers', key: 'customers', icon: Users, minRole: 'AGENT' },
{ href: '/dashboard/offers', key: 'offers', icon: Tag, minRole: 'MANAGER' },
{ href: '/dashboard/team', key: 'team', icon: UserPlus, minRole: 'AGENT' },
{ href: '/dashboard/reports', key: 'reports', icon: BarChart2, minRole: 'MANAGER' },
{ href: '/dashboard/subscription', key: 'subscription', icon: CreditCard, minRole: 'OWNER' },
{ href: '/dashboard/billing', key: 'billing', icon: CreditCard, minRole: 'MANAGER' },
{ href: '/dashboard/contracts', key: 'contracts', icon: FileText, minRole: 'AGENT' },
{ href: '/dashboard/notifications', key: 'notifications', icon: Bell, minRole: 'AGENT' },
{ href: '/dashboard/settings', key: 'settings', icon: Settings, minRole: 'OWNER' },
{ href: '/', key: 'dashboard', icon: LayoutDashboard, exact: true, minRole: 'AGENT' },
{ href: '/fleet', key: 'fleet', icon: Car, minRole: 'AGENT' },
{ href: '/reservations', key: 'reservations', icon: Calendar, minRole: 'AGENT' },
{ href: '/online-reservations', key: 'onlineReservations', icon: Globe, minRole: 'AGENT' },
{ href: '/customers', key: 'customers', icon: Users, minRole: 'AGENT' },
{ href: '/offers', key: 'offers', icon: Tag, minRole: 'MANAGER' },
{ href: '/team', key: 'team', icon: UserPlus, minRole: 'AGENT' },
{ href: '/reports', key: 'reports', icon: BarChart2, minRole: 'MANAGER' },
{ href: '/subscription', key: 'subscription', icon: CreditCard, minRole: 'OWNER' },
{ href: '/billing', key: 'billing', icon: CreditCard, minRole: 'MANAGER' },
{ href: '/contracts', key: 'contracts', icon: FileText, minRole: 'AGENT' },
{ href: '/notifications', key: 'notifications', icon: Bell, minRole: 'AGENT' },
{ href: '/settings', key: 'settings', icon: Settings, minRole: 'OWNER' },
] as const
const ROLE_RANK: Record<string, number> = { OWNER: 3, MANAGER: 2, AGENT: 1 }
@@ -82,10 +83,16 @@ function hasMinRole(employeeRole: string, minRole: string): boolean {
return (ROLE_RANK[employeeRole] ?? 0) >= (ROLE_RANK[minRole] ?? 0)
}
function notifyParent(message: Record<string, unknown>) {
if (typeof window === 'undefined' || window.parent === window) return
window.parent.postMessage(message, '*')
}
export default function Sidebar() {
const { dict, language, setLanguage } = useDashboardI18n()
const isRtl = language === 'ar'
const pathname = usePathname()
const appPath = toDashboardAppPath(pathname)
const router = useRouter()
const [brand, setBrand] = useState<BrandSettings | null>(null)
const [user, setUser] = useState<SidebarUser>({
@@ -153,15 +160,17 @@ export default function Sidebar() {
useEffect(() => { setOpen(false) }, [pathname])
const isActive = (item: typeof NAV_ITEMS[number]) => {
if ('exact' in item && item.exact) return pathname === item.href
return pathname.startsWith(item.href)
if ('exact' in item && item.exact) return appPath === item.href
return appPath.startsWith(item.href)
}
function signOut() {
localStorage.removeItem(EMPLOYEE_TOKEN_KEY)
localStorage.removeItem(EMPLOYEE_PROFILE_KEY)
document.cookie = 'employee_token=; path=/; max-age=0; samesite=lax'
router.push('/sign-in')
window.dispatchEvent(new CustomEvent('rentaldrivego:auth-changed'))
notifyParent({ type: 'rentaldrivego:employee-logout' })
window.location.href = marketplaceUrl
}
return (
@@ -5,6 +5,7 @@ import { usePathname, useRouter } from 'next/navigation'
import { useState, useEffect } from 'react'
import { EMPLOYEE_PROFILE_KEY, EMPLOYEE_TOKEN_KEY, apiFetch } from '@/lib/api'
import { useDashboardI18n } from '@/components/I18nProvider'
import { toDashboardAppPath } from '@/lib/dashboardPaths'
function computeInitials(name: string): string {
const parts = name.trim().split(/\s+/).filter(Boolean)
@@ -16,6 +17,7 @@ function computeInitials(name: string): string {
export default function TopBar() {
const { dict } = useDashboardI18n()
const pathname = usePathname()
const appPath = toDashboardAppPath(pathname)
const router = useRouter()
const [unreadCount, setUnreadCount] = useState(0)
const [showNotifs, setShowNotifs] = useState(false)
@@ -33,11 +35,11 @@ export default function TopBar() {
useEffect(() => { setMounted(true) }, [])
const title = (() => {
if (!mounted) return dict.titles['/dashboard']
if (dict.titles[pathname]) return dict.titles[pathname]
if (pathname.startsWith('/dashboard/contracts/')) return dict.titles['/dashboard/contracts'] ?? dict.titles['/dashboard']
if (pathname.startsWith('/dashboard/reservations/')) return dict.titles['/dashboard/reservations'] ?? dict.titles['/dashboard']
return dict.titles['/dashboard']
if (!mounted) return dict.titles['/']
if (dict.titles[appPath]) return dict.titles[appPath]
if (appPath.startsWith('/contracts/')) return dict.titles['/contracts'] ?? dict.titles['/']
if (appPath.startsWith('/reservations/')) return dict.titles['/reservations'] ?? dict.titles['/']
return dict.titles['/']
})()
async function refreshUnreadCount() {
try {
@@ -139,7 +141,7 @@ export default function TopBar() {
} catch {}
}
setShowNotifs(false)
router.push('/dashboard/notifications')
router.push('/notifications')
}
return (