Skip to content

Commit

Permalink
implement a notification center
Browse files Browse the repository at this point in the history
  • Loading branch information
thangqp committed Jun 26, 2024
1 parent 65d4b7d commit ea559fa
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 38 deletions.
4 changes: 2 additions & 2 deletions src/components/2-molecules/SetGroupSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ const SetGroupSelect = (props: SetGroupSelectProps) => {
return (
<Grid container justifyContent={'flex-start'}>
<Grid item container justifyContent={'flex-start'}>
<Grid container item xs="auto" sx={styles.gridItem}>
<Grid container item xs sx={styles.gridItem}>
<Typography variant="subtitle1">{`${isAbsoluteLabel} :`}</Typography>
</Grid>
<Grid item container xs justifyContent={'flex-end'}>
<Grid item container xs="auto" justifyContent={'flex-end'}>
<Checkbox
checked={isAbsolute}
onChange={onAbsoluteChange}
Expand Down
16 changes: 13 additions & 3 deletions src/components/3-organisms/Filter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import { Grid } from '@mui/material';
import { getOperandsOptions } from '../../utils/optionsBuilders';
import { multipleOperands } from '../../constants/operands';
import { useFormContext } from 'react-hook-form';
import {
CustomReactQueryBuilder,
EXPERT_FILTER_FIELDS,
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,7 +43,7 @@ const Filter = (props) => {
// --- begin new code rqb --- //
const intl = useIntl();

const { getValues, setValue: setValueForm } = useFormContext();
const { handleSubmit, watch } = useFormContext();

const translatedFields = useMemo(() => {
return EXPERT_FILTER_FIELDS[equipmentType]?.map((field) => {
Expand All @@ -53,6 +53,16 @@ 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
75 changes: 43 additions & 32 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, useState } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
makeChangeFilterValueThenGetNetworkMatches,
Expand All @@ -19,11 +19,13 @@ 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';

const filterFormSchema = yup
.object()
Expand All @@ -32,15 +34,21 @@ const filterFormSchema = yup
})
.required();

const actionTypes = [
MappingSlice.actions.selectMapping.type,
MappingSlice.actions.changeFilteredType.type,
MappingSlice.actions.deleteRule.type,
];

const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
// Data
const getFilter = useMemo(makeGetFilter, []);
const filter = useSelector((state) =>
getFilter(state, { rule: ruleIndex /*filter: filterIndex */ })
);

console.log('filter', { filter });
const { id, rules: rootFilterRule } = filter;
//console.log('filter', { filter });
const { id, rules: filterValue } = filter;
// const fullProperty = equipmentType
// ? getProperty(equipmentType, property)
// : undefined;
Expand Down Expand Up @@ -92,25 +100,6 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
makeChangeFilterValueThenGetNetworkMatches,
[]
);
const setValue = useCallback(
(value) => {
dispatch(
changeFilterValueThenGetNetworkMatches({
ruleIndex,
/*filterIndex,*/
//value: isUniqueSelectFilter ? [value] : value,
value,
})
);
},
[
dispatch,
ruleIndex,
// filterIndex,
// isUniqueSelectFilter,
changeFilterValueThenGetNetworkMatches,
]
);

// const properties = equipmentType ? getPropertiesOptions(equipmentType) : [];
// const possibleValues =
Expand All @@ -123,7 +112,8 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
// : undefined);

// --- begin new code --- //
const [filterDataReady, setFilterDataReady] = useState(false);

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

// how to set default values from useSelector and via reset???
const formMethods = useForm({
Expand All @@ -137,16 +127,37 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {

const isValidating = errors.root?.isValidating;

useEffect(() => {
const query = importExpertRules(filter[EXPERT_FILTER_QUERY]);
const setValue = useCallback(
(formData) => {
const newQuery = exportExpertRules(formData[EXPERT_FILTER_QUERY]);
dispatch(
changeFilterValueThenGetNetworkMatches({
ruleIndex,
/*filterIndex,*/
//value: isUniqueSelectFilter ? [value] : value,
value: newQuery,
})
);
},
[
dispatch,
ruleIndex,
// filterIndex,
// isUniqueSelectFilter,
changeFilterValueThenGetNetworkMatches,
]
);

console.log('query in effect', { query });
// 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,
});
setFilterDataReady(true);
}, [reset, filter]);
reset({ [EXPERT_FILTER_QUERY]: query });
setReady(true);
}
}, [reset, filterValue, ready, setReady]);

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

Expand All @@ -155,7 +166,7 @@ const FilterContainer = ({ ruleIndex, /*filterIndex,*/ equipmentType }) => {
{...formMethods}
validationSchema={filterFormSchema}
>
{filterDataReady && (
{ready && (
<Filter
id={id}
isValid={isValid}
Expand Down
55 changes: 55 additions & 0 deletions src/hooks/useNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* 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 { useEffect, useId, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
makeGetNotification,
NotificationSlice,
RootState,
} from '../redux/slices/Notification';

const useNotification = (actionTypes: string[]) => {
const [ready, setReady] = useState(false);
const subscriberId = useId();
const dispatch = useDispatch();

const getNotification = useMemo(makeGetNotification, []);
const notification = useSelector((state: RootState) =>
getNotification(state, { subscriberId })
);

// to subscribe notification center
useEffect(() => {
dispatch(
NotificationSlice.actions.subscribe({
subscriberId,
actionTypes,
})
);

return () => {
// Unsubscribe when component unmounts
dispatch(
NotificationSlice.actions.unsubscribe({
subscriberId,
actionTypes,
})
);
};
}, [dispatch, subscriberId, actionTypes]);

useEffect(() => {
if (notification) {
setReady(false);
dispatch(NotificationSlice.actions.clear(notification));
}
}, [notification, dispatch]);

return { setReady, ready };
};

export default useNotification;
28 changes: 28 additions & 0 deletions src/middlewares/NotificationMiddleware.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/.
*/

// middleware/notificationMiddleware.ts
import { Middleware } from '@reduxjs/toolkit';
import { NotificationSlice } from '../redux/slices/Notification';

const notificationMiddleware: Middleware =
(storeAPI) => (next) => (action: any) => {
const result = next(action);
if (
!Object.values(NotificationSlice.actions)
.map((action) => action.type)
.some((type) => type === action.type)
) {
// notify only action not in notification slice
storeAPI.dispatch(
NotificationSlice.actions.notify({ actionType: action.type })
);
}
return result;
};

export default notificationMiddleware;
2 changes: 2 additions & 0 deletions src/redux/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { UserReducer } from './slices/User';
import { ScriptsReducer } from './slices/Script';
import { NetworkReducer } from './slices/Network';
import { ModelReducer } from './slices/Model';
import { NotificationReducer } from './slices/Notification';

export const reducer = combineReducers({
user: UserReducer,
Expand All @@ -20,4 +21,5 @@ export const reducer = combineReducers({
models: ModelReducer,
scripts: ScriptsReducer,
network: NetworkReducer,
notification: NotificationReducer,
});
Loading

0 comments on commit ea559fa

Please sign in to comment.