Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kontaktinfo #1703

Merged
merged 19 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 1 addition & 19 deletions server/mock/innloggetMock.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
const sessions = {};
export const mock = function (app) {
app.get('/min-side-arbeidsgiver/api/innlogget', (req, res) => {
const token = sessions[req.ip];
if (token) {
console.log('innlogget? ja (session eksisterer)');
res.status(200).send();
} else {
console.log('innlogget? nei (session mangler)');
res.status(401).send();
}
res.status(200).send();
});
app.get('/min-side-arbeidsgiver/redirect-til-login', async (req, res) => {
const response = await fetch('https://fakedings.intern.dev.nav.no/fake/custom', {
method: 'POST',
headers: {
'Content-type': 'application/x-www-form-urlencoded',
},
body: `sub=00112233445&aud=${encodeURIComponent('bruker-api')}&acr=Level4`,
});
const token = await response.text();
sessions[req.ip] = token;
console.log(`login: setter session til ${token}`);
res.redirect(req.get('referer'));
});
};
53 changes: 53 additions & 0 deletions server/mock/kontaktinfoApiMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const response = [
{
hovedenhet: null,
underenhet: null,
},
{
hovedenhet: {
eposter: [],
telefonnumre: [],
},
underenhet: {
eposter: [],
telefonnumre: [],
},
},
{
hovedenhet: {
eposter: ['[email protected]'],
telefonnumre: [],
},
underenhet: {
eposter: [],
telefonnumre: ['+4700000'],
},
},
{
hovedenhet: {
eposter: ['[email protected]', '[email protected]'],
telefonnumre: [],
},
underenhet: {
eposter: ['[email protected]'],
telefonnumre: ['+4700000'],
},
},
{
hovedenhet: {
eposter: ['[email protected]', '[email protected]'],
telefonnumre: ['+4700000'],
},
underenhet: {
eposter: [],
telefonnumre: ['+4700000'],
},
},
];

