diff --git a/.env.template b/.env.template
index 46c84eb..234b9d3 100644
--- a/.env.template
+++ b/.env.template
@@ -1,7 +1,6 @@
NODE_ENV=development
SESSION_KEY=dette-er-en-lang-og-sikker-streng-for-signering-av-session-cookies
AUTH_REDIRECT_URI=http://localhost:8080/oauth2/callback
-INTERNARBEIDSFLATEDECORATOR_HOST=internarbeidsflatedecorator-q1.dev.intern.nav.no
MODIACONTEXTHOLDER_HOST=modiacontextholder.dev.intern.nav.no
MODIACONTEXTHOLDER_AAD_APP_CLIENT_ID=dev-gcp.personoversikt.modiacontextholder
FASTLEGEREST_HOST=https://fastlegerest.intern.dev.nav.no
diff --git a/.nais/naiserator-dev.yaml b/.nais/naiserator-dev.yaml
index 05375dc..37af269 100644
--- a/.nais/naiserator-dev.yaml
+++ b/.nais/naiserator-dev.yaml
@@ -31,12 +31,8 @@ spec:
value: production
- name: REDIS_HOST
value: finnfastlege-redis
- - name: FINNFASTLEGE_URL
- value: "http://finnfastlege"
- name: AUTH_REDIRECT_URI
value: "https://finnfastlege.intern.dev.nav.no/oauth2/callback"
- - name: INTERNARBEIDSFLATEDECORATOR_HOST
- value: "internarbeidsflatedecorator-q1.dev-fss-pub.nais.io"
- name: FASTLEGEREST_AAD_APP_CLIENT_ID
value: "dev-gcp.teamsykefravr.fastlegerest"
- name: SYFOPERSON_AAD_APP_CLIENT_ID
@@ -63,7 +59,6 @@ spec:
outbound:
external:
- host: "login.microsoftonline.com"
- - host: "internarbeidsflatedecorator-q1.dev-fss-pub.nais.io"
rules:
- application: fastlegerest
- application: istilgangskontroll
diff --git a/.nais/naiserator-prod.yaml b/.nais/naiserator-prod.yaml
index ea8a573..939f9b5 100644
--- a/.nais/naiserator-prod.yaml
+++ b/.nais/naiserator-prod.yaml
@@ -31,12 +31,8 @@ spec:
value: production
- name: REDIS_HOST
value: finnfastlege-redis
- - name: FINNFASTLEGE_URL
- value: "http://finnfastlege"
- name: AUTH_REDIRECT_URI
value: "https://finnfastlege.intern.nav.no/oauth2/callback"
- - name: INTERNARBEIDSFLATEDECORATOR_HOST
- value: "internarbeidsflatedecorator.prod-fss-pub.nais.io"
- name: FASTLEGEREST_AAD_APP_CLIENT_ID
value: "prod-gcp.teamsykefravr.fastlegerest"
- name: SYFOPERSON_AAD_APP_CLIENT_ID
@@ -63,7 +59,6 @@ spec:
outbound:
external:
- host: "login.microsoftonline.com"
- - host: "internarbeidsflatedecorator.prod-fss-pub.nais.io"
rules:
- application: fastlegerest
- application: istilgangskontroll
diff --git a/public/index.html b/public/index.html
index 400c6e1..13800fc 100644
--- a/public/index.html
+++ b/public/index.html
@@ -6,16 +6,16 @@
<% if (process.env.NODE_ENV !== 'development') { %>
-
+
<% } %> <% if (process.env.NODE_ENV === 'development') { %>
-
+
<% } %>
diff --git a/server/authUtils.ts b/server/authUtils.ts
index 0631df3..301c41a 100644
--- a/server/authUtils.ts
+++ b/server/authUtils.ts
@@ -34,7 +34,7 @@ async function initJWKSet() {
_remoteJWKSet = await createRemoteJWKSet(new URL(Config.auth.jwksUri));
}
-const retrieveToken = async (
+const retrieveAndValidateToken = async (
req: Request,
azureAdIssuer: OpenIdClient.Issuer
): Promise => {
@@ -95,7 +95,7 @@ export const getOrRefreshOnBehalfOfToken = async (
req: Request,
clientId: string
): Promise => {
- const token = await retrieveToken(req, issuer);
+ const token = await retrieveAndValidateToken(req, issuer);
if (!token) {
throw Error(
"Could not get on-behalf-of token because the token was undefined"
@@ -104,6 +104,7 @@ export const getOrRefreshOnBehalfOfToken = async (
if (req.session.tokenCache === undefined) {
req.session.tokenCache = {};
}
+
let cachedOboToken = req.session.tokenCache[clientId];
if (cachedOboToken && isNotExpired(cachedOboToken)) {
return cachedOboToken.token;
diff --git a/server/config.ts b/server/config.ts
index ec6ad27..627a3b7 100644
--- a/server/config.ts
+++ b/server/config.ts
@@ -43,16 +43,6 @@ export interface ExternalAppConfig {
export const server = {
host: envVar({ name: "HOST", defaultValue: "localhost" }),
port: Number.parseInt(envVar({ name: "PORT", defaultValue: "8080" })),
- finnfastlegeUrl: envVar({
- name: "FINNFASTLEGE_URL",
- defaultValue: "http://localhost:8080",
- }),
-
- frontendDir: envVar({
- name: "FRONTEND_DIR",
- defaultValue: path.join(__dirname, "frontend"),
- }),
-
sessionKey: envVar({ name: "SESSION_KEY" }),
sessionCookieName: envVar({
name: "SESSION_COOKIE_NAME",
@@ -109,10 +99,6 @@ export const auth = {
responseMode: "query",
tokenEndpointAuthSigningAlg: "RS256",
- internarbeidsflatedecoratorHost: envVar({
- name: "INTERNARBEIDSFLATEDECORATOR_HOST",
- }),
-
modiacontextholder: {
applicationName: "modiacontextholder",
clientId: envVar({
@@ -121,6 +107,7 @@ export const auth = {
host: envVar({
name: "MODIACONTEXTHOLDER_HOST",
}),
+ removePathPrefix: true,
},
fastlegerest: {
diff --git a/server/proxy.ts b/server/proxy.ts
index 5162ee8..6e5f5c0 100644
--- a/server/proxy.ts
+++ b/server/proxy.ts
@@ -168,28 +168,5 @@ export const setupProxy = (
);
}
);
-
- router.use(
- "/internarbeidsflatedecorator",
- expressHttpProxy(Config.auth.internarbeidsflatedecoratorHost, {
- https: true,
- proxyReqPathResolver: (req) => {
- return `/internarbeidsflatedecorator${req.url}`;
- },
- proxyErrorHandler: (err, res, next) => {
- console.log(
- `Error in proxy for internarbeidsflatedecorator ${err.message}, ${err.code}`
- );
- if (err && err.code === "ECONNREFUSED") {
- console.log("proxyErrorHandler: Got ECONNREFUSED");
- return res
- .status(503)
- .send({ message: `Could not contact internarbeidsflatedecorator` });
- }
- next(err);
- },
- })
- );
-
return router;
};
diff --git a/src/api/axios.ts b/src/api/axios.ts
index 0a4a57d..8639cce 100644
--- a/src/api/axios.ts
+++ b/src/api/axios.ts
@@ -75,3 +75,23 @@ export const get = (
}
});
};
+
+export const post = (
+ url: string,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ data: Record | Record[],
+ personIdent?: string
+): Promise => {
+ return axios
+ .post(url, data, {
+ headers: defaultRequestHeaders(personIdent),
+ })
+ .then((response) => response.data)
+ .catch(function (error) {
+ if (axios.isAxiosError(error)) {
+ handleAxiosError(error);
+ } else {
+ throw new ApiErrorException(generalError(error), error.code);
+ }
+ });
+};
diff --git a/src/api/constants.ts b/src/api/constants.ts
index fb4430d..ce47fd6 100644
--- a/src/api/constants.ts
+++ b/src/api/constants.ts
@@ -1,3 +1,4 @@
+export const MODIACONTEXTHOLDER_ROOT = "/modiacontextholder/api";
export const SYFOPERSON_ROOT = "/syfoperson/api/v2";
export const FASTLEGEREST_ROOT = "/fastlegerest/api/v2";
export const TILGANGSKONTROLL_AD_PATH =
diff --git a/src/data/modiacontext/useAktivBruker.ts b/src/data/modiacontext/useAktivBruker.ts
new file mode 100644
index 0000000..60c7714
--- /dev/null
+++ b/src/data/modiacontext/useAktivBruker.ts
@@ -0,0 +1,14 @@
+import { post } from "@/api/axios";
+import { MODIACONTEXTHOLDER_ROOT } from "@/api/constants";
+import { useMutation } from "@tanstack/react-query";
+
+const NY_AKTIV_BRUKER = "NY_AKTIV_BRUKER";
+
+export const useAktivBruker = () =>
+ useMutation({
+ mutationFn: (fnr: string) =>
+ post(`${MODIACONTEXTHOLDER_ROOT}/context`, {
+ verdi: fnr,
+ eventType: NY_AKTIV_BRUKER,
+ }),
+ });
diff --git a/src/decorator/Decorator.tsx b/src/decorator/Decorator.tsx
index 787b313..1b1e203 100644
--- a/src/decorator/Decorator.tsx
+++ b/src/decorator/Decorator.tsx
@@ -3,16 +3,23 @@ import NAVSPA from "@navikt/navspa";
import { DecoratorProps } from "./decoratorProps";
import decoratorConfig from "./decoratorconfig";
import { fullNaisUrlDefault } from "@/utils/miljoUtil";
+import { useAktivBruker } from "@/data/modiacontext/useAktivBruker";
const InternflateDecorator = NAVSPA.importer(
- "internarbeidsflatefs"
+ "internarbeidsflate-decorator-v3"
);
const Decorator = () => {
+ const aktivBruker = useAktivBruker();
+
const handlePersonsokSubmit = (nyttFnr: string) => {
- const host = "syfomodiaperson";
- const path = `/sykefravaer/${nyttFnr}`;
- window.location.href = fullNaisUrlDefault(host, path);
+ aktivBruker.mutate(nyttFnr, {
+ onSuccess: () => {
+ const host = "syfomodiaperson";
+ const path = `/sykefravaer`;
+ window.location.href = fullNaisUrlDefault(host, path);
+ },
+ });
};
const config = useCallback(decoratorConfig, [handlePersonsokSubmit])(
diff --git a/src/decorator/decoratorProps.ts b/src/decorator/decoratorProps.ts
index c10492a..625c897 100644
--- a/src/decorator/decoratorProps.ts
+++ b/src/decorator/decoratorProps.ts
@@ -1,48 +1,67 @@
-interface TogglesConfig {
- visVeileder: boolean;
+export interface DecoratorProps {
+ enhet?: string | undefined; // Konfigurasjon av enhet-kontekst
+ accessToken?: string | undefined; // Manuell innsending av JWT, settes som Authorization-header. Om null sendes cookies vha credentials: 'include'
+ fnr?: string | undefined; // Konfigurasjon av fødselsnummer-kontekst
+ userKey?: string | undefined; // Om man ikke ønsker å bruke fnr i urler, kan andre apper kalle contextholder for å generere en midlertidig kode. Hvis App A skal navigere til App B som har dekoratøren, må App A først sende en post request til /fnr-code/generate med {fnr: string} i bodyen, dette returnerer {fnr: string, code: string} til App A. App A kan så navigere til App B og sende med denne koden. App B kan så sende den koden inn til dekoratøren i userKey propen og så henter dekoratøren fnr for den koden fra contextholderen.
+ enableHotkeys?: boolean | undefined; // Aktivere hurtigtaster
+ fetchActiveEnhetOnMount?: boolean | undefined; // Om enhet er undefined fra container appen, og denne er satt til true, henter den sist aktiv enhet og bruker denne.
+ fetchActiveUserOnMount?: boolean | undefined; // Om fnr er undefined fra container appen, og denne er satt til true for at den skal hente siste aktiv fnr.
+ onEnhetChanged: (enhetId?: string | null, enhet?: Enhet) => void; // Kalles når enheten endres
+ onFnrChanged: (fnr?: string | null) => void; // Kalles når fnr enheten endres
+ onLinkClick?: (link: { text: string; url: string }) => void; // Kan brukes for å legge til callbacks ved klikk på lenker i menyen. Merk at callbacken ikke kan awaites og man må selv håndtere at siden lukkes. Nyttig for å f.eks tracke navigasjon events i amplitude
+ appName: string; // Navn på applikasjonen
+ hotkeys?: Hotkey[]; // Konfigurasjon av hurtigtaster
+ markup?: Markup; // Egen HTML
+ showEnheter: boolean; // Vis enheter
+ showSearchArea: boolean; // Vis søkefelt
+ showHotkeys: boolean; // Vis hurtigtaster
+ environment: Environment; // Miljø som skal brukes.
+ urlFormat: UrlFormat; // URL format
+ proxy?: string | undefined; // Manuell overstyring av urlene til BFFs. Gjør alle kall til relativt path hvis true, og bruker verdien som domene om satt til en string. Default: false
}
-interface Markup {
- etterSokefelt?: string;
+export interface Markup {
+ etterSokefelt?: string; // Gir muligheten for sende inn egen html som blir en del av dekoratøren
}
-export interface ControlledContextvalue extends BaseContextvalue {
- value?: string;
-}
-interface UncontrolledContextvalue extends BaseContextvalue {
- initialValue?: string;
+export interface Enhet {
+ readonly enhetId: string;
+ readonly navn: string;
}
-interface BaseContextvalue {
- display: T;
- onChange(value?: string): void;
- skipModal?: boolean;
- ignoreWsEvents?: boolean;
-}
+// Miljø
+export type Environment =
+ | "q0"
+ | "q1"
+ | "q2"
+ | "q3"
+ | "q4"
+ | "prod"
+ | "local"
+ | "mock";
-export type Contextvalue =
- | ControlledContextvalue
- | UncontrolledContextvalue;
+export type UrlFormat = "LOCAL" | "NAV_NO" | "ANSATT"; // UrlFormat. Brukes om proxy ikke er satt & i url til websocket.
-export enum EnhetDisplay {
- ENHET = "ENHET",
- ENHET_VALG = "ENHET_VALG",
+export interface HotkeyObject {
+ char: string;
+ altKey?: boolean;
+ ctrlKey?: boolean;
+ metaKey?: boolean;
+ shiftKey?: boolean;
}
-export enum FnrDisplay {
- SOKEFELT = "SOKEFELT",
+export interface HotkeyDescription {
+ key: HotkeyObject;
+ description: string;
+ forceOverride?: boolean;
}
-type EnhetContextvalue = Contextvalue;
-type FnrContextvalue = Contextvalue;
-type ProxyConfig = boolean | string;
+export interface ActionHotKey extends HotkeyDescription {
+ action(event: KeyboardEvent): void;
+}
-export interface DecoratorProps {
- appname: string;
- fnr?: FnrContextvalue;
- enhet?: EnhetContextvalue;
- toggles?: TogglesConfig;
- markup?: Markup;
- useProxy?: ProxyConfig;
- accessToken?: string;
+export interface DocumentingHotKey extends HotkeyDescription {
+ documentationOnly: boolean;
}
+
+export type Hotkey = ActionHotKey | DocumentingHotKey;
diff --git a/src/decorator/decoratorconfig.ts b/src/decorator/decoratorconfig.ts
index 13f97e2..cf6ac3a 100644
--- a/src/decorator/decoratorconfig.ts
+++ b/src/decorator/decoratorconfig.ts
@@ -1,34 +1,48 @@
-import { DecoratorProps, EnhetDisplay, FnrDisplay } from "./decoratorProps";
+import {
+ DecoratorProps,
+ Enhet,
+ Environment,
+ UrlFormat,
+} from "./decoratorProps";
+import { erAnsattDev, erDev, erLokal, erProd } from "@/utils/miljoUtil";
-const RESET_VALUE = "\u0000";
-
-const decoratorconfig = (setFnr: (fnr: string) => void): DecoratorProps => {
+const decoratorConfig = (setFnr: (fnr: string) => void): DecoratorProps => {
return {
- appname: "Sykefraværsoppfølging",
- fnr: {
- initialValue: RESET_VALUE,
- display: FnrDisplay.SOKEFELT,
- ignoreWsEvents: true,
- skipModal: true,
- onChange: (value) => {
- if (value) {
- setFnr(value);
- }
- },
- },
- enhet: {
- initialValue: undefined,
- display: EnhetDisplay.ENHET_VALG,
- onChange(): void {
- /* Do nothing */
- },
- skipModal: true,
+ appName: "Sykefraværsoppfølging",
+ fetchActiveEnhetOnMount: false,
+ onEnhetChanged: (enhetId?: string | null, enhet?: Enhet) => {
+ // do nothing
},
- toggles: {
- visVeileder: true,
+ onFnrChanged: (fnr?: string | null) => {
+ if (fnr) {
+ setFnr(fnr);
+ }
},
- useProxy: true,
+ showEnheter: true,
+ showSearchArea: true,
+ showHotkeys: false,
+ environment: getEnvironment(),
+ urlFormat: getUrlFormat(),
+ proxy: "/modiacontextholder",
};
};
-export default decoratorconfig;
+const getEnvironment = (): Environment => {
+ if (erProd()) {
+ return "prod";
+ } else if (erDev()) {
+ return "q2";
+ } else {
+ return "local";
+ }
+};
+
+const getUrlFormat = (): UrlFormat => {
+ if (erAnsattDev()) {
+ return "ANSATT";
+ } else if (erLokal()) {
+ return "LOCAL";
+ } else return "NAV_NO";
+};
+
+export default decoratorConfig;
diff --git a/src/faro.ts b/src/faro.ts
index 9c1ec11..4c50ae8 100644
--- a/src/faro.ts
+++ b/src/faro.ts
@@ -1,11 +1,11 @@
import { getWebInstrumentations, initializeFaro } from "@grafana/faro-react";
import { TracingInstrumentation } from "@grafana/faro-web-tracing";
-import { erLokal, erPreProd } from "@/utils/miljoUtil";
+import { erLokal, erDev } from "@/utils/miljoUtil";
const getUrl = () => {
if (erLokal()) {
return "/collect";
- } else if (erPreProd()) {
+ } else if (erDev()) {
return "https://telemetry.ekstern.dev.nav.no/collect";
} else {
return "https://telemetry.nav.no/collect";
diff --git a/src/utils/fnrValideringUtil.ts b/src/utils/fnrValideringUtil.ts
index f32c0b5..23478e7 100644
--- a/src/utils/fnrValideringUtil.ts
+++ b/src/utils/fnrValideringUtil.ts
@@ -1,4 +1,4 @@
-import { erPreProd } from "@/utils/miljoUtil";
+import { erDev } from "@/utils/miljoUtil";
const kontrollRekke1 = [3, 7, 6, 1, 8, 9, 4, 5, 2];
const kontrollRekke2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
@@ -35,7 +35,7 @@ const erGyldigSkatteetatenTestdato = (dag: number, maned: number) => {
const erGyldigTestdato = (dag: number, maned: number) => {
return (
- erPreProd() &&
+ erDev() &&
(erGyldigNavTestdato(dag, maned) ||
erGyldigSkatteetatenTestdato(dag, maned))
);
diff --git a/src/utils/miljoUtil.ts b/src/utils/miljoUtil.ts
index 911a27d..a26c335 100644
--- a/src/utils/miljoUtil.ts
+++ b/src/utils/miljoUtil.ts
@@ -1,16 +1,30 @@
-export const erPreProd = () => {
+export const erDev = (): boolean => {
return (
+ window.location.href.indexOf("dev.intern.nav.no") > -1 ||
window.location.href.indexOf("intern.dev.nav.no") > -1 ||
- window.location.href.indexOf("dev.intern.nav.no") > -1
+ erAnsattDev()
);
};
-export const erLokal = () => {
+export const erAnsattDev = (): boolean => {
+ return window.location.href.indexOf("ansatt.dev.nav.no") > -1;
+};
+
+export const erLokal = (): boolean => {
return window.location.host.indexOf("localhost") > -1;
};
+export function erProd(): boolean {
+ return window.location.href.indexOf("finnfastlege.intern.nav.no") > -1;
+}
-export const finnNaisUrlDefault = () => {
- return erPreProd() ? ".dev.intern.nav.no" : ".intern.nav.no";
+const finnNaisUrlDefault = (): string => {
+ if (erAnsattDev()) {
+ return ".ansatt.dev.nav.no";
+ } else if (erDev()) {
+ return ".intern.dev.nav.no";
+ } else {
+ return ".intern.nav.no";
+ }
};
export const fullNaisUrlDefault = (host: string, path: string) => {