diff --git a/web/src/lib/components/shared/navigation-bar.svelte b/web/src/lib/components/shared/navigation-bar.svelte index 22f9c518c9..a9fcebf6f7 100644 --- a/web/src/lib/components/shared/navigation-bar.svelte +++ b/web/src/lib/components/shared/navigation-bar.svelte @@ -4,13 +4,15 @@ import type { ImmichUser } from '$lib/models/immich-user'; import { onMount } from 'svelte'; import { fade } from 'svelte/transition'; + import { postRequest } from '../../api'; import { serverEndpoint } from '../../constants'; + import { clickOutside } from './click-outside'; export let user: ImmichUser; let shouldShowAccountInfo = false; let shouldShowProfileImage = false; - + let shouldShowAccountInfoPanel = false; onMount(async () => { const res = await fetch(`${serverEndpoint}/user/profile-image/${user.id}`, { method: 'GET' }); @@ -24,6 +26,18 @@ const navigateToAdmin = () => { goto('/admin'); }; + + const showAccountInfoPanel = () => { + shouldShowAccountInfoPanel = true; + }; + + const logOut = async () => { + const res = await fetch('auth/logout', { method: 'POST' }); + + if (res.status == 200 && res.statusText == 'OK') { + goto('/auth/login'); + } + }; </script> <section id="dashboard-navbar" class="fixed w-screen z-[100] bg-immich-bg text-sm"> @@ -35,6 +49,7 @@ <div class="flex-1 ml-24"> <input class="w-[50%] border rounded-md bg-gray-200 px-8 py-4" placeholder="Search - Coming soon" /> </div> + <section class="flex gap-6 place-items-center"> <!-- <div>Upload</div> --> @@ -51,6 +66,7 @@ on:mouseover={() => (shouldShowAccountInfo = true)} on:focus={() => (shouldShowAccountInfo = true)} on:mouseleave={() => (shouldShowAccountInfo = false)} + on:click={showAccountInfoPanel} > <button class="flex place-items-center place-content-center rounded-full bg-immich-primary/80 h-12 w-12 text-gray-100 hover:bg-immich-primary" @@ -79,4 +95,48 @@ </div> </section> </div> + + {#if shouldShowAccountInfoPanel} + <div + in:fade={{ duration: 100 }} + out:fade={{ duration: 100 }} + id="account-info-panel" + class="absolute right-[25px] top-[75px] bg-white shadow-lg rounded-2xl w-[360px] text-center" + use:clickOutside + on:outclick={() => (shouldShowAccountInfoPanel = false)} + > + <div class="flex place-items-center place-content-center mt-6"> + <button + class="flex place-items-center place-content-center rounded-full bg-immich-primary/80 h-20 w-20 text-gray-100 hover:bg-immich-primary" + > + {#if shouldShowProfileImage} + <img + src={`${serverEndpoint}/user/profile-image/${user.id}`} + alt="profile-img" + class="inline rounded-full h-20 w-20 object-cover shadow-md" + /> + {:else} + <div class="text-lg"> + {getFirstLetter(user.firstName)}{getFirstLetter(user.lastName)} + </div> + {/if} + </button> + </div> + + <p class="text-lg text-immich-primary font-medium mt-4"> + {user.firstName} + {user.lastName} + </p> + + <p class="text-sm text-gray-500">{user.email}</p> + + <div class="my-4"> + <hr /> + </div> + + <div class="mb-6"> + <button class="border rounded-3xl px-6 py-2 hover:bg-gray-50" on:click={logOut}>Sign Out</button> + </div> + </div> + {/if} </section> diff --git a/web/src/routes/__layout.svelte b/web/src/routes/__layout.svelte index 6245af9503..5468e49856 100644 --- a/web/src/routes/__layout.svelte +++ b/web/src/routes/__layout.svelte @@ -7,7 +7,6 @@ if (browser) { const { shouldShowAnnouncement, localVersion, remoteVersion } = await checkAppVersion(); - console.log('Recheck'); return { props: { url, shouldShowAnnouncement, localVersion, remoteVersion } }; } else { return { diff --git a/web/src/routes/auth/logout.ts b/web/src/routes/auth/logout.ts new file mode 100644 index 0000000000..59e0229dc6 --- /dev/null +++ b/web/src/routes/auth/logout.ts @@ -0,0 +1,12 @@ +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async ({ request }) => { + return { + headers: { + 'Set-Cookie': 'session=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT', + }, + body: { + ok: true, + }, + }; +};