feat: navbar reacts to login + logout route

This commit is contained in:
niko 2025-05-26 05:39:11 -04:00
parent 21ae7a4db9
commit a5d00da6ea
No known key found for this signature in database
GPG Key ID: C3B29CF2BA3406AD
3 changed files with 77 additions and 14 deletions

View File

@ -2,7 +2,6 @@
const { locales, setLocale } = useI18n();
const openDropdown = ref<boolean | string>(false);
const loggedIn = ref(false);
function handleDropdownButton(dropdown: boolean | string) {
if (!openDropdown.value) {
openDropdown.value = dropdown;
@ -20,6 +19,26 @@ onMounted(() => {
scrollY.value = window.scrollY;
});
});
interface InfoCCResponse {
username: string;
mii: {
name: string;
image_url: string;
};
}
const route = useRoute();
const accountInfo = await useFetch<InfoCCResponse>('/api/account/info'); // TODO: does doing this cause too many requests? can't depend on route due to hydration issues
async function logoutClick() {
await $fetch('/api/account/logout');
accountInfo.clear();
if (route.path == '/account') {
navigateTo('/');
}
}
</script>
<template>
@ -451,28 +470,31 @@ onMounted(() => {
</div>
<div
v-if="loggedIn"
v-if="accountInfo.data.value"
class="user-widget-wrapper logged-in"
>
<div class="user-widget-toggle">
<img
src="url"
:src="accountInfo.data.value.mii?.image_url"
alt="name"
@click="handleDropdownButton('user')"
>
</div>
<div class="user-widget">
<div
:class="`user-widget ${openDropdown === 'user' ? 'active' : ''}`"
>
<div class="user-avatar">
<img
src=""
:src="accountInfo.data.value.mii?.image_url"
alt="miiname"
>
</div>
<div class="user-info">
<div class="mii-name">
miiname
{{ accountInfo.data.value.mii?.name }}
</div>
<div class="pnid">
pnid
{{ accountInfo.data.value.username }}
</div>
</div>
<div class="buttons">
@ -481,17 +503,18 @@ onMounted(() => {
{{ $t("nav.accountWidget.settings") }}
</button>
</a>
<a href="/account/logout">
<button class="button logout">
{{ $t("nav.accountWidget.logout") }}
</button>
</a>
<button
class="button logout"
@click="logoutClick"
>
{{ $t("nav.accountWidget.logout") }}
</button>
</div>
</div>
</div>
<div
v-if="!loggedIn"
v-else
class="user-widget-wrapper"
>
<a
@ -863,7 +886,7 @@ header .user-widget {
overflow: hidden;
box-sizing: border-box;
transition: max-height 300ms, padding 200ms, opacity 150ms;
transition: opacity 150ms;
position: absolute;
right: 0;

View File

@ -0,0 +1,31 @@
import { FetchError } from 'ofetch';
interface InfoCCResponse { // TODO: de-dupe this. don't know where to coalesce types. feels like we should have a library for this but this should be handled when we switch to gRPC later
username: string;
mii: {
name: string;
image_url: string;
};
}
export default defineEventHandler(async (event) => {
try {
const cookies = parseCookies(event);
return await $fetch<InfoCCResponse>(`/v1/user`, {
method: 'GET',
baseURL: useRuntimeConfig(event).apiBase,
headers: { Authorization: `${cookies?.token_type} ${cookies?.access_token}` }
});
} catch (error: unknown) {
if (error instanceof FetchError) {
setResponseStatus(event, error.status, error.data.error);
} else {
setResponseStatus(event, 500);
}
event.node.res.end();
return;
}
});

View File

@ -0,0 +1,9 @@
export default defineEventHandler(async (event) => {
deleteCookie(event, 'refresh_token');
deleteCookie(event, 'access_token');
deleteCookie(event, 'token_type');
event.node.res.end();
return;
});