Compare commits

...

28 Commits

Author SHA1 Message Date
Dave
ad520ab23e feature/IO-3548-Bill-Modal-TabOrder 2026-02-03 15:42:10 -05:00
Patrick Fic
db1b701a96 Merged in hotfix/2026-02-02 (pull request #2951)
Hotfix/2026 02 02

Approved-by: Dave Richer
2026-02-02 22:49:14 +00:00
Dave
2746421c09 hotfix/2026-02-02 - 2026-02-02 17:48:03 -05:00
Dave
5217120994 hotfix/2026-02-02 - Parts order manual discounting box 2026-02-02 17:39:47 -05:00
Dave
77f72a2a12 Merge branch 'hotfix/2026-02-02' of bitbucket.org:snaptsoft/bodyshop into hotfix/2026-02-02 2026-02-02 17:11:06 -05:00
Dave
a84ad4ee32 hotfix/2026-02-02 - remove check on missing line ids 2026-02-02 17:10:56 -05:00
Dave Richer
2cacd75822 Merged in bugfix/IO-3533 (pull request #2948)
bugfix/IO-3533 - Fix
2026-02-02 22:05:56 +00:00
Dave
217a0b84ac bugfix/IO-3533 - Fix 2026-02-02 17:04:06 -05:00
Dave Richer
f53ed8c427 Merged in feature/IO-3532-parts-queue-ui-adjustments (pull request #2944)
feature/IO-3532-parts-queue-ui-adjustments

Approved-by: Patrick Fic
2026-02-02 21:51:31 +00:00
Dave Richer
f8b7588a04 Merged in feature/IO-3542-fix-searches (pull request #2945)
feature/IO-3542-fix-searches

Approved-by: Patrick Fic
2026-02-02 21:46:24 +00:00
Patrick Fic
ee3cb4456d Merged in feature/IO-3531-apollo-rerender (pull request #2946)
IO-3531 remove loading on parts order page.
2026-02-02 21:45:59 +00:00
Patrick Fic
ae05692c46 IO-3531 remove loading on parts order page. 2026-02-02 13:45:25 -08:00
Dave
e01a2af5a4 feature/IO-3542-fix-searches 2026-02-02 16:44:49 -05:00
Patrick Fic
b9f398cf2d Merged in feature/IO-3532-parts-queue-ui-adjustments (pull request #2943)
IO-3532 resolve tooltip on owner name.
2026-02-02 20:57:05 +00:00
Patrick Fic
1e44d4fe42 Merged in feature/IO-3539-print-center-popovers (pull request #2941)
IO-3539 resolve print center popoves.
2026-02-02 20:38:49 +00:00
Patrick Fic
0f42875d1b IO-3539 resolve print center popoves. 2026-02-02 12:38:29 -08:00
Patrick Fic
a0f1299006 Merged in feature/IO-3538-receivec-cm-on-parts-order (pull request #2940)
IO-3538 Resolve missing id on receive return.
2026-02-02 20:23:20 +00:00
Patrick Fic
87d8a5d746 IO-3538 Resolve missing id on receive return. 2026-02-02 12:22:58 -08:00
Patrick Fic
268851902a Merged in feature/IO-3535-fed-tax-toggle-bill-posting (pull request #2935)
IO-3535 Resolve federal tax default off on received parts order.
2026-02-02 20:07:26 +00:00
Dave Richer
68bb7d2529 Merged in bugfix/IO-3533 (pull request #2937)
bugfix/IO-3533 - Disable on blurr and on focus handlers in bill entry modal

Approved-by: Patrick Fic
2026-02-02 20:06:13 +00:00
Patrick Fic
d50db12330 Merged in feature/IO-3534-bill-discrep-coloring (pull request #2936)
IO-3534 Adjust value prop to content for antd prop change to fix color display.
2026-02-02 20:05:54 +00:00
Patrick Fic
1438986c18 Merged in feature/IO-3532-parts-queue-ui-adjustments (pull request #2938)
IO-3532 Resolve parts queue pages.
2026-02-02 20:05:15 +00:00
Patrick Fic
c047699fbb Merged in feature/IO-3531-apollo-rerender (pull request #2939)
IO-3531 Change global apollo config setting to prevent rerenders.
2026-02-02 20:03:29 +00:00
Patrick Fic
e5b7fcb919 IO-3531 Change global apollo config setting to prevent rerenders. 2026-02-02 12:02:11 -08:00
Dave
55023ceaca feature/IO-3534-bill-discrep-coloring: Remove unused console.log 2026-02-02 12:47:04 -05:00
Dave
45e143578c bugfix/IO-3533 - Disable on blurr and on focus handlers in bill entry modal 2026-02-02 12:34:54 -05:00
Patrick Fic
28a41f7637 IO-3534 Adjust value prop to content for antd prop change to fix color display. 2026-02-02 09:33:37 -08:00
Patrick Fic
2a2edeadb9 IO-3535 Resolve federal tax default off on received parts order. 2026-02-02 09:25:58 -08:00
23 changed files with 192 additions and 140 deletions

View File

@@ -52,6 +52,9 @@ export default function BillCmdReturnsTableComponent({ form, returnLoading, retu
{fields.map((field, index) => (
<tr key={field.key}>
<td>
<Form.Item hidden key={`${index}id`} name={[field.name, "id"]}>
<ReadOnlyFormItemComponent />
</Form.Item>
<Form.Item
// label={t("joblines.fields.line_desc")}
key={`${index}line_desc`}

View File

@@ -373,9 +373,11 @@ export function BillFormComponent({
"local_tax_rate"
]);
let totals;
if (!!values.total && !!values.billlines && values.billlines.length > 0)
if (!!values.total && !!values.billlines && values.billlines.length > 0) {
totals = CalculateBillTotal(values);
if (totals)
}
if (totals) {
return (
// TODO: Align is not correct
// eslint-disable-next-line react/no-unknown-property
@@ -414,7 +416,7 @@ export function BillFormComponent({
<Statistic
title={t("bills.labels.discrepancy")}
styles={{
value: {
content: {
color: totals.discrepancy.getAmount() === 0 ? "green" : "red"
}
}}
@@ -427,6 +429,7 @@ export function BillFormComponent({
) : null}
</div>
);
}
return null;
}}
</Form.Item>

View File

@@ -1,6 +1,7 @@
import { DeleteFilled, DollarCircleFilled } from "@ant-design/icons";
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
import { Button, Checkbox, Form, Input, InputNumber, Select, Space, Switch, Table, Tooltip } from "antd";
import { useRef } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -32,6 +33,7 @@ export function BillEnterModalLinesComponent({
}) {
const { t } = useTranslation();
const { setFieldsValue, getFieldsValue, getFieldValue } = form;
const firstFieldRefs = useRef({});
const CONTROL_HEIGHT = 32;
@@ -90,6 +92,7 @@ export function BillEnterModalLinesComponent({
});
};
// Only fill actual_cost when the user forward-tabs out of Retail (actual_price)
const autofillActualCost = (index) => {
Promise.resolve().then(() => {
const retailRaw = form.getFieldValue(["billlines", index, "actual_price"]);
@@ -154,6 +157,9 @@ export function BillEnterModalLinesComponent({
),
formInput: (record, index) => (
<BillLineSearchSelect
ref={(el) => {
firstFieldRefs.current[index] = el;
}}
disabled={disabled}
options={lineData}
style={{
@@ -164,10 +170,9 @@ export function BillEnterModalLinesComponent({
}}
allowRemoved={form.getFieldValue("is_credit_memo") || false}
onSelect={(value, opt) => {
const d = normalizeDiscount(discount);
const retail = Number(opt.cost);
const computedActual = Number.isFinite(retail) ? round2(retail * (1 - d)) : null;
// IMPORTANT:
// Do NOT autofill actual_cost here. It should only fill when the user forward-tabs
// from Retail (actual_price) -> Actual Cost (actual_cost).
setFieldsValue({
billlines: (getFieldValue("billlines") || []).map((item, idx) => {
if (idx !== index) return item;
@@ -178,7 +183,7 @@ export function BillEnterModalLinesComponent({
quantity: opt.part_qty || 1,
actual_price: opt.cost,
original_actual_price: opt.cost,
actual_cost: isBlank(item.actual_cost) ? computedActual : item.actual_cost,
// actual_cost intentionally untouched here
cost_center: opt.part_type
? bodyshopHasDmsKey(bodyshop)
? opt.part_type !== "PAE"
@@ -205,7 +210,7 @@ export function BillEnterModalLinesComponent({
label: t("billlines.fields.line_desc"),
rules: [{ required: true }]
}),
formInput: () => <Input.TextArea disabled={disabled} autoSize />
formInput: () => <Input.TextArea disabled={disabled} autoSize tabIndex={0} />
},
{
title: t("billlines.fields.quantity"),
@@ -234,7 +239,7 @@ export function BillEnterModalLinesComponent({
})
]
}),
formInput: () => <InputNumber precision={0} min={1} disabled={disabled} />
formInput: () => <InputNumber precision={0} min={1} disabled={disabled} tabIndex={0} />
},
{
title: t("billlines.fields.actual_price"),
@@ -251,9 +256,10 @@ export function BillEnterModalLinesComponent({
<CurrencyInput
min={0}
disabled={disabled}
onBlur={() => autofillActualCost(index)}
tabIndex={0}
// NOTE: Autofill should only happen on forward Tab out of Retail
onKeyDown={(e) => {
if (e.key === "Tab") autofillActualCost(index);
if (e.key === "Tab" && !e.shiftKey) autofillActualCost(index);
}}
/>
),
@@ -328,8 +334,9 @@ export function BillEnterModalLinesComponent({
min={0}
disabled={disabled}
controls={false}
tabIndex={0}
style={{ width: "100%", height: CONTROL_HEIGHT }}
onFocus={() => autofillActualCost(index)}
// NOTE: No auto-fill on focus/blur; only triggered from Retail on Tab
/>
</Form.Item>
</div>
@@ -392,7 +399,7 @@ export function BillEnterModalLinesComponent({
rules: [{ required: true }]
}),
formInput: () => (
<Select showSearch style={{ minWidth: "3rem" }} disabled={disabled}>
<Select showSearch style={{ minWidth: "3rem" }} disabled={disabled} tabIndex={0}>
{bodyshopHasDmsKey(bodyshop)
? CiecaSelect(true, false)
: responsibilityCenters.costs.map((item) => <Select.Option key={item.name}>{item.name}</Select.Option>)}
@@ -412,7 +419,7 @@ export function BillEnterModalLinesComponent({
name: [field.name, "location"]
}),
formInput: () => (
<Select disabled={disabled}>
<Select disabled={disabled} tabIndex={0}>
{bodyshop.md_parts_locations.map((loc, idx) => (
<Select.Option key={idx} value={loc}>
{loc}
@@ -432,7 +439,7 @@ export function BillEnterModalLinesComponent({
key: `${field.name}deductedfromlbr`,
name: [field.name, "deductedfromlbr"]
}),
formInput: () => <Switch disabled={disabled} />,
formInput: () => <Switch disabled={disabled} tabIndex={0} />,
additional: (record, index) => (
<Form.Item shouldUpdate noStyle style={{ display: "inline-block" }}>
{() => {
@@ -517,9 +524,13 @@ export function BillEnterModalLinesComponent({
formItemProps: (field) => ({
key: `${field.name}fedtax`,
valuePropName: "checked",
name: [field.name, "applicable_taxes", "federal"]
name: [field.name, "applicable_taxes", "federal"],
initialValue: InstanceRenderManager({
imex: true,
rome: false
})
}),
formInput: () => <Switch disabled={disabled} />
formInput: () => <Switch disabled={disabled} tabIndex={0} />
}
]
}),
@@ -534,7 +545,7 @@ export function BillEnterModalLinesComponent({
valuePropName: "checked",
name: [field.name, "applicable_taxes", "state"]
}),
formInput: () => <Switch disabled={disabled} />
formInput: () => <Switch disabled={disabled} tabIndex={0} />
},
...InstanceRenderManager({
@@ -550,7 +561,7 @@ export function BillEnterModalLinesComponent({
valuePropName: "checked",
name: [field.name, "applicable_taxes", "local"]
}),
formInput: () => <Switch disabled={disabled} />
formInput: () => <Switch disabled={disabled} tabIndex={0} />
}
]
}),
@@ -570,6 +581,7 @@ export function BillEnterModalLinesComponent({
icon={<DeleteFilled />}
disabled={disabled || invLen > 0}
onClick={() => remove(record.name)}
tabIndex={0}
/>
{Simple_Inventory.treatment === "on" && (
@@ -641,12 +653,19 @@ export function BillEnterModalLinesComponent({
<Button
disabled={disabled}
onClick={() => {
const newIndex = fields.length;
add(
InstanceRenderManager({
imex: { applicable_taxes: { federal: true } },
rome: { applicable_taxes: { federal: false } }
})
);
setTimeout(() => {
const firstField = firstFieldRefs.current[newIndex];
if (firstField?.focus) {
firstField.focus();
}
}, 100);
}}
style={{ width: "100%" }}
>

View File

@@ -57,7 +57,6 @@ const CardPaymentModalComponent = ({
QUERY_RO_AND_OWNER_BY_JOB_PKS,
{
fetchPolicy: "network-only",
notifyOnNetworkStatusChange: true
}
);

View File

@@ -47,7 +47,6 @@ export function ChatPopupComponent({ chatVisible, selectedConversation, toggleCh
const [getConversations, { loading, data, refetch, called }] = useLazyQuery(CONVERSATION_LIST_QUERY, {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
notifyOnNetworkStatusChange: true,
...(pollInterval > 0 ? { pollInterval } : {})
});

View File

@@ -36,7 +36,7 @@ export function DashboardTotalProductionHours({ bodyshop, data, ...cardProps })
<Statistic
title={t("dashboard.labels.prodhrs")}
value={hours.total.toFixed(1)}
styles={{ value: { color: aboveTargetHours ? "green" : "red" } }}
styles={{ content: { color: aboveTargetHours ? "green" : "red" } }}
/>
</Space>
</Card>

View File

@@ -404,7 +404,7 @@ export default function CdkLikePostForm({ bodyshop, socket, job, logsRef, mode,
<Typography.Title>=</Typography.Title>
<Statistic
title={t("jobs.labels.dms.notallocated")}
styles={{ value: { color: discrep.getAmount() === 0 ? "green" : "red" } }}
styles={{ content: { color: discrep.getAmount() === 0 ? "green" : "red" } }}
value={discrep.toFormat()}
/>
<Button disabled={disablePost} htmlType="submit">

View File

@@ -14,8 +14,11 @@ export default function GlobalSearch() {
const [callSearch, { loading, error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
const navigate = useNavigate();
const executeSearch = (v) => {
if (v && v.variables.search && v.variables.search !== "" && v.variables.search.length >= 3) callSearch(v);
const executeSearch = (variables) => {
if (variables?.search !== "" && variables?.search?.length >= 3)
callSearch({
variables
});
};
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
@@ -157,7 +160,9 @@ export default function GlobalSearch() {
return (
<AutoComplete
options={options}
onSearch={handleSearch}
showSearch={{
onSearch: handleSearch
}}
defaultActiveFirstOption
onKeyDown={(e) => {
if (e.key !== "Enter") return;

View File

@@ -97,7 +97,7 @@ export function Jobd3RdPartyModal({ bodyshop, jobId, job, technician }) {
return (
<>
<Button onClick={showModal}>{t("printcenter.jobs.3rdpartypayer")}</Button>
<Modal open={isModalVisible} onOk={handleOk} onCancel={handleCancel}>
<Modal open={isModalVisible} onOk={handleOk} onCancel={handleCancel} getContainer={() => document.body}>
<Form onFinish={handleFinish} autoComplete={"off"} layout="vertical" form={form}>
<Form.Item label={t("bills.fields.vendor")} name="vendorid">
<VendorSearchSelect options={VendorAutoCompleteData?.vendors} onSelect={handleVendorSelect} />

View File

@@ -157,7 +157,6 @@ export function JobsDetailHeaderActions({
variables: watcherVars,
skip: !jobId,
fetchPolicy: "cache-first",
notifyOnNetworkStatusChange: true
});
const jobWatchersCount = jobWatchersData?.job_watchers?.length ?? job?.job_watchers?.length ?? 0;

View File

@@ -56,7 +56,6 @@ const NotificationCenterContainer = ({ visible, onClose, bodyshop, unreadCount,
where: whereClause
},
fetchPolicy: "cache-and-network",
notifyOnNetworkStatusChange: true,
errorPolicy: "all",
pollInterval: isConnected ? 0 : day.duration(NOTIFICATION_POLL_INTERVAL_SECONDS, "seconds").asMilliseconds(),
skip: skipQuery

View File

@@ -16,9 +16,10 @@ const OwnerSearchSelect = ({ value, onChange, onBlur, disabled, ref }) => {
SEARCH_OWNERS_BY_ID_FOR_AUTOCOMPLETE
);
const executeSearch = (v) => {
if (v && v.variables?.search !== "" && v.variables.search.length >= 2) callSearch({ variables: v.variables });
const executeSearch = (variables) => {
if (variables?.search !== "" && variables?.search?.length >= 2) callSearch({ variables });
};
const debouncedExecuteSearch = _.debounce(executeSearch, 500);
const handleSearch = (value) => {

View File

@@ -1,94 +1,121 @@
import { DownOutlined } from "@ant-design/icons";
import { Dropdown, InputNumber, Space } from "antd";
import { Button, Divider, Dropdown, InputNumber, Space, theme } from "antd";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
const DISCOUNT_PRESETS = [5, 10, 15, 20, 25, 40];
export default function PartsOrderModalPriceChange({ form, field }) {
const { t } = useTranslation();
const menu = {
items: [
{
key: "5",
label: t("parts_orders.labels.discount", { percent: "5%" })
},
{
key: "10",
label: t("parts_orders.labels.discount", { percent: "10%" })
},
{
key: "15",
label: t("parts_orders.labels.discount", { percent: "15%" })
},
{
key: "20",
label: t("parts_orders.labels.discount", { percent: "20%" })
},
{
key: "25",
label: t("parts_orders.labels.discount", { percent: "25%" })
},
{
key: "40",
label: t("parts_orders.labels.discount", { percent: "40%" })
},
{
key: "custom",
label: (
<Space.Compact>
<InputNumber
onClick={(e) => e.stopPropagation()}
onKeyUp={(e) => {
if (e.key === "Enter") {
const values = form.getFieldsValue();
const { parts_order_lines } = values;
const { token } = theme.useToken();
form.setFieldsValue({
parts_order_lines: {
data: parts_order_lines.data.map((p, idx) => {
if (idx !== field.name) return p;
console.log(p, e.target.value, (p.act_price || 0) * ((100 - (e.target.value || 0)) / 100));
return {
...p,
act_price: (p.act_price || 0) * ((100 - (e.target.value || 0)) / 100)
};
})
}
});
e.target.value = 0;
}
}}
min={0}
max={100}
/>
<span style={{ padding: "0 11px", backgroundColor: "#fafafa", border: "1px solid #d9d9d9", borderLeft: 0 }}>%</span>
</Space.Compact>
)
const [open, setOpen] = useState(false);
const [customPercent, setCustomPercent] = useState(0);
const applyDiscountPercent = (percent) => {
const pct = Number(percent) || 0;
const values = form.getFieldsValue();
const parts_order_lines = values?.parts_order_lines;
const data = Array.isArray(parts_order_lines?.data) ? parts_order_lines.data : [];
if (!data.length) return;
form.setFieldsValue({
parts_order_lines: {
data: data.map((p, idx) => {
if (idx !== field.name) return p;
return {
...p,
act_price: (p.act_price || 0) * ((100 - pct) / 100)
};
})
}
],
});
};
const applyCustom = () => {
logImEXEvent("parts_order_manual_discount", {});
applyDiscountPercent(customPercent);
setCustomPercent(0);
setOpen(false);
};
const menu = {
// Kill the menu “card” styling so our wrapper becomes the single card.
style: {
background: "transparent",
boxShadow: "none"
},
items: DISCOUNT_PRESETS.map((pct) => ({
key: String(pct),
label: t("parts_orders.labels.discount", { percent: `${pct}%` })
})),
onClick: ({ key }) => {
logImEXEvent("parts_order_manual_discount", {});
if (key === "custom") return;
const values = form.getFieldsValue();
const { parts_order_lines } = values;
form.setFieldsValue({
parts_order_lines: {
data: parts_order_lines.data.map((p, idx) => {
if (idx !== field.name) return p;
return {
...p,
act_price: (p.act_price || 0) * ((100 - key) / 100)
};
})
}
});
applyDiscountPercent(key);
setOpen(false);
}
};
return (
<Dropdown menu={menu} trigger="click">
<Dropdown
menu={menu}
trigger={["click"]}
open={open}
onOpenChange={(nextOpen) => setOpen(nextOpen)}
getPopupContainer={(triggerNode) => triggerNode?.parentElement ?? document.body}
popupRender={(menus) => (
<div
// This makes the whole dropdown (menu + footer) look like one panel in both light/dark.
style={{
background: token.colorBgElevated,
borderRadius: token.borderRadiusLG,
boxShadow: token.boxShadowSecondary,
overflow: "hidden",
minWidth: 180
}}
onClick={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
>
{menus}
<Divider style={{ margin: 0 }} />
<div style={{ padding: token.paddingXS }}>
<Space.Compact style={{ width: "100%" }}>
<InputNumber
value={customPercent}
min={0}
max={100}
precision={0}
controls={false}
style={{ width: "100%" }}
formatter={(v) => (v === null || v === undefined ? "" : `${v}%`)}
parser={(v) =>
String(v ?? "")
.replace("%", "")
.trim()
}
onChange={(v) => setCustomPercent(v ?? 0)}
onKeyDown={(e) => {
e.stopPropagation();
if (e.key === "Enter") {
e.preventDefault();
applyCustom();
}
}}
/>
<Button type="primary" onClick={applyCustom}>
{t("general.labels.apply")}
</Button>
</Space.Compact>
</div>
</div>
)}
>
<Space>
%
<DownOutlined />
% <DownOutlined />
</Space>
</Dropdown>
);

View File

@@ -17,7 +17,6 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import PartsOrderModalComponent from "./parts-order-modal.component";
import axios from "axios";
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
@@ -66,7 +65,7 @@ export function PartsOrderModalContainer({
const sendTypeState = useState("e");
const sendType = sendTypeState[0];
const { loading, error, data } = useQuery(QUERY_ALL_VENDORS_FOR_ORDER, {
const { error, data } = useQuery(QUERY_ALL_VENDORS_FOR_ORDER, {
skip: !open,
variables: { jobId: jobId },
fetchPolicy: "network-only",
@@ -94,16 +93,6 @@ export function PartsOrderModalContainer({
};
});
const missingIdx = forcedLines.findIndex((l) => !l?.job_line_id);
if (missingIdx !== -1) {
notification.error({
title: t("parts_orders.errors.creating"),
description: `Missing job_line_id for parts line #${missingIdx + 1}`
});
setSaving(false);
return;
}
let insertResult;
try {
insertResult = await insertPartOrder({
@@ -372,6 +361,7 @@ export function PartsOrderModalContainer({
}
}, [open, linesToOrder, form]);
//This used to have a loading component spinner for the vendor data. With Apollo 4, the NetworkState isn't emitting correctly, so loading just gets set to true the second time, and no longer works as expected.
return (
<Modal
open={open}
@@ -390,18 +380,14 @@ export function PartsOrderModalContainer({
>
{error ? <AlertComponent title={error.message} type="error" /> : null}
<Form form={form} layout="vertical" autoComplete="no" onFinish={handleFinish} initialValues={initialValues}>
{loading ? (
<LoadingSpinner />
) : (
<PartsOrderModalComponent
form={form}
vendorList={data?.vendors || []}
sendTypeState={sendTypeState}
isReturn={isReturn}
preferredMake={data && data.jobs[0] && data.jobs[0].v_make_desc}
job={job}
/>
)}
<PartsOrderModalComponent
form={form}
vendorList={data?.vendors || []}
sendTypeState={sendTypeState}
isReturn={isReturn}
preferredMake={data && data.jobs[0] && data.jobs[0].v_make_desc}
job={job}
/>
</Form>
</Modal>
);

View File

@@ -33,7 +33,7 @@ export default function PaymentFormTotalPayments({ jobid }) {
{balance && (
<Statistic
title={t("payments.labels.balance")}
styles={{ value: { color: balance.getAmount() !== 0 ? "red" : "green" } }}
styles={{ content: { color: balance.getAmount() !== 0 ? "red" : "green" } }}
value={(balance && balance.toFormat()) || ""}
/>
)}

View File

@@ -108,7 +108,7 @@ export function PrintCenterJobsLabels({ jobId }) {
</Card>
);
return (
<Popover content={content} open={isModalVisible}>
<Popover content={content} open={isModalVisible} getPopupContainer={(trigger) => trigger.parentElement}>
<Button onClick={() => setIsModalVisible(true)}>{t("printcenter.jobs.labels.labels")}</Button>
</Popover>
);

View File

@@ -18,9 +18,10 @@ const VehicleSearchSelect = ({ value, onChange, onBlur, disabled, ref }) => {
SEARCH_VEHICLES_BY_ID_FOR_AUTOCOMPLETE
);
const executeSearch = (v) => {
if (v && v.variables?.search !== "" && v.variables.search.length >= 2) callSearch({ variables: v.variables });
const executeSearch = (variables) => {
if (variables?.search !== "" && variables?.search?.length >= 2) callSearch({ variables });
};
const debouncedExecuteSearch = _.debounce(executeSearch, 500);
const handleSearch = (value) => {

View File

@@ -510,7 +510,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, set
<Statistic
title={t("jobs.labels.pimraryamountpayable")}
styles={{
value: {
content: {
color: discrep.getAmount() >= 0 ? "green" : "red"
}
}}

View File

@@ -17,7 +17,10 @@ import "./tech.page.styles.scss";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component.jsx";
import { lazyDev } from "../../utils/lazyWithPreload.jsx";
const TimeTicketModalContainer = lazyDev(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
const NoteUpsertModal = lazyDev(() => import("../../components/note-upsert-modal/note-upsert-modal.container.jsx"));
const TimeTicketModalContainer = lazyDev(
() => import("../../components/time-ticket-modal/time-ticket-modal.container")
);
const EmailOverlayContainer = lazyDev(() => import("../../components/email-overlay/email-overlay.container.jsx"));
const PrintCenterModalContainer = lazyDev(
() => import("../../components/print-center-modal/print-center-modal.container")
@@ -34,7 +37,9 @@ const TimeTicketModalTask = lazyDev(
const TechAssignedProdJobs = lazyDev(() => import("../tech-assigned-prod-jobs/tech-assigned-prod-jobs.component"));
const TechDispatchedParts = lazyDev(() => import("../tech-dispatched-parts/tech-dispatched-parts.page"));
const TaskUpsertModalContainer = lazyDev(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
const TaskUpsertModalContainer = lazyDev(
() => import("../../components/task-upsert-modal/task-upsert-modal.container")
);
const { Content } = Layout;
@@ -70,6 +75,8 @@ export function TechPage({ technician }) {
<TechHeader />
<TaskUpsertModalContainer />
<NoteUpsertModal />
<Content className="tech-content-container">
<ErrorBoundary>
<Suspense

View File

@@ -1288,6 +1288,7 @@
"vehicle": "Vehicle"
},
"labels": {
"apply": "Apply",
"actions": "Actions",
"areyousure": "Are you sure?",
"barcode": "Barcode",

View File

@@ -1288,6 +1288,7 @@
"vehicle": ""
},
"labels": {
"apply": "",
"actions": "Comportamiento",
"areyousure": "",
"barcode": "código de barras",

View File

@@ -1288,6 +1288,7 @@
"vehicle": ""
},
"labels": {
"apply": "",
"actions": "actes",
"areyousure": "",
"barcode": "code à barre",

View File

@@ -248,7 +248,8 @@ const client = new ApolloClient({
watchQuery: {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
errorPolicy: "ignore"
errorPolicy: "ignore",
notifyOnNetworkStatusChange: false
},
query: {
fetchPolicy: "network-only",