Files
bodyshop/client/src/components/shop-info/useFormDataPreservation.js
Allan Carr eb18130e51 IO-3310 Shop Info Data Preservation
Correction to preserve hidden data

Signed-off-by: Allan Carr <allan@imexsystems.ca>
2025-09-01 20:29:39 -07:00

125 lines
4.4 KiB
JavaScript

import { useCallback, useEffect, useMemo } from "react";
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
/**
* Custom hook to preserve form data for conditionally hidden fields based on feature access
* @param {Object} form - Ant Design form instance
* @param {Object} bodyshop - Bodyshop data for feature access checks (also contains existing database values)
* @param {Object} featureConfig - Configuration object defining which features and their associated fields to preserve
*/
export const useFormDataPreservation = (form, bodyshop, featureConfig) => {
// Safe nested getters/setters using path arrays
const getNestedValue = (obj, path) => path?.reduce((acc, key) => acc?.[key], obj);
const setNestedValue = (obj, path, value) => {
const lastKey = path[path.length - 1];
const parent = path.slice(0, -1).reduce((curr, key) => {
if (!curr[key] || typeof curr[key] !== "object") curr[key] = {};
return curr[key];
}, obj);
parent[lastKey] = value;
};
// Paths for features that are NOT accessible
const disabledPaths = useMemo(() => {
const result = [];
if (!featureConfig) return result;
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
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]);
const preserveHiddenFormData = useCallback(() => {
const currentValues = form.getFieldsValue();
const preservationData = {};
let hasAny = false;
disabledPaths.forEach((path) => {
let value = getNestedValue(currentValues, path);
if (value == null) value = getNestedValue(bodyshop, path);
if (value != null) {
setNestedValue(preservationData, path, value);
hasAny = true;
}
});
if (hasAny) form.setFieldsValue(preservationData);
}, [form, bodyshop, disabledPaths]);
const getCompleteFormValues = () => {
const currentValues = form.getFieldsValue();
const complete = { ...currentValues };
disabledPaths.forEach((path) => {
let value = getNestedValue(currentValues, path);
if (value == null) value = getNestedValue(bodyshop, path);
if (value != null) setNestedValue(complete, path, value);
});
return complete;
};
const createSubmissionHandler = (originalHandler) => {
return () => {
const completeValues = getCompleteFormValues();
// Call the original handler with complete values including hidden data
return originalHandler(completeValues);
};
};
useEffect(() => {
preserveHiddenFormData();
}, [bodyshop, preserveHiddenFormData]);
return { preserveHiddenFormData, getCompleteFormValues, createSubmissionHandler };
};
/**
* Predefined feature configurations for common shop-info components
*/
export const FEATURE_CONFIGS = {
responsibilitycenters: {
export: [
["md_responsibility_centers", "costs"],
["md_responsibility_centers", "profits"],
["md_responsibility_centers", "defaults"],
["md_responsibility_centers", "dms_defaults"],
["md_responsibility_centers", "taxes"],
["md_responsibility_centers", "cieca_pfl"],
["md_responsibility_centers", "ar"],
["md_responsibility_centers", "refund"],
["md_responsibility_centers", "sales_tax_codes"],
["md_responsibility_centers", "ttl_adjustment"],
["md_responsibility_centers", "ttl_tax_adjustment"]
]
},
general: {
export: [
["accountingconfig", "qbo"],
["accountingconfig", "qbo_usa"],
["accountingconfig", "qbo_departmentid"],
["accountingconfig", "tiers"],
["accountingconfig", "twotierpref"],
["accountingconfig", "printlater"],
["accountingconfig", "emaillater"],
["accountingconfig", "ReceivableCustomField1"],
["accountingconfig", "ReceivableCustomField2"],
["accountingconfig", "ReceivableCustomField3"],
["md_classes"],
["enforce_class"],
["accountingconfig", "ClosingPeriod"],
["accountingconfig", "companyCode"],
["accountingconfig", "batchID"]
],
bills: [
["bill_tax_rates", "federal_tax_rate"],
["bill_tax_rates", "state_tax_rate"],
["bill_tax_rates", "local_tax_rate"]
],
timetickets: [["tt_allow_post_to_invoiced"], ["tt_enforce_hours_for_tech_console"], ["bill_allow_post_to_closed"]]
}
};