export const mock = (app) => {
app.post('/min-side-arbeidsgiver/api/kontaktinfo/v1', (req, res) => {
const randomRespons = response[Math.floor(Math.random() * 5)];
return res.send(randomRespons);
});
};
1 change: 1 addition & 0 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ const main = async () => {
(await import('./mock/refusjonsStatusMock.js')).mock(app);
(await import('./mock/presenterteKandidaterMock.js')).mock(app);
(await import('./mock/storageMock.js')).mock(app);
(await import('./mock/kontaktinfoApiMock.js')).mock(app);

const {
applyNotifikasjonMockMiddleware,
Expand Down
2 changes: 1 addition & 1 deletion src/App/InformasjonOmBedrift/InformasjonOmBedrift.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.informasjon-om-bedrift {
margin: 2rem auto;
margin: 24px auto;
padding: 2rem;
max-width: 60rem;
width: 100%;
Expand Down
68 changes: 40 additions & 28 deletions src/App/InformasjonOmBedrift/InformasjonOmBedrift.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,72 @@
import React, {FunctionComponent, useContext, useEffect, useState} from 'react';
import {OrganisasjonsDetaljerContext} from '../OrganisasjonDetaljerProvider';
import {Enhet, hentOverordnetEnhet, hentUnderenhet} from '../../api/enhetsregisteretApi';
import React, { FunctionComponent, useContext, useEffect, useState } from 'react';
import { OrganisasjonsDetaljerContext } from '../OrganisasjonDetaljerProvider';
import { Enhet, hentOverordnetEnhet, hentUnderenhet } from '../../api/enhetsregisteretApi';
import Underenhet from './Underenhet/Underenhet';
import OverordnetEnhet from './OverordnetEnhet/OverordnetEnhet';
import Brodsmulesti from '../Brodsmulesti/Brodsmulesti';
import './InformasjonOmBedrift.css';
import {Panel} from "@navikt/ds-react";
import { Panel } from '@navikt/ds-react';

interface Enheter {
export interface Enheter {
underenhet: Enhet;
hovedenhet: Enhet;
}

const hentEnheter = async (orgnr: string): Promise<Enheter | undefined> => {
const underenhet = await hentUnderenhet(orgnr)
const underenhet = await hentUnderenhet(orgnr);
if (underenhet === undefined) {
return undefined
return undefined;
}
if (underenhet.overordnetEnhet === undefined) {
return undefined
return undefined;
}
const hovedenhet = await hentOverordnetEnhet(underenhet.overordnetEnhet)
const hovedenhet = await hentOverordnetEnhet(underenhet.overordnetEnhet);
if (hovedenhet === undefined) {
return undefined
return undefined;
}
return {underenhet, hovedenhet}
}
return { underenhet, hovedenhet };
};

const Kontaktpanel = ({ children }: { children: React.ReactNode }) => (
<Panel className="informasjon-om-bedrift">{children}</Panel>
);

const InformasjonOmBedrift: FunctionComponent = () => {
const {valgtOrganisasjon} = useContext(OrganisasjonsDetaljerContext);
const { valgtOrganisasjon } = useContext(OrganisasjonsDetaljerContext);
const [enheter, setEnheter] = useState<Enheter | undefined>(undefined);
const orgnr = valgtOrganisasjon?.organisasjon.OrganizationNumber ?? '';
const orgnr = valgtOrganisasjon?.organisasjon.OrganizationNumber;

useEffect(() => {
if (orgnr !== '') {
hentEnheter(orgnr).then(setEnheter)
if (orgnr !== undefined) {
hentEnheter(orgnr).then(setEnheter);
} else {
setEnheter(undefined)
setEnheter(undefined);
}
}, [orgnr]);

return (
<>
<Brodsmulesti brodsmuler={[{url: '/bedriftsinformasjon', title: 'Bedriftsprofil', handleInApp: true}]}/>
<Panel className='informasjon-om-bedrift'>
{enheter !== undefined ? (
<>
<Underenhet underenhet={enheter.underenhet}/>
<OverordnetEnhet overordnetenhet={enheter.hovedenhet}/>
</>
) : (
<Brodsmulesti
brodsmuler={[
{ url: '/bedriftsinformasjon', title: 'Bedriftsprofil', handleInApp: true },
]}
/>
{enheter !== undefined ? (
<div className="">
ebelegu marked this conversation as resolved.
Show resolved Hide resolved
<Kontaktpanel>
<Underenhet underenhet={enheter.underenhet} />
</Kontaktpanel>
<Kontaktpanel>
<OverordnetEnhet enheter={enheter} />
</Kontaktpanel>
</div>
) : (
<Kontaktpanel>
<div>Kunne ikke hente informasjon</div>
)}
</Panel>
</Kontaktpanel>
)}
</>
);
};

export default InformasjonOmBedrift;
export default InformasjonOmBedrift;
17 changes: 17 additions & 0 deletions src/App/InformasjonOmBedrift/Kontaktinfo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.kontaktinfo{
display: flex;
flex-direction: column;
gap: 16px;
max-width: 32rem;
margin-top: 16px;
}

.kontaktinfo p {
margin: 0;
}

.kontaktinfo-tittel{
display: flex;
align-items: center;
gap: 8px;
}
150 changes: 150 additions & 0 deletions src/App/InformasjonOmBedrift/Kontaktinfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { z } from 'zod';
import React, { useState } from 'react';
import useSWR from 'swr';
import * as Sentry from '@sentry/browser';
import { Alert, BodyShort, Heading, HelpText } from '@navikt/ds-react';
import { LenkeMedLogging } from '../../GeneriskeElementer/LenkeMedLogging';
import './Kontaktinfo.css';

const KontaktinfoRespons = z.object({
hovedenhet: z
.object({
eposter: z.array(z.string()),
telefonnumre: z.array(z.string()),
})
.nullable(),
underenhet: z
.object({
eposter: z.array(z.string()),
telefonnumre: z.array(z.string()),
})
.nullable(),
});

const fetcher = async ({ url, orgnr }: { url: string; orgnr: string }) => {
const body = { virksomhetsnummer: orgnr };
const response = await fetch(url, {
body: JSON.stringify(body),
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (response.status !== 200) {
throw response;
}
return KontaktinfoRespons.parse(await response.json());
};

export const useKontaktinfo = (orgnr?: string) => {
const [retries, setRetries] = useState(0);

const { data: kontaktinfo } = useSWR(
orgnr === undefined ? null : { url: `/min-side-arbeidsgiver/api/kontaktinfo/v1/`, orgnr },
fetcher,
{
onSuccess: () => setRetries(0),
onError: (error) => {
if (retries === 5) {
Sentry.captureMessage(
`hent kontaktinfo fra min-side-arbeidsgiver-api feilet med ${
error.status !== undefined
? `${error.status} ${error.statusText}`
: error
}`
);
}
setRetries((x) => x + 1);
},
errorRetryInterval: 300,
}
);
return kontaktinfo;
};

const AltinnLenke = () => (
<LenkeMedLogging
loggLenketekst={'Oppdatere kofuvi Altinn ekstern lenke'}
href="https://www.altinn.no/hjelp/profil/kontaktinformasjon-og-varslinger/"
>
Les om varslingsadresser på Altinn
</LenkeMedLogging>
);

const TittelMedHjelpetekst = ({ children }: { children: React.ReactNode }) => (
<div className="kontaktinfo-tittel">
<Heading size="small">{children}</Heading>
<HelpText title="Hva brukes det til?">
Varslingsadressen brukes slik det offentlige kan kommunisere digitalt med virksomheten.
</HelpText>
</div>
);

interface KontaktinfoProps {
orgnr?: string;
}

export const KontaktinfoUnderenhet = ({ orgnr }: KontaktinfoProps) => {
const kontaktinfo = useKontaktinfo(orgnr)?.underenhet ?? null;
if (kontaktinfo === null) return null;
if (kontaktinfo.eposter.length === 0 && kontaktinfo.telefonnumre.length === 0) return null;
return (
<div className="kontaktinfo">
<TittelMedHjelpetekst>Varslingsadresser for underenhet</TittelMedHjelpetekst>
{kontaktinfo.eposter.length > 0 ? (
<div>
<Heading size="xsmall">E-post</Heading>
{kontaktinfo.eposter.map((epost) => (
<BodyShort key={epost}>{epost}</BodyShort>
))}
</div>
) : null}
{kontaktinfo.telefonnumre.length > 0 ? (
<div>
<Heading size="xsmall">SMS</Heading>
{kontaktinfo.telefonnumre.map((telefonnummer) => (
<BodyShort key={telefonnummer}>{telefonnummer}</BodyShort>
))}
</div>
) : null}
<AltinnLenke />
</div>
);
};

export const KontaktinfoHovedenhet = ({ orgnr }: KontaktinfoProps) => {
const kontaktinfo = useKontaktinfo(orgnr)?.hovedenhet ?? null;
if (kontaktinfo === null) return null;
return (
<div className="kontaktinfo">
<TittelMedHjelpetekst>Varslingsadresser for hovedenhet</TittelMedHjelpetekst>
{kontaktinfo.eposter.length === 0 && kontaktinfo.telefonnumre.length === 0 ? (
<Alert variant="warning">
Det mangler varslingsadresse. Varslingsadressen brukes slik det offentlige kan
kommunisere digitalt med virksomheten. Dere er må å ha minst en e-post eller
mobilnummer for varsling.
</Alert>
) : (
<>
{kontaktinfo.eposter.length > 0 ? (
<div>
<Heading size="xsmall">E-post</Heading>
{kontaktinfo.eposter.map((epost) => (
<BodyShort key={epost}>{epost}</BodyShort>
))}
</div>
) : null}
{kontaktinfo.telefonnumre.length > 0 ? (
<div>
<Heading size="xsmall">SMS</Heading>
{kontaktinfo.telefonnumre.map((telefonnummer) => (
<BodyShort key={telefonnummer}>{telefonnummer}</BodyShort>
))}
</div>
) : null}
</>
)}
<AltinnLenke />
</div>
);
};
Loading