IO-3310 Shop Info Data Preservation

Correction to preserve hidden data

Signed-off-by: Allan Carr <allan@imexsystems.ca>
This commit is contained in:
Allan Carr
2025-09-01 20:29:39 -07:00
parent f817902d5c
commit eb18130e51
2 changed files with 57 additions and 59 deletions

View File

@@ -23,13 +23,24 @@ export default function ShopInfoContainer() {
}); });
const notification = useNotification(); const notification = useNotification();
const combinedFeatureConfig = { const combineFeatureConfigs = (...configs) =>
...FEATURE_CONFIGS.general, (configs || [])
...FEATURE_CONFIGS.responsibilitycenters .filter(Boolean)
}; .flatMap((cfg) => Object.entries(cfg))
.reduce((acc, [featureName, fieldPaths]) => {
if (!Array.isArray(fieldPaths)) return acc;
acc[featureName] = [...(acc[featureName] ?? []), ...fieldPaths];
return acc;
}, {});
const combinedFeatureConfig = combineFeatureConfigs(FEATURE_CONFIGS.general, FEATURE_CONFIGS.responsibilitycenters);
// Use form data preservation for all shop-info features // Use form data preservation for all shop-info features
const { createSubmissionHandler } = useFormDataPreservation(form, data?.bodyshops[0], combinedFeatureConfig); const { createSubmissionHandler, preserveHiddenFormData } = useFormDataPreservation(
form,
data?.bodyshops[0],
combinedFeatureConfig
);
const handleFinish = createSubmissionHandler((values) => { const handleFinish = createSubmissionHandler((values) => {
setSaveLoading(true); setSaveLoading(true);
@@ -51,8 +62,11 @@ export default function ShopInfoContainer() {
}); });
useEffect(() => { useEffect(() => {
if (data) form.resetFields(); if (!data) return;
}, [form, data]); form.resetFields();
// After reset, re-apply hidden field preservation so values aren't wiped
preserveHiddenFormData();
}, [data, form, preserveHiddenFormData]);
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
if (loading) return <LoadingSpinner />; if (loading) return <LoadingSpinner />;

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect } from "react"; import { useCallback, useEffect, useMemo } from "react";
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component"; import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
/** /**
@@ -8,73 +8,57 @@ import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component
* @param {Object} featureConfig - Configuration object defining which features and their associated fields to preserve * @param {Object} featureConfig - Configuration object defining which features and their associated fields to preserve
*/ */
export const useFormDataPreservation = (form, bodyshop, featureConfig) => { export const useFormDataPreservation = (form, bodyshop, featureConfig) => {
const getNestedValue = (obj, path) => { // Safe nested getters/setters using path arrays
return path.reduce((current, key) => current?.[key], obj); const getNestedValue = (obj, path) => path?.reduce((acc, key) => acc?.[key], obj);
};
const setNestedValue = (obj, path, value) => { const setNestedValue = (obj, path, value) => {
const lastKey = path[path.length - 1]; const lastKey = path[path.length - 1];
const parentPath = path.slice(0, -1); const parent = path.slice(0, -1).reduce((curr, key) => {
if (!curr[key] || typeof curr[key] !== "object") curr[key] = {};
const parent = parentPath.reduce((current, key) => { return curr[key];
if (!current[key]) current[key] = {};
return current[key];
}, obj); }, obj);
parent[lastKey] = value; parent[lastKey] = value;
}; };
const preserveHiddenFormData = useCallback(() => { // Paths for features that are NOT accessible
const preservationData = {}; const disabledPaths = useMemo(() => {
let hasDataToPreserve = false; const result = [];
if (!featureConfig) return result;
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => { Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
const hasAccess = HasFeatureAccess({ featureName, bodyshop }); const hasAccess = HasFeatureAccess({ featureName, bodyshop });
if (hasAccess || !Array.isArray(fieldPaths)) return;
fieldPaths.forEach((p) => Array.isArray(p) && p.length && result.push(p));
});
return result;
}, [featureConfig, bodyshop]);
if (!hasAccess) { const preserveHiddenFormData = useCallback(() => {
fieldPaths.forEach((fieldPath) => { const currentValues = form.getFieldsValue();
const currentValues = form.getFieldsValue(); const preservationData = {};
let value = getNestedValue(currentValues, fieldPath); let hasAny = false;
if (value === undefined || value === null) { disabledPaths.forEach((path) => {
value = getNestedValue(bodyshop, fieldPath); let value = getNestedValue(currentValues, path);
} if (value == null) value = getNestedValue(bodyshop, path);
if (value != null) {
if (value !== undefined && value !== null) { setNestedValue(preservationData, path, value);
setNestedValue(preservationData, fieldPath, value); hasAny = true;
hasDataToPreserve = true;
}
});
} }
}); });
if (hasDataToPreserve) { if (hasAny) form.setFieldsValue(preservationData);
form.setFieldsValue(preservationData); }, [form, bodyshop, disabledPaths]);
}
}, [form, featureConfig, bodyshop]);
const getCompleteFormValues = () => { const getCompleteFormValues = () => {
const currentFormValues = form.getFieldsValue(); const currentValues = form.getFieldsValue();
const completeValues = { ...currentFormValues }; const complete = { ...currentValues };
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => { disabledPaths.forEach((path) => {
const hasAccess = HasFeatureAccess({ featureName, bodyshop }); let value = getNestedValue(currentValues, path);
if (value == null) value = getNestedValue(bodyshop, path);
if (!hasAccess) { if (value != null) setNestedValue(complete, path, value);
fieldPaths.forEach((fieldPath) => {
let value = getNestedValue(currentFormValues, fieldPath);
if (value === undefined || value === null) {
value = getNestedValue(bodyshop, fieldPath);
}
if (value !== undefined && value !== null) {
setNestedValue(completeValues, fieldPath, value);
}
});
}
}); });
return completeValues; return complete;
}; };
const createSubmissionHandler = (originalHandler) => { const createSubmissionHandler = (originalHandler) => {
@@ -103,8 +87,8 @@ export const FEATURE_CONFIGS = {
["md_responsibility_centers", "profits"], ["md_responsibility_centers", "profits"],
["md_responsibility_centers", "defaults"], ["md_responsibility_centers", "defaults"],
["md_responsibility_centers", "dms_defaults"], ["md_responsibility_centers", "dms_defaults"],
["md_responsibility_centers", "taxes", "itemexemptcode"], ["md_responsibility_centers", "taxes"],
["md_responsibility_centers", "taxes", "invoiceexemptcode"], ["md_responsibility_centers", "cieca_pfl"],
["md_responsibility_centers", "ar"], ["md_responsibility_centers", "ar"],
["md_responsibility_centers", "refund"], ["md_responsibility_centers", "refund"],
["md_responsibility_centers", "sales_tax_codes"], ["md_responsibility_centers", "sales_tax_codes"],