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"]] } };