From 5a3293d87798a86db52614ca8d920e04a33acc8e Mon Sep 17 00:00:00 2001 From: Matteo Miotello Date: Fri, 12 Jan 2024 12:51:26 +0100 Subject: [PATCH] rimozione dipendenza react-router --- package.json | 1 - src/Form/useForm.ts | 20 +++++++-- src/Provider/ShellyProvider.tsx | 1 + src/Table/FilteredTable.tsx | 29 +++++++------ src/Table/TableButtons.tsx | 2 +- src/hooks/useNavigate.ts | 21 ++++++++++ src/hooks/useQueryParams.ts | 74 +++++++++++++++++++++++++++++++++ yarn.lock | 20 --------- 8 files changed, 128 insertions(+), 40 deletions(-) create mode 100644 src/hooks/useNavigate.ts create mode 100644 src/hooks/useQueryParams.ts diff --git a/package.json b/package.json index 7be413e..962a2e4 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-quill": "^2.0.0", - "react-router-dom": "^6.16.0", "tailwindcss": "^3.3.2" }, "devDependencies": { diff --git a/src/Form/useForm.ts b/src/Form/useForm.ts index 6e7492c..5837057 100755 --- a/src/Form/useForm.ts +++ b/src/Form/useForm.ts @@ -71,9 +71,23 @@ class FormValues { } public isEqual(values: T): boolean { - const exists = Object.entries( values ).find( ([key, value]) => this.formValues[ key ] !== value ); + if ( !values ) { + return false; + } + + if ( Object.entries( values ).length !== Object.entries( this.formValues ).length ) { + return false; + } + + let isEqual = true; + + Object.entries( values ).forEach( ( [key, value] ) => { + if ( this.formValues[ key ] !== value ) { + isEqual = false; + } + }); - return Boolean( !exists ); + return isEqual; } } @@ -170,7 +184,7 @@ const useForm = (props?: UseFormProps): FormHandler => { }; const resetFormValues = () => { - setValues({}); + setValues({...{}}); }; const resetErrors = (): void => { diff --git a/src/Provider/ShellyProvider.tsx b/src/Provider/ShellyProvider.tsx index c0dfa25..f892bc1 100644 --- a/src/Provider/ShellyProvider.tsx +++ b/src/Provider/ShellyProvider.tsx @@ -3,6 +3,7 @@ import React from "react"; export type ShellyConfig = { spinnerElement?: ReactElement + navigateCallback?: () => ( path: string ) => void } type ShellyProviderProps = { diff --git a/src/Table/FilteredTable.tsx b/src/Table/FilteredTable.tsx index 27ff59f..18a6a9b 100755 --- a/src/Table/FilteredTable.tsx +++ b/src/Table/FilteredTable.tsx @@ -5,8 +5,8 @@ import Button from "../Button"; import Input from "../Input"; import { FormHandler } from "../Form/useForm"; import _ from "lodash"; -import { useSearchParams } from "react-router-dom"; import { RowData } from "@tanstack/react-table"; +import { useQueryParams } from "../hooks/useQueryParams"; type FilteredTableProps = PaginateTableProps & PropsWithChildren @@ -25,15 +25,14 @@ type FilterFormProps = { const FilterForm: React.FC = ( {children, id, form, updateAsyncFilters} ) => { const [loading, setIsLoading] = useState(false); - const [queryParameters, setQueryParams] = useSearchParams(); + const [queryParameters, setQueryParams] = useQueryParams(); useEffect( () => { - let formValues = {}; - if ( !queryParameters ) { return; } - + + let formValues = {}; queryParameters.forEach( ( val, key ) => { formValues = { ...formValues, @@ -41,6 +40,7 @@ const FilterForm: React.FC = ( {children, id, form, updateAsync }; } ); + if ( formValues == form.state.formValues ) { return; } @@ -50,19 +50,18 @@ const FilterForm: React.FC = ( {children, id, form, updateAsync if ( !_.isEmpty( formValues ) ) { saveForm( formValues ); } - }, [] ); + }, [queryParameters] ); const saveForm = ( formData: any ) => { - for( const key of queryParameters.keys() ) { - queryParameters.delete( key ); - } - - Object.entries( formData ).map( ([key, value]) => { - queryParameters.set(key, value as string); - } ); - - setQueryParams( queryParameters ); + const qp = new URLSearchParams; + + if ( formData.length !== 0 ) { + Object.entries( formData ).map( ([k, v]) => { + qp.set(k, v as string); + } ); + } + setQueryParams( qp ); if ( updateAsyncFilters ) { setIsLoading( true ); diff --git a/src/Table/TableButtons.tsx b/src/Table/TableButtons.tsx index 2491cdc..9023364 100755 --- a/src/Table/TableButtons.tsx +++ b/src/Table/TableButtons.tsx @@ -3,8 +3,8 @@ import Button from "../Button"; import { ButtonProps } from "../Button/Button"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faMagnifyingGlassPlus, faPencil, faTimes } from "@fortawesome/free-solid-svg-icons"; -import { useNavigate } from "react-router-dom"; import Tooltip from "../Tooltip"; +import { useNavigate } from "../hooks/useNavigate"; type TableButtonsProps = PropsWithChildren diff --git a/src/hooks/useNavigate.ts b/src/hooks/useNavigate.ts new file mode 100644 index 0000000..d5856a2 --- /dev/null +++ b/src/hooks/useNavigate.ts @@ -0,0 +1,21 @@ +import { useContext } from "react"; +import { ShellyConfig } from ".."; +import { ShellyContext } from "../Provider/ShellyProvider"; + +const useShellyContext = (): ShellyConfig => { + return useContext( ShellyContext ); +}; + +export const useNavigate = (): ( path: string ) => void => { + const config = useShellyContext(); + + if ( !config.navigateCallback ) { + throw Error( 'navigateCallback must be provided in ShellyProvider.' ); + } + + return (path) => { + if ( config.navigateCallback ) { + config.navigateCallback()( path ); + } + }; +}; \ No newline at end of file diff --git a/src/hooks/useQueryParams.ts b/src/hooks/useQueryParams.ts new file mode 100644 index 0000000..bf51bfa --- /dev/null +++ b/src/hooks/useQueryParams.ts @@ -0,0 +1,74 @@ +import { useCallback, useEffect, useState } from "react"; + +type ParamsObject = { [key: string]: string } + +type QueryParamsResult = [ + params: URLSearchParams, + setQueryParams: (params: URLSearchParams | ParamsObject) => void +] + +const isEqual = (prev: URLSearchParams, params: URLSearchParams) => { + let equals = true; + + prev.sort(); + params.sort(); + + if ( params.toString() !== prev.toString() ) { + return false; + } + + prev.forEach((val, key) => { + if (val !== params.get(key)) { + equals = false; + } + }); + + return equals; +}; + +export const useQueryParams = (): QueryParamsResult => { + const [params, setParams] = useState(new URLSearchParams); + + useEffect(() => { + if (!document) { + return; + } + + const url = new URL(document.URL); + const queryParams = url.searchParams; + + if (isEqual(queryParams, params)) { + return; + } + + setParams(queryParams); + }, [document.URL]); + + const setQueryParams = useCallback((newParams: URLSearchParams | ParamsObject) => { + if (!window) { + return; + } + + if ( !(newParams instanceof URLSearchParams) ) { + newParams = new URLSearchParams( newParams ); + } + + newParams.sort(); + params.sort(); + + if ( params.toString() === newParams.toString() ) { + return; + } + + const url = new URL(document.URL ); + url.search = newParams.toString(); + window.history.replaceState( {}, 'replace', url.href ); + + setParams( newParams ); + }, [params]); + + return [ + params, + setQueryParams + ]; +}; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2813095..0be9831 100644 --- a/yarn.lock +++ b/yarn.lock @@ -509,11 +509,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@remix-run/router@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.9.0.tgz#9033238b41c4cbe1e961eccb3f79e2c588328cf6" - integrity sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA== - "@rollup/pluginutils@^4.1.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" @@ -2461,21 +2456,6 @@ react-refresh@^0.14.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== -react-router-dom@^6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.16.0.tgz#86f24658da35eb66727e75ecbb1a029e33ee39d9" - integrity sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg== - dependencies: - "@remix-run/router" "1.9.0" - react-router "6.16.0" - -react-router@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.16.0.tgz#abbf3d5bdc9c108c9b822a18be10ee004096fb81" - integrity sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA== - dependencies: - "@remix-run/router" "1.9.0" - react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"