IO-3515 Add translations and logging.

This commit is contained in:
Patrick Fic
2026-02-19 13:54:39 -08:00
parent ae1408012f
commit b2bc19c5c9
7 changed files with 463 additions and 78 deletions

View File

@@ -7,7 +7,7 @@ import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext";
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { useApolloClient } from "@apollo/client/react";
import { useTranslation } from "react-i18next";
const mapStateToProps = createStructuredSelector({
billEnterModal: selectBillEnterModal,
@@ -26,23 +26,20 @@ function BillEnterAiScan({
setIsAiScan
}) {
const notification = useNotification();
const { t } = useTranslation();
const [showBetaModal, setShowBetaModal] = useState(false);
const BETA_ACCEPTANCE_KEY = "ai_scan_beta_acceptance";
const client = useApolloClient();
const handleBetaAcceptance = () => {
localStorage.setItem(BETA_ACCEPTANCE_KEY, "true");
setShowBetaModal(false);
// Trigger the file input after acceptance
fileInputRef.current?.click();
};
const checkBetaAcceptance = () => {
const hasAccepted = localStorage.getItem(BETA_ACCEPTANCE_KEY);
if (hasAccepted) {
// User has already accepted, proceed with file selection
fileInputRef.current?.click();
} else {
// Show beta modal
setShowBetaModal(true);
}
};
@@ -65,8 +62,7 @@ function BillEnterAiScan({
form.setFieldsValue(data.data.billForm);
await form.validateFields(["billlines"], { recursive: true });
notification.success({
title: "AI Scan Complete",
message: "Invoice data has been extracted successfully"
title: t(".bills.labels.ai.scancomplete")
});
}
} else if (data.status === "FAILED") {
@@ -78,8 +74,8 @@ function BillEnterAiScan({
setScanLoading(false);
notification.error({
title: "AI Scan Failed",
message: data.error || "Failed to process the invoice"
title: t("bills.labels.ai.scanfailed"),
message: data.error || ""
});
}
// If status is IN_PROGRESS, continue polling
@@ -92,7 +88,7 @@ function BillEnterAiScan({
setScanLoading(false);
notification.error({
title: "AI Scan Error",
title: t("bills.labels.ai.scanfailed"),
message: error.response?.data?.message || error.message || "Failed to check scan status"
});
}
@@ -123,8 +119,8 @@ function BillEnterAiScan({
if (status === 202) {
// Multipage PDF - start polling
notification.info({
title: "Processing Invoice",
message: "This is a multipage document. Processing may take a few moments..."
title: t("bills.labels.ai.scanstarted"),
message: t("bills.labels.ai.multipage")
});
//Workaround needed to bypass react-compiler error about manipulating refs in child components. Refactor may be needed in the future to clean this up.
@@ -144,14 +140,13 @@ function BillEnterAiScan({
await form.validateFields(["billlines"], { recursive: true });
notification.success({
title: "AI Scan Complete",
message: "Invoice data has been extracted successfully"
title: t("bills.labels.ai.scancomplete")
});
}
} catch (error) {
setScanLoading(false);
notification.error({
title: "AI Scan Failed",
title: t("bills.labels.ai.scanfailed"),
message: error.response?.data?.message || error.message || "Failed to process invoice"
});
}
@@ -162,20 +157,21 @@ function BillEnterAiScan({
/>
<Button onClick={checkBetaAcceptance} icon={<FaWandMagicSparkles />} loading={scanLoading} disabled={scanLoading}>
{scanLoading ? "Processing Invoice..." : "AI Scan"}
<Tag color="red">BETA</Tag>
{scanLoading ? t("bills.labels.ai.processing") : t("bills.labels.ai.scan")}
<Tag color="red">{t("general.labels.beta")}</Tag>
</Button>
<Modal
title="AI Scan Beta Disclaimer"
title={t("bills.labels.ai.disclaimer_title")}
open={showBetaModal}
onOk={handleBetaAcceptance}
onCancel={() => setShowBetaModal(false)}
okText="Accept and Continue"
cancelText="Cancel"
okText={t("bills.labels.ai.accept_and_continue")}
cancelText={t("general.labels.cancel")}
>
<Typography.Title level={2}>AI Usage Disclaimer</Typography.Title>
{
//This is explicitly not translated.
}
<Typography.Text>
This AI scanning feature is currently in <strong>beta</strong>. While it can accelerate data entry, you{" "}
<strong>must carefully review all extracted results</strong> for accuracy.

View File

@@ -36,11 +36,9 @@ const ConfidenceDisplay = ({ rowValue: { confidence, actual_price, actual_cost }
<Tooltip
title={
<div style={{ padding: "4px 0" }}>
<div style={{ marginBottom: 8, fontWeight: 600 }}>
{t("billlines.confidence.breakdown", { defaultValue: "Confidence Breakdown" })}
</div>
<div style={{ marginBottom: 8, fontWeight: 600 }}>{t("bills.labels.ai.confidence.breakdown")}</div>
<div style={{ marginBottom: 4 }}>
<strong>{t("billlines.confidence.overall", { defaultValue: "Overall" })}:</strong> {total.toFixed(1)}%
<strong>{t("bills.labels.ai.confidence.overall")}:</strong> {total.toFixed(1)}%
<Progress
percent={total}
size="small"
@@ -50,7 +48,7 @@ const ConfidenceDisplay = ({ rowValue: { confidence, actual_price, actual_cost }
/>
</div>
<div style={{ marginBottom: 4 }}>
<strong>{t("billlines.confidence.ocr", { defaultValue: "OCR" })}:</strong> {ocr.toFixed(1)}%
<strong>{t("bills.labels.ai.confidence.ocr")}:</strong> {ocr.toFixed(1)}%
<Progress
percent={ocr}
size="small"
@@ -60,7 +58,7 @@ const ConfidenceDisplay = ({ rowValue: { confidence, actual_price, actual_cost }
/>
</div>
<div>
<strong>{t("billlines.confidence.match", { defaultValue: "Job Match" })}:</strong> {jobMatch.toFixed(1)}%
<strong>{t("bills.labels.ai.confidence.match")}:</strong> {jobMatch.toFixed(1)}%
<Progress
percent={jobMatch}
size="small"
@@ -75,7 +73,7 @@ const ConfidenceDisplay = ({ rowValue: { confidence, actual_price, actual_cost }
<Space size="small">
{!parsed_actual_cost || !parsed_actual_price || parsed_actual_cost === 0 || parsed_actual_price === 0 ? (
<Tag color="red" style={{ margin: 0, cursor: "help", userSelect: "none" }}>
{t("billlines.confidence.missing_data", { defaultValue: "Missing Data" })}
{t("bills.labels.ai.confidence.missing_data")}
</Tag>
) : null}
<Tag color={color} style={{ margin: 0, cursor: "help", userSelect: "none" }}>

View File

@@ -218,6 +218,23 @@
},
"labels": {
"actions": "Actions",
"ai": {
"accept_and_continue": "Accept and Continue",
"confidence": {
"breakdown": "Confidence Breakdown",
"match": "Jobline Match",
"missing_data": "Missing Data",
"ocr": "Optical Character Recognition",
"overall": "Overall"
},
"disclaimer_title": "AI Scan Beta Disclaimer",
"multipage": "The is a multi-page document. Processing will take a few moments.",
"processing": "Analyzing Bill",
"scan": "AI Bill Scanner",
"scancomplete": "AI Scan Complete",
"scanfailed": "AI Scan Failed",
"scanstarted": "AI Scan Started"
},
"bill_lines": "Bill Lines",
"bill_total": "Bill Total Amount",
"billcmtotal": "Credit Memos",
@@ -1296,6 +1313,7 @@
"apply": "Apply",
"areyousure": "Are you sure?",
"barcode": "Barcode",
"beta": "BETA",
"cancel": "Are you sure you want to cancel? Your changes will not be saved.",
"changelog": "Change Log",
"clear": "Clear",

View File

@@ -218,6 +218,23 @@
},
"labels": {
"actions": "",
"ai": {
"accept_and_continue": "",
"confidence": {
"breakdown": "",
"match": "",
"missing_data": "",
"ocr": "",
"overall": ""
},
"disclaimer_title": "",
"multipage": "",
"processing": "",
"scan": "",
"scancomplete": "",
"scanfailed": "",
"scanstarted": ""
},
"bill_lines": "",
"bill_total": "",
"billcmtotal": "",
@@ -1296,6 +1313,7 @@
"apply": "",
"areyousure": "",
"barcode": "código de barras",
"beta": "",
"cancel": "",
"changelog": "",
"clear": "",

View File

@@ -218,6 +218,23 @@
},
"labels": {
"actions": "",
"ai": {
"accept_and_continue": "",
"confidence": {
"breakdown": "",
"match": "",
"missing_data": "",
"ocr": "",
"overall": ""
},
"disclaimer_title": "",
"multipage": "",
"processing": "",
"scan": "",
"scancomplete": "",
"scanfailed": "",
"scanstarted": ""
},
"bill_lines": "",
"bill_total": "",
"billcmtotal": "",
@@ -1296,6 +1313,7 @@
"apply": "",
"areyousure": "",
"barcode": "code à barre",
"beta": "",
"cancel": "",
"changelog": "",
"clear": "",