diff --git a/i18n/en.json b/i18n/en.json index 8404d6d1d0..239936471d 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -853,6 +853,7 @@ "failed_to_keep_this_delete_others": "Failed to keep this asset and delete the other assets", "failed_to_load_asset": "Failed to load asset", "failed_to_load_assets": "Failed to load assets", + "failed_to_load_notifications": "Failed to load notifications", "failed_to_load_people": "Failed to load people", "failed_to_remove_product_key": "Failed to remove product key", "failed_to_stack_assets": "Failed to stack assets", diff --git a/web/src/lib/managers/event-manager.svelte.ts b/web/src/lib/managers/event-manager.svelte.ts index 335c5cbefb..5494314725 100644 --- a/web/src/lib/managers/event-manager.svelte.ts +++ b/web/src/lib/managers/event-manager.svelte.ts @@ -1,3 +1,5 @@ +import type { LoginResponseDto } from '@immich/sdk'; + type Listener, K extends keyof EventMap> = (...params: EventMap[K]) => void; class EventManager> { @@ -50,6 +52,7 @@ class EventManager> { export const eventManager = new EventManager<{ 'user.login': []; + 'auth.login': [LoginResponseDto]; 'auth.logout': []; 'language.change': [{ name: string; code: string; rtl?: boolean }]; }>(); diff --git a/web/src/lib/stores/notification-manager.svelte.ts b/web/src/lib/stores/notification-manager.svelte.ts index 0e520f0a69..3eba15deed 100644 --- a/web/src/lib/stores/notification-manager.svelte.ts +++ b/web/src/lib/stores/notification-manager.svelte.ts @@ -1,24 +1,27 @@ import { eventManager } from '$lib/managers/event-manager.svelte'; +import { handlePromiseError } from '$lib/utils'; +import { handleError } from '$lib/utils/handle-error'; import { getNotifications, updateNotification, updateNotifications, type NotificationDto } from '@immich/sdk'; +import { t } from 'svelte-i18n'; +import { get } from 'svelte/store'; class NotificationStore { notifications = $state([]); constructor() { - // TODO replace this with an `auth.login` event - this.refresh().catch(() => {}); - + eventManager.on('auth.login', () => handlePromiseError(this.refresh())); eventManager.on('auth.logout', () => this.clear()); } - get hasUnread() { - return this.notifications.length > 0; + async refresh() { + try { + this.notifications = await getNotifications({ unread: true }); + } catch (error) { + const translate = get(t); + handleError(error, translate('errors.failed_to_load_notifications')); + } } - refresh = async () => { - this.notifications = await getNotifications({ unread: true }); - }; - markAsRead = async (id: string) => { this.notifications = this.notifications.filter((notification) => notification.id !== id); await updateNotification({ id, notificationUpdateDto: { readAt: new Date().toISOString() } }); diff --git a/web/src/routes/auth/login/+page.svelte b/web/src/routes/auth/login/+page.svelte index 1dcb91f996..fdad88e1ff 100644 --- a/web/src/routes/auth/login/+page.svelte +++ b/web/src/routes/auth/login/+page.svelte @@ -2,15 +2,15 @@ import { goto } from '$app/navigation'; import AuthPageLayout from '$lib/components/layouts/AuthPageLayout.svelte'; import { AppRoute } from '$lib/constants'; + import { eventManager } from '$lib/managers/event-manager.svelte'; import { featureFlags, serverConfig } from '$lib/stores/server-config.store'; import { oauth } from '$lib/utils'; import { getServerErrorMessage, handleError } from '$lib/utils/handle-error'; - import { login } from '@immich/sdk'; + import { login, type LoginResponseDto } from '@immich/sdk'; import { Alert, Button, Field, Input, PasswordInput, Stack } from '@immich/ui'; import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; import type { PageData } from './$types'; - import { notificationManager } from '$lib/stores/notification-manager.svelte'; interface Props { data: PageData; @@ -25,10 +25,11 @@ let loading = $state(false); let oauthLoading = $state(true); - const onSuccess = async () => { - await notificationManager.refresh(); + const onSuccess = async (user: LoginResponseDto) => { await goto(AppRoute.PHOTOS, { invalidateAll: true }); + eventManager.emit('auth.login', user); }; + const onFirstLogin = async () => await goto(AppRoute.AUTH_CHANGE_PASSWORD); const onOnboarding = async () => await goto(AppRoute.AUTH_ONBOARDING); @@ -40,8 +41,8 @@ if (oauth.isCallback(globalThis.location)) { try { - await oauth.login(globalThis.location); - await onSuccess(); + const user = await oauth.login(globalThis.location); + await onSuccess(user); return; } catch (error) { console.error('Error [login-form] [oauth.callback]', error); @@ -78,7 +79,7 @@ await onFirstLogin(); return; } - await onSuccess(); + await onSuccess(user); return; } catch (error) { errorMessage = getServerErrorMessage(error) || $t('errors.incorrect_email_or_password');