Files
Web-Antrean/components/SideBar1.vue
2025-11-05 13:00:06 +07:00

209 lines
5.3 KiB
Vue

<template>
<v-navigation-drawer
:model-value="drawer"
:rail="rail"
permanent
app
class="bg-white"
@update:model-value="emit('update:drawer', $event)"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<v-list-item
class="py-4 px-2"
:class="{'text-center': rail}"
>
<div class="d-flex align-center" :class="{'justify-center': rail}">
<v-icon color="orange-darken-2" size="36">mdi-hospital-box-outline</v-icon>
<v-list-item-title v-if="!rail" class="ml-2 text-h6 font-weight-bold text-blue-grey-darken-4">
<span class="text-orange-darken-2">Antrian</span> RSSA
</v-list-item-title>
</div>
</v-list-item>
<v-divider></v-divider>
<v-list density="compact" nav class="mt-2" v-model:opened="openedGroups">
<template v-for="item in items" :key="item.name">
<v-list-group
v-if="item.children"
:value="item.name"
:disabled="rail"
>
<template v-slot:activator="{ props: groupProps }">
<v-list-item
v-bind="groupProps"
:prepend-icon="item.icon"
:title="item.name"
color="orange-darken-2"
active-class="bg-orange-lighten-5 text-orange-darken-2 font-weight-bold"
></v-list-item>
</template>
<v-list-item
v-for="child in item.children"
:key="child.name"
:to="child.path"
:title="child.name"
:prepend-icon="child.icon"
link
class="pl-8"
color="orange-darken-2"
active-class="bg-orange-lighten-5 text-orange-darken-2 font-weight-bold"
></v-list-item>
</v-list-group>
<v-tooltip
v-else
:disabled="!rail"
open-on-hover
location="end"
:text="item.name"
>
<template #activator="{ props: tooltipProps }">
<v-list-item
v-bind="tooltipProps"
:prepend-icon="item.icon"
:title="item.name"
:to="item.path"
link
color="orange-darken-2"
active-class="bg-orange-lighten-5 text-orange-darken-2 font-weight-bold"
></v-list-item>
</template>
</v-tooltip>
</template>
</v-list>
<v-spacer></v-spacer>
<v-divider></v-divider>
<v-list v-if="user" nav density="compact" class="pa-2">
<ProfilePopup
:user="user"
@logout="handleLogout"
:rail="rail"
/>
</v-list>
<v-list v-else nav density="compact">
<v-list-item
@click="redirectToLogin"
prepend-icon="mdi-login"
title="Login"
link
color="blue-grey-darken-4"
></v-list-item>
</v-list>
</v-navigation-drawer>
</template>
<script setup lang="ts">
import { defineProps, defineEmits, onMounted, ref, watch } from 'vue';
import { navigateTo, useRoute } from '#app';
import ProfilePopup from './ProfilePopup.vue';
import { useAuth } from '~/composables/useAuth'; // Ensure this path is correct
const { user, logout, checkAuth } = useAuth();
const route = useRoute(); // Access the current route
interface NavItem {
id: number;
name: string;
path: string;
icon: string;
children?: NavItem[];
}
const props = defineProps({
items: {
type: Array as () => NavItem[],
required: true,
},
rail: {
type: Boolean,
required: true,
},
drawer: {
type: Boolean,
required: true,
},
});
const emit = defineEmits(['update:drawer', 'toggle-rail']);
const openedGroups = ref<string[]>([]);
const isHovering = ref(false);
// --- WATCHERS FOR DROPDOWN AND HIGHLIGHTING ---
// 1. WATCHER: Close dropdowns when sidebar collapses (rail = true)
watch(() => props.rail, (newRailState) => {
if (newRailState === true) {
openedGroups.value = [];
}
});
// 2. WATCHER: Open the parent group when a child route is active
watch(() => route.path, (newPath) => {
// Find the parent item whose children contain the current path
const activeParent = props.items.find(item =>
item.children && item.children.some(child =>
child.path === newPath
)
);
if (activeParent) {
// If a parent is active, ensure it's in the openedGroups array
if (!openedGroups.value.includes(activeParent.name)) {
openedGroups.value.push(activeParent.name);
}
// Optional: Keep only the active parent open, closing others
// openedGroups.value = [activeParent.name];
}
}, { immediate: true });
// --- HOVER LOGIC for Rail Expansion ---
const handleMouseEnter = () => {
if (props.rail) {
isHovering.value = true;
emit('toggle-rail');
}
};
const handleMouseLeave = () => {
if (isHovering.value) {
isHovering.value = false;
emit('toggle-rail');
}
};
// --- AUTH LOGIC ---
const handleLogout = async () => {
console.log('🚪 SideBar logout initiated...');
try {
// Calls the external logout function (from useAuth.ts)
await logout();
} catch (error) {
console.error('❌ SideBar logout error:', error);
}
};
const redirectToLogin = () => {
navigateTo('/LoginPage');
};
onMounted(async () => {
// Fetches real user data on mount
await checkAuth();
});
</script>
<style scoped>
/* No specific overrides needed */
</style>