Skip to content

Commit

Permalink
ruster opp logging og feilhåndtering
Browse files Browse the repository at this point in the history
* fikser next-logger
* har global feilside (ingen flere hvite  "unhandled client exceptions"-skjermer)
* har ordentlig 404-feilside
* splitter layout inn i locale/no locale
(så jeg kan ha error routes)
  • Loading branch information
toresbe committed Nov 20, 2024
1 parent 4583f50 commit e327a92
Show file tree
Hide file tree
Showing 21 changed files with 242 additions and 120 deletions.
18 changes: 14 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.2",
"i18next-resources-to-backend": "^1.2.1",
"js-cookie": "^3.0.5",
"jsdom": "^25.0.1",
"libphonenumber-js": "^1.11.14",
"markdown-to-jsx": "^7.6.2",
Expand Down
60 changes: 23 additions & 37 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,12 @@ import Behov from "./sider/kort/02-behov";
import ArbeidOgFamilie from "./sider/kort/03-arbeid-og-familie";
import {SwitchSoknadType} from "./SwitchSoknadType.tsx";
import Inntekt from "./sider/kort/04-inntekt";
import {BASE_PATH} from "./lib/constants";
import {configureLogger} from "@navikt/next-logger";
import "./faro";
import "./lib/i18n/reacti18Next.ts";
import {initAmplitude} from "./lib/amplitude/Amplitude.tsx";
import {getPathPrefixIncludingLocale} from "./getPathPrefixIncludingLocale.ts";
import {onLanguageSelect, setParams} from "@navikt/nav-dekoratoren-moduler";
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
import {ReactQueryDevtools} from "@tanstack/react-query-devtools";

configureLogger({basePath: BASE_PATH});
const queryClient = new QueryClient();

