Skip to content

Commit

Permalink
implement round trip between redux and react hook form for expert filter
Browse files Browse the repository at this point in the history
  • Loading branch information
thangqp committed Jul 1, 2024
1 parent ea559fa commit e82f336
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 94 deletions.
14 changes: 1 addition & 13 deletions src/components/3-organisms/Filter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import React, { useCallback, useEffect, useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { Grid } from '@mui/material';
import { getOperandsOptions } from '../../utils/optionsBuilders';
Expand All @@ -16,7 +16,6 @@ import {
EXPERT_FILTER_QUERY,
} from '@gridsuite/commons-ui';
import { useIntl } from 'react-intl';
import { useFormContext } from 'react-hook-form';

const COPY_FILTER_LABEL = 'Copy filter';
const DELETE_FILTER_LABEL = 'Delete filter';
Expand All @@ -43,8 +42,6 @@ const Filter = (props) => {
// --- begin new code rqb --- //
const intl = useIntl();

const { handleSubmit, watch } = useFormContext();

const translatedFields = useMemo(() => {
return EXPERT_FILTER_FIELDS[equipmentType]?.map((field) => {
return {
Expand All @@ -54,15 +51,6 @@ const Filter = (props) => {
});
}, [intl, equipmentType]);

// submit when OnChange occurs
// see https://stackoverflow.com/questions/63466463/how-to-submit-react-form-fields-on-onchange-rather-than-on-submit-using-react-ho
useEffect(() => {
const subscription = watch(() => handleSubmit(setValue)());
return () => {
subscription.unsubscribe();
};
}, [handleSubmit, watch, setValue]);

// --- end new code rqb --- //
const handleAutocompleteChange = useCallback(
(newValue) => setValue(newValue),
Expand Down
4 changes: 2 additions & 2 deletions src/components/3-organisms/Rule.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const Rule = (props) => {
mappedModel,
setGroup,
groupType,
filtersNumber,
hasFilter,
matches = [],
} = rule;

Expand Down Expand Up @@ -198,7 +198,7 @@ const Rule = (props) => {
{children}
</Grid>
<Grid item xs={12} md={12} paddingTop={1}>
{isNetworkAttached && !!filtersNumber && (
{isNetworkAttached && hasFilter && (
<Paper sx={styles.matches}>
<Grid container>
<Grid item xs={4}>
Expand Down
87 changes: 45 additions & 42 deletions src/containers/FilterContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import React, { useCallback, useEffect, useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
makeChangeFilterValueThenGetNetworkMatches,
Expand All @@ -19,13 +19,12 @@ import {
CustomFormProvider,
EXPERT_FILTER_QUERY,
EXPERT_FILTER_SCHEMA,
exportExpertRules,
importExpertRules,
yup,
} from '@gridsuite/commons-ui';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import useNotification from '../hooks/useNotification';
import useFormChange from '../hooks/useFormChange';
import useFormUpdate from '../hooks/useFormUpdate';

const filterFormSchema = yup
.object()
Expand All @@ -44,11 +43,9 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
// Data
const getFilter = useMemo(makeGetFilter, []);
const filter = useSelector((state) =>
getFilter(state, { rule: ruleIndex /*filter: filterIndex */ })
getFilter(state, ruleIndex /*{ rule: ruleIndex, filter: filterIndex }*/)
);

//console.log('filter', { filter });
const { id, rules: filterValue } = filter;
const { id, rules: filterQuery } = filter;
// const fullProperty = equipmentType
// ? getProperty(equipmentType, property)
// : undefined;
Expand Down Expand Up @@ -113,29 +110,28 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {

// --- begin new code --- //

const { ready, setReady } = useNotification(actionTypes);

// how to set default values from useSelector and via reset???
const formMethods = useForm({
resolver: yupResolver(filterFormSchema),
});

const {
reset,
formState: { errors },
setValue: setFormValue,
} = formMethods;

const isValidating = errors.root?.isValidating;

const setValue = useCallback(
(formData) => {
const newQuery = exportExpertRules(formData[EXPERT_FILTER_QUERY]);
const rqbQuery = formData[EXPERT_FILTER_QUERY];
//const newFilterQuery = exportExpertRules(rqbQuery);
dispatch(
changeFilterValueThenGetNetworkMatches({
ruleIndex,
/*filterIndex,*/
//value: isUniqueSelectFilter ? [value] : value,
value: newQuery,
value: rqbQuery,
})
);
},
Expand All @@ -148,16 +144,25 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
]
);

// effect to init react query builder filter form value
useEffect(() => {
if (!ready) {
console.log('filter value in effect', { filterValue });
const query = importExpertRules(filterValue);

reset({ [EXPERT_FILTER_QUERY]: query });
setReady(true);
}
}, [reset, filterValue, ready, setReady]);
// const formData = watch();
// const prevFormData = usePrevious(formData);
//
// // submit when OnChange occurs
// // see https://stackoverflow.com/questions/63466463/how-to-submit-react-form-fields-on-onchange-rather-than-on-submit-using-react-ho
// useEffect(() => {
// // const subscription = watch(() => handleSubmit(setValue)());
// // return () => {
// // subscription.unsubscribe();
// // };
// if (!isDeepEqualReact(prevFormData, formData)) {
// console.log('submit', { formData });
// handleSubmit(setValue)();
// }
// }, [handleSubmit, watch, setValue, formData, prevFormData]);

useFormChange(formMethods, setValue);

useFormUpdate(formMethods, filter);

// --- end new code --- //

Expand All @@ -166,31 +171,29 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
{...formMethods}
validationSchema={filterFormSchema}
>
{ready && (
<Filter
id={id}
isValid={isValid}
// property={property}
// propertyType={fullProperty?.type}
// properties={properties}
// setProperty={setProperty}
// operand={operand}
// setOperand={setOperand}
// value={isUniqueSelectFilter && value.length > 0 ? value[0] : value}
// possibleValues={possibleValues}
// networkValues={networkValues}
setValue={setValue}
// new code props
equipmentType={equipmentType}
/>
)}
<Filter
id={id}
isValid={isValid}
// property={property}
// propertyType={fullProperty?.type}
// properties={properties}
// setProperty={setProperty}
// operand={operand}
// setOperand={setOperand}
// value={isUniqueSelectFilter && value.length > 0 ? value[0] : value}
// possibleValues={possibleValues}
// networkValues={networkValues}
setValue={setValue}
// new code props
equipmentType={equipmentType}
/>
</CustomFormProvider>
);
};

FilterContainer.propTypes = {
ruleIndex: PropTypes.number.isRequired,
filterIndex: PropTypes.number.isRequired,
// filterIndex: PropTypes.number.isRequired,
equipmentType: PropTypes.string.isRequired,
};

Expand Down
37 changes: 19 additions & 18 deletions src/containers/RuleContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ const RuleContainer = ({ index, editParameters }) => {
const rule = useSelector((state) => getRule(state, index));
const {
type,
filtersNumber,
hasFilter,
mappedModel,
setGroup,
groupType,
composition,
//composition,
} = rule;
console.log('rule', { rule });
const isRuleValidSelector = useMemo(makeIsRuleValid, []);
const isRuleValid = useSelector((state) =>
isRuleValidSelector(state, index)
Expand Down Expand Up @@ -186,20 +187,20 @@ const RuleContainer = ({ index, editParameters }) => {
originIndex: index,
});

function buildFilters() {
const filters = [];
for (let i = 0; i < filtersNumber; i++) {
filters.push(
<FilterContainer
key={`filter-container-${i}`}
ruleIndex={index}
// filterIndex={i}
equipmentType={type}
/>
);
}
return filters;
}
// function buildFilters() {
// const filters = [];
// for (let i = 0; i < filtersNumber; i++) {
// filters.push(
// <FilterContainer
// key={`filter-container-${i}`}
// ruleIndex={index}
// // filterIndex={i}
// equipmentType={type}
// />
// );
// }
// return filters;
// }

// function buildFiltersGroup(groupArray, groupIndex) {
// const groupOperator = groupArray[1] ?? '||';
Expand Down Expand Up @@ -252,7 +253,7 @@ const RuleContainer = ({ index, editParameters }) => {
if (!!currentNetworkId && isRuleValid) {
dispatch(getNetworkMatchesFromRule(index));
}
}, [currentNetworkId, isRuleValid, index, composition, dispatch]);
}, [currentNetworkId, isRuleValid, index, /*composition,*/ dispatch]);

return (
<Rule
Expand All @@ -276,7 +277,7 @@ const RuleContainer = ({ index, editParameters }) => {
controlledParameters={controlledParameters}
isNetworkAttached={!!currentNetworkId}
>
{rule.filtersNumber > 0 ? (
{hasFilter ? (
<>
{
/*showAdvanced && <FiltersTemplate>
Expand Down
27 changes: 27 additions & 0 deletions src/hooks/useFormChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { usePrevious } from '@gridsuite/commons-ui';
import { useEffect } from 'react';
import isDeepEqualReact from 'fast-deep-equal/react';
import { FieldValues, UseFormReturn } from 'react-hook-form';

const useFormChange = (
formApi: UseFormReturn,
onChange: (formData: FieldValues) => void
) => {
const formData = formApi.watch();
const prevFormData = usePrevious(formData);

useEffect(() => {
if (!isDeepEqualReact(prevFormData, formData)) {
console.log('handleSubmit', { formData });
formApi.handleSubmit(onChange)();
}
}, [formApi, onChange, formData, prevFormData]);
};

export default useFormChange;
28 changes: 28 additions & 0 deletions src/hooks/useFormUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { usePrevious } from '@gridsuite/commons-ui';
import { useEffect } from 'react';
import isDeepEqualReact from 'fast-deep-equal/react';
import { UseFormReturn } from 'react-hook-form';

const useFormUpdate = (formApi: UseFormReturn, data: any) => {
const prevData = usePrevious(data);

useEffect(() => {
if (!isDeepEqualReact(prevData, data)) {
console.log('setValue', { data });
const setValueToKey = ([key, value]: [string, any]) => {
formApi.setValue(key, value, { shouldDirty: false });
};

Object.entries(data).forEach(setValueToKey);
}
}, [formApi, data, prevData]);
};

export default useFormUpdate;
Loading

0 comments on commit e82f336

Please sign in to comment.