Skip to content

Commit 000de29

Browse files
committed
refactor the subscription logic
1 parent 80d6694 commit 000de29

File tree

9 files changed

+110
-129
lines changed

9 files changed

+110
-129
lines changed

src/admin/units/units.component.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ import {
2525
COLUMN_FILTER_MODE_OPTIONS,
2626
COLUMN_FILTER_VARIANTS,
2727
TableBodyCellOverFlowTip,
28-
TableHeaderOverflowTip,
2928
TableCellOverFlowTipProps,
29+
TableHeaderOverflowTip,
30+
customFilterFunctions,
3031
displayTableRowCountText,
3132
formatDateTimeStrings,
3233
getInitialColumnFilterFnState,
3334
getPageHeightCalc,
3435
mrtTheme,
35-
customFilterFunctions,
3636
} from '../../utils';
3737
import DeleteUnitDialog from './deleteUnitsDialog.component.tsx';
3838
import UnitsDialog from './unitsDialog.component.tsx';

src/catalogue/category/catalogueCategoryDialog.component.tsx

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@ import {
1919
} from '@mui/material';
2020
import { AxiosError } from 'axios';
2121
import React from 'react';
22-
import { Controller, FormProvider, useForm } from 'react-hook-form';
2322
import {
24-
APIError,
23+
Controller,
24+
createFormControl,
25+
FormProvider,
26+
useForm,
27+
} from 'react-hook-form';
28+
import {
2529
AllowedValues,
30+
APIError,
2631
CatalogueCategory,
2732
CatalogueCategoryPost,
2833
CatalogueCategoryPostProperty,
@@ -139,6 +144,39 @@ function transformPostPropertyToAddProperty(
139144
return modifiedCatalogueItemProperty;
140145
}
141146

147+
// Using `any` instead of `FieldPath` to avoid circular dependencies
148+
function getProperty<T extends Record<string, unknown>>(
149+
obj: T,
150+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
151+
key: any
152+
) {
153+
if (key === undefined) return undefined;
154+
155+
const keys = key.toString().split('.');
156+
let current: unknown = obj;
157+
158+
for (const part of keys) {
159+
if (current && typeof current === 'object' && part in current) {
160+
current = (current as Record<string, unknown>)[part];
161+
} else {
162+
return undefined;
163+
}
164+
}
165+
166+
return current;
167+
}
168+
const { formControl } =
169+
createFormControl<AddCatalogueCategoryWithPlacementIds>();
170+
171+
formControl.subscribe({
172+
// @ts-expect-error: The callback is missing name, when the type exist
173+
callback: ({ name, errors }) => {
174+
if (errors && !!getProperty(errors, name)) {
175+
formControl.clearErrors(name);
176+
}
177+
},
178+
});
179+
142180
export interface CatalogueCategoryDialogProps {
143181
open: boolean;
144182
onClose: () => void;
@@ -187,6 +225,7 @@ const CatalogueCategoryDialog = (props: CatalogueCategoryDialogProps) => {
187225
}, [requestType, duplicate, selectedCatalogueCategory]);
188226

189227
const formMethods = useForm<AddCatalogueCategoryWithPlacementIds>({
228+
formControl,
190229
resolver: zodResolver(CatalogueCategorySchema),
191230
defaultValues: initialCatalogueCategory,
192231
});
@@ -285,9 +324,7 @@ const CatalogueCategoryDialog = (props: CatalogueCategoryDialogProps) => {
285324
if (requestType === 'patch') {
286325
handleEditCatalogueCategory(transformedData);
287326
} else {
288-
handleAddCatalogueCategory({
289-
...transformedData,
290-
});
327+
handleAddCatalogueCategory({ ...transformedData });
291328
}
292329
};
293330

src/catalogue/category/property/propertyDialog.component.tsx

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,6 @@ import {
4949
import { transformAllowedValues } from '../catalogueCategoryDialog.component';
5050
import AllowedValuesListTextFields from './allowedValuesListTextFields.component';
5151

52-
// Using `any` instead of `FieldPath` to avoid circular dependencies
53-
function getProperty<T extends Record<string, unknown>>(
54-
obj: T,
55-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
56-
key: any
57-
) {
58-
if (key === undefined) return undefined;
59-
60-
const keys = key.toString().split('.');
61-
let current: unknown = obj;
62-
63-
for (const part of keys) {
64-
if (current && typeof current === 'object' && part in current) {
65-
current = (current as Record<string, unknown>)[part];
66-
} else {
67-
return undefined;
68-
}
69-
}
70-
71-
return current;
72-
}
73-
7452
interface MigrationWarningMessageProps {
7553
isChecked: boolean;
7654
setIsChecked: (isChecked: boolean) => void;
@@ -155,21 +133,10 @@ const PropertyDialog = (props: PropertyDialogProps) => {
155133
setValue: setValueAdd,
156134
resetField: resetFieldAdd,
157135
trigger: triggerAdd,
158-
clearErrors: clearErrorsAdd,
159136
} = formMethodsAdd;
160137

161138
const propertyAdd = watchAdd();
162139

163-
// Clears form errors when a value has been changed
164-
React.useEffect(() => {
165-
const subscription = watchAdd((_, type) => {
166-
if (type.name && !!getProperty(errorsAdd, type.name)) {
167-
clearErrorsAdd(type.name);
168-
}
169-
});
170-
return () => subscription.unsubscribe();
171-
}, [clearErrorsAdd, errorsAdd, watchAdd]);
172-
173140
const allowedValuesTypeAdd =
174141
propertyAdd.properties &&
175142
propertyAdd?.properties[index]?.allowed_values?.type;

src/catalogue/items/catalogueItemsDialog.component.tsx

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ import {
5252
} from '../../form.schemas';
5353
import handleIMS_APIError from '../../handleIMS_APIError';
5454
import ManufacturerDialog from '../../manufacturer/manufacturerDialog.component';
55-
import { sortDataList } from '../../utils';
55+
import {
56+
createFormControlWithRootErrorClearing,
57+
sortDataList,
58+
} from '../../utils';
5659

5760
const RECENT_MANUFACTURER_CUTOFF_TIME = 10 * 60 * 1000;
5861

@@ -157,6 +160,12 @@ function convertToCatalogueItemDetailsStepPost(
157160
};
158161
}
159162

163+
const formControlDetailsStep =
164+
createFormControlWithRootErrorClearing<CatalogueItemDetailsStep>();
165+
166+
const formControlPropertiesStep =
167+
createFormControlWithRootErrorClearing<PropertiesStep>();
168+
160169
export interface CatalogueItemsDialogProps {
161170
open: boolean;
162171
onClose: () => void;
@@ -181,8 +190,9 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
181190
[parentInfo]
182191
);
183192

184-
const CatalogueItemDetailsStepFormMethods = useForm<CatalogueItemDetailsStep>(
193+
const catalogueItemDetailsStepFormMethods = useForm<CatalogueItemDetailsStep>(
185194
{
195+
formControl: formControlDetailsStep,
186196
resolver: zodResolver(CatalogueItemDetailsStepSchema(requestType)),
187197
defaultValues: toCatalogueItemDetailsStep(selectedCatalogueItem),
188198
}
@@ -195,10 +205,10 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
195205
control: controlDetailsStep,
196206
clearErrors: clearErrorsDetailsStep,
197207
reset: resetDetailsStep,
198-
watch: watchDetailsStep,
199-
} = CatalogueItemDetailsStepFormMethods;
208+
} = catalogueItemDetailsStepFormMethods;
200209

201210
const catalogueItemPropertiesStepFormMethods = useForm<PropertiesStep>({
211+
formControl: formControlPropertiesStep,
202212
resolver: zodResolver(PropertiesStepSchema),
203213
defaultValues: {
204214
properties: convertToPropertyValueList(
@@ -215,7 +225,6 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
215225
control: controlPropertiesStep,
216226
clearErrors: clearErrorsPropertiesStep,
217227
reset: resetPropertiesStep,
218-
watch: watchPropertiesStep,
219228
setError: setErrorPropertiesStep,
220229
} = catalogueItemPropertiesStepFormMethods;
221230

@@ -251,21 +260,6 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
251260
selectedCatalogueItem?.properties,
252261
]);
253262

254-
// Clears form errors when a value has been changed
255-
React.useEffect(() => {
256-
const subscription1 = watchDetailsStep(() =>
257-
clearErrorsPropertiesStep('root.formError')
258-
);
259-
return () => subscription1.unsubscribe();
260-
}, [clearErrorsPropertiesStep, watchDetailsStep]);
261-
262-
React.useEffect(() => {
263-
const subscription = watchPropertiesStep(() =>
264-
clearErrorsPropertiesStep('root.formError')
265-
);
266-
return () => subscription.unsubscribe();
267-
}, [clearErrorsPropertiesStep, watchPropertiesStep]);
268-
269263
const { mutateAsync: postCatalogueItem, isPending: isAddPending } =
270264
usePostCatalogueItem();
271265
const { mutateAsync: patchCatalogueItem, isPending: isEditPending } =
@@ -387,12 +381,17 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
387381
if (response && error.response?.status === 409) {
388382
if (response.detail.includes('child elements')) {
389383
// find the name of the manufacturer, so it can be used in the error message
390-
const manufacturerName = manufacturerList?.find(
391-
(manufacturer) => manufacturer.id === selectedCatalogueItem?.manufacturer_id
392-
) || null;
384+
const manufacturerName =
385+
manufacturerList?.find(
386+
(manufacturer) =>
387+
manufacturer.id ===
388+
selectedCatalogueItem?.manufacturer_id
389+
) || null;
393390
// add the manufacturer name into the error message
394-
const childElementsMessage = "Unable to update catalogue item properties and manufacturer ("
395-
+ manufacturerName?.name + "), as the catalogue item has associated items.";
391+
const childElementsMessage =
392+
'Unable to update catalogue item properties and manufacturer (' +
393+
manufacturerName?.name +
394+
'), as the catalogue item has associated items.';
396395
setErrorPropertiesStep('root.formError', {
397396
message: childElementsMessage,
398397
});
@@ -504,10 +503,7 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
504503
const options = (): Array<Manufacturer & { isRecent: string }> => {
505504
const classifiedManufacturers = manufacturerList
506505
? manufacturerList.map((option) => {
507-
return {
508-
...option,
509-
isRecent: 'A-Z',
510-
};
506+
return { ...option, isRecent: 'A-Z' };
511507
})
512508
: [];
513509

@@ -521,10 +517,7 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
521517
return isRecent;
522518
})
523519
.map((option) => {
524-
return {
525-
...option,
526-
isRecent: 'Recently Added',
527-
};
520+
return { ...option, isRecent: 'Recently Added' };
528521
});
529522

530523
/*returns them in reverse alphabetical order, since they will be sorted by "isRecent",
@@ -940,10 +933,8 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
940933
sx={{ marginTop: 2 }}
941934
>
942935
{STEPS.map((label, index) => {
943-
const labelProps: {
944-
optional?: React.ReactNode;
945-
error?: boolean;
946-
} = {};
936+
const labelProps: { optional?: React.ReactNode; error?: boolean } =
937+
{};
947938

948939
if (isStepFailed(index)) {
949940
labelProps.optional = (
@@ -1002,11 +993,7 @@ function CatalogueItemsDialog(props: CatalogueItemsDialogProps) {
1002993
)}
1003994
</DialogActions>
1004995
<Box
1005-
sx={{
1006-
width: '100%',
1007-
justifyContent: 'center',
1008-
alignItems: 'center',
1009-
}}
996+
sx={{ width: '100%', justifyContent: 'center', alignItems: 'center' }}
1010997
>
1011998
{errorsPropertiesStep.root?.formError && (
1012999
<FormHelperText sx={{ marginBottom: 2, textAlign: 'center' }} error>

src/common/editFileDialog.component.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ import {
2727
} from '../api/api.types';
2828
import { FileSchemaPatch } from '../form.schemas';
2929
import handleIMS_APIError from '../handleIMS_APIError';
30-
import { getNameAndExtension } from '../utils';
30+
import {
31+
createFormControlWithRootErrorClearing,
32+
getNameAndExtension,
33+
} from '../utils';
3134

35+
const formControl =
36+
createFormControlWithRootErrorClearing<ObjectFilePatchBase>();
3237
export interface BaseFileDialogProps {
3338
open: boolean;
3439
onClose: () => void;
@@ -75,11 +80,11 @@ const EditFileDialog = (props: FileDialogProps) => {
7580
handleSubmit,
7681
register,
7782
formState: { errors },
78-
watch,
7983
setError,
8084
clearErrors,
8185
reset,
8286
} = useForm<ObjectFilePatchBase>({
87+
formControl,
8388
resolver: zodResolver(FileSchemaPatch),
8489
defaultValues: initialFile,
8590
});
@@ -89,14 +94,6 @@ const EditFileDialog = (props: FileDialogProps) => {
8994
reset(initialFile);
9095
}, [initialFile, reset]);
9196

92-
// Clears form errors when a value has been changed
93-
React.useEffect(() => {
94-
if (errors.root?.formError) {
95-
const subscription = watch(() => clearErrors('root.formError'));
96-
return () => subscription.unsubscribe();
97-
}
98-
}, [clearErrors, errors, selectedFile, watch]);
99-
10097
const handleClose = React.useCallback(() => {
10198
reset();
10299
clearErrors();

0 commit comments

Comments
 (0)