From 8b4d841023be2a8804536296df36c0d2bf322581 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Wed, 9 Feb 2022 21:12:32 +0200 Subject: [PATCH] feat(BS|PL): integrate report query with location query. --- package.json | 1 + .../BalanceSheet/BalanceSheetHeader.js | 4 +- .../FinancialStatements/BalanceSheet/utils.js | 13 ++- .../ProfitLossSheet/utils.js | 9 +- src/hooks/index.js | 29 +----- src/hooks/useQueryString.ts | 89 +++++++++++++++++++ 6 files changed, 102 insertions(+), 43 deletions(-) create mode 100644 src/hooks/useQueryString.ts diff --git a/package.json b/package.json index e0e766a3e..77cf277f3 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "postcss-preset-env": "6.7.0", "postcss-rtl": "^1.7.3", "postcss-safe-parser": "4.0.1", + "query-string": "^7.1.1", "ramda": "^0.27.1", "react": "^16.12.0", "react-app-polyfill": "^1.0.6", diff --git a/src/containers/FinancialStatements/BalanceSheet/BalanceSheetHeader.js b/src/containers/FinancialStatements/BalanceSheet/BalanceSheetHeader.js index 78ec8ddca..c576adceb 100644 --- a/src/containers/FinancialStatements/BalanceSheet/BalanceSheetHeader.js +++ b/src/containers/FinancialStatements/BalanceSheet/BalanceSheetHeader.js @@ -13,8 +13,8 @@ import FinancialStatementHeader from '../../FinancialStatements/FinancialStateme import { compose, transformToForm } from 'utils'; import { - getBalanceSheetHeaderDefaultValues, getBalanceSheetHeaderValidationSchema, + getDefaultBalanceSheetQuery, } from './utils'; /** @@ -31,7 +31,7 @@ function BalanceSheetHeader({ // #withBalanceSheetActions toggleBalanceSheetFilterDrawer: toggleFilterDrawer, }) { - const defaultValues = getBalanceSheetHeaderDefaultValues(); + const defaultValues = getDefaultBalanceSheetQuery(); // Filter form initial values. const initialValues = transformToForm( diff --git a/src/containers/FinancialStatements/BalanceSheet/utils.js b/src/containers/FinancialStatements/BalanceSheet/utils.js index ba14968ca..262aecf0a 100644 --- a/src/containers/FinancialStatements/BalanceSheet/utils.js +++ b/src/containers/FinancialStatements/BalanceSheet/utils.js @@ -5,7 +5,7 @@ import * as Yup from 'yup'; import intl from 'react-intl-universal'; import { transformToForm } from 'utils'; -import { useLocationQuery, useMutateLocationQuery } from 'hooks'; +import { useAppQueryString } from 'hooks'; /** * Retrieves the default balance sheet query. @@ -27,8 +27,8 @@ export const getDefaultBalanceSheetQuery = () => ({ previousPeriodPercentageChange: false, // Percentage columns. - percentageColumn: false, - percentageRow: false, + percentageOfColumn: false, + percentageOfRow: false, }); /** @@ -36,10 +36,7 @@ export const getDefaultBalanceSheetQuery = () => ({ */ export const useBalanceSheetQuery = () => { // Retrieves location query. - const locationQuery = useLocationQuery(); - - // Mutates the location query. - const { mutate: setLocationQuery } = useMutateLocationQuery(); + const [locationQuery, setLocationQuery] = useAppQueryString(); // Merges the default filter query with location URL query. const query = React.useMemo(() => { @@ -47,7 +44,7 @@ export const useBalanceSheetQuery = () => { return { ...defaultQuery, - ...transformToForm(Object.fromEntries([...locationQuery]), defaultQuery), + ...transformToForm(locationQuery, defaultQuery), }; }, [locationQuery]); diff --git a/src/containers/FinancialStatements/ProfitLossSheet/utils.js b/src/containers/FinancialStatements/ProfitLossSheet/utils.js index a010ac632..a2e889d9c 100644 --- a/src/containers/FinancialStatements/ProfitLossSheet/utils.js +++ b/src/containers/FinancialStatements/ProfitLossSheet/utils.js @@ -4,7 +4,7 @@ import moment from 'moment'; import intl from 'react-intl-universal'; import * as Yup from 'yup'; -import { useMutateLocationQuery, useLocationQuery } from 'hooks'; +import { useAppQueryString } from 'hooks'; import { transformToForm } from 'utils'; /** @@ -38,10 +38,7 @@ export const getDefaultProfitLossQuery = () => ({ */ export const useProfitLossSheetQuery = () => { // Retrieves location query. - const locationQuery = useLocationQuery(); - - // Mutate the location query. - const { mutate: setLocationQuery } = useMutateLocationQuery(); + const [locationQuery, setLocationQuery] = useAppQueryString(); // Merges the default query with location query. const query = React.useMemo(() => { @@ -49,7 +46,7 @@ export const useProfitLossSheetQuery = () => { return { ...defaultQuery, - ...transformToForm(Object.fromEntries([...locationQuery]), defaultQuery), + ...transformToForm(locationQuery, defaultQuery), }; }, [locationQuery]); diff --git a/src/hooks/index.js b/src/hooks/index.js index cc22b5491..47aec372c 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -4,6 +4,7 @@ import useAutofocus from './useAutofocus'; import { useLocalStorage } from './utils/useLocalStorage'; export * from './utils'; +export * from './useQueryString'; export function useIsValuePassed(value, compatatorValue) { const cache = useRef([value]); @@ -53,30 +54,4 @@ export function useMemorizedColumnsWidths(tableName) { save(columnsResizing.columnWidths); }; return [get, save, handleColumnResizing]; -} - -/** - * Retrieve the URL location search params. - */ -export const useLocationQuery = () => { - const { search } = useLocation(); - - return useMemo(() => { - return new URLSearchParams(search); - }, [search]); -}; - -/** - * Mutates the URL location params. - */ -export const useMutateLocationQuery = () => { - const location = useLocation(); - const history = useHistory(); - - return { - mutate: (query) => { - const params = new URLSearchParams(query).toString(); - history.push({ pathname: location.pathname, search: params.toString() }); - }, - }; -}; +} \ No newline at end of file diff --git a/src/hooks/useQueryString.ts b/src/hooks/useQueryString.ts new file mode 100644 index 000000000..444a8846c --- /dev/null +++ b/src/hooks/useQueryString.ts @@ -0,0 +1,89 @@ +import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'; +import { + ParseOptions, + ParsedQuery, + StringifyOptions, + parse, + stringify, +} from 'query-string'; +import { useHistory } from 'react-router'; + +export interface QueryStringResult { + [0]: ParsedQuery; + [1]: Dispatch>>; +} + +type NavigateCallback = ( + pathnameWithParams: string, + pathname: string, + stringifedParams: string, +) => void; + +/** + * Query string. + * @param {Location} location + * @param {NavigateCallback} navigate + * @param {ParseOptions} parseOptions + * @param {StringifyOptions} stringifyOptions + * @returns {QueryStringResult} + */ +export function useQueryString( + location: Location, + navigate: NavigateCallback, + parseOptions?: ParseOptions, + stringifyOptions?: StringifyOptions, +): QueryStringResult { + const isFirst = useRef(true); + const [state, setState] = useState(parse(location.search, parseOptions)); + + useEffect((): void => { + if (isFirst.current) { + isFirst.current = false; + } else { + const pathname = location.pathname; + const stringifedParams = stringify(state, stringifyOptions); + const pathnameWithParams = pathname + '?' + stringifedParams; + + navigate(pathnameWithParams, pathname, stringifedParams); + } + }, [state]); + + const setQuery: typeof setState = (values): void => { + const nextState = typeof values === 'function' ? values(state) : values; + setState( + (state): ParsedQuery => ({ + ...state, + ...nextState, + }), + ); + }; + + return [state, setQuery]; +} + +/** + * Query string hook integrate with react router of the application. + * @param {NavigateCallback} navigate + * @param {ParseOptions} parseOptions + * @returns {QueryStringResult} + */ +export const useAppQueryString = ( + navigate: NavigateCallback, + parseOptions: ParseOptions = {}, +): QueryStringResult => { + const history = useHistory(); + + return useQueryString( + window.location, + (pathnameWithParams, pathname, stringifiedParams) => { + history.push({ pathname, search: stringifiedParams }); + + navigate && navigate(pathnameWithParams, pathname, stringifiedParams); + }, + { + parseNumbers: true, + parseBooleans: true, + ...parseOptions, + }, + ); +};