176 lines
4.8 KiB
Vue
176 lines
4.8 KiB
Vue
<template>
|
|
<v-menu
|
|
v-model="menu"
|
|
:close-on-content-click="false"
|
|
location="top end"
|
|
origin="bottom right"
|
|
transition="slide-y-transition"
|
|
open-on-hover
|
|
>
|
|
<template v-slot:activator="{ props: menuProps }">
|
|
<v-list-item
|
|
v-if="!rail"
|
|
v-bind="menuProps"
|
|
:title="user?.name || user?.preferred_username || 'User'"
|
|
:subtitle="user?.email || 'No email'"
|
|
class="pa-2 ma-1 rounded-lg bg-blue-grey-lighten-5 text-blue-grey-darken-4"
|
|
color="blue-grey-darken-4"
|
|
link
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-avatar size="40">
|
|
<v-img
|
|
:src="user?.picture || 'https://i.pravatar.cc/300?img=68'"
|
|
:alt="`${user?.name || 'User'} Profile`"
|
|
></v-img>
|
|
</v-avatar>
|
|
</template>
|
|
<template v-slot:append>
|
|
<v-icon size="20">mdi-chevron-up</v-icon>
|
|
</template>
|
|
</v-list-item>
|
|
|
|
<v-btn
|
|
v-else
|
|
icon
|
|
v-bind="menuProps"
|
|
size="large"
|
|
variant="text"
|
|
color="blue-grey-darken-4"
|
|
:title="user?.name || 'Profile'"
|
|
>
|
|
<v-avatar size="40">
|
|
<v-img
|
|
:src="user?.picture || 'https://i.pravatar.cc/300?img=68'"
|
|
:alt="`${user?.name || 'User'} Profile`"
|
|
></v-img>
|
|
</v-avatar>
|
|
</v-btn>
|
|
</template>
|
|
|
|
<v-card class="rounded-lg elevation-4 pa-4" width="300" color="blue-grey-lighten-5">
|
|
<div class="d-flex align-center pb-2">
|
|
<v-avatar size="48">
|
|
<v-img
|
|
:src="user?.picture || 'https://i.pravatar.cc/300?img=68'"
|
|
:alt="`${user?.name || 'User'} Profile`"
|
|
></v-img>
|
|
</v-avatar>
|
|
<div class="ml-4">
|
|
<div class="text-subtitle-1 font-weight-bold text-blue-grey-darken-4">
|
|
{{ user?.name || user?.preferred_username || 'User' }}
|
|
</div>
|
|
<div class="text-caption text-grey-darken-1">
|
|
{{ user?.email || 'No email' }}
|
|
</div>
|
|
<div class="text-caption text-grey-darken-2">
|
|
ID: {{ user?.id?.substring(0, 8) }}...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<v-divider class="my-2"></v-divider>
|
|
|
|
<v-list dense>
|
|
<v-list-item link class="rounded-lg text-blue-grey-darken-4" @click="handleAction('account')">
|
|
<template v-slot:prepend>
|
|
<v-icon color="blue-grey-darken-4">mdi-cog</v-icon>
|
|
</template>
|
|
<v-list-item-title>Pengaturan Akun</v-list-item-title>
|
|
</v-list-item>
|
|
|
|
<v-list-item link class="rounded-lg text-blue-grey-darken-4" @click="handleAction('darkMode')">
|
|
<template v-slot:prepend>
|
|
<v-icon color="blue-grey-darken-4">mdi-weather-night</v-icon>
|
|
</template>
|
|
<v-list-item-title>Mode Gelap</v-list-item-title>
|
|
<template v-slot:append>
|
|
<v-switch
|
|
v-model="darkMode"
|
|
hide-details
|
|
density="compact"
|
|
color="orange-darken-2"
|
|
></v-switch>
|
|
</template>
|
|
</v-list-item>
|
|
|
|
<v-list-item link class="rounded-lg text-blue-grey-darken-4" @click="handleAction('profile')">
|
|
<template v-slot:prepend>
|
|
<v-icon color="blue-grey-darken-4">mdi-account</v-icon>
|
|
</template>
|
|
<v-list-item-title>Profil Saya</v-list-item-title>
|
|
</v-list-item>
|
|
|
|
<v-divider class="my-2"></v-divider>
|
|
|
|
<v-list-item
|
|
link
|
|
class="rounded-lg text-red"
|
|
@click="signOut"
|
|
:disabled="isLoggingOut"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-icon color="red">mdi-logout</v-icon>
|
|
</template>
|
|
<v-list-item-title>
|
|
{{ isLoggingOut ? 'Logging out...' : 'Keluar' }}
|
|
</v-list-item-title>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-card>
|
|
</v-menu>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue';
|
|
import { navigateTo } from '#app';
|
|
|
|
const props = defineProps({
|
|
user: {
|
|
type: Object,
|
|
required: true
|
|
},
|
|
rail: {
|
|
type: Boolean,
|
|
required: true
|
|
}
|
|
})
|
|
|
|
const menu = ref(false);
|
|
const darkMode = ref(false);
|
|
const isLoggingOut = ref(false);
|
|
const emit = defineEmits(['logout']);
|
|
|
|
const signOut = async () => {
|
|
if (isLoggingOut.value) return;
|
|
isLoggingOut.value = true;
|
|
menu.value = false;
|
|
|
|
try {
|
|
// 🚨 Emits event up to SideBar to trigger useAuth().logout()
|
|
emit('logout');
|
|
} finally {
|
|
isLoggingOut.value = false;
|
|
}
|
|
};
|
|
|
|
const handleAction = (action) => {
|
|
switch(action) {
|
|
case 'account':
|
|
navigateTo('/settings/account')
|
|
break;
|
|
case 'profile':
|
|
navigateTo('/profile')
|
|
break;
|
|
}
|
|
|
|
if (action !== 'darkMode') {
|
|
menu.value = false;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.text-red {
|
|
color: rgb(244, 67, 54) !important;
|
|
}
|
|
</style> |