const RedirectToStandard = () => {
Expand All @@ -36,8 +31,6 @@ const RedirectToStandard = () => {
};

export default function App() {
initAmplitude();

// @ts-expect-error Polyfill for react-pdf, se https://github.com/wojtekmaj/react-pdf/issues/1831
if (typeof Promise.withResolvers === "undefined") {
// @ts-expect-error this is expected to not work
Expand All @@ -51,50 +44,43 @@ export default function App() {
};
}

const [basename, path] = getPathPrefixIncludingLocale();

onLanguageSelect(({locale: language, url}) =>
setParams({language}).then(() => window.location.assign(`${url}${path}`))
);

const {prefix} = getPathPrefixIncludingLocale();
return (
<Suspense fallback={<ApplicationSpinner />}>
<QueryClientProvider client={queryClient}>
<BrowserRouter
basename={basename}
basename={prefix}
future={{
// these are just to stop react-router-dom from spamming
v7_relativeSplatPath: true,
v7_startTransition: true,
}}
>
<Routes>
<Route>
<Route path={"skjema"}>
<Route path="kort/:behandlingsId">
<Route element={<SwitchSoknadType />}>
<Route path="1" element={<RedirectToStandard />} />
<Route path="2" element={<Behov />} />
<Route path="3" element={<ArbeidOgFamilie />} />
<Route path="4" element={<Inntekt />} />
<Route path="5" element={<Oppsummering />} />
</Route>
<Route path={"skjema"}>
<Route path="kort/:behandlingsId">
<Route element={<SwitchSoknadType />}>
<Route path="1" element={<RedirectToStandard />} />
<Route path="2" element={<Behov />} />
<Route path="3" element={<ArbeidOgFamilie />} />
<Route path="4" element={<Inntekt />} />
<Route path="5" element={<Oppsummering />} />
</Route>
<Route path=":behandlingsId">
<Route index path="1" element={<Personopplysninger shortSpacing />} />
<Route element={<SwitchSoknadType />}>
<Route path="2" element={<Begrunnelse />} />
<Route path="3" element={<ArbeidOgUtdanning />} />
<Route path="4" element={<Familie />} />
<Route path="5" element={<Bosituasjon />} />
<Route path="6" element={<InntektFormue />} />
<Route path="7" element={<UtgifterGjeld />} />
<Route path="8" element={<OkonomiskeOpplysningerView />} />
<Route path="9" element={<Oppsummering />} />
<Route element={<IkkeFunnet />} />
</Route>
</Route>
<Route path=":behandlingsId">
<Route index path="1" element={<Personopplysninger shortSpacing />} />
<Route element={<SwitchSoknadType />}>
<Route path="2" element={<Begrunnelse />} />
<Route path="3" element={<ArbeidOgUtdanning />} />
<Route path="4" element={<Familie />} />
<Route path="5" element={<Bosituasjon />} />
<Route path="6" element={<InntektFormue />} />
<Route path="7" element={<UtgifterGjeld />} />
<Route path="8" element={<OkonomiskeOpplysningerView />} />
<Route path="9" element={<Oppsummering />} />
</Route>
</Route>
<Route path="*" element={<IkkeFunnet />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
10 changes: 9 additions & 1 deletion src/app/[locale]/[...slug]/client.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
"use client";

import React from "react";
import React, {useEffect} from "react";
import dynamic from "next/dynamic";
import {BASE_PATH} from "../../../lib/constants.ts";
import {configureLogger} from "@navikt/next-logger";
import {initAmplitude} from "../../../lib/amplitude/Amplitude.tsx";

const App = dynamic(() => import("../../../app.tsx"), {ssr: false});

export function ClientOnly() {
configureLogger({basePath: BASE_PATH});
useEffect(() => {
initAmplitude();
}, []);

return <App />;
}
16 changes: 0 additions & 16 deletions src/app/[locale]/error.tsx

This file was deleted.

50 changes: 12 additions & 38 deletions src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,26 @@
import {fetchDecoratorReact} from "@navikt/nav-dekoratoren-moduler/ssr";
import Script from "next/script";
import {DECORATOR_SETTINGS} from "../../decoratorSettings.tsx";
import {Driftsmeldinger} from "../../lib/driftsmeldinger/Driftsmeldinger.tsx";
import {notFound} from "next/navigation";
import {isSupportedLanguage} from "../../lib/i18n/common.ts";
import {getMessages} from "next-intl/server";
import {NextIntlClientProvider} from "next-intl";
import "../../index.css";
import {DigisosContextProvider} from "../../lib/providers/DigisosContextProvider.tsx";
import {NextIntlClientProvider} from "next-intl";
import {getMessages} from "next-intl/server";

export const dynamic = "force-dynamic";

export default async function RootLayout({
export default async function Layout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{locale: string}>;
}) {
const {locale} = await params;
if (!isSupportedLanguage(locale)) notFound();

const Decorator = await fetchDecoratorReact({
...DECORATOR_SETTINGS,
params: {...DECORATOR_SETTINGS.params, language: locale},
});

const {locale: localeParam} = await params;
const messages = await getMessages();

// locale blir hentet via middleware.ts,
// og html lang leses (som document.documentElement.lang) av både analytics og klientside i18n
const locale = isSupportedLanguage(localeParam) ? localeParam : "nb";
return (
<html lang={locale}>
<head>
<title>Søknad om økonomisk sosialhjelp</title>
<Decorator.HeadAssets />
</head>
<body>
<Decorator.Header />
<Driftsmeldinger />
<div id="root" className={"bg-digisosGronnBakgrunn"} role={"none"}>
<NextIntlClientProvider messages={messages}>
<DigisosContextProvider>{children}</DigisosContextProvider>
</NextIntlClientProvider>
</div>
<Decorator.Footer />
<Decorator.Scripts loader={Script} />
</body>
</html>
<NextIntlClientProvider messages={messages} locale={locale}>
<DigisosContextProvider locale={locale}>{children}</DigisosContextProvider>
</NextIntlClientProvider>
);
}

export async function generateStaticParams() {
return [{locale: "nb"}, {locale: "nn"}, {locale: "en"}];
}
18 changes: 18 additions & 0 deletions src/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
"use client";
import Informasjon from "../../sider/hovedmeny";
import {getPathPrefixIncludingLocale} from "../../getPathPrefixIncludingLocale.ts";
import {onLanguageSelect, setParams} from "@navikt/nav-dekoratoren-moduler";
import {useContext, useEffect} from "react";
import {DigisosContext} from "../../lib/providers/DigisosContext.ts";
import {BASE_PATH} from "../../lib/constants.ts";
import {configureLogger} from "@navikt/next-logger";
import {initAmplitude} from "../../lib/amplitude/Amplitude.tsx";

const Page = () => {
configureLogger({basePath: BASE_PATH});
initAmplitude();
const {path} = getPathPrefixIncludingLocale();
const locale = useContext(DigisosContext)!.locale;
useEffect(() => {
document.documentElement.lang = locale;
setParams({language: locale}).then(() => {});
}, [locale]);
onLanguageSelect(({locale: language, url}) =>
setParams({language}).then(() => window.location.assign(`${url}${path}`))
);
return <Informasjon />;
};

Expand Down
File renamed without changes.
23 changes: 23 additions & 0 deletions src/app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client";

import TekniskFeil from "../sider/feilsider/TekniskFeil.tsx";
import {logger} from "@navikt/next-logger";
import {logError} from "../lib/log/loggerUtils.ts";
import {useEffect} from "react";
import {faro} from "@grafana/faro-react";

export const ErrorComponent = ({error, reset}: {error: Error; reset: () => void}) => {
if (faro.api) faro.api.pushError(error);
useEffect(() => {
if (process.env.NEXT_PUBLIC_DIGISOS_ENV === "localhost") {
logger.error(
{errorMessage: error.message, referrer: document.referrer, location: document.location.href},
`En bruker har sett TekniskFeil`
);
logError(`Viser feilside, error, referrer: ${document.referrer}`);
}
}, [error]);
return <TekniskFeil error={error} reset={reset} />;
};

export default ErrorComponent;
39 changes: 39 additions & 0 deletions src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";

import {configureLogger, logger} from "@navikt/next-logger";
import Cookie from "js-cookie";
import {BASE_PATH, DECORATOR_LANG_COOKIE} from "../lib/constants.ts";
import {isSupportedLanguage} from "../lib/i18n/common.ts";
import {AbstractIntlMessages, NextIntlClientProvider} from "next-intl";
import TekniskFeil from "../sider/feilsider/TekniskFeil.tsx";
import {useEffect, useState} from "react";

export default function GlobalError({error, reset}: {error: Error & {digest?: string}; reset: () => void}) {
configureLogger({basePath: BASE_PATH, apiPath: `${BASE_PATH}/api`});

useEffect(() => {
if (process.env.NEXT_PUBLIC_DIGISOS_ENV !== "localhost")
logger.error(`En bruker har sett GlobalError, error: ${error} referrer: ${document.referrer}`);
}, [error]);
const langCookie = Cookie.get(DECORATOR_LANG_COOKIE);
const locale = langCookie && isSupportedLanguage(langCookie) ? langCookie : "nb";
const [messages, setMessages] = useState<AbstractIntlMessages | null>();
import(`../../messages/${locale}.json`).then((module) => module.default).then(setMessages);

return (
<html lang={locale}>
<head>
<title>Søknad om økonomisk sosialhjelp</title>
</head>
<body>
<div id="root" className={"bg-digisosGronnBakgrunn"} role={"none"}>
{messages && (
<NextIntlClientProvider messages={messages} locale={locale}>
<TekniskFeil error={error} reset={reset} />
</NextIntlClientProvider>
)}
</div>
</body>
</html>
);
}
44 changes: 44 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {fetchDecoratorReact} from "@navikt/nav-dekoratoren-moduler/ssr";
import Script from "next/script";
import {DECORATOR_SETTINGS} from "../decoratorSettings.tsx";
import {isSupportedLanguage} from "../lib/i18n/common.ts";
import {getMessages} from "next-intl/server";
import {NextIntlClientProvider} from "next-intl";
import "../index.css";
import {cookies} from "next/headers";
import {DECORATOR_LANG_COOKIE} from "../lib/constants.ts";

export const dynamic = "force-dynamic";

export default async function RootLayout({children}: {children: React.ReactNode}) {
const jar = await cookies();
const cookie = jar.get(DECORATOR_LANG_COOKIE)?.value;
const locale = cookie && isSupportedLanguage(cookie) ? cookie : "nb";

const Decorator = await fetchDecoratorReact({
...DECORATOR_SETTINGS,
params: {...DECORATOR_SETTINGS.params, language: locale},
});

const messages = await getMessages();
// locale blir hentet via middleware.ts,
// og html lang leses (som document.documentElement.lang) av både analytics og klientside i18n
return (
<html lang={locale}>
<head>
<title>Søknad om økonomisk sosialhjelp</title>
<Decorator.HeadAssets />
</head>
<body>
<Decorator.Header />
<div id="root" className={"bg-digisosGronnBakgrunn"} role={"none"}>
<NextIntlClientProvider messages={messages} locale={locale}>
{children}
</NextIntlClientProvider>
</div>
<Decorator.Footer />
<Decorator.Scripts loader={Script} />
</body>
</html>
);
}
13 changes: 13 additions & 0 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client";

import IkkeFunnet from "../sider/feilsider/IkkeFunnet.tsx";

const NotFound = () => {
return (
<div className={"grow bg-white flex-col flex"}>
<IkkeFunnet />
</div>
);
};

export default NotFound;
Loading

0 comments on commit e327a92

Please sign in to comment.