Files
simrsx-fe/app/components/layout/AppSidebar.vue
2025-11-12 06:51:03 +07:00

119 lines
3.0 KiB
Vue

<script setup lang="ts">
type NavGroup = {
heading?: string
items: any[]
}
const { getActiveRole } = useUserStore()
const navMenu = ref<NavGroup[]>([])
const teams: {
name: string
logo: string
plan: string
}[] = [
{
name: 'SIMRS - RSSA',
logo: '/rssa-logo.png',
plan: 'Saiful Anwar Hospital',
},
]
type Sidebar = {
collapsible: 'offcanvas' | 'icon' | 'none'
side: 'left' | 'right'
variant: 'sidebar' | 'floating' | 'inset'
}
const sidebar: Sidebar = {
collapsible: 'offcanvas', // 'offcanvas' | 'icon' | 'none'
side: 'left', // 'left' | 'right'
variant: 'sidebar', // 'sidebar' | 'floating' | 'inset'
}
const navMenuBottom: any[] = [
{
title: 'Help & Support',
icon: 'i-lucide-circle-help',
link: 'https://github.com/simrs/simrs-fe',
},
]
onMounted(async () => {
await setMenu()
})
async function setMenu() {
const activeRole = getActiveRole()
const activeRoleParts = activeRole ? activeRole.split('|') : []
const role = activeRoleParts[0]+(activeRoleParts.length > 1 ? `-${activeRoleParts[1]}` : '')
try {
const res = await fetch(`/side-menu-items/${role.toLowerCase()}.json`)
const rawMenu = await res.text()
navMenu.value = JSON.parse(rawMenu)
} catch (e) {
const res = await fetch(`/side-menu-items/blank.json`)
const rawMenu = await res.text()
navMenu.value = JSON.parse(rawMenu)
}
}
function resolveNavItemComponent(item: any): any {
if ('children' in item) return resolveComponent('LayoutSidebarNavGroup')
return resolveComponent('LayoutSidebarNavLink')
}
watch(getActiveRole, async () => {
await setMenu()
// const activeRole = getActiveRole()
// const res = await fetch(`/side-menu-items/${activeRole}.json`)
// const rawMenu = await res.text()
// navMenu.value = JSON.parse(rawMenu)
})
</script>
<template>
<Sidebar :collapsible="sidebar.collapsible" :side="sidebar.side" :variant="sidebar.variant">
<SidebarHeader>
<LayoutSidebarNavHeader :teams="teams" />
</SidebarHeader>
<SidebarContent>
<template v-if="navMenu.length > 0">
<SidebarGroup v-for="(nav, indexGroup) in navMenu" :key="indexGroup">
<SidebarGroupLabel v-if="nav.heading">
{{ nav.heading }}
</SidebarGroupLabel>
<component
:is="resolveNavItemComponent(item)"
v-for="(item, index) in nav.items"
:key="index"
:item="item"
class="my-1 mb-1"
/>
</SidebarGroup>
</template>
<template v-else>
<div class="p-5">
<div v-for="n in 10" :key="n" class="my-4 h-8 animate-pulse rounded bg-gray-200 py-2"></div>
</div>
</template>
<SidebarGroup class="mt-auto">
<component
:is="resolveNavItemComponent(item)"
v-for="(item, index) in navMenuBottom"
:key="index"
:item="item"
size="sm"
/>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<LayoutSidebarNavFooter />
</SidebarFooter>
<SidebarRail />
</Sidebar>
</template>
<style scoped></style>