make the booking in many steps
Build & Deploy / Build & Push Docker Image (push) Successful in 8m27s
Test / Type Check (all packages) (push) Successful in 3m34s
Build & Deploy / Deploy to VPS (push) Successful in 2s
Test / API Unit Tests (push) Failing after 3m16s
Test / Homepage Unit Tests (push) Failing after 2m40s
Test / Storefront Unit Tests (push) Failing after 24s
Test / Admin Unit Tests (push) Failing after 22s
Test / Dashboard Unit Tests (push) Failing after 24s
Test / API Integration Tests (push) Failing after 33s
Build & Deploy / Build & Push Docker Image (push) Successful in 8m27s
Test / Type Check (all packages) (push) Successful in 3m34s
Build & Deploy / Deploy to VPS (push) Successful in 2s
Test / API Unit Tests (push) Failing after 3m16s
Test / Homepage Unit Tests (push) Failing after 2m40s
Test / Storefront Unit Tests (push) Failing after 24s
Test / Admin Unit Tests (push) Failing after 22s
Test / Dashboard Unit Tests (push) Failing after 24s
Test / API Integration Tests (push) Failing after 33s
This commit is contained in:
@@ -87,22 +87,16 @@ function toSidebarUser(profile: Partial<EmployeeProfile>, fallbackName: string,
|
||||
|
||||
const NAV_ITEMS = [
|
||||
{ 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: '/fleet', key: 'fleet', icon: Car, 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: '/reviews', key: 'reviews', icon: Star, minRole: 'AGENT' },
|
||||
{ href: '/complaints', key: 'complaints', icon: AlertTriangle, minRole: 'AGENT' },
|
||||
{ href: '/notifications', key: 'notifications', icon: Bell, minRole: 'AGENT' },
|
||||
{ href: '/settings', key: 'settings', icon: Settings, minRole: 'OWNER' },
|
||||
] as const
|
||||
|
||||
export const APPROVED_BASELINE_MENU_KEYS = NAV_ITEMS.map((item) => item.key)
|
||||
|
||||
const ICON_MAP = {
|
||||
LayoutDashboard,
|
||||
Car,
|
||||
@@ -156,6 +150,7 @@ export default function Sidebar() {
|
||||
})
|
||||
const [role, setRole] = useState<string>('AGENT')
|
||||
const [menuItems, setMenuItems] = useState<GeneratedMenuItem[] | null>(null)
|
||||
const [menuLoadState, setMenuLoadState] = useState<'loading' | 'loaded' | 'failed'>('loading')
|
||||
const [open, setOpen] = useState(false)
|
||||
const [mounted, setMounted] = useState(false)
|
||||
|
||||
@@ -229,7 +224,12 @@ export default function Sidebar() {
|
||||
window.localStorage.setItem(EMPLOYEE_PROFILE_KEY, JSON.stringify(employee))
|
||||
setUser(toSidebarUser(employee, dict.workspaceUser, dict.localAuth))
|
||||
if (employee.role) setRole(employee.role)
|
||||
if (menu?.items) setMenuItems(menu.items)
|
||||
if (menu) {
|
||||
setMenuItems(menu.items)
|
||||
setMenuLoadState('loaded')
|
||||
} else {
|
||||
setMenuLoadState('failed')
|
||||
}
|
||||
if (employee.preferredLanguage === 'en' || employee.preferredLanguage === 'fr' || employee.preferredLanguage === 'ar') {
|
||||
// Only apply the server-side preference when the employee has no local preference
|
||||
// stored yet — avoids overriding a language the user manually switched to.
|
||||
@@ -243,6 +243,7 @@ export default function Sidebar() {
|
||||
.catch(() => {
|
||||
if (cancelled) return
|
||||
if (!cached) setUser(toSidebarUser({}, dict.workspaceUser, dict.localAuth))
|
||||
setMenuLoadState('failed')
|
||||
})
|
||||
|
||||
return () => { cancelled = true }
|
||||
@@ -278,8 +279,8 @@ export default function Sidebar() {
|
||||
children: [],
|
||||
}))
|
||||
|
||||
const useGeneratedMenu = hasRenderableMenuItems(menuItems)
|
||||
const resolvedMenuItems = useGeneratedMenu && menuItems ? menuItems : fallbackMenuItems
|
||||
const useGeneratedMenu = menuLoadState === 'loaded'
|
||||
const resolvedMenuItems = useGeneratedMenu ? (menuItems ?? []) : fallbackMenuItems
|
||||
|
||||
function renderGeneratedMenu(items: GeneratedMenuItem[], depth = 0): ReactNode {
|
||||
return items.map((item) => {
|
||||
@@ -406,33 +407,7 @@ export default function Sidebar() {
|
||||
</a>
|
||||
|
||||
<nav className="flex-1 space-y-1.5 overflow-y-auto px-3 py-5">
|
||||
{useGeneratedMenu ? renderGeneratedMenu(resolvedMenuItems) : NAV_ITEMS.filter((item) => !mounted || hasMinRole(role, item.minRole)).map((item) => {
|
||||
const Icon = item.icon
|
||||
const active = mounted && isActive(item)
|
||||
return (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={[
|
||||
'relative flex items-center gap-3 rounded-lg px-3.5 py-3 text-sm font-medium transition-all duration-200',
|
||||
active
|
||||
? 'bg-blue-500/10 text-blue-950 shadow-[inset_2px_0_0_#3b82f6,0_0_18px_rgba(59,130,246,0.10)] dark:text-slate-50'
|
||||
: 'text-slate-500 hover:bg-blue-500/10 hover:text-blue-950 dark:text-slate-400 dark:hover:text-slate-50',
|
||||
].join(' ')}
|
||||
>
|
||||
<Icon className={['h-[18px] w-[18px] flex-shrink-0', active ? 'text-blue-700 dark:text-blue-300' : ''].join(' ')} />
|
||||
{dict.nav[item.key]}
|
||||
{item.key === 'dashboard' ? (
|
||||
<span className="ml-auto rounded-full border border-blue-400/30 bg-blue-500/15 px-2 py-0.5 text-[10px] font-medium text-blue-700 dark:text-blue-300">
|
||||
Live
|
||||
</span>
|
||||
) : null}
|
||||
{item.key === 'notifications' && active ? (
|
||||
<span className="ml-auto h-1.5 w-1.5 rounded-full bg-orange-400 shadow-[0_0_10px_rgba(249,115,22,0.5)]" />
|
||||
) : null}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
{renderGeneratedMenu(resolvedMenuItems)}
|
||||
</nav>
|
||||
|
||||
<div className="border-t border-blue-200/70 px-3 py-4 dark:border-blue-400/10">
|
||||
|
||||
Reference in New Issue
Block a user