diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c3817..b43b88f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- added the `usePersistentReactDataTableState` hook which saves it's own state into the local storage + ### Changed - migrated to eslint 9 flat config diff --git a/package.json b/package.json index ee5d65e..2ee9872 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@dnd-kit/core": "^6.1.0", "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/sortable": "^8.0.0", + "@neolution-ch/javascript-utils": "^2.2.0", "@neolution-ch/react-pattern-ui": "^5.3.0", "@tanstack/react-table": "^8.12.0", "@tanstack/react-virtual": "^3.13.12", diff --git a/src/index.ts b/src/index.ts index 0b01578..86d326e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ export * from "./lib/translations/translations"; export * from "./lib/useReactDataTableState/useReactDataTableState"; export * from "./lib/useReactDataTableState/useReactDataTableStateProps"; +export * from "./lib/useReactDataTableState/usePersistentReactDataTableState"; export * from "./lib/useReactDataTable/useReactDataTable"; export * from "./lib/useReactDataTable/useReactDataTableProps"; export * from "./lib/useReactDataTable/useReactDataTableResult"; diff --git a/src/lib/useReactDataTableState/usePersistentReactDataTableState.ts b/src/lib/useReactDataTableState/usePersistentReactDataTableState.ts new file mode 100644 index 0000000..ba5ceea --- /dev/null +++ b/src/lib/useReactDataTableState/usePersistentReactDataTableState.ts @@ -0,0 +1,97 @@ +import { getLocalStorageItem, setLocalStorageItem } from "@neolution-ch/javascript-utils"; +import { OptionalNullable } from "../types/NullableTypes"; +import { useReactDataTableStateProps } from "./useReactDataTableStateProps"; +import { useReactDataTableStateResult } from "./useReactDataTableStateResult"; +import { useReactDataTableState } from "./useReactDataTableState"; +import { useEffect } from "react"; + +const usePersistentReactDataTableState = >( + props: OptionalNullable> & { localStorageKey: string }, +): useReactDataTableStateResult => { + const { + pagination, + setPagination, + columnFilters, + columnPinning, + expanded, + rowSelection, + sorting, + setColumnFilters, + afterSearchFilter, + setAfterSearchFilter, + setColumnPinning, + setExpanded, + setRowSelection, + setSorting, + } = useReactDataTableState({ + initialColumnPinning: + getLocalStorageItem["initialColumnPinning"]>(`${props.localStorageKey}_columnPinning`) ?? + props?.initialColumnPinning, + initialExpanded: + getLocalStorageItem["initialExpanded"]>(`${props.localStorageKey}_expanded`) ?? + props?.initialExpanded, + initialPagination: + getLocalStorageItem["initialPagination"]>(`${props.localStorageKey}_pagination`) ?? + props?.initialPagination, + initialRowSelection: + getLocalStorageItem["initialRowSelection"]>(`${props.localStorageKey}_rowSelection`) ?? + props?.initialRowSelection, + initialSorting: + getLocalStorageItem["initialSorting"]>(`${props.localStorageKey}_sorting`) ?? + props?.initialSorting, + } as OptionalNullable>); + + useEffect(() => { + // We can't set these values directly in the useReactDataTableState hook above, + // because the filter would be taken as default value also for the reset function. + const storedColumnFilters = getLocalStorageItem(`${props.localStorageKey}_columnFilters`); + if (storedColumnFilters) { + setColumnFilters(storedColumnFilters); + } + + const storedAfterSearchFilter = getLocalStorageItem(`${props.localStorageKey}_afterSearchFilter`); + if (storedAfterSearchFilter) { + setAfterSearchFilter(storedAfterSearchFilter); + } + }, [props.localStorageKey, setColumnFilters, setAfterSearchFilter]); + + return { + pagination, + setPagination: (newPagination) => { + setPagination(newPagination); + setLocalStorageItem(`${props.localStorageKey}_pagination`, newPagination); + }, + columnFilters, + setColumnFilters: (newColumnFilters) => { + setColumnFilters(newColumnFilters); + setLocalStorageItem(`${props.localStorageKey}_columnFilters`, newColumnFilters); + }, + afterSearchFilter, + setAfterSearchFilter: (newAfterSearchFilter) => { + setAfterSearchFilter(newAfterSearchFilter); + setLocalStorageItem(`${props.localStorageKey}_afterSearchFilter`, newAfterSearchFilter); + }, + columnPinning, + setColumnPinning: (newColumnPinning) => { + setColumnPinning(newColumnPinning); + setLocalStorageItem(`${props.localStorageKey}_columnPinning`, newColumnPinning); + }, + expanded, + setExpanded: (newExpanded) => { + setExpanded(newExpanded); + setLocalStorageItem(`${props.localStorageKey}_expanded`, newExpanded); + }, + rowSelection, + setRowSelection: (newRowSelection) => { + setRowSelection(newRowSelection); + setLocalStorageItem(`${props.localStorageKey}_rowSelection`, newRowSelection); + }, + sorting, + setSorting: (newSorting) => { + setSorting(newSorting); + setLocalStorageItem(`${props.localStorageKey}_sorting`, newSorting); + }, + }; +}; + +export { usePersistentReactDataTableState }; diff --git a/yarn.lock b/yarn.lock index 15faefa..675d06a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2101,6 +2101,14 @@ eslint-plugin-unicorn "^61.0.2" typescript-eslint "^8.46.1" +"@neolution-ch/javascript-utils@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@neolution-ch/javascript-utils/-/javascript-utils-2.2.0.tgz#11260342ef66f6ca1b3933282683b687bfe5a20a" + integrity sha512-2QO1l94EjiSbQEVDAKtWlaKJgWFj8hXY43AOKvYpNYJ7y6BbOZAwhbjEFKwgSpfVizpuyqHSsTPSHSKG8WNYhQ== + dependencies: + date-fns "^2.30.0" + uuid "^9.0.1" + "@neolution-ch/react-pattern-ui@^5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@neolution-ch/react-pattern-ui/-/react-pattern-ui-5.3.0.tgz#c900bdfc6947cfbe108910425b4dcb4027cdf34f" @@ -6610,7 +6618,7 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" -date-fns@^2.29.3: +date-fns@^2.29.3, date-fns@^2.30.0: version "2.30.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== @@ -15893,6 +15901,11 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-to-istanbul@^8.1.0: version "8.1.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"