From 888a40f810a393684a5c4194477625de6cb04e77 Mon Sep 17 00:00:00 2001 From: Anders Nomerstad Date: Wed, 15 May 2024 08:58:16 +0200 Subject: [PATCH] Flytter feilmelding for notifications inn i usermenu-komponenten --- packages/server/src/env/schema.ts | 2 + packages/server/src/handlers/auth-handler.ts | 8 ++- .../server/src/handlers/search-handler.ts | 2 +- packages/server/src/notifications.ts | 28 +++------- .../src/views/errors/notifications-error.ts | 10 ++++ .../server/src/views/errors/search-error.ts | 10 ++++ .../src/views/header/user-menu-dropdown.ts | 26 +++++----- packages/server/src/views/header/user-menu.ts | 9 ++-- .../src/views/notifications/notifications.ts | 51 +++++++++++-------- packages/shared/views/errors/search-error.ts | 10 ---- 10 files changed, 82 insertions(+), 74 deletions(-) create mode 100644 packages/server/src/views/errors/notifications-error.ts create mode 100644 packages/server/src/views/errors/search-error.ts delete mode 100644 packages/shared/views/errors/search-error.ts diff --git a/packages/server/src/env/schema.ts b/packages/server/src/env/schema.ts index 5e0e4547..a10352cb 100644 --- a/packages/server/src/env/schema.ts +++ b/packages/server/src/env/schema.ts @@ -14,6 +14,7 @@ export const serverSchema = z.object({ HOST: z.string().url(), VARSEL_API_URL: z.string().url(), API_DEKORATOREN_URL: z.string().url(), + LOGIN_URL: z.string().url(), }); export type RunningEnv = z.infer["ENV"]; @@ -34,6 +35,7 @@ export const serverEnv = { HOST: process.env.HOST, VARSEL_API_URL: process.env.VARSEL_API_URL, API_DEKORATOREN_URL: process.env.API_DEKORATOREN_URL, + LOGIN_URL: process.env.LOGIN_URL, }; // This is session URL for prod diff --git a/packages/server/src/handlers/auth-handler.ts b/packages/server/src/handlers/auth-handler.ts index 7837ae2f..3315d011 100644 --- a/packages/server/src/handlers/auth-handler.ts +++ b/packages/server/src/handlers/auth-handler.ts @@ -15,7 +15,6 @@ import { getNotifications } from "../notifications"; import { ArbeidsgiverUserMenu } from "../views/header/arbeidsgiver-user-menu"; import { AnchorIconButton } from "../views/icon-button"; import { LogoutIcon } from "decorator-shared/views/icons/logout"; -import html from "decorator-shared/html"; import { Language, type Params } from "decorator-shared/params"; const notAuthenticatedResponse = (language: Language) => @@ -69,14 +68,13 @@ const buildUsermenuHtml = async ( const notificationsResult = await getNotifications({ request, }); - if (!notificationsResult.ok) { - return html`
Error
`; - } return UserMenuDropdown({ texts: localTexts, name: auth.name, - notifications: notificationsResult.data, + notifications: notificationsResult.ok + ? notificationsResult.data + : null, level: `Level${auth.securityLevel}`, logoutUrl: logoutUrl as string, minsideUrl: clientEnv.MIN_SIDE_URL, diff --git a/packages/server/src/handlers/search-handler.ts b/packages/server/src/handlers/search-handler.ts index 5ca530a1..8b95c8ae 100644 --- a/packages/server/src/handlers/search-handler.ts +++ b/packages/server/src/handlers/search-handler.ts @@ -4,7 +4,7 @@ import { HandlerFunction, responseBuilder } from "../lib/handler"; import { SearchHits } from "../views/search-hits"; import { texts } from "../texts"; import { z } from "zod"; -import { SearchErrorView } from "decorator-shared/views/errors/search-error"; +import { SearchErrorView } from "../views/errors/search-error"; import { fetchAndValidateJson } from "../lib/fetch-and-validate"; export type SearchResult = z.infer; diff --git a/packages/server/src/notifications.ts b/packages/server/src/notifications.ts index f842767f..25cc5781 100644 --- a/packages/server/src/notifications.ts +++ b/packages/server/src/notifications.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { env } from "./env/server"; import { Result, ResultType } from "./result"; +import { fetchAndValidateJson } from "./lib/fetch-and-validate"; const varselSchema = z.object({ eventId: z.string(), @@ -65,34 +66,19 @@ export const getNotifications = async ({ }: { request: Request; }): Promise> => { - const fetchResult = await fetch( + return fetchAndValidateJson( `${env.VARSEL_API_URL}/varselbjelle/varsler`, { headers: { cookie: request.headers.get("cookie") || "", }, }, + varslerSchema, + ).then((result) => + result.ok + ? { ...result, data: varslerToNotifications(result.data) } + : result, ); - - if (!fetchResult.ok) { - return Result.Error(await fetchResult.text()); - } - - try { - const json = await fetchResult.json(); - - const validationResult = varslerSchema.safeParse(json); - if (!validationResult.success) { - return Result.Error(validationResult.error); - } - - return Result.Ok(varslerToNotifications(validationResult.data)); - } catch (error) { - if (error instanceof Error) { - return Result.Error(error); - } - throw error; - } }; export const archiveNotification = async ({ diff --git a/packages/server/src/views/errors/notifications-error.ts b/packages/server/src/views/errors/notifications-error.ts new file mode 100644 index 00000000..3757f510 --- /dev/null +++ b/packages/server/src/views/errors/notifications-error.ts @@ -0,0 +1,10 @@ +import html from "decorator-shared/html"; +import { Alert } from "decorator-shared/views/alert"; + +// TODO: add texts/translations +export const NotificationsErrorView = () => { + return html`${Alert({ + variant: "error", + content: html`
Åh nei, kunne ikke laste varsler!
`, + })}`; +}; diff --git a/packages/server/src/views/errors/search-error.ts b/packages/server/src/views/errors/search-error.ts new file mode 100644 index 00000000..72953662 --- /dev/null +++ b/packages/server/src/views/errors/search-error.ts @@ -0,0 +1,10 @@ +import html from "decorator-shared/html"; +import { Alert } from "decorator-shared/views/alert"; + +// TODO: add texts/translations +export const SearchErrorView = () => { + return html`${Alert({ + variant: "error", + content: html`
Åh nei, søket feilet!
`, + })}`; +}; diff --git a/packages/server/src/views/header/user-menu-dropdown.ts b/packages/server/src/views/header/user-menu-dropdown.ts index c3c58794..696a5ad1 100644 --- a/packages/server/src/views/header/user-menu-dropdown.ts +++ b/packages/server/src/views/header/user-menu-dropdown.ts @@ -12,8 +12,8 @@ import { Notification } from "../../notifications"; export type UserMenuDropdownProps = { texts: Texts; - name?: string; - notifications?: Notification[]; + name: string; + notifications: Notification[] | null; level: LoginLevel; logoutUrl: string; minsideUrl: string; @@ -28,18 +28,19 @@ export const UserMenuDropdown = ({ logoutUrl, minsideUrl, personopplysningerUrl, -}: UserMenuDropdownProps) => - DropdownMenu({ +}: UserMenuDropdownProps) => { + return DropdownMenu({ button: IconButton({ className: cls.userMenuButton, - text: name ?? "", - Icon: notifications?.length - ? PersonCircleNotificationIcon({ - className: cls.icon, - }) - : PersonCircleIcon({ - className: cls.icon, - }), + text: name, + Icon: + notifications && notifications.length > 0 + ? PersonCircleNotificationIcon({ + className: cls.icon, + }) + : PersonCircleIcon({ + className: cls.icon, + }), }), dropdownClass: cls.userMenuDropdown, dropdownContent: UserMenu({ @@ -52,3 +53,4 @@ export const UserMenuDropdown = ({ personopplysningerUrl, }), }); +}; diff --git a/packages/server/src/views/header/user-menu.ts b/packages/server/src/views/header/user-menu.ts index e6b0a447..9becfffc 100644 --- a/packages/server/src/views/header/user-menu.ts +++ b/packages/server/src/views/header/user-menu.ts @@ -11,11 +11,12 @@ import { Notifications } from "../notifications/notifications"; import { LoginLevel } from "decorator-shared/params"; import { Alert } from "decorator-shared/views/alert"; import { Notification } from "../../notifications"; +import { env } from "../../env/server"; export type UserMenuProps = { texts: Texts; - name?: string; - notifications?: Notification[]; + name: string; + notifications: Notification[] | null; level: LoginLevel; logoutUrl: string; minsideUrl: string; @@ -31,7 +32,7 @@ export const UserMenu = ({ minsideUrl, personopplysningerUrl, }: UserMenuProps) => - html`
+ html`
${texts.logged_in}
@@ -43,7 +44,7 @@ export const UserMenu = ({ content: html`
${texts.security_level_info} - Logg inn med BankID, Buypass, eller Commfides diff --git a/packages/server/src/views/notifications/notifications.ts b/packages/server/src/views/notifications/notifications.ts index a89bc50d..8ef8297c 100644 --- a/packages/server/src/views/notifications/notifications.ts +++ b/packages/server/src/views/notifications/notifications.ts @@ -11,10 +11,11 @@ import { Notification, UnmaskedNotification, } from "../../notifications"; +import { NotificationsErrorView } from "../errors/notifications-error"; export type NotificationsProps = { texts: Texts; - notifications?: Notification[]; + notifications: Notification[] | null; }; const kanalerToMetadata = (kanaler: string[], texts: Texts) => { @@ -36,7 +37,7 @@ const MaskedNotificationComp = ({ notification: MaskedNotification; texts: Texts; }) => - html`
+ html`
${type === "task" ? TaskIcon() : MessageIcon()} @@ -58,7 +59,7 @@ const NotificationComp = ({ texts: Texts; notification: UnmaskedNotification; }) => - html` @@ -74,7 +75,7 @@ const NotificationComp = ({
${text} ${channels.length > 0 && - html`
+ html`
${kanalerToMetadata(channels, texts)}
`} `; @@ -86,7 +87,7 @@ const ArchivableNotification = ({ notification: UnmaskedNotification; texts: Texts; }) => - html` + html`
${type === "task" ? TaskIcon() : MessageIcon()} @@ -97,7 +98,7 @@ const ArchivableNotification = ({
${text}
${channels.length > 0 && - html`
+ html`
${kanalerToMetadata(channels, texts)}
`} @@ -105,22 +106,30 @@ const ArchivableNotification = ({ `; export function Notifications({ texts, notifications }: NotificationsProps) { - return html`
+ return html`

${texts.notifications}

-
    - ${notifications?.map( - (notification) => html` -
  • - ${notification.masked === true - ? MaskedNotificationComp({ notification, texts }) - : notification.type === "message" && - !notification.link - ? ArchivableNotification({ notification, texts }) - : NotificationComp({ notification, texts })} -
  • - `, - )} -
+ ${notifications + ? html`
    + ${notifications.map( + (notification) => html` +
  • + ${notification.masked + ? MaskedNotificationComp({ + notification, + texts, + }) + : notification.type === "message" && + !notification.link + ? ArchivableNotification({ + notification, + texts, + }) + : NotificationComp({ notification, texts })} +
  • + `, + )} +
` + : NotificationsErrorView()} { - return html`${Alert({ - variant: "error", - content: html`
Åh nei, søket feilet!
`, - })}`; -};