From e44d7e3f4dcf843d8568537a31f70e0a23964d1a Mon Sep 17 00:00:00 2001 From: matsbyfl Date: Mon, 16 Dec 2024 22:18:33 +0100 Subject: [PATCH] Fkytter filter for oppgavebenk til egen komponent og flytter filterstate til egen context --- client/src/App.tsx | 7 +- client/src/oppgavebenk/FilterContext.tsx | 79 +++++++++++++++++++ client/src/oppgavebenk/OppgaveFilter.tsx | 53 +++++++++++++ client/src/oppgavebenk/Oppgavebenk.tsx | 74 ++--------------- client/src/oppgaveliste/Oppgaveliste.tsx | 2 +- .../oppgaveliste/filter/CheckboxFilter.tsx | 68 ++++++++++++++++ client/src/oppgaveliste/filter/ShowMore.tsx | 69 ++++++++++++++++ .../src/oppgaveliste/{ => filter}/filter.tsx | 0 8 files changed, 283 insertions(+), 69 deletions(-) create mode 100644 client/src/oppgavebenk/FilterContext.tsx create mode 100644 client/src/oppgavebenk/OppgaveFilter.tsx create mode 100644 client/src/oppgaveliste/filter/CheckboxFilter.tsx create mode 100644 client/src/oppgaveliste/filter/ShowMore.tsx rename client/src/oppgaveliste/{ => filter}/filter.tsx (100%) diff --git a/client/src/App.tsx b/client/src/App.tsx index 758bdd79..14ec3349 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,8 +1,8 @@ import { ComponentType, lazy, Suspense } from 'react' import { ErrorBoundary } from 'react-error-boundary' -import { BrowserRouter, Route, Routes } from 'react-router-dom' import { Helmet } from 'react-helmet' import { useParams } from 'react-router' +import { BrowserRouter, Route, Routes } from 'react-router-dom' import { RecoilRoot } from 'recoil' import { SWRConfig } from 'swr' @@ -12,6 +12,7 @@ import { Feilside } from './feilsider/Feilside' import { GlobalFeilside } from './feilsider/GlobalFeilside' import { Eksperiment } from './felleskomponenter/Eksperiment' import { Toppmeny } from './header/Toppmeny' +import { FilterProvider } from './oppgavebenk/FilterContext' import { PersonProvider } from './personoversikt/PersonContext' import { useAuthentication } from './state/authentication' import { amplitude_taxonomy, logAmplitudeEvent } from './utils/amplitude' @@ -94,7 +95,9 @@ function App() { - + + + } diff --git a/client/src/oppgavebenk/FilterContext.tsx b/client/src/oppgavebenk/FilterContext.tsx new file mode 100644 index 00000000..61d50284 --- /dev/null +++ b/client/src/oppgavebenk/FilterContext.tsx @@ -0,0 +1,79 @@ +import { createContext, ReactNode, useContext } from 'react' +import { useLocalStorageState } from '../oppgaveliste/useLocalStorageState' +import { OppgaveGjelderFilter, TildeltFilter } from '../types/experimentalTypes' +import { SortState } from '@navikt/ds-react' + +interface FilterContextType { + tildeltFilter: TildeltFilter + setTildeltFilter: (tildelt: TildeltFilter) => void + gjelderFilter: OppgaveGjelderFilter + setGjelderFilter: (gjelder: OppgaveGjelderFilter) => void + currentPage: number + setCurrentPage: (currentPage: number) => void + sort: SortState + setSort: (sort: SortState) => void + clearFilters: () => void +} + +const initialSortState: SortState = { + orderBy: 'OPPRETTET_TIDSPUNKT', + direction: 'descending', +} + +const initialState: FilterContextType = { + tildeltFilter: TildeltFilter.INGEN, + setTildeltFilter: () => {}, + gjelderFilter: OppgaveGjelderFilter.ALLE, + setGjelderFilter: () => {}, + currentPage: 1, + setCurrentPage: () => {}, + sort: initialSortState, + setSort: () => {}, + clearFilters: () => {}, +} + +const FilterContext = createContext(initialState) + +function FilterProvider({ children }: { children: ReactNode }) { + const [tildeltFilter, setTildeltFilter] = useLocalStorageState('oppgaverFilter', initialState.tildeltFilter) + const [gjelderFilter, setGjelderFilter] = useLocalStorageState('oppgavebenkGjelderFilter', initialState.gjelderFilter) + const [currentPage, setCurrentPage] = useLocalStorageState('currentPage', initialState.currentPage) + const [sort, setSort] = useLocalStorageState('oppgavebenkSortState', initialSortState) + + function clearFilters() { + setGjelderFilter(OppgaveGjelderFilter.ALLE) + setTildeltFilter(TildeltFilter.INGEN) + setSort(initialSortState) + setCurrentPage(1) + } + + return ( + + {children} + + ) +} + +function useFilterContext(): FilterContextType { + const context = useContext(FilterContext) + + if (!context) { + throw new Error('usePersonContext must be used within a PersonProvider') + } + + return context +} + +export { FilterContext, FilterProvider, useFilterContext } diff --git a/client/src/oppgavebenk/OppgaveFilter.tsx b/client/src/oppgavebenk/OppgaveFilter.tsx new file mode 100644 index 00000000..d1f0332c --- /dev/null +++ b/client/src/oppgavebenk/OppgaveFilter.tsx @@ -0,0 +1,53 @@ +import { Box, Button, HStack, ToggleGroup } from '@navikt/ds-react' +import { FilterDropdown } from '../oppgaveliste/filter/filter' +import { OppgaveGjelderFilter, OppgavetemaLabel, TildeltFilter } from '../types/experimentalTypes' +import { useFilterContext } from './FilterContext' + +export function Oppgavefilter() { + const { setCurrentPage, gjelderFilter, setGjelderFilter, tildeltFilter, setTildeltFilter, clearFilters } = + useFilterContext() + + const handleFilter = (handler: (...args: any[]) => any, value: OppgaveGjelderFilter | string) => { + handler(value) + setCurrentPage(1) + } + + return ( + + + { + handleFilter(setTildeltFilter, filterValue) + }} + style={{ background: 'var(--a-bg-default)' }} + > + + + + + { + handleFilter(setGjelderFilter, filterValue) + }} + label="Gjelder" + value={gjelderFilter} + options={OppgavetemaLabel} + /> + {/**/} + + + + ) +} diff --git a/client/src/oppgavebenk/Oppgavebenk.tsx b/client/src/oppgavebenk/Oppgavebenk.tsx index ad6b34d0..bd4ca411 100644 --- a/client/src/oppgavebenk/Oppgavebenk.tsx +++ b/client/src/oppgavebenk/Oppgavebenk.tsx @@ -1,4 +1,4 @@ -import { Box, Button, HStack, Link, SortState, Table, ToggleGroup } from '@navikt/ds-react' +import { Box, Link, Table } from '@navikt/ds-react' import styled from 'styled-components' import { IngentingFunnet } from '../felleskomponenter/IngenOppgaver' @@ -7,49 +7,26 @@ import { EllipsisCell, TekstCell } from '../felleskomponenter/table/Celle' import { DataCell, KolonneHeader } from '../felleskomponenter/table/KolonneHeader' import { Toast } from '../felleskomponenter/Toast' import { Skjermlesertittel } from '../felleskomponenter/typografi' -import { FilterDropdown } from '../oppgaveliste/filter' import { OppgavelisteTabs } from '../oppgaveliste/OppgavelisteTabs' -import { useLocalStorageState } from '../oppgaveliste/useLocalStorageState' -import { OppgaveApiOppgave, OppgaveGjelderFilter, TildeltFilter, OppgavetemaLabel } from '../types/experimentalTypes' +import { Paging } from '../oppgaveliste/paging/Paging' +import { OppgaveApiOppgave } from '../types/experimentalTypes' import { Oppgavetype } from '../types/types.internal' import { formaterDato, formaterTidsstempel } from '../utils/dato' import { formaterFødselsnummer, formaterNavn, storForbokstavIAlleOrd, storForbokstavIOrd } from '../utils/formater' import { isError } from '../utils/type' -import { useOppgavelisteV2 } from './useOppgavelisteV2' +import { useFilterContext } from './FilterContext' +import { Oppgavefilter } from './OppgaveFilter' import { Oppgavetildeling } from './Oppgavetildeling' -import { Paging } from '../oppgaveliste/paging/Paging' +import { useOppgavelisteV2 } from './useOppgavelisteV2' export function Oppgavebenk() { - const [tildeltFilter, setTildeltFilter] = useLocalStorageState('oppgaverFilter', TildeltFilter.INGEN) - const [gjelderFilter, setGjelderFilter] = useLocalStorageState('oppgavebenkGjelderFilter', OppgaveGjelderFilter.ALLE) - //const [områdeFilter, setOmrådeFilter] = useLocalStorageState('områdeFilter', OmrådeFilter.ALLE) - //const [sakstypeFilter, setSakstypeFilter] = useLocalStorageState('sakstypeFilter', SakstypeFilter.ALLE) - const [currentPage, setCurrentPage] = useLocalStorageState('currentPage', 1) - - const initialSortState: SortState = { - orderBy: 'OPPRETTET_TIDSPUNKT', - direction: 'descending', - } - - const [sort, setSort] = useLocalStorageState('oppgavebenkSortState', initialSortState) + const { tildeltFilter, gjelderFilter, currentPage, setCurrentPage, sort, setSort } = useFilterContext() const { oppgaver, isLoading, error, totalElements } = useOppgavelisteV2(currentPage, sort, { tildeltFilter, gjelderFilter, }) - const handleFilter = (handler: (...args: any[]) => any, value: OppgaveGjelderFilter | string) => { - handler(value) - setCurrentPage(1) - } - - const clearFilters = () => { - setGjelderFilter(OppgaveGjelderFilter.ALLE) - setTildeltFilter(TildeltFilter.INGEN) - setSort(initialSortState) - setCurrentPage(1) - } - const kolonner = [ { key: 'EIER', @@ -200,42 +177,7 @@ export function Oppgavebenk() { <> Oppgaveliste - - - { - handleFilter(setTildeltFilter, filterValue) - }} - style={{ background: 'var(--a-bg-default)' }} - > - - - - - { - handleFilter(setGjelderFilter, filterValue) - }} - label="Gjelder" - value={gjelderFilter} - options={OppgavetemaLabel} - /> - - - - + {isLoading ? ( Henter oppgaver ) : ( diff --git a/client/src/oppgaveliste/Oppgaveliste.tsx b/client/src/oppgaveliste/Oppgaveliste.tsx index 019978d1..fe84ab11 100644 --- a/client/src/oppgaveliste/Oppgaveliste.tsx +++ b/client/src/oppgaveliste/Oppgaveliste.tsx @@ -27,7 +27,7 @@ import { import { formaterTidsstempel } from '../utils/dato' import { formaterFødselsnummer, formaterNavn, storForbokstavIAlleOrd } from '../utils/formater' import { isError } from '../utils/type' -import { FilterDropdown, FilterToggle } from './filter' +import { FilterDropdown, FilterToggle } from './filter/filter.tsx' import { MenyKnapp } from './kolonner/MenyKnapp' import { SakstypeEtikett } from './kolonner/SakstypeEtikett' import { Tildeling } from './kolonner/Tildeling' diff --git a/client/src/oppgaveliste/filter/CheckboxFilter.tsx b/client/src/oppgaveliste/filter/CheckboxFilter.tsx new file mode 100644 index 00000000..3bfedcfb --- /dev/null +++ b/client/src/oppgaveliste/filter/CheckboxFilter.tsx @@ -0,0 +1,68 @@ +import { Checkbox, CheckboxGroup, VStack } from '@navikt/ds-react' +import { Strek } from '../../felleskomponenter/Strek' +import ShowMore from './ShowMore' + +type CheckboxFilterInputProps = { + options: string[] + selected: string[] +} + +export const CheckboxFilter = ({ options, selected }: CheckboxFilterInputProps) => { + const notSelectedFilters = options.filter((option) => !selected.includes(option)).sort() + + const showMoreLabel = selected.length > 0 ? `Gjelder (${selected.length})` : 'Alle' + + return ( + + + <> + + {selected.map((f) => ( + { + if (event.key === 'Space') { + event.preventDefault() + event.currentTarget?.form?.requestSubmit() + } + }} + onChange={(e) => { + e.currentTarget?.form?.requestSubmit() + }} + > + {f} + + ))} + + + + {notSelectedFilters.map((f) => ( + { + if (event.key === 'Space') { + event.preventDefault() + // event.currentTarget?.form?.requestSubmit() + } + }} + onChange={(e) => { + // e.currentTarget?.form?.requestSubmit() + }} + > + {f} + + ))} + + + + + ) +} diff --git a/client/src/oppgaveliste/filter/ShowMore.tsx b/client/src/oppgaveliste/filter/ShowMore.tsx new file mode 100644 index 00000000..e83143e7 --- /dev/null +++ b/client/src/oppgaveliste/filter/ShowMore.tsx @@ -0,0 +1,69 @@ +import { ChevronDownIcon } from '@navikt/aksel-icons' +import { HStack } from '@navikt/ds-react' +import React, { useCallback, useEffect } from 'react' +import styled from 'styled-components' + +type Props = { + title: string + children: React.ReactNode + //className?: string + open?: boolean + spacing?: boolean +} + +const ShowMore = ({ title, children, /*, className,*/ open /*, spacing*/ }: Props) => { + const detailsRef = React.useRef(null) + + const handleKeyUp = useCallback((event: KeyboardEvent) => { + if (event.key === 'Escape' && detailsRef.current) { + detailsRef.current.open = false // Close the details element + } + }, []) + + useEffect(() => { + const currentDetailsRef = detailsRef.current + if (currentDetailsRef) { + currentDetailsRef.addEventListener('keyup', handleKeyUp) + } + return () => { + if (currentDetailsRef) { + currentDetailsRef.removeEventListener('keyup', handleKeyUp) + } + } + }, [handleKeyUp]) + + return ( + + + {title} +
+ +
+
+ {children} +
+ ) +} + +const PostionDiv = styled.details` + height: fit-content; + position: relative; +` + +const DropdownContainer = styled.div` + border: 1px solid var(--a-border-divider); + top: 48px; + border-top: none; + border-radius: 0 0 4px 4px; + box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); + position: absolute; + left: 0; + background-color: white; + width: 100%; + z-index: 4; + padding: 10px; + padding-top: var(--a-spacing-4); + padding-bottom: var(--a-spacing-6); +` + +export default ShowMore diff --git a/client/src/oppgaveliste/filter.tsx b/client/src/oppgaveliste/filter/filter.tsx similarity index 100% rename from client/src/oppgaveliste/filter.tsx rename to client/src/oppgaveliste/filter/filter.tsx