Skip to content

Commit cdb388f

Browse files
Validation added for voltage init filters (#905)
Signed-off-by: benrejebmoh <[email protected]> Co-authored-by: FranckLecuyer <[email protected]>
1 parent 79860f9 commit cdb388f

File tree

2 files changed

+86
-44
lines changed

2 files changed

+86
-44
lines changed

src/components/inputs/reactHookForm/DirectoryItemsInput.tsx

Lines changed: 83 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import { Box, Chip, FormControl, FormHelperText, Grid, IconButton, Tooltip } from '@mui/material';
99
import { Folder as FolderIcon } from '@mui/icons-material';
10-
import { useCallback, useMemo, useState } from 'react';
11-
import { FieldValues, useController, useFieldArray } from 'react-hook-form';
10+
import { useCallback, useEffect, useMemo, useState } from 'react';
11+
import { FieldValues, useController, useFieldArray, useWatch } from 'react-hook-form';
1212
import { FormattedMessage, useIntl } from 'react-intl';
1313
import type { UUID } from 'node:crypto';
1414
import { RawReadOnlyInput } from './RawReadOnlyInput';
@@ -100,7 +100,8 @@ export function DirectoryItemsInput({
100100
});
101101

102102
const formContext = useCustomFormContext();
103-
const { getValues, validationSchema } = formContext;
103+
const { getValues, validationSchema, setError, clearErrors, getFieldState } = formContext;
104+
const watchedElements = useWatch({ name }) as FieldValues[] | undefined;
104105

105106
const {
106107
fieldState: { error },
@@ -172,6 +173,28 @@ export function DirectoryItemsInput({
172173
return allowMultiSelect === false && elements?.length === 1;
173174
}, [allowMultiSelect, elements]);
174175

176+
const hasElementsWithoutName = useMemo(() => {
177+
const elementsToCheck = (watchedElements ?? elements) as FieldValues[] | undefined;
178+
179+
return (elementsToCheck ?? []).some((item) => !item?.[NAME]);
180+
}, [elements, watchedElements]);
181+
182+
useEffect(() => {
183+
const errorMessage = intl.formatMessage({ id: 'elementNotFound' });
184+
const fieldState = getFieldState(name);
185+
186+
if (hasElementsWithoutName) {
187+
if (fieldState.error?.message !== errorMessage) {
188+
setError(name as any, {
189+
type: 'manual',
190+
message: errorMessage,
191+
});
192+
}
193+
} else if (fieldState.error?.type === 'manual' && fieldState.error?.message === errorMessage) {
194+
clearErrors(name as any);
195+
}
196+
}, [clearErrors, getFieldState, hasElementsWithoutName, intl, name, setError]);
197+
175198
return (
176199
<>
177200
<FormControl
@@ -190,46 +213,64 @@ export function DirectoryItemsInput({
190213
)}
191214
{elements?.length > 0 && (
192215
<FormControl sx={styles.formDirectoryElements2}>
193-
{elements.map((item, index) => (
194-
<Box
195-
key={item.id}
196-
sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column', gap: 1 }}
197-
>
198-
<Chip
199-
size="small"
200-
sx={{
201-
backgroundColor:
202-
item?.specificMetadata?.equipmentType &&
203-
equipmentColorsMap?.get(item?.specificMetadata?.equipmentType),
204-
}}
205-
onDelete={() => removeElements(index)}
206-
onClick={() => handleChipClick(index)}
207-
label={
208-
<OverflowableText
209-
text={
210-
getValues(`${name}.${index}.${NAME}`) ? (
211-
<RawReadOnlyInput name={`${name}.${index}.${NAME}`} />
212-
) : (
213-
intl.formatMessage({ id: 'elementNotFound' })
214-
)
215-
}
216-
sx={{ width: '100%' }}
217-
/>
218-
}
219-
/>
220-
{equipmentColorsMap && (
221-
<FormHelperText>
222-
{item?.specificMetadata?.equipmentType ? (
223-
<FormattedMessage
224-
id={getFilterEquipmentTypeLabel(item.specificMetadata.equipmentType)}
225-
/>
226-
) : (
227-
''
216+
{elements.map((item, index) => {
217+
const elementName =
218+
watchedElements?.[index]?.[NAME] ??
219+
getValues(`${name}.${index}.${NAME}`) ??
220+
(item as FieldValues)?.[NAME];
221+
222+
return (
223+
<Box
224+
key={item.id}
225+
sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column', gap: 1 }}
226+
>
227+
<Chip
228+
size="small"
229+
sx={mergeSx(
230+
{
231+
backgroundColor:
232+
item?.specificMetadata?.equipmentType &&
233+
equipmentColorsMap?.get(item?.specificMetadata?.equipmentType),
234+
},
235+
!elementName
236+
? (theme) => ({
237+
backgroundColor: theme.palette.error.light,
238+
borderColor: theme.palette.error.main,
239+
color: theme.palette.error.contrastText,
240+
})
241+
: undefined
228242
)}
229-
</FormHelperText>
230-
)}
231-
</Box>
232-
))}
243+
onDelete={() => removeElements(index)}
244+
onClick={() => handleChipClick(index)}
245+
label={
246+
<OverflowableText
247+
text={
248+
elementName ? (
249+
<RawReadOnlyInput name={`${name}.${index}.${NAME}`} />
250+
) : (
251+
intl.formatMessage({ id: 'elementNotFound' })
252+
)
253+
}
254+
sx={{ width: '100%' }}
255+
/>
256+
}
257+
/>
258+
{equipmentColorsMap && (
259+
<FormHelperText>
260+
{item?.specificMetadata?.equipmentType ? (
261+
<FormattedMessage
262+
id={getFilterEquipmentTypeLabel(
263+
item.specificMetadata.equipmentType
264+
)}
265+
/>
266+
) : (
267+
''
268+
)}
269+
</FormHelperText>
270+
)}
271+
</Box>
272+
);
273+
})}
233274
</FormControl>
234275
)}
235276
<Grid item xs>

src/components/inputs/reactHookForm/utils/SubmitButton.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import { useFormState } from 'react-hook-form';
1010
import { FormattedMessage } from 'react-intl';
1111

1212
export function SubmitButton(buttonProps: Readonly<ButtonProps>) {
13-
const { isDirty } = useFormState();
13+
const { isDirty, errors } = useFormState();
14+
const hasErrors = Object.keys(errors ?? {}).length > 0;
1415

1516
return (
16-
<Button {...buttonProps} disabled={!isDirty || (buttonProps?.disabled ?? false)}>
17+
<Button {...buttonProps} disabled={!isDirty || hasErrors || (buttonProps?.disabled ?? false)}>
1718
<FormattedMessage id="validate" />
1819
</Button>
1920
);

0 commit comments

Comments
 (0)