Files
radicall/resources/js/Client/components/sidebar/SidebarComponent.vue
T

216 lines
7.7 KiB
Vue

<script setup lang="ts">
import {ref, computed, onMounted, watch} from 'vue';
import {Link, usePage, useForm} from '@inertiajs/inertia-vue3';
import type { Ref } from 'vue';
import type { MenuItem } from 'primevue/menuitem';
import {useGlobalStore} from '../../store/Global';
import HomeSvg from "../svg/home.svg"
import documentTextSvg from "../svg/documentText.svg"
import LogoutSvg from "../svg/logout.svg"
import CalendarSvg from "../svg/calendar.svg"
import StatusUpSvg from "../svg/statusUp.svg"
import PetSvg from "../svg/pet.svg"
interface SidebarItem extends MenuItem {
label: string;
icon?: any;
to?: string;
expanded?: boolean;
items?: SidebarItem[];
permission?: string | null;
}
const globalStore = useGlobalStore();
const {url ,props} = usePage();
const currentUser = ref(props.value.auth.User);
const userPermissions = computed(() => props.value.auth.permissions ?? []);
function hasPermission(permission) {
if (!permission) return true;
return userPermissions.value.includes(permission);
}
function filterSidebarItems(items) {
return items
.filter(item => hasPermission(item.permission))
.map(item => {
if (item.items) {
const filteredChildren = filterSidebarItems(item.items);
if (filteredChildren.length > 0) {
return { ...item, items: filteredChildren };
} else if (!item.permission) {
return null;
}
}
return item;
})
.filter(Boolean);
}
const filteredItems = computed(() => filterSidebarItems(items.value));
// @ts-ignore
const items: Ref<SidebarItem[]> = ref([
{
label: "داشبورد",
icon: HomeSvg,
to: "/dashboard",
key: 'dashboard',
expanded: false,
permission: null,
},
{
label: "پرونده های باز",
icon: documentTextSvg,
to: "/dashboard/documents",
key: 'documents',
permission: null,
},
{
label: "کیس ها",
icon: PetSvg,
to: "/dashboard/cases",
key: 'cases',
permission: null,
},
{
label: "گزارشات",
icon: StatusUpSvg,
to: "/dashboard/reports",
key: 'reports',
permission: null,
},
{
label: "شیفت ها",
icon: CalendarSvg,
to: "/dashboard/shifts",
key: 'shifts',
permission: null,
},
// {
// label: "خروج از سامانه",
// icon: LogoutSvg,
// to: "/auth/logout",
// permission: null,
// },
]);
const toggleSubmenu = (item: SidebarItem) => {
// expandedKeys.value = {};
// item.expanded = !item.expanded;
};
const closeSidebarOnClick = () => {
globalStore.sidebarOpen = false;
};
const expandedKeys = ref<Record<string, boolean>>({});
onMounted(() => {
globalStore.current_user = currentUser;
const saved = localStorage.getItem('expandedKeys')
if (saved) expandedKeys.value = JSON.parse(saved)
updateExpandedKeys()
document.addEventListener('click', (e) => {
if (e.target.closest('.p-panelmenu-content a')) {
globalStore.sidebarOpen = false;
}
});
});
watch(expandedKeys, v => {
localStorage.setItem('expandedKeys', JSON.stringify(v))
})
watch(() => url.value, () => {
updateExpandedKeys()
})
const isActive = (item: SidebarItem): boolean => {
return expandedKeys.value[item.key] === true;
};
const loadSvgContent = async (svgName) => {
try {
const svgModule = await import(`../../components/svg/${svgName}.svg?raw`)
return svgModule.default
} catch (error) {
return null
}
}
const updateExpandedKeys = () => {
const newKeys = {}
items.value.forEach(item => {
if (item.to === url.value || item.items?.some(c => url.value.startsWith(c.to || ''))) {
newKeys[item.key] = true
}
})
expandedKeys.value = newKeys
};
</script>
<template>
<div v-if="globalStore.sidebarOpen"
class="fixed inset-0 bg-black/10 backdrop-blur-sm bg-opacity-50 z-10 sm:hidden"
@click="globalStore.sidebarOpen = false">
</div>
<aside class="shadow-client-gray/5 w-[16rem] bg-white
py-4 pt-0 pb-8 fixed h-full top-0 z-30 inset-y-0 right-0 sm:inset-auto transition-transform duration-300"
:class="[globalStore.sidebarOpen ? 'translate-x-0' : 'translate-x-full sm:translate-x-0']">
<figure class="w-[16rem] h-[5rem] flex justify-center">
<img class="!w-full h-full object-contain" src="@/images/SidebarPanelLogo.png" alt="">
</figure>
<section class="">
<div class="grid grid-rows-[1fr_auto] h-[calc(100svh-6.5rem)]">
<PanelMenu
:pt="{
header: 'custom-header',
headerAction: 'custom-header-action',
menuContent: 'custom-menu-content',
menuitem: 'custom-menuitem',
action: 'custom-action',
icon: 'custom-icon',
submenuIcon: 'custom-submenu-icon !text-xl',
}"
v-model:expanded-keys="expandedKeys"
:model="filteredItems"
class="custom-menu px-4">
<template #item="{ item, root, hasSubmenu, toggle }">
<div
:class="url === item.to ? 'active' : 'text-client-Fontcolor'"
class="flex items-center h-10 justify-between pl-2 text-client-Fontcolor rounded-lg cursor-pointer w-full"
@click="hasSubmenu ? toggleSubmenu(item) : null">
<div class="px-2 flex w-full items-center">
<Link v-if="item.to" :href="item.to" class="flex items-center h-10 w-full" @click="globalStore.sidebarOpen = false">
<component v-if="typeof item.icon === 'object'" :is="item.icon" class="flex w-7 items-center justify-start"></component>
<i v-else-if="item.icon" :class="item.icon" class="flex !text-[1.2rem] -mt-0.5"></i>
<div class="flex items-center font-semibold text-sm p-2 text-dominant-300 gap-2 w-full">
{{ item.label }}
</div>
</Link>
<div v-else class="flex items-center h-10 w-full">
<component v-if="typeof item.icon === 'object'" :is="item.icon" class="flex !text-[1.2rem] -mt-0.5"></component>
<i v-else-if="item.icon" :class="item.icon" class="flex !text-[1.2rem] -mt-0.5"></i>
<span class="w-full p-2 text-sm text-client-Fontcolor">{{ item.label }}</span>
</div>
</div>
<i v-if="hasSubmenu"
class="fi fi-rr-angle-small-left !text-sm flex transition-transform duration-300"
:class="[{ 'rotate-90': item.expanded || isActive }]">
</i>
</div>
</template>
</PanelMenu>
<Link :href="route('dashboard.logout')" method="get" class="grid grid-cols-2a items-center h-10 justify-start p-4 px-6">
<LogoutSvg class="" />
<span class="flex items-center font-semibold text-sm p-2 text-dominant-300 gap-2 w-full">
خروج از سامانه
</span>
</Link>
</div>
</section>
</aside>
</template>