From 87ee5aa78cedb6fae4bca3f3a0425ef96ce77465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vebj=C3=B8rn=20Nordby?= Date: Thu, 19 Dec 2024 12:30:41 +0100 Subject: [PATCH] Ux forbedringer (#3553) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Henter saksbehandler fra global data i stedet for useQuery. Appen rendres ikke før data er på plass der, og den refetcher ikke så da slipper man å tenke på staleTime og at det refetches når man ikke vil * individuell loading-state for køer som berikes med antall * try catch på henting av antall * henter saksbehandlerinfo med react-query overalt, uten refetching * legger til optional chaining for å fikse test. I appen bør innloggetsaksbehandler aldri være undefined her * whoops --- src/client/app/admin/AdminIndex.tsx | 5 +- .../app/api/queries/saksbehandlerQueries.ts | 7 ++- src/client/app/app/AppConfigResolver.tsx | 27 +++++++---- .../app/components/HeaderWithErrorPanel.tsx | 21 ++++---- src/client/app/app/components/Home.tsx | 12 ++--- src/client/app/app/navAnsattTsType.ts | 1 + .../avdelingsleder/AvdelingslederIndex.tsx | 9 ++-- .../BehandlingskoerIndex.tsx | 48 +++++++++++-------- .../app/saksbehandler/SaksbehandlerIndex.tsx | 8 ++-- .../components/SaksbehandlerDashboard.tsx | 14 ++++-- .../saksbehandler/sokeboks/OppgaveModal.tsx | 7 +-- 11 files changed, 87 insertions(+), 72 deletions(-) diff --git a/src/client/app/admin/AdminIndex.tsx b/src/client/app/admin/AdminIndex.tsx index 72abdd306..46b4c826d 100644 --- a/src/client/app/admin/AdminIndex.tsx +++ b/src/client/app/admin/AdminIndex.tsx @@ -9,6 +9,7 @@ import useTrackRouteParam from 'app/data/trackRouteParam'; import NavAnsatt from 'app/navAnsattTsType'; import { getPanelLocationCreator } from 'app/paths'; import { RestApiGlobalStatePathsKeys } from 'api/k9LosApi'; +import { useInnloggetSaksbehandler } from 'api/queries/saksbehandlerQueries'; import useGlobalStateRestApiData from 'api/rest-api-hooks/src/global-data/useGlobalStateRestApiData'; import LoadingPanel from 'sharedComponents/LoadingPanel'; import { parseQueryString } from 'utils/urlUtils'; @@ -65,9 +66,9 @@ export const AdminIndex: FunctionComponent = () => { const getDriftsmeldingerPanelLocation = getPanelLocationCreator(location); const activePanel = activePanelTemp || hentPanelFromUrlOrDefault(location); - const { kanDrifte } = useGlobalStateRestApiData(RestApiGlobalStatePathsKeys.NAV_ANSATT); + const { data: saksbehandler } = useInnloggetSaksbehandler(); - if (!kanDrifte) { + if (!saksbehandler.kanDrifte) { return ; } if (activePanel) { diff --git a/src/client/app/api/queries/saksbehandlerQueries.ts b/src/client/app/api/queries/saksbehandlerQueries.ts index a4c727023..45c956f0d 100644 --- a/src/client/app/api/queries/saksbehandlerQueries.ts +++ b/src/client/app/api/queries/saksbehandlerQueries.ts @@ -15,7 +15,12 @@ import { OppgavekøV3Enkel } from 'types/OppgavekøV3Type'; import { axiosInstance } from 'utils/reactQueryConfig'; export const useInnloggetSaksbehandler = (options: UseQueryOptions = {}) => - useQuery(apiPaths.saksbehandler, options); + useQuery(apiPaths.saksbehandler, { + ...options, + staleTime: Infinity, + cacheTime: Infinity, + refetchOnWindowFocus: false, + }); export const useGetAlleSaksbehandlere = (options: UseQueryOptions = {}) => useQuery(apiPaths.hentSaksbehandlereSomSaksbehandler, options); diff --git a/src/client/app/app/AppConfigResolver.tsx b/src/client/app/app/AppConfigResolver.tsx index 26280160e..87e541983 100644 --- a/src/client/app/app/AppConfigResolver.tsx +++ b/src/client/app/app/AppConfigResolver.tsx @@ -1,6 +1,7 @@ import React, { FunctionComponent, ReactElement, useEffect } from 'react'; import useRestApiErrorDispatcher from 'api/error/useRestApiErrorDispatcher'; import { RestApiGlobalStatePathsKeys, k9LosApi } from 'api/k9LosApi'; +import { useInnloggetSaksbehandler } from 'api/queries/saksbehandlerQueries'; import { useGlobalStateRestApi } from 'api/rest-api-hooks'; import RestApiState from 'api/rest-api-hooks/src/RestApiState'; import LoadingPanel from 'sharedComponents/LoadingPanel'; @@ -15,26 +16,32 @@ const AppConfigResolver: FunctionComponent = ({ children }) => { k9LosApi().setAddErrorMessageHandler(addErrorMessage); }, []); - const { state: stateNavAnsatt } = useGlobalStateRestApi(RestApiGlobalStatePathsKeys.NAV_ANSATT); + const { + data: innloggetSaksbehandler, + isSuccess: harHentetInnloggetSaksbehandler, + isLoading: isLoadingSaksbehandler, + } = useInnloggetSaksbehandler(); + const { state: stateK9sakUrl } = useGlobalStateRestApi(RestApiGlobalStatePathsKeys.K9SAK_URL, undefined, { - suspendRequest: stateNavAnsatt !== RestApiState.SUCCESS, - updateTriggers: [stateNavAnsatt], + suspendRequest: !harHentetInnloggetSaksbehandler, + updateTriggers: [innloggetSaksbehandler], }); const { state: stateKodeverk } = useGlobalStateRestApi(RestApiGlobalStatePathsKeys.KODEVERK, undefined, { - suspendRequest: stateNavAnsatt !== RestApiState.SUCCESS, - updateTriggers: [stateNavAnsatt], + suspendRequest: !harHentetInnloggetSaksbehandler, + updateTriggers: [innloggetSaksbehandler], }); const { state: stateSseUrl } = useGlobalStateRestApi(RestApiGlobalStatePathsKeys.REFRESH_URL, undefined, { - suspendRequest: stateNavAnsatt !== RestApiState.SUCCESS, - updateTriggers: [stateNavAnsatt], + suspendRequest: !harHentetInnloggetSaksbehandler, + updateTriggers: [innloggetSaksbehandler], }); const { state: stateK9punsjUrl } = useGlobalStateRestApi(RestApiGlobalStatePathsKeys.PUNSJ_URL, undefined, { - suspendRequest: stateNavAnsatt !== RestApiState.SUCCESS, - updateTriggers: [stateNavAnsatt], + suspendRequest: !harHentetInnloggetSaksbehandler, + updateTriggers: [innloggetSaksbehandler], }); if ( - [stateK9sakUrl, stateNavAnsatt, stateKodeverk, stateSseUrl, stateK9punsjUrl].some((v) => v === RestApiState.LOADING) + isLoadingSaksbehandler || + [stateK9sakUrl, stateKodeverk, stateSseUrl, stateK9punsjUrl].some((v) => v === RestApiState.LOADING) ) { return ; } diff --git a/src/client/app/app/components/HeaderWithErrorPanel.tsx b/src/client/app/app/components/HeaderWithErrorPanel.tsx index 4a4334866..d753ec988 100644 --- a/src/client/app/app/components/HeaderWithErrorPanel.tsx +++ b/src/client/app/app/components/HeaderWithErrorPanel.tsx @@ -5,12 +5,11 @@ import Endringslogg from '@navikt/familie-endringslogg'; import { BoxedListWithLinks, Header, Popover, SystemButton, UserPanel } from '@navikt/ft-plattform-komponenter'; import DriftsmeldingPanel from 'app/components/DriftsmeldingPanel'; import ErrorFormatter from 'app/feilhandtering/ErrorFormatter'; -import NavAnsatt from 'app/navAnsattTsType'; import { RETTSKILDE_URL, SHAREPOINT_URL } from 'api/eksterneLenker'; import useRestApiError from 'api/error/useRestApiError'; import useRestApiErrorDispatcher from 'api/error/useRestApiErrorDispatcher'; -import { K9LosApiKeys, RestApiGlobalStatePathsKeys } from 'api/k9LosApi'; -import { useGlobalStateRestApiData } from 'api/rest-api-hooks'; +import { K9LosApiKeys } from 'api/k9LosApi'; +import { useInnloggetSaksbehandler } from 'api/queries/saksbehandlerQueries'; import useRestApi from 'api/rest-api-hooks/src/local-data/useRestApi'; import { Driftsmelding } from '../../admin/driftsmeldinger/driftsmeldingTsType'; import ErrorMessagePanel from './ErrorMessagePanel'; @@ -70,7 +69,7 @@ const HeaderWithErrorPanel: FunctionComponent = ({ queryStrings, crash const navigate = useNavigate(); const intl = useIntl(); - const navAnsatt = useGlobalStateRestApiData(RestApiGlobalStatePathsKeys.NAV_ANSATT); + const { data: innloggetSaksbehandler } = useInnloggetSaksbehandler(); const { data: driftsmeldinger = [] } = useRestApi(K9LosApiKeys.DRIFTSMELDINGER); const errorMessages = useRestApiError() || []; @@ -86,7 +85,7 @@ const HeaderWithErrorPanel: FunctionComponent = ({ queryStrings, crash setLenkePanelApent, setAvdelingerPanelApent, ); - const brukerPanel = ; + const brukerPanel = ; const fixedHeaderRef = useRef(null); const goTilAvdelingslederPanel = () => { @@ -109,20 +108,20 @@ const HeaderWithErrorPanel: FunctionComponent = ({ queryStrings, crash }; const visAvdelingslederKnapp = (): boolean => { - if (!navAnsatt.kanOppgavestyre) { + if (!innloggetSaksbehandler?.kanOppgavestyre) { return false; } - if (navAnsatt.kanOppgavestyre && window.location.href.includes('avdelingsleder')) { + if (innloggetSaksbehandler?.kanOppgavestyre && window.location.href.includes('avdelingsleder')) { return false; } return true; }; const visAdminKnapp = (): boolean => { - if (!navAnsatt.kanDrifte) { + if (!innloggetSaksbehandler?.kanDrifte) { return false; } - if (navAnsatt.kanDrifte && window.location.href.includes('admin')) { + if (innloggetSaksbehandler?.kanDrifte && window.location.href.includes('admin')) { return false; } return true; @@ -187,10 +186,10 @@ const HeaderWithErrorPanel: FunctionComponent = ({ queryStrings, crash https://github.com/navikt/familie-endringslogg For å nå backend lokalt må man være tilkoblet naisdevice og kjøre opp k9-sak-web på port 8000 pga CORS */} - {navAnsatt?.brukerIdent && window.location.hostname.includes('nav') && ( + {innloggetSaksbehandler?.brukerIdent && window.location.hostname.includes('nav') && (
{ const { data } = useQuery<{ felter: Oppgavefelt[] }>(apiPaths.hentOppgaveFelter); - const { kanOppgavestyre, brukerIdent } = useGlobalStateRestApiData(RestApiGlobalStatePathsKeys.NAV_ANSATT); + const { data: saksbehandler } = useInnloggetSaksbehandler(); const queryClient = useQueryClient(); useEffect(() => { - if (brukerIdent) { - if (kanOppgavestyre) { + if (saksbehandler.brukerIdent) { + if (saksbehandler.kanOppgavestyre) { queryClient.prefetchQuery(apiPaths.hentSaksbehandlereAvdelingsleder); } queryClient.prefetchQuery(apiPaths.hentSaksbehandlereSomSaksbehandler); } - }, [queryClient, brukerIdent, kanOppgavestyre]); + }, [queryClient, saksbehandler.brukerIdent, saksbehandler.kanOppgavestyre]); const contextValues = useMemo(() => ({ felter: data ? data.felter : [] }), [data]); diff --git a/src/client/app/app/navAnsattTsType.ts b/src/client/app/app/navAnsattTsType.ts index cfea12d07..97d4c0eaa 100644 --- a/src/client/app/app/navAnsattTsType.ts +++ b/src/client/app/app/navAnsattTsType.ts @@ -8,6 +8,7 @@ type NavAnsatt = Readonly<{ kanReservere: boolean; funksjonellTid: string; kanDrifte: boolean; + finnesISaksbehandlerTabell: boolean; }>; export default NavAnsatt; diff --git a/src/client/app/avdelingsleder/AvdelingslederIndex.tsx b/src/client/app/avdelingsleder/AvdelingslederIndex.tsx index 1e32fb18b..c9c3c594c 100644 --- a/src/client/app/avdelingsleder/AvdelingslederIndex.tsx +++ b/src/client/app/avdelingsleder/AvdelingslederIndex.tsx @@ -15,10 +15,9 @@ import { import { BodyShort, Heading } from '@navikt/ds-react'; import useTrackRouteParam from 'app/data/trackRouteParam'; import { avdelingslederTilgangTilNyeKoer } from 'app/envVariablesUtils'; -import NavAnsatt from 'app/navAnsattTsType'; import { getPanelLocationCreator } from 'app/paths'; -import { K9LosApiKeys, RestApiGlobalStatePathsKeys } from 'api/k9LosApi'; -import useGlobalStateRestApiData from 'api/rest-api-hooks/src/global-data/useGlobalStateRestApiData'; +import { K9LosApiKeys } from 'api/k9LosApi'; +import { useInnloggetSaksbehandler } from 'api/queries/saksbehandlerQueries'; import useRestApiRunner from 'api/rest-api-hooks/src/local-data/useRestApiRunner'; import DagensTallPanel from 'avdelingsleder/dagensTall/DagensTallPanel'; import ApneBehandlinger from 'avdelingsleder/dagensTall/apneBehandlingerTsType'; @@ -137,12 +136,12 @@ export const AvdelingslederIndex: FunctionComponent = () => { return panelFromUrl.avdelingsleder ? panelFromUrl.avdelingsleder : AvdelingslederPanels.BEHANDLINGSKOER; }; - const { kanOppgavestyre } = useGlobalStateRestApiData(RestApiGlobalStatePathsKeys.NAV_ANSATT); + const { data: innnloggetSaksbehandler } = useInnloggetSaksbehandler(); const getAvdelingslederPanelLocation = getPanelLocationCreator(location); const activeAvdelingslederPanel = activeAvdelingslederPanelTemp || getPanelFromUrlOrDefault(location); - if (!kanOppgavestyre) { + if (!innnloggetSaksbehandler.kanOppgavestyre) { return ; } diff --git a/src/client/app/avdelingsleder/behandlingskoerV3/BehandlingskoerIndex.tsx b/src/client/app/avdelingsleder/behandlingskoerV3/BehandlingskoerIndex.tsx index fafeb65b6..317556999 100644 --- a/src/client/app/avdelingsleder/behandlingskoerV3/BehandlingskoerIndex.tsx +++ b/src/client/app/avdelingsleder/behandlingskoerV3/BehandlingskoerIndex.tsx @@ -1,5 +1,5 @@ -import React, { Fragment, useState } from 'react'; -import { useQuery } from 'react-query'; +import React, { useState } from 'react'; +import { useQueries } from 'react-query'; import dayjs from 'dayjs'; import { PlusCircleIcon } from '@navikt/aksel-icons'; import { Button, Loader, Skeleton, Table } from '@navikt/ds-react'; @@ -26,26 +26,34 @@ function scrollToId(id: string) { intervalId = setInterval(scroll, 100); } -const berikMedAntallOppgaver = (køArray: OppgavekøV3Enkel[]) => - useQuery( - ['beriketAntallOppgaver', køArray], - async () => { - const requests = køArray.map(async (kø) => { +const berikMedAntallOppgaverIndividuelt = (køArray: OppgavekøV3Enkel[]) => { + const queries = useQueries( + køArray.map((kø) => ({ + queryKey: ['antallOppgaver', kø.id], + queryFn: async () => { try { const { data } = await axiosInstance.get(apiPaths.antallOppgaverIKoV3(kø.id)); return { ...kø, ...data }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error) { + console.error('Error fetching antallOppgaver', error); return { ...kø }; } - }); - return Promise.all(requests); - }, - { - enabled: !!køArray, - }, + }, + enabled: !!køArray.length, + })), ); + const isSuccess = queries.every((query) => query.isSuccess); + const results = queries.map((query, index) => ({ + ...(køArray[index] || {}), + ...query.data, + isLoading: query.isLoading, + isError: query.isError, + })); + + return { results, isSuccess }; +}; + const Row = ({ kø, ekspandert, @@ -82,11 +90,9 @@ const Row = ({ ); const BehandlingskoerIndex = () => { const { data: initielleKøer, isLoading, error } = useAlleKoer(); - const { - data: køerMedAntallOppgaver, - isLoading: isLoadingAntallOppgaver, - isSuccess: harHentetAntallOppgaver, - } = berikMedAntallOppgaver(initielleKøer); + const { results: køerMedAntallOppgaver, isSuccess: isSuccessAll } = berikMedAntallOppgaverIndividuelt( + initielleKøer || [], + ); const [visNyKøModal, setVisNyKøModal] = useState(false); const [sort, setSort] = useState(null); const [ekspanderteKøer, setEkspanderteKøer] = useState([]); @@ -160,7 +166,7 @@ const BehandlingskoerIndex = () => { Saksbehandlere - + Antall oppgaver (med reserverte) @@ -174,7 +180,7 @@ const BehandlingskoerIndex = () => { toggleExpand(kø.id)} /> diff --git a/src/client/app/saksbehandler/SaksbehandlerIndex.tsx b/src/client/app/saksbehandler/SaksbehandlerIndex.tsx index d8fa4f888..88187bf88 100644 --- a/src/client/app/saksbehandler/SaksbehandlerIndex.tsx +++ b/src/client/app/saksbehandler/SaksbehandlerIndex.tsx @@ -1,7 +1,5 @@ import React from 'react'; -import NavAnsatt from 'app/navAnsattTsType'; -import { RestApiGlobalStatePathsKeys } from 'api/k9LosApi'; -import useGlobalStateRestApiData from 'api/rest-api-hooks/src/global-data/useGlobalStateRestApiData'; +import { useInnloggetSaksbehandler } from 'api/queries/saksbehandlerQueries'; import IkkeTilgangTilAvdelingslederPanel from 'avdelingsleder/components/IkkeTilgangTilAvdelingslederPanel'; import SaksbehandlerDashboard from './components/SaksbehandlerDashboard'; @@ -10,8 +8,8 @@ import SaksbehandlerDashboard from './components/SaksbehandlerDashboard'; */ const SaksbehandlerIndex = () => { - const { kanSaksbehandle } = useGlobalStateRestApiData(RestApiGlobalStatePathsKeys.NAV_ANSATT); - if (!kanSaksbehandle) { + const { data: saksbehandler } = useInnloggetSaksbehandler(); + if (!saksbehandler.kanSaksbehandle) { return ; } return ; diff --git a/src/client/app/saksbehandler/components/SaksbehandlerDashboard.tsx b/src/client/app/saksbehandler/components/SaksbehandlerDashboard.tsx index c3b8ee5a4..800174821 100644 --- a/src/client/app/saksbehandler/components/SaksbehandlerDashboard.tsx +++ b/src/client/app/saksbehandler/components/SaksbehandlerDashboard.tsx @@ -2,6 +2,7 @@ import React, { FunctionComponent } from 'react'; import Panel from 'nav-frontend-paneler'; import { sokeboksNyeKoer } from 'app/envVariablesUtils'; import { RestApiGlobalStatePathsKeys } from 'api/k9LosApi'; +import { useInnloggetSaksbehandler } from 'api/queries/saksbehandlerQueries'; import useGlobalStateRestApiData from 'api/rest-api-hooks/src/global-data/useGlobalStateRestApiData'; import { Søkeboks } from 'saksbehandler/sokeboks/Søkeboks'; import BehandlingskoerIndex from '../behandlingskoer/BehandlingskoerIndex'; @@ -15,6 +16,7 @@ import * as styles from './saksbehandlerDashboard.css'; export const SaksbehandlerDashboard: FunctionComponent = () => { const k9sakUrl = useGlobalStateRestApiData<{ verdi?: string }>(RestApiGlobalStatePathsKeys.K9SAK_URL); const k9punsjUrl = useGlobalStateRestApiData<{ verdi?: string }>(RestApiGlobalStatePathsKeys.PUNSJ_URL); + const { data: saksbehandler } = useInnloggetSaksbehandler(); return (
@@ -28,11 +30,13 @@ export const SaksbehandlerDashboard: FunctionComponent = () => { )} -
- - - -
+ {saksbehandler.finnesISaksbehandlerTabell && ( +
+ + + +
+ )}
diff --git a/src/client/app/saksbehandler/sokeboks/OppgaveModal.tsx b/src/client/app/saksbehandler/sokeboks/OppgaveModal.tsx index d01615769..8ce32d119 100644 --- a/src/client/app/saksbehandler/sokeboks/OppgaveModal.tsx +++ b/src/client/app/saksbehandler/sokeboks/OppgaveModal.tsx @@ -14,7 +14,8 @@ const åpneOppgave = (oppgave: SøkeboksOppgaveDto) => { }; export function OppgaveModal(props: { oppgave: SøkeboksOppgaveDto; open: boolean; closeModal: () => void }) { - const { isFetched: isFetchedSaksbehandler, data: innloggetSaksbehandler } = useInnloggetSaksbehandler(); + const { data: innloggetSaksbehandler } = useInnloggetSaksbehandler(); + const { isLoading: isLoadingEndreReservasjoner, mutate: endreReservasjoner } = useEndreReservasjoner(() => åpneOppgave(props.oppgave), ); @@ -25,10 +26,6 @@ export function OppgaveModal(props: { oppgave: SøkeboksOppgaveDto; open: boolea props.closeModal, ); - if (!isFetchedSaksbehandler) { - return null; - } - const { visÅpneOgReserverKnapp, visÅpneOgEndreReservasjonKnapp, visLeggTilbakeIKøKnapp, heading, modaltekst } = modalInnhold(props.oppgave, innloggetSaksbehandler);