feature/IO-3499-React-19: Bug Fixes / Checkpoint
This commit is contained in:
@@ -59,8 +59,8 @@ export function ContractCreatePageContainer({ bodyshop, setBreadcrumbs, setSelec
|
||||
if (!result.errors) {
|
||||
//Update the courtesy car to have the damage.
|
||||
logImEXEvent("courtesy_car_contract_created", {});
|
||||
notification["success"]({
|
||||
message: t("contracts.successes.saved")
|
||||
notification.success({
|
||||
title: t("contracts.successes.saved")
|
||||
});
|
||||
|
||||
//Intake the job if required
|
||||
@@ -76,8 +76,8 @@ export function ContractCreatePageContainer({ bodyshop, setBreadcrumbs, setSelec
|
||||
}
|
||||
});
|
||||
if (result2.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.saving", {
|
||||
notification.error({
|
||||
title: t("jobs.errors.saving", {
|
||||
error: JSON.stringify(!result2.errors)
|
||||
})
|
||||
});
|
||||
@@ -89,15 +89,15 @@ export function ContractCreatePageContainer({ bodyshop, setBreadcrumbs, setSelec
|
||||
form.resetFields();
|
||||
history(`/manage/courtesycars/contracts/${result.data.insert_cccontracts.returning[0].id}`);
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
notification.error({
|
||||
title: t("contracts.errors.saving", {
|
||||
error: JSON.stringify(!result.errors)
|
||||
})
|
||||
});
|
||||
}
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.selectjobandcar")
|
||||
notification.error({
|
||||
title: t("contracts.errors.selectjobandcar")
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
|
||||
@@ -86,14 +86,14 @@ export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, set
|
||||
variables: { cccontract: { ...values }, contractId: contractId }
|
||||
});
|
||||
if (result.errors) {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
notification.error({
|
||||
title: t("contracts.errors.saving", {
|
||||
message: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
return;
|
||||
}
|
||||
notification["success"]({ message: t("contracts.successes.saved") });
|
||||
notification.success({ title: t("contracts.successes.saved") });
|
||||
if (refetch) await refetch();
|
||||
setsaveLoading(false);
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ export function CourtesyCarCreateContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
});
|
||||
|
||||
if (result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", {
|
||||
notification.error({
|
||||
title: t("courtesycars.errors.saving", {
|
||||
message: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
@@ -48,7 +48,7 @@ export function CourtesyCarCreateContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
setLoading(false);
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
notification["success"]({ message: t("courtesycars.successes.saved") });
|
||||
notification.success({ title: t("courtesycars.successes.saved") });
|
||||
history(`/manage/courtesycars/${result.data.insert_courtesycars.returning[0].id}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,13 +104,13 @@ export function CourtesyCarDetailPageContainer({ setBreadcrumbs, addRecentItem,
|
||||
});
|
||||
|
||||
if (result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", { error: error })
|
||||
notification.error({
|
||||
title: t("courtesycars.errors.saving", { error: error })
|
||||
});
|
||||
}
|
||||
|
||||
notification["success"]({
|
||||
message: t("courtesycars.successes.saved")
|
||||
notification.success({
|
||||
title: t("courtesycars.successes.saved")
|
||||
});
|
||||
|
||||
setSaveLoading(false);
|
||||
|
||||
@@ -83,9 +83,8 @@ export function DmsContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
});
|
||||
|
||||
socket.on("ap-export-complete", () => {
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: t("jobs.labels.dms.apexported")
|
||||
notification.success({
|
||||
title: t("jobs.labels.dms.apexported")
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -235,8 +235,8 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
const sev = severity || (isRrOpenRoLimit ? "warning" : "error");
|
||||
|
||||
if (!isRrOpenRoLimit) {
|
||||
const notifyKind = sev === "warning" && typeof notification.warning === "function" ? "warning" : "error";
|
||||
notification[notifyKind]({ message: vendorTitle, description: msg, duration: 10 });
|
||||
const type = sev === "warning" && typeof notification.warning === "function" ? "warning" : "error";
|
||||
notification.open({ type, tile: vendorTitle, description: msg, duration: 10 });
|
||||
} else {
|
||||
setRrOpenRoLimit(true);
|
||||
}
|
||||
@@ -307,7 +307,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
const onConnectError = (err) => {
|
||||
// Legacy and WSS both emit this
|
||||
console.log(`connect_error due to ${err}`, err);
|
||||
notification.error({ message: err.message });
|
||||
notification.error({ title: err.message });
|
||||
};
|
||||
|
||||
activeSocket.on("disconnect", onDisconnect);
|
||||
@@ -333,7 +333,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
// Success / Failed
|
||||
const onExportSuccess = (payload) => {
|
||||
const jobIdResolved = payload?.jobId ?? payload;
|
||||
notification.success({ message: t("jobs.successes.exported") });
|
||||
notification.success({ title: t("jobs.successes.exported") });
|
||||
|
||||
// Clear RR Validation flag if any
|
||||
setrrValidationPending(false);
|
||||
@@ -414,7 +414,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
if (!isWssMode(mode)) return; // RR is WSS-only
|
||||
activeSocket.emit("rr-finalize-repair-order", { jobId }, (ack) => {
|
||||
if (ack?.ok) return;
|
||||
if (ack?.error) notification.error({ message: ack.error });
|
||||
if (ack?.error) notification.error({ title: ack.error });
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -114,8 +114,8 @@ export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, set
|
||||
// notification["success"]({ message: t("jobs.successes.save") });
|
||||
// form.resetFields();
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("job.errors.saving", {
|
||||
notification.error({
|
||||
title: t("job.errors.saving", {
|
||||
error: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
@@ -125,8 +125,8 @@ export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, set
|
||||
if (!closeResult.errors) {
|
||||
setLoading(false);
|
||||
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.closed")
|
||||
notification.success({
|
||||
title: t("jobs.successes.closed")
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
@@ -143,8 +143,8 @@ export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, set
|
||||
// history(`/manage/jobs/${job.id}`);
|
||||
} else {
|
||||
setLoading(false);
|
||||
notification["error"]({
|
||||
message: t("job.errors.closing", {
|
||||
notification.error({
|
||||
title: t("job.errors.closing", {
|
||||
error: JSON.stringify(closeResult.errors)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -85,8 +85,8 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, curr
|
||||
logImEXEvent("manual_job_create_completed", {});
|
||||
})
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.creating", { error: error })
|
||||
notification.error({
|
||||
title: t("jobs.errors.creating", { error: error })
|
||||
});
|
||||
setState({ ...state, error: error });
|
||||
});
|
||||
|
||||
@@ -192,12 +192,12 @@ export function JobsDetailPage({
|
||||
});
|
||||
|
||||
if (newTotals.status !== 200 || result.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc")
|
||||
notification.error({
|
||||
title: t("jobs.errors.totalscalc")
|
||||
});
|
||||
} else {
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.savetitle")
|
||||
notification.success({
|
||||
title: t("jobs.successes.savetitle")
|
||||
});
|
||||
const changedAuditFields = form.getFieldsValue(
|
||||
[
|
||||
@@ -261,8 +261,8 @@ export function JobsDetailPage({
|
||||
form.resetFields();
|
||||
}
|
||||
} catch {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc")
|
||||
notification.error({
|
||||
title: t("jobs.errors.totalscalc")
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
||||
@@ -145,10 +145,16 @@ export function Manage({ conflict, bodyshop, partsManagementOnly, isDarkMode, cu
|
||||
}, [t]);
|
||||
|
||||
// This is a required safety check to prevent parts management only users from accessing /manage based routes
|
||||
useEffect(() => {
|
||||
if (partsManagementOnly && !import.meta.env.DEV) {
|
||||
// This NEEDS to be done this way, DO NOT use the react router, it will cause a ton of side effects
|
||||
window.location = "/parts";
|
||||
}
|
||||
}, [partsManagementOnly]);
|
||||
|
||||
// Prevent rendering if redirecting
|
||||
if (partsManagementOnly && !import.meta.env.DEV) {
|
||||
// This NEEDS to be done this way, DO NOT use the react router, it will cause a ton of side effects
|
||||
window.location = "/parts";
|
||||
return null; // Prevent further rendering
|
||||
return null;
|
||||
}
|
||||
|
||||
const AppRouteTable = (
|
||||
|
||||
@@ -23,6 +23,7 @@ const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
isPartsEntry: selectIsPartsEntry
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPrintCenterContext: (context) =>
|
||||
dispatch(
|
||||
@@ -36,9 +37,13 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO, job, refetch, isPartsEntry }) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const history = useNavigate();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const [loading] = useState(false);
|
||||
const search = queryString.parse(useLocation().search);
|
||||
|
||||
// Parse once per render; do not mutate this object.
|
||||
const search = queryString.parse(location.search);
|
||||
|
||||
const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, {
|
||||
variables: { jobid: job.id },
|
||||
@@ -47,44 +52,43 @@ export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
//form.setFieldsValue(transormJobToForm(job));
|
||||
form.resetFields();
|
||||
}, [form, job]);
|
||||
|
||||
const navigateWithSearch = (nextSearchObj) => {
|
||||
navigate({ search: queryString.stringify(nextSearchObj) });
|
||||
};
|
||||
|
||||
const omitKey = (obj, key) => {
|
||||
if (!obj) return {};
|
||||
// immutable omit
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { [key]: _omit, ...rest } = obj;
|
||||
return rest;
|
||||
};
|
||||
|
||||
const handleBillOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.billid = record.id;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.billid;
|
||||
history({ search: queryString.stringify(search) });
|
||||
if (record?.id) {
|
||||
navigateWithSearch({ ...search, billid: record.id });
|
||||
return;
|
||||
}
|
||||
navigateWithSearch(omitKey(search, "billid"));
|
||||
};
|
||||
|
||||
const handlePartsOrderOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.partsorderid = record.id;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.partsorderid;
|
||||
history({ search: queryString.stringify(search) });
|
||||
if (record?.id) {
|
||||
navigateWithSearch({ ...search, partsorderid: record.id });
|
||||
return;
|
||||
}
|
||||
navigateWithSearch(omitKey(search, "partsorderid"));
|
||||
};
|
||||
|
||||
const handlePartsDispatchOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.partsdispatchid = record.id;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.partsdispatchid;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
if (record?.id) {
|
||||
navigateWithSearch({ ...search, partsdispatchid: record.id });
|
||||
return;
|
||||
}
|
||||
navigateWithSearch(omitKey(search, "partsdispatchid"));
|
||||
};
|
||||
|
||||
const menuExtra = (
|
||||
@@ -98,7 +102,9 @@ export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO
|
||||
<SyncOutlined />
|
||||
{t("general.labels.refresh")}
|
||||
</Button>
|
||||
|
||||
<JobsChangeStatus job={job} />
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setPrintCenterContext({
|
||||
@@ -127,6 +133,8 @@ export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO
|
||||
</Space>
|
||||
);
|
||||
|
||||
const activeTabKey = (search?.tab && String(search.tab)) || "repairdata";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<JobLineUpsertModalContainer />
|
||||
@@ -135,9 +143,10 @@ export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO
|
||||
<JobsDetailHeader job={job} />
|
||||
<Divider orientation="horizontal" />
|
||||
<FormFieldsChanged form={form} />
|
||||
|
||||
<Tabs
|
||||
defaultActiveKey={search.tab}
|
||||
onChange={(key) => history({ search: `?tab=${key}` })}
|
||||
defaultActiveKey={activeTabKey}
|
||||
onChange={(key) => navigateWithSearch({ ...search, tab: key })}
|
||||
tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }}
|
||||
items={[
|
||||
{
|
||||
@@ -159,7 +168,6 @@ export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
||||
{
|
||||
key: "partssublet",
|
||||
id: "job-details-partssublet",
|
||||
|
||||
@@ -31,6 +31,14 @@ const VehiclesContainer = lazy(() => import("../vehicles/vehicles.page.container
|
||||
const VehiclesDetailContainer = lazy(() => import("../vehicles-detail/vehicles-detail.page.container.jsx"));
|
||||
const { Content } = Layout;
|
||||
|
||||
// Redirector to strip '/parts/jobs' from path for non-detail routes
|
||||
function JobsStripRedirect() {
|
||||
const location = useLocation();
|
||||
const { pathname, search, hash } = location;
|
||||
const target = pathname.replace("/parts/jobs", "/parts") + (search || "") + (hash || "");
|
||||
return <Navigate to={target} replace />;
|
||||
}
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
conflict: selectInstanceConflict,
|
||||
bodyshop: selectBodyshop
|
||||
@@ -39,15 +47,6 @@ const mapStateToProps = createStructuredSelector({
|
||||
export function SimplifiedPartsPage({ conflict, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Redirector to strip '/parts/jobs' from path for non-detail routes
|
||||
function JobsStripRedirect() {
|
||||
// lazy import to avoid top-level import churn
|
||||
const location = useLocation();
|
||||
const { pathname, search, hash } = location;
|
||||
const target = pathname.replace("/parts/jobs", "/parts") + (search || "") + (hash || "");
|
||||
return <Navigate to={target} replace />;
|
||||
}
|
||||
|
||||
// Centralized alerts handling (fetch + dedupe + notifications)
|
||||
useAlertsNotifications();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user