Compare commits
4 Commits
release/20
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15ea4e6afa | ||
|
|
953e70efef | ||
|
|
17285fc029 | ||
|
|
401e3cff73 |
@@ -1,45 +0,0 @@
|
||||
#Elastic Beanstalk Nginx Configuration File
|
||||
|
||||
user nginx;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
worker_processes auto;
|
||||
worker_rlimit_nofile 200000;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
}
|
||||
|
||||
http {
|
||||
server_tokens off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
include conf.d/*.conf;
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default "upgrade";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
client_max_body_size 50M;
|
||||
client_body_buffer_size 5M;
|
||||
client_header_timeout 60;
|
||||
client_body_timeout 60;
|
||||
keepalive_timeout 60;
|
||||
gzip off;
|
||||
gzip_comp_level 4;
|
||||
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml>
|
||||
|
||||
# Include the Elastic Beanstalk generated locations
|
||||
include conf.d/elasticbeanstalk/*.conf;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import { Form } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../graphql/bodyshop.queries";
|
||||
import dayjs from "../../utils/day";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import FormsFieldChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import ShopInfoComponent from "./shop-info.component";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { FEATURE_CONFIGS, useFormDataPreservation } from "./useFormDataPreservation";
|
||||
|
||||
export default function ShopInfoContainer() {
|
||||
const [form] = Form.useForm();
|
||||
@@ -22,16 +23,24 @@ export default function ShopInfoContainer() {
|
||||
});
|
||||
const notification = useNotification();
|
||||
|
||||
const handleFinish = (values) => {
|
||||
const combinedFeatureConfig = {
|
||||
...FEATURE_CONFIGS.general,
|
||||
...FEATURE_CONFIGS.responsibilitycenters
|
||||
};
|
||||
|
||||
// Use form data preservation for all shop-info features
|
||||
const { createSubmissionHandler } = useFormDataPreservation(form, data?.bodyshops[0], combinedFeatureConfig);
|
||||
|
||||
const handleFinish = createSubmissionHandler((values) => {
|
||||
setSaveLoading(true);
|
||||
logImEXEvent("shop_update");
|
||||
|
||||
updateBodyshop({
|
||||
variables: { id: data.bodyshops[0].id, shop: values }
|
||||
})
|
||||
.then((r) => {
|
||||
.then(() => {
|
||||
notification["success"]({ message: t("bodyshop.successes.save") });
|
||||
refetch().then((_) => form.resetFields());
|
||||
refetch().then(() => form.resetFields());
|
||||
})
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
@@ -39,7 +48,7 @@ export default function ShopInfoContainer() {
|
||||
});
|
||||
});
|
||||
setSaveLoading(false);
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data) form.resetFields();
|
||||
|
||||
140
client/src/components/shop-info/useFormDataPreservation.js
Normal file
140
client/src/components/shop-info/useFormDataPreservation.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import { useEffect } 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) => {
|
||||
const getNestedValue = (obj, path) => {
|
||||
return path.reduce((current, key) => current?.[key], obj);
|
||||
};
|
||||
|
||||
const setNestedValue = (obj, path, value) => {
|
||||
const lastKey = path[path.length - 1];
|
||||
const parentPath = path.slice(0, -1);
|
||||
|
||||
const parent = parentPath.reduce((current, key) => {
|
||||
if (!current[key]) current[key] = {};
|
||||
return current[key];
|
||||
}, obj);
|
||||
|
||||
parent[lastKey] = value;
|
||||
};
|
||||
|
||||
const preserveHiddenFormData = () => {
|
||||
const preservationData = {};
|
||||
let hasDataToPreserve = false;
|
||||
|
||||
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
|
||||
const hasAccess = HasFeatureAccess({ featureName, bodyshop });
|
||||
|
||||
if (!hasAccess) {
|
||||
fieldPaths.forEach((fieldPath) => {
|
||||
const currentValues = form.getFieldsValue();
|
||||
let value = getNestedValue(currentValues, fieldPath);
|
||||
|
||||
if (value === undefined || value === null) {
|
||||
value = getNestedValue(bodyshop, fieldPath);
|
||||
}
|
||||
|
||||
if (value !== undefined && value !== null) {
|
||||
setNestedValue(preservationData, fieldPath, value);
|
||||
hasDataToPreserve = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (hasDataToPreserve) {
|
||||
form.setFieldsValue(preservationData);
|
||||
}
|
||||
};
|
||||
|
||||
const getCompleteFormValues = () => {
|
||||
const currentFormValues = form.getFieldsValue();
|
||||
const completeValues = { ...currentFormValues };
|
||||
|
||||
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
|
||||
const hasAccess = HasFeatureAccess({ featureName, bodyshop });
|
||||
|
||||
if (!hasAccess) {
|
||||
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;
|
||||
};
|
||||
|
||||
const createSubmissionHandler = (originalHandler) => {
|
||||
return () => {
|
||||
const completeValues = getCompleteFormValues();
|
||||
|
||||
// Call the original handler with complete values including hidden data
|
||||
return originalHandler(completeValues);
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
preserveHiddenFormData();
|
||||
}, [bodyshop]);
|
||||
|
||||
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", "itemexemptcode"],
|
||||
["md_responsibility_centers", "taxes", "invoiceexemptcode"],
|
||||
["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"]]
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user