@pagamio/frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
134 lines (133 loc) • 6.61 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { useEffect, useRef, useState } from 'react';
import BaseDrawer from './components/BaseDrawer';
import DrawerContent from './components/DrawerContent';
const FormEngineDrawer = ({ title, cancelButtonText = 'Cancel', submitButtonText = 'Submit', showForm = true, showDrawerButtons = true, isOpen, fields: initialFields, initialValues, children, marginTop = '0px', onClose, onSubmit, onFieldUpdate, onFieldChange, persistenceKey, }) => {
const [fields, setFields] = useState(initialFields);
const initializedRef = useRef(false);
const processingDependencyRef = useRef(false);
const pendingUpdatesRef = useRef(new Map());
// Update fields when initialFields changes while preserving values
useEffect(() => {
setFields((prevFields) => {
const existingFieldsMap = new Map(prevFields.map((field) => [field.name, field]));
return initialFields.map((newField) => {
const existingField = existingFieldsMap.get(newField.name);
if (existingField) {
return {
...existingField,
...newField,
options: existingField.options || newField.options,
label: existingField.label || newField.label,
};
}
return newField;
});
});
}, [initialFields]);
useEffect(() => {
if (isOpen) {
document.body.classList.add('overflow-hidden');
}
else {
document.body.classList.remove('overflow-hidden');
// Reset initialization flag when drawer closes
initializedRef.current = false;
// Clear pending updates to prevent stale state
pendingUpdatesRef.current.clear();
// Reset fields to initial state when drawer closes
setFields(initialFields);
}
return () => {
document.body.classList.remove('overflow-hidden');
};
}, [isOpen, initialFields]);
const setFieldHidden = (fieldName, hidden) => {
setFields((currentFields) => currentFields.map((field) => (field.name === fieldName ? { ...field, isHidden: hidden } : field)));
};
const updateFieldLabel = (fieldName, newLabelName) => {
setFields((currentFields) => currentFields.map((field) => (field.name === fieldName ? { ...field, label: newLabelName } : field)));
};
const updateFieldOptions = (fieldName, newOptions) => {
setFields((currentFields) => currentFields.map((field) => (field.name === fieldName ? { ...field, options: newOptions } : field)));
};
const updateFieldValidation = (fieldName, newValidation) => {
setFields((currentFields) => currentFields.map((field) => field.name === fieldName
? {
...field,
validation: {
...(field.validation ?? {}),
...newValidation,
},
}
: field));
};
const addField = (field) => {
const isFieldAlreadyAdded = fields.some((f) => f.name === field.name);
if (isFieldAlreadyAdded) {
updateFieldLabel(field.name, field.label);
if (field.options) {
updateFieldOptions(field.name, field.options);
}
}
else {
setFields((currentFields) => [...currentFields, field]);
}
};
// Helper function to check if a value is valid for processing
const isValidValue = (value) => {
return value !== undefined && value !== null && value !== '';
};
// Helper function to apply field updates based on the result
const applyFieldUpdate = (result) => {
if (!result)
return;
// Apply field modifications based on result
if (result.hideField !== undefined && setFieldHidden) {
setFieldHidden(result.field, result.hideField);
}
if (result.options !== undefined && updateFieldOptions) {
updateFieldOptions(result.field, result.options);
}
if (result.label !== undefined && updateFieldLabel) {
updateFieldLabel(result.field, result.label);
}
};
// Process a single field's updates
const processFieldUpdate = async (fieldName, updates, value) => {
for (const update of updates) {
try {
const result = await update.action(value, true);
applyFieldUpdate(result);
}
catch (error) {
console.error(`Error processing initial dependency for ${fieldName}:`, error);
}
}
};
// Main function with reduced complexity
const processInitialFieldUpdates = async (getValues) => {
// Early return if conditions aren't met
if (!onFieldUpdate || initializedRef.current || processingDependencyRef.current)
return;
processingDependencyRef.current = true;
try {
const processedFields = new Set();
for (const [fieldName, updates] of Object.entries(onFieldUpdate)) {
if (processedFields.has(fieldName))
continue;
const currentValue = getValues(fieldName);
if (!isValidValue(currentValue))
continue;
await processFieldUpdate(fieldName, updates, currentValue);
processedFields.add(fieldName);
}
initializedRef.current = true;
}
finally {
processingDependencyRef.current = false;
}
};
return (_jsx(BaseDrawer, { title: title, isOpen: isOpen, marginTop: marginTop, onClose: onClose, children: _jsx(DrawerContent, { isOpen: isOpen, fields: fields, onSubmit: onSubmit, handleCloseDrawer: onClose, initialValues: initialValues, showForm: showForm, showDrawerButtons: showDrawerButtons, cancelButtonText: cancelButtonText, submitButtonText: submitButtonText, onFieldUpdate: onFieldUpdate, onFieldChange: onFieldChange, updateFieldOptions: updateFieldOptions, updateFieldLabel: updateFieldLabel, setFieldHidden: setFieldHidden, addField: addField, updateFieldValidation: updateFieldValidation, processInitialFieldUpdates: processInitialFieldUpdates, processingDependencyRef: processingDependencyRef, pendingUpdatesRef: pendingUpdatesRef, persistenceKey: persistenceKey, children: children }, `${persistenceKey}-${isOpen ? 'open' : 'closed'}`) }));
};
export default FormEngineDrawer;