@open-mercato/core 0.4.5-develop-636d33c995 → 0.4.5-develop-3d8e759e45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +17 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +30 -0
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/inbox-actions.js +51 -0
- package/dist/modules/catalog/inbox-actions.js.map +7 -0
- package/dist/modules/catalog/lib/messageObjectPreviews.js +146 -0
- package/dist/modules/catalog/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/catalog/message-objects.js +95 -0
- package/dist/modules/catalog/message-objects.js.map +7 -0
- package/dist/modules/currencies/backend/currencies/[id]/page.js +21 -0
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/lib/messageObjectPreviews.js +51 -0
- package/dist/modules/currencies/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/currencies/message-objects.js +41 -0
- package/dist/modules/currencies/message-objects.js.map +7 -0
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +20 -0
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +20 -0
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyHighlights.js +18 -14
- package/dist/modules/customers/components/detail/CompanyHighlights.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonHighlights.js +18 -14
- package/dist/modules/customers/components/detail/PersonHighlights.js.map +2 -2
- package/dist/modules/customers/inbox-actions.js +230 -0
- package/dist/modules/customers/inbox-actions.js.map +7 -0
- package/dist/modules/customers/lib/messageObjectPreviews.js +41 -5
- package/dist/modules/customers/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/customers/message-objects.js +31 -11
- package/dist/modules/customers/message-objects.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js +40 -1
- package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/extract/route.js +87 -0
- package/dist/modules/inbox_ops/api/extract/route.js.map +7 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js +6 -1
- package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +40 -14
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +161 -79
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +109 -62
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +3 -3
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +36 -14
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/ActionCard.js +65 -10
- package/dist/modules/inbox_ops/components/proposals/ActionCard.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +58 -10
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/inbox_ops/lib/constants.js.map +2 -2
- package/dist/modules/inbox_ops/lib/contactValidation.js +40 -0
- package/dist/modules/inbox_ops/lib/contactValidation.js.map +7 -0
- package/dist/modules/inbox_ops/lib/executionEngine.js +31 -826
- package/dist/modules/inbox_ops/lib/executionEngine.js.map +3 -3
- package/dist/modules/inbox_ops/lib/executionHelpers.js +368 -0
- package/dist/modules/inbox_ops/lib/executionHelpers.js.map +7 -0
- package/dist/modules/inbox_ops/lib/extractionPrompt.js +28 -35
- package/dist/modules/inbox_ops/lib/extractionPrompt.js.map +3 -3
- package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js +1 -0
- package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js.map +7 -0
- package/dist/modules/inbox_ops/lib/translationProvider.js +15 -10
- package/dist/modules/inbox_ops/lib/translationProvider.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js +16 -16
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +3 -0
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js +6 -1
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +4 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/frontend/messages/view/[token]/page.js +1 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -7
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/lib/messageObjectPreviews.js +43 -0
- package/dist/modules/resources/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/resources/message-objects.js +37 -0
- package/dist/modules/resources/message-objects.js.map +7 -0
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +19 -0
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +23 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/quotes/[id]/page.js +1 -1
- package/dist/modules/sales/backend/sales/quotes/[id]/page.js.map +2 -2
- package/dist/modules/sales/inbox-actions.js +278 -0
- package/dist/modules/sales/inbox-actions.js.map +7 -0
- package/dist/modules/sales/lib/messageObjectPreviews.js +49 -4
- package/dist/modules/sales/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/sales/message-objects.js +44 -2
- package/dist/modules/sales/message-objects.js.map +2 -2
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +59 -30
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +2 -2
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +1 -1
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +8 -30
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-availability/page.js +13 -0
- package/dist/modules/staff/backend/staff/my-availability/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +8 -31
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +32 -10
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +14 -1
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +4 -2
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamRoleForm.js +4 -2
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/dist/modules/staff/lib/messageObjectPreviews.js +111 -2
- package/dist/modules/staff/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/staff/message-objects.js +79 -8
- package/dist/modules/staff/message-objects.js.map +2 -2
- package/jest.config.cjs +1 -0
- package/jest.mocks/inbox-actions.generated.js +5 -0
- package/package.json +2 -2
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +19 -5
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +14 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +40 -0
- package/src/modules/catalog/inbox-actions.ts +60 -0
- package/src/modules/catalog/lib/messageObjectPreviews.ts +176 -0
- package/src/modules/catalog/message-objects.ts +102 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -0
- package/src/modules/currencies/lib/messageObjectPreviews.ts +65 -0
- package/src/modules/currencies/message-objects.ts +40 -0
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +19 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +13 -0
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +19 -0
- package/src/modules/customers/components/detail/CompanyHighlights.tsx +14 -9
- package/src/modules/customers/components/detail/PersonHighlights.tsx +14 -9
- package/src/modules/customers/inbox-actions.ts +285 -0
- package/src/modules/customers/lib/messageObjectPreviews.ts +43 -3
- package/src/modules/customers/message-objects.ts +31 -11
- package/src/modules/inbox_ops/api/emails/[id]/route.ts +44 -0
- package/src/modules/inbox_ops/api/extract/route.ts +94 -0
- package/src/modules/inbox_ops/api/proposals/[id]/translate/route.ts +6 -1
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +2 -0
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +43 -13
- package/src/modules/inbox_ops/backend/inbox-ops/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +176 -81
- package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +122 -68
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +36 -14
- package/src/modules/inbox_ops/components/proposals/ActionCard.tsx +91 -7
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +64 -12
- package/src/modules/inbox_ops/lib/constants.ts +9 -0
- package/src/modules/inbox_ops/lib/contactValidation.ts +54 -0
- package/src/modules/inbox_ops/lib/executionEngine.ts +47 -1060
- package/src/modules/inbox_ops/lib/executionHelpers.ts +527 -0
- package/src/modules/inbox_ops/lib/extractionPrompt.ts +45 -34
- package/src/modules/inbox_ops/lib/inbox-actions-generated.d.ts +11 -0
- package/src/modules/inbox_ops/lib/translationProvider.ts +16 -10
- package/src/modules/inbox_ops/subscribers/extractionWorker.ts +16 -18
- package/src/modules/messages/commands/messages.ts +4 -0
- package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +8 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +3 -0
- package/src/modules/messages/frontend/messages/view/[token]/page.tsx +1 -0
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +20 -4
- package/src/modules/resources/lib/messageObjectPreviews.ts +55 -0
- package/src/modules/resources/message-objects.ts +36 -0
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +18 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -0
- package/src/modules/sales/backend/sales/quotes/[id]/page.tsx +1 -1
- package/src/modules/sales/inbox-actions.ts +359 -0
- package/src/modules/sales/lib/messageObjectPreviews.ts +54 -4
- package/src/modules/sales/message-objects.ts +44 -2
- package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +72 -34
- package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +1 -1
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +7 -29
- package/src/modules/staff/backend/staff/my-availability/page.tsx +14 -0
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +8 -30
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +28 -7
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +12 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +12 -0
- package/src/modules/staff/components/TeamForm.tsx +3 -0
- package/src/modules/staff/components/TeamRoleForm.tsx +3 -0
- package/src/modules/staff/lib/messageObjectPreviews.ts +133 -2
- package/src/modules/staff/message-objects.ts +79 -8
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +0 -51
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +0 -7
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +0 -35
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +0 -7
- package/dist/modules/customers/widgets/messages/index.js +0 -7
- package/dist/modules/customers/widgets/messages/index.js.map +0 -7
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +0 -51
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +0 -7
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +0 -34
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +0 -7
- package/dist/modules/staff/widgets/messages/index.js +0 -7
- package/dist/modules/staff/widgets/messages/index.js.map +0 -7
- package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +0 -57
- package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +0 -49
- package/src/modules/customers/widgets/messages/index.ts +0 -2
- package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +0 -57
- package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +0 -44
- package/src/modules/staff/widgets/messages/index.ts +0 -2
|
@@ -6,28 +6,50 @@ import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
|
6
6
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
7
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
8
|
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
9
|
+
import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
|
|
9
10
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
11
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
10
12
|
import { ArrowLeft, Copy, CheckCircle } from "lucide-react";
|
|
11
13
|
const LANGUAGE_KEYS = ["en", "de", "es", "pl"];
|
|
12
14
|
function InboxSettingsPage() {
|
|
13
15
|
const t = useT();
|
|
16
|
+
const { runMutation } = useGuardedMutation({
|
|
17
|
+
contextId: "inbox-ops-settings"
|
|
18
|
+
});
|
|
14
19
|
const languageOptions = LANGUAGE_KEYS.map((key) => ({
|
|
15
20
|
value: key,
|
|
16
21
|
label: t(`inbox_ops.settings.language_${key}`, key)
|
|
17
22
|
}));
|
|
18
23
|
const [settings, setSettings] = React.useState(null);
|
|
19
24
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
25
|
+
const [error, setError] = React.useState(null);
|
|
20
26
|
const [copied, setCopied] = React.useState(false);
|
|
21
27
|
const [isSavingLanguage, setIsSavingLanguage] = React.useState(false);
|
|
22
28
|
React.useEffect(() => {
|
|
29
|
+
let cancelled = false;
|
|
23
30
|
async function load() {
|
|
24
31
|
setIsLoading(true);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
setError(null);
|
|
33
|
+
try {
|
|
34
|
+
const result = await apiCall("/api/inbox_ops/settings");
|
|
35
|
+
if (!cancelled) {
|
|
36
|
+
if (result?.ok && result.result?.settings) {
|
|
37
|
+
setSettings(result.result.settings);
|
|
38
|
+
} else {
|
|
39
|
+
setError(t("inbox_ops.settings.load_failed", "Failed to load settings"));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
if (!cancelled) setError(t("inbox_ops.settings.load_failed", "Failed to load settings"));
|
|
44
|
+
} finally {
|
|
45
|
+
if (!cancelled) setIsLoading(false);
|
|
46
|
+
}
|
|
28
47
|
}
|
|
29
48
|
load();
|
|
30
|
-
|
|
49
|
+
return () => {
|
|
50
|
+
cancelled = true;
|
|
51
|
+
};
|
|
52
|
+
}, [t]);
|
|
31
53
|
const handleCopy = React.useCallback(() => {
|
|
32
54
|
if (settings?.inboxAddress) {
|
|
33
55
|
navigator.clipboard.writeText(settings.inboxAddress);
|
|
@@ -38,9 +60,12 @@ function InboxSettingsPage() {
|
|
|
38
60
|
const handleLanguageChange = React.useCallback(async (event) => {
|
|
39
61
|
const workingLanguage = event.target.value;
|
|
40
62
|
setIsSavingLanguage(true);
|
|
41
|
-
const result = await
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
const result = await runMutation({
|
|
64
|
+
operation: () => apiCall("/api/inbox_ops/settings", {
|
|
65
|
+
method: "PATCH",
|
|
66
|
+
body: JSON.stringify({ workingLanguage })
|
|
67
|
+
}),
|
|
68
|
+
context: {}
|
|
44
69
|
});
|
|
45
70
|
if (result?.ok && result.result?.ok) {
|
|
46
71
|
setSettings((prev) => prev ? { ...prev, workingLanguage: result.result.settings.workingLanguage } : prev);
|
|
@@ -49,22 +74,19 @@ function InboxSettingsPage() {
|
|
|
49
74
|
flash(t("inbox_ops.settings.language_save_failed", "Failed to update working language"), "error");
|
|
50
75
|
}
|
|
51
76
|
setIsSavingLanguage(false);
|
|
52
|
-
}, [t]);
|
|
77
|
+
}, [t, runMutation]);
|
|
53
78
|
return /* @__PURE__ */ jsxs(Page, { children: [
|
|
54
79
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-3 py-3 md:px-6 md:py-4", children: [
|
|
55
|
-
/* @__PURE__ */ jsx(Link, { href: "/backend/inbox-ops", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }) }) }),
|
|
80
|
+
/* @__PURE__ */ jsx(Link, { href: "/backend/inbox-ops", children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }) }) }),
|
|
56
81
|
/* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold", children: t("inbox_ops.settings.title", "Inbox Settings") })
|
|
57
82
|
] }),
|
|
58
|
-
/* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx("div", { className: "max-w-lg", children: isLoading ? /* @__PURE__ */ jsxs("div", { className: "
|
|
59
|
-
/* @__PURE__ */ jsx("div", { className: "h-6 bg-muted rounded w-1/3" }),
|
|
60
|
-
/* @__PURE__ */ jsx("div", { className: "h-12 bg-muted rounded" })
|
|
61
|
-
] }) : settings ? /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
83
|
+
/* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx("div", { className: "max-w-lg", children: isLoading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("inbox_ops.settings.loading", "Loading settings...") }) : error ? /* @__PURE__ */ jsx(ErrorMessage, { label: error }) : settings ? /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
62
84
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
63
85
|
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-foreground", children: t("inbox_ops.settings.forwarding_address", "Forwarding Address") }),
|
|
64
86
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: t("inbox_ops.settings.forwarding_hint", "Forward email threads to this address to create proposals") }),
|
|
65
87
|
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
66
88
|
/* @__PURE__ */ jsx("div", { className: "flex-1 bg-muted rounded-lg px-4 py-3", children: /* @__PURE__ */ jsx("code", { className: "text-sm font-mono", children: settings.inboxAddress }) }),
|
|
67
|
-
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "h-11 md:h-9", onClick: handleCopy, children: [
|
|
89
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "h-11 md:h-9", onClick: handleCopy, children: [
|
|
68
90
|
copied ? /* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 text-green-600" }) : /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" }),
|
|
69
91
|
/* @__PURE__ */ jsx("span", { className: "ml-1", children: copied ? t("inbox_ops.settings.copied", "Copied") : t("inbox_ops.settings.copy", "Copy") })
|
|
70
92
|
] })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ArrowLeft, Copy, CheckCircle } from 'lucide-react'\n\nconst LANGUAGE_KEYS = ['en', 'de', 'es', 'pl'] as const\n\nexport default function InboxSettingsPage() {\n const t = useT()\n\n const languageOptions = LANGUAGE_KEYS.map((key) => ({\n value: key,\n label: t(`inbox_ops.settings.language_${key}` as never, key),\n }))\n const [settings, setSettings] = React.useState<{ inboxAddress?: string; isActive?: boolean; workingLanguage?: string } | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [copied, setCopied] = React.useState(false)\n const [isSavingLanguage, setIsSavingLanguage] = React.useState(false)\n\n React.useEffect(() => {\n async function load() {\n setIsLoading(true)\n const result = await apiCall<{ settings: { inboxAddress?: string; isActive?: boolean; workingLanguage?: string } | null }>('/api/inbox_ops/settings')\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { ArrowLeft, Copy, CheckCircle } from 'lucide-react'\n\nconst LANGUAGE_KEYS = ['en', 'de', 'es', 'pl'] as const\n\nexport default function InboxSettingsPage() {\n const t = useT()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-settings',\n })\n\n const languageOptions = LANGUAGE_KEYS.map((key) => ({\n value: key,\n label: t(`inbox_ops.settings.language_${key}` as never, key),\n }))\n const [settings, setSettings] = React.useState<{ inboxAddress?: string; isActive?: boolean; workingLanguage?: string } | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [copied, setCopied] = React.useState(false)\n const [isSavingLanguage, setIsSavingLanguage] = React.useState(false)\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setError(null)\n try {\n const result = await apiCall<{ settings: { inboxAddress?: string; isActive?: boolean; workingLanguage?: string } | null }>('/api/inbox_ops/settings')\n if (!cancelled) {\n if (result?.ok && result.result?.settings) {\n setSettings(result.result.settings)\n } else {\n setError(t('inbox_ops.settings.load_failed', 'Failed to load settings'))\n }\n }\n } catch {\n if (!cancelled) setError(t('inbox_ops.settings.load_failed', 'Failed to load settings'))\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [t])\n\n const handleCopy = React.useCallback(() => {\n if (settings?.inboxAddress) {\n navigator.clipboard.writeText(settings.inboxAddress)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }, [settings])\n\n const handleLanguageChange = React.useCallback(async (event: React.ChangeEvent<HTMLSelectElement>) => {\n const workingLanguage = event.target.value\n setIsSavingLanguage(true)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; settings: { workingLanguage: string } }>('/api/inbox_ops/settings', {\n method: 'PATCH',\n body: JSON.stringify({ workingLanguage }),\n }),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n setSettings((prev) => prev ? { ...prev, workingLanguage: result.result!.settings.workingLanguage } : prev)\n flash(t('inbox_ops.settings.language_saved', 'Working language updated'), 'success')\n } else {\n flash(t('inbox_ops.settings.language_save_failed', 'Failed to update working language'), 'error')\n }\n setIsSavingLanguage(false)\n }, [t, runMutation])\n\n return (\n <Page>\n <div className=\"flex items-center gap-3 px-3 py-3 md:px-6 md:py-4\">\n <Link href=\"/backend/inbox-ops\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\"><ArrowLeft className=\"h-4 w-4\" /></Button>\n </Link>\n <h1 className=\"text-lg font-semibold\">{t('inbox_ops.settings.title', 'Inbox Settings')}</h1>\n </div>\n\n <PageBody>\n <div className=\"max-w-lg\">\n {isLoading ? (\n <LoadingMessage label={t('inbox_ops.settings.loading', 'Loading settings...')} />\n ) : error ? (\n <ErrorMessage label={error} />\n ) : settings ? (\n <div className=\"space-y-6\">\n <div>\n <label className=\"text-sm font-medium text-foreground\">\n {t('inbox_ops.settings.forwarding_address', 'Forwarding Address')}\n </label>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {t('inbox_ops.settings.forwarding_hint', 'Forward email threads to this address to create proposals')}\n </p>\n <div className=\"mt-2 flex items-center gap-2\">\n <div className=\"flex-1 bg-muted rounded-lg px-4 py-3\">\n <code className=\"text-sm font-mono\">{settings.inboxAddress}</code>\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"h-11 md:h-9\" onClick={handleCopy}>\n {copied ? <CheckCircle className=\"h-4 w-4 text-green-600\" /> : <Copy className=\"h-4 w-4\" />}\n <span className=\"ml-1\">{copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}</span>\n </Button>\n </div>\n </div>\n\n <div>\n <label className=\"text-sm font-medium text-foreground\">{t('inbox_ops.settings.status', 'Status')}</label>\n <div className=\"mt-1\">\n <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${\n settings.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'\n }`}>\n {settings.isActive ? t('inbox_ops.settings.active', 'Active') : t('inbox_ops.settings.inactive', 'Inactive')}\n </span>\n </div>\n </div>\n\n <div>\n <label htmlFor=\"working-language\" className=\"text-sm font-medium text-foreground\">\n {t('inbox_ops.settings.working_language', 'Working Language')}\n </label>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {t('inbox_ops.settings.working_language_hint', 'AI summaries and action descriptions will be generated in this language')}\n </p>\n <select\n id=\"working-language\"\n className=\"mt-2 block w-full sm:w-[200px] h-11 md:h-9 rounded-md border border-input bg-background px-3 text-sm\"\n value={settings.workingLanguage || 'en'}\n onChange={handleLanguageChange}\n disabled={isSavingLanguage}\n >\n {languageOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n </div>\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.settings.not_found', 'No inbox settings found. Settings are created when a new tenant is provisioned.')}</p>\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,11 +3,11 @@ const metadata = {
|
|
|
3
3
|
requireFeatures: ["inbox_ops.settings.manage"],
|
|
4
4
|
pageTitle: "Inbox Settings",
|
|
5
5
|
pageTitleKey: "inbox_ops.nav.settings",
|
|
6
|
-
pageGroup: "
|
|
6
|
+
pageGroup: "AI Inbox Actions",
|
|
7
7
|
pageGroupKey: "inbox_ops.nav.group",
|
|
8
8
|
navHidden: true,
|
|
9
9
|
breadcrumb: [
|
|
10
|
-
{ label: "
|
|
10
|
+
{ label: "AI Inbox Actions", labelKey: "inbox_ops.nav.group", href: "/backend/inbox-ops" },
|
|
11
11
|
{ label: "Settings", labelKey: "inbox_ops.nav.settings" }
|
|
12
12
|
]
|
|
13
13
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/inbox_ops/backend/inbox-ops/settings/page.meta.ts"],
|
|
4
|
-
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.settings.manage'],\n pageTitle: 'Inbox Settings',\n pageTitleKey: 'inbox_ops.nav.settings',\n pageGroup: '
|
|
5
|
-
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,2BAA2B;AAAA,EAC7C,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,
|
|
4
|
+
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.settings.manage'],\n pageTitle: 'Inbox Settings',\n pageTitleKey: 'inbox_ops.nav.settings',\n pageGroup: 'AI Inbox Actions',\n pageGroupKey: 'inbox_ops.nav.group',\n navHidden: true,\n breadcrumb: [\n { label: 'AI Inbox Actions', labelKey: 'inbox_ops.nav.group', href: '/backend/inbox-ops' },\n { label: 'Settings', labelKey: 'inbox_ops.nav.settings' },\n ],\n}\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,2BAA2B;AAAA,EAC7C,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,oBAAoB,UAAU,uBAAuB,MAAM,qBAAqB;AAAA,IACzF,EAAE,OAAO,YAAY,UAAU,yBAAyB;AAAA,EAC1D;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -17,6 +17,44 @@ import {
|
|
|
17
17
|
Activity,
|
|
18
18
|
ShoppingBag
|
|
19
19
|
} from "lucide-react";
|
|
20
|
+
import { hasContactNameIssue } from "../../lib/contactValidation.js";
|
|
21
|
+
function useDiscrepancyDescriptions() {
|
|
22
|
+
const t = useT();
|
|
23
|
+
const translations = {
|
|
24
|
+
"inbox_ops.discrepancy.desc.no_channel": t("inbox_ops.discrepancy.desc.no_channel", "No sales channel available. Create a channel in Sales settings before accepting this order."),
|
|
25
|
+
"inbox_ops.discrepancy.desc.no_currency": t("inbox_ops.discrepancy.desc.no_currency", "No currency could be resolved for this order. Set a currency code or configure a sales channel with a default currency."),
|
|
26
|
+
"inbox_ops.discrepancy.desc.product_not_matched": t("inbox_ops.discrepancy.desc.product_not_matched", "Product could not be matched to any catalog product"),
|
|
27
|
+
"inbox_ops.discrepancy.desc.no_matching_contact": t("inbox_ops.discrepancy.desc.no_matching_contact", "No matching contact found"),
|
|
28
|
+
"inbox_ops.discrepancy.desc.draft_reply_no_contact": t("inbox_ops.discrepancy.desc.draft_reply_no_contact", "Draft reply target has no matching contact. Create the contact first."),
|
|
29
|
+
"inbox_ops.discrepancy.desc.duplicate_order_reference": t("inbox_ops.discrepancy.desc.duplicate_order_reference", "An order with this customer reference already exists")
|
|
30
|
+
};
|
|
31
|
+
return (description, foundValue) => {
|
|
32
|
+
const translated = translations[description];
|
|
33
|
+
if (!translated) return description;
|
|
34
|
+
if (foundValue && (description === "inbox_ops.discrepancy.desc.product_not_matched" || description === "inbox_ops.discrepancy.desc.no_matching_contact")) {
|
|
35
|
+
return `${translated}: ${foundValue}`;
|
|
36
|
+
}
|
|
37
|
+
return translated;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function useActionDescriptionResolver() {
|
|
41
|
+
const t = useT();
|
|
42
|
+
return (description, payload) => {
|
|
43
|
+
if (!description.startsWith("inbox_ops.action.desc.")) return description;
|
|
44
|
+
const name = payload.name || payload.contactName || "";
|
|
45
|
+
const email = payload.email || payload.emailAddress || "";
|
|
46
|
+
const title = payload.title || "";
|
|
47
|
+
const toName = payload.toName || payload.to || "";
|
|
48
|
+
const subject = payload.subject || "";
|
|
49
|
+
const translations = {
|
|
50
|
+
"inbox_ops.action.desc.create_contact": t("inbox_ops.action.desc.create_contact", "Create contact for {name} ({email})").replace("{name}", name).replace("{email}", email),
|
|
51
|
+
"inbox_ops.action.desc.link_contact": t("inbox_ops.action.desc.link_contact", "Link {name} ({email}) to existing contact").replace("{name}", name).replace("{email}", email),
|
|
52
|
+
"inbox_ops.action.desc.create_product": t("inbox_ops.action.desc.create_product", 'Create catalog product "{title}"').replace("{title}", title),
|
|
53
|
+
"inbox_ops.action.desc.draft_reply": t("inbox_ops.action.desc.draft_reply", "Draft reply to {toName}: {subject}").replace("{toName}", toName).replace("{subject}", subject)
|
|
54
|
+
};
|
|
55
|
+
return translations[description] || description;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
20
58
|
const ACTION_TYPE_ICONS = {
|
|
21
59
|
create_order: Package,
|
|
22
60
|
create_quote: FileText,
|
|
@@ -157,14 +195,16 @@ function ActionCard({
|
|
|
157
195
|
onReject,
|
|
158
196
|
onRetry,
|
|
159
197
|
onEdit,
|
|
160
|
-
translatedDescription
|
|
198
|
+
translatedDescription,
|
|
199
|
+
resolveDiscrepancyDescription
|
|
161
200
|
}) {
|
|
162
201
|
const t = useT();
|
|
163
202
|
const Icon = ACTION_TYPE_ICONS[action.actionType] || Package;
|
|
164
203
|
const label = actionTypeLabels[action.actionType] || action.actionType;
|
|
204
|
+
const resolveActionDescription = useActionDescriptionResolver();
|
|
165
205
|
const actionDiscrepancies = discrepancies.filter((d) => d.actionId === action.id && !d.resolved);
|
|
166
206
|
const hasBlockingDiscrepancies = actionDiscrepancies.some((d) => d.severity === "error");
|
|
167
|
-
const displayDescription = translatedDescription || action.description;
|
|
207
|
+
const displayDescription = translatedDescription || resolveActionDescription(action.description, action.payload);
|
|
168
208
|
if (action.status === "executed") {
|
|
169
209
|
return /* @__PURE__ */ jsxs("div", { className: "border rounded-lg p-3 md:p-4 bg-green-50 dark:bg-green-950/20", children: [
|
|
170
210
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
@@ -173,8 +213,7 @@ function ActionCard({
|
|
|
173
213
|
] }),
|
|
174
214
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: displayDescription }),
|
|
175
215
|
action.createdEntityId && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxs("span", { className: "text-xs text-green-600", children: [
|
|
176
|
-
"Created ",
|
|
177
|
-
action.createdEntityType,
|
|
216
|
+
t("inbox_ops.action.created_entity", "Created {type}").replace("{type}", action.createdEntityType || ""),
|
|
178
217
|
" \xB7 ",
|
|
179
218
|
action.executedAt && new Date(action.executedAt).toLocaleString()
|
|
180
219
|
] }) })
|
|
@@ -203,6 +242,7 @@ function ActionCard({
|
|
|
203
242
|
/* @__PURE__ */ jsxs(
|
|
204
243
|
Button,
|
|
205
244
|
{
|
|
245
|
+
type: "button",
|
|
206
246
|
size: "sm",
|
|
207
247
|
className: "h-11 md:h-9",
|
|
208
248
|
onClick: () => onRetry(action.id),
|
|
@@ -215,6 +255,7 @@ function ActionCard({
|
|
|
215
255
|
/* @__PURE__ */ jsxs(
|
|
216
256
|
Button,
|
|
217
257
|
{
|
|
258
|
+
type: "button",
|
|
218
259
|
variant: "outline",
|
|
219
260
|
size: "sm",
|
|
220
261
|
className: "h-11 md:h-9",
|
|
@@ -228,6 +269,7 @@ function ActionCard({
|
|
|
228
269
|
/* @__PURE__ */ jsxs(
|
|
229
270
|
Button,
|
|
230
271
|
{
|
|
272
|
+
type: "button",
|
|
231
273
|
variant: "outline",
|
|
232
274
|
size: "sm",
|
|
233
275
|
className: "h-11 md:h-9",
|
|
@@ -241,6 +283,7 @@ function ActionCard({
|
|
|
241
283
|
] })
|
|
242
284
|
] });
|
|
243
285
|
}
|
|
286
|
+
const hasNameIssue = hasContactNameIssue(action);
|
|
244
287
|
return /* @__PURE__ */ jsxs("div", { className: "border rounded-lg p-3 md:p-4", children: [
|
|
245
288
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
246
289
|
/* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 text-primary flex-shrink-0" }),
|
|
@@ -253,28 +296,35 @@ function ActionCard({
|
|
|
253
296
|
actionDiscrepancies.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3 space-y-1", children: actionDiscrepancies.map((d) => /* @__PURE__ */ jsxs("div", { className: `flex items-start gap-2 text-xs rounded px-2 py-1.5 ${d.severity === "error" ? "bg-red-50 text-red-700 dark:bg-red-950/20" : "bg-yellow-50 text-yellow-700 dark:bg-yellow-950/20"}`, children: [
|
|
254
297
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3 mt-0.5 flex-shrink-0" }),
|
|
255
298
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
256
|
-
/* @__PURE__ */ jsx("span", { children: d.description }),
|
|
299
|
+
/* @__PURE__ */ jsx("span", { children: resolveDiscrepancyDescription ? resolveDiscrepancyDescription(d.description, d.foundValue) : d.description }),
|
|
257
300
|
(d.expectedValue || d.foundValue) && /* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-[11px] opacity-80", children: [
|
|
258
301
|
d.expectedValue && /* @__PURE__ */ jsxs("span", { children: [
|
|
259
|
-
"
|
|
302
|
+
t("inbox_ops.discrepancy.expected", "Expected"),
|
|
303
|
+
": ",
|
|
260
304
|
d.expectedValue
|
|
261
305
|
] }),
|
|
262
306
|
d.expectedValue && d.foundValue && /* @__PURE__ */ jsx("span", { children: " \xB7 " }),
|
|
263
307
|
d.foundValue && /* @__PURE__ */ jsxs("span", { children: [
|
|
264
|
-
"
|
|
308
|
+
t("inbox_ops.discrepancy.found", "Found"),
|
|
309
|
+
": ",
|
|
265
310
|
d.foundValue
|
|
266
311
|
] })
|
|
267
312
|
] })
|
|
268
313
|
] })
|
|
269
314
|
] }, d.id)) }),
|
|
315
|
+
hasNameIssue && /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-start gap-2 text-xs rounded px-2 py-1.5 bg-amber-50 text-amber-700 dark:bg-amber-950/20 dark:text-amber-300", children: [
|
|
316
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3 mt-0.5 flex-shrink-0" }),
|
|
317
|
+
/* @__PURE__ */ jsx("span", { children: action.actionType === "link_contact" ? t("inbox_ops.contact.link_name_missing_warning", "Contact name is missing. Please edit and provide a name before accepting.") : t("inbox_ops.contact.name_missing_warning", "First and last name could not be extracted. Please edit before accepting.") })
|
|
318
|
+
] }),
|
|
270
319
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
271
|
-
/* @__PURE__ */ jsx("div", { title: hasBlockingDiscrepancies ? t("inbox_ops.action.accept_blocked", "Resolve errors before accepting") : void 0, children: /* @__PURE__ */ jsxs(
|
|
320
|
+
/* @__PURE__ */ jsx("div", { title: hasNameIssue ? action.actionType === "link_contact" ? t("inbox_ops.contact.link_name_missing_warning", "Contact name is missing. Please edit and provide a name before accepting.") : t("inbox_ops.contact.name_missing_warning", "First and last name could not be extracted. Please edit before accepting.") : hasBlockingDiscrepancies ? t("inbox_ops.action.accept_blocked", "Resolve errors before accepting") : void 0, children: /* @__PURE__ */ jsxs(
|
|
272
321
|
Button,
|
|
273
322
|
{
|
|
323
|
+
type: "button",
|
|
274
324
|
size: "sm",
|
|
275
325
|
className: "h-11 md:h-9",
|
|
276
326
|
onClick: () => onAccept(action.id),
|
|
277
|
-
disabled: hasBlockingDiscrepancies,
|
|
327
|
+
disabled: hasBlockingDiscrepancies || hasNameIssue,
|
|
278
328
|
children: [
|
|
279
329
|
/* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 mr-1" }),
|
|
280
330
|
t("inbox_ops.action.accept", "Accept")
|
|
@@ -284,6 +334,7 @@ function ActionCard({
|
|
|
284
334
|
/* @__PURE__ */ jsxs(
|
|
285
335
|
Button,
|
|
286
336
|
{
|
|
337
|
+
type: "button",
|
|
287
338
|
variant: "outline",
|
|
288
339
|
size: "sm",
|
|
289
340
|
className: "h-11 md:h-9",
|
|
@@ -297,6 +348,7 @@ function ActionCard({
|
|
|
297
348
|
/* @__PURE__ */ jsxs(
|
|
298
349
|
Button,
|
|
299
350
|
{
|
|
351
|
+
type: "button",
|
|
300
352
|
variant: "outline",
|
|
301
353
|
size: "sm",
|
|
302
354
|
className: "h-11 md:h-9",
|
|
@@ -313,6 +365,9 @@ function ActionCard({
|
|
|
313
365
|
export {
|
|
314
366
|
ActionCard,
|
|
315
367
|
ConfidenceBadge,
|
|
316
|
-
|
|
368
|
+
hasContactNameIssue,
|
|
369
|
+
useActionDescriptionResolver,
|
|
370
|
+
useActionTypeLabels,
|
|
371
|
+
useDiscrepancyDescriptions
|
|
317
372
|
};
|
|
318
373
|
//# sourceMappingURL=ActionCard.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/inbox_ops/components/proposals/ActionCard.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n CheckCircle,\n XCircle,\n Pencil,\n AlertTriangle,\n RefreshCw,\n Package,\n FileText,\n MessageSquare,\n Truck,\n UserPlus,\n Link2,\n Activity,\n ShoppingBag,\n} from 'lucide-react'\nimport type { ActionDetail, DiscrepancyDetail } from './types'\n\nconst ACTION_TYPE_ICONS: Record<string, React.ElementType> = {\n create_order: Package,\n create_quote: FileText,\n update_order: Package,\n update_shipment: Truck,\n create_contact: UserPlus,\n create_product: ShoppingBag,\n link_contact: Link2,\n log_activity: Activity,\n draft_reply: MessageSquare,\n}\n\nexport function useActionTypeLabels(): Record<string, string> {\n const t = useT()\n return {\n create_order: t('inbox_ops.action_type.create_order', 'Create Sales Order'),\n create_quote: t('inbox_ops.action_type.create_quote', 'Create Quote'),\n update_order: t('inbox_ops.action_type.update_order', 'Update Order'),\n update_shipment: t('inbox_ops.action_type.update_shipment', 'Update Shipment'),\n create_contact: t('inbox_ops.action_type.create_contact', 'Create Contact'),\n create_product: t('inbox_ops.action_type.create_product', 'Create Product'),\n link_contact: t('inbox_ops.action_type.link_contact', 'Link Contact'),\n log_activity: t('inbox_ops.action_type.log_activity', 'Log Activity'),\n draft_reply: t('inbox_ops.action_type.draft_reply', 'Draft Reply'),\n }\n}\n\nexport function ConfidenceBadge({ value }: { value: string }) {\n const num = parseFloat(value)\n const pct = Math.round(num * 100)\n const color = num >= 0.8 ? 'text-green-600' : num >= 0.6 ? 'text-yellow-600' : 'text-red-600'\n const bgColor = num >= 0.8 ? 'bg-green-200' : num >= 0.6 ? 'bg-yellow-200' : 'bg-red-200'\n const width = Math.round(num * 100)\n return (\n <div className=\"flex items-center gap-2\">\n <span className={`text-sm font-medium ${color}`}>{pct}%</span>\n <div className=\"w-24 h-2 bg-muted rounded-full overflow-hidden\">\n <div className={`h-full ${bgColor} rounded-full`} style={{ width: `${width}%` }} />\n </div>\n </div>\n )\n}\n\nfunction OrderPreview({ payload }: { payload: Record<string, unknown> }) {\n const t = useT()\n const lineItems = (payload.lineItems as Record<string, unknown>[]) || []\n const customerName = (payload.customerName as string) || ''\n const currencyCode = (payload.currencyCode as string) || ''\n const notes = (payload.notes as string) || ''\n const deliveryDate = (payload.requestedDeliveryDate as string) || ''\n\n return (\n <div className=\"mt-2 space-y-2 text-xs\">\n {customerName && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.customer', 'Customer')}:</span>\n <span>{customerName}</span>\n {typeof payload.customerEmail === 'string' && <span className=\"text-muted-foreground\">({payload.customerEmail})</span>}\n </div>\n )}\n {lineItems.length > 0 && (\n <div className=\"border rounded overflow-hidden\">\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"bg-muted/50\">\n <th className=\"text-left px-2 py-1 font-medium\">{t('inbox_ops.preview.product', 'Product')}</th>\n <th className=\"text-right px-2 py-1 font-medium\">{t('inbox_ops.preview.qty', 'Qty')}</th>\n <th className=\"text-right px-2 py-1 font-medium\">{t('inbox_ops.preview.price', 'Price')}</th>\n </tr>\n </thead>\n <tbody>\n {lineItems.map((item, index) => (\n <tr key={index} className=\"border-t\">\n <td className=\"px-2 py-1\">{(item.productName as string) || '\u2014'}</td>\n <td className=\"px-2 py-1 text-right\">{String(item.quantity ?? '')}</td>\n <td className=\"px-2 py-1 text-right\">{item.unitPrice ? `${item.unitPrice} ${currencyCode}` : '\u2014'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n {(deliveryDate || notes) && (\n <div className=\"flex flex-wrap gap-3\">\n {deliveryDate && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.delivery', 'Delivery')}:</span>\n <span>{deliveryDate}</span>\n </div>\n )}\n {notes && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.notes', 'Notes')}:</span>\n <span className=\"truncate max-w-[200px]\">{notes}</span>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction ProductPreview({ payload }: { payload: Record<string, unknown> }) {\n const t = useT()\n const title = (payload.title as string) || ''\n const sku = (payload.sku as string) || ''\n const unitPrice = (payload.unitPrice as string) || ''\n const currencyCode = (payload.currencyCode as string) || ''\n const kind = (payload.kind as string) || 'product'\n\n return (\n <div className=\"mt-2 space-y-1 text-xs\">\n {title && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.product_title', 'Title')}:</span>\n <span className=\"font-medium\">{title}</span>\n </div>\n )}\n <div className=\"flex flex-wrap gap-3\">\n {sku && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.sku', 'SKU')}:</span>\n <span>{sku}</span>\n </div>\n )}\n {unitPrice && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.price', 'Price')}:</span>\n <span>{unitPrice}{currencyCode ? ` ${currencyCode}` : ''}</span>\n </div>\n )}\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.edit_dialog.kind', 'Kind')}:</span>\n <span>{kind}</span>\n </div>\n </div>\n </div>\n )\n}\n\nexport function ActionCard({\n action,\n discrepancies,\n actionTypeLabels,\n onAccept,\n onReject,\n onRetry,\n onEdit,\n translatedDescription,\n}: {\n action: ActionDetail\n discrepancies: DiscrepancyDetail[]\n actionTypeLabels: Record<string, string>\n onAccept: (id: string) => void\n onReject: (id: string) => void\n onRetry: (id: string) => void\n onEdit: (action: ActionDetail) => void\n translatedDescription?: string\n}) {\n const t = useT()\n const Icon = ACTION_TYPE_ICONS[action.actionType] || Package\n const label = actionTypeLabels[action.actionType] || action.actionType\n\n const actionDiscrepancies = discrepancies.filter((d) => d.actionId === action.id && !d.resolved)\n const hasBlockingDiscrepancies = actionDiscrepancies.some((d) => d.severity === 'error')\n const displayDescription = translatedDescription || action.description\n\n if (action.status === 'executed') {\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-green-50 dark:bg-green-950/20\">\n <div className=\"flex items-center gap-2 mb-2\">\n <CheckCircle className=\"h-5 w-5 text-green-600 flex-shrink-0\" />\n <span className=\"text-sm font-medium\">{label}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{displayDescription}</p>\n {action.createdEntityId && (\n <div className=\"mt-2\">\n <span className=\"text-xs text-green-600\">\n Created {action.createdEntityType} \u00B7 {action.executedAt && new Date(action.executedAt).toLocaleString()}\n </span>\n </div>\n )}\n </div>\n )\n }\n\n if (action.status === 'rejected') {\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-muted/50 opacity-60\">\n <div className=\"flex items-center gap-2 mb-2\">\n <XCircle className=\"h-5 w-5 text-muted-foreground flex-shrink-0\" />\n <span className=\"text-sm font-medium line-through\">{label}</span>\n <span className=\"text-xs text-muted-foreground\">{t('inbox_ops.status.rejected', 'Rejected')}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{displayDescription}</p>\n </div>\n )\n }\n\n if (action.status === 'failed') {\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-red-50 dark:bg-red-950/20\">\n <div className=\"flex items-center gap-2 mb-2\">\n <AlertTriangle className=\"h-5 w-5 text-red-600 flex-shrink-0\" />\n <span className=\"text-sm font-medium\">{label}</span>\n <span className=\"text-xs text-red-600\">{t('inbox_ops.extraction_failed', 'Failed')}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{displayDescription}</p>\n {action.executionError && (\n <p className=\"text-xs text-red-600 mt-1\">{action.executionError}</p>\n )}\n <div className=\"mt-3 flex items-center gap-2\">\n <Button\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onRetry(action.id)}\n >\n <RefreshCw className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.retry', 'Retry')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onEdit(action)}\n >\n <Pencil className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.edit', 'Edit')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onReject(action.id)}\n >\n <XCircle className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.reject', 'Reject')}\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"border rounded-lg p-3 md:p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <Icon className=\"h-5 w-5 text-primary flex-shrink-0\" />\n <span className=\"text-sm font-medium\">{label}</span>\n <ConfidenceBadge value={action.confidence} />\n </div>\n <p className=\"text-sm text-foreground/80 mb-2\">{displayDescription}</p>\n\n {(action.actionType === 'create_order' || action.actionType === 'create_quote') && (\n <OrderPreview payload={action.payload} />\n )}\n\n {action.actionType === 'create_product' && (\n <ProductPreview payload={action.payload} />\n )}\n\n {actionDiscrepancies.length > 0 && (\n <div className=\"mb-3 space-y-1\">\n {actionDiscrepancies.map((d) => (\n <div key={d.id} className={`flex items-start gap-2 text-xs rounded px-2 py-1.5 ${\n d.severity === 'error' ? 'bg-red-50 text-red-700 dark:bg-red-950/20' : 'bg-yellow-50 text-yellow-700 dark:bg-yellow-950/20'\n }`}>\n <AlertTriangle className=\"h-3 w-3 mt-0.5 flex-shrink-0\" />\n <div>\n <span>{d.description}</span>\n {(d.expectedValue || d.foundValue) && (\n <div className=\"mt-0.5 text-[11px] opacity-80\">\n {d.expectedValue && <span>Expected: {d.expectedValue}</span>}\n {d.expectedValue && d.foundValue && <span> \u00B7 </span>}\n {d.foundValue && <span>Found: {d.foundValue}</span>}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div title={hasBlockingDiscrepancies ? t('inbox_ops.action.accept_blocked', 'Resolve errors before accepting') : undefined}>\n <Button\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onAccept(action.id)}\n disabled={hasBlockingDiscrepancies}\n >\n <CheckCircle className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.accept', 'Accept')}\n </Button>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onEdit(action)}\n >\n <Pencil className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.edit', 'Edit')}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onReject(action.id)}\n >\n <XCircle className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.reject', 'Reject')}\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n CheckCircle,\n XCircle,\n Pencil,\n AlertTriangle,\n RefreshCw,\n Package,\n FileText,\n MessageSquare,\n Truck,\n UserPlus,\n Link2,\n Activity,\n ShoppingBag,\n} from 'lucide-react'\nimport type { ActionDetail, DiscrepancyDetail } from './types'\nimport { hasContactNameIssue } from '../../lib/contactValidation'\n\nexport { hasContactNameIssue }\n\n/**\n * Resolves discrepancy description i18n keys stored in the database.\n * Falls back to the raw description string for legacy data or LLM-generated descriptions.\n */\nexport function useDiscrepancyDescriptions(): (description: string, foundValue?: string | null) => string {\n const t = useT()\n const translations: Record<string, string> = {\n 'inbox_ops.discrepancy.desc.no_channel': t('inbox_ops.discrepancy.desc.no_channel', 'No sales channel available. Create a channel in Sales settings before accepting this order.'),\n 'inbox_ops.discrepancy.desc.no_currency': t('inbox_ops.discrepancy.desc.no_currency', 'No currency could be resolved for this order. Set a currency code or configure a sales channel with a default currency.'),\n 'inbox_ops.discrepancy.desc.product_not_matched': t('inbox_ops.discrepancy.desc.product_not_matched', 'Product could not be matched to any catalog product'),\n 'inbox_ops.discrepancy.desc.no_matching_contact': t('inbox_ops.discrepancy.desc.no_matching_contact', 'No matching contact found'),\n 'inbox_ops.discrepancy.desc.draft_reply_no_contact': t('inbox_ops.discrepancy.desc.draft_reply_no_contact', 'Draft reply target has no matching contact. Create the contact first.'),\n 'inbox_ops.discrepancy.desc.duplicate_order_reference': t('inbox_ops.discrepancy.desc.duplicate_order_reference', 'An order with this customer reference already exists'),\n }\n return (description: string, foundValue?: string | null) => {\n const translated = translations[description]\n if (!translated) return description\n if (foundValue && (description === 'inbox_ops.discrepancy.desc.product_not_matched' || description === 'inbox_ops.discrepancy.desc.no_matching_contact')) {\n return `${translated}: ${foundValue}`\n }\n return translated\n }\n}\n\n/**\n * Resolves action description i18n keys stored in the database.\n * Auto-generated actions store keys like `inbox_ops.action.desc.create_contact`;\n * LLM-generated actions store plain text which is returned as-is.\n */\nexport function useActionDescriptionResolver(): (description: string, payload: Record<string, unknown>) => string {\n const t = useT()\n return (description: string, payload: Record<string, unknown>) => {\n if (!description.startsWith('inbox_ops.action.desc.')) return description\n const name = (payload.name as string) || (payload.contactName as string) || ''\n const email = (payload.email as string) || (payload.emailAddress as string) || ''\n const title = (payload.title as string) || ''\n const toName = (payload.toName as string) || (payload.to as string) || ''\n const subject = (payload.subject as string) || ''\n const translations: Record<string, string> = {\n 'inbox_ops.action.desc.create_contact': t('inbox_ops.action.desc.create_contact', 'Create contact for {name} ({email})')\n .replace('{name}', name).replace('{email}', email),\n 'inbox_ops.action.desc.link_contact': t('inbox_ops.action.desc.link_contact', 'Link {name} ({email}) to existing contact')\n .replace('{name}', name).replace('{email}', email),\n 'inbox_ops.action.desc.create_product': t('inbox_ops.action.desc.create_product', 'Create catalog product \"{title}\"')\n .replace('{title}', title),\n 'inbox_ops.action.desc.draft_reply': t('inbox_ops.action.desc.draft_reply', 'Draft reply to {toName}: {subject}')\n .replace('{toName}', toName).replace('{subject}', subject),\n }\n return translations[description] || description\n }\n}\n\nconst ACTION_TYPE_ICONS: Record<string, React.ElementType> = {\n create_order: Package,\n create_quote: FileText,\n update_order: Package,\n update_shipment: Truck,\n create_contact: UserPlus,\n create_product: ShoppingBag,\n link_contact: Link2,\n log_activity: Activity,\n draft_reply: MessageSquare,\n}\n\nexport function useActionTypeLabels(): Record<string, string> {\n const t = useT()\n return {\n create_order: t('inbox_ops.action_type.create_order', 'Create Sales Order'),\n create_quote: t('inbox_ops.action_type.create_quote', 'Create Quote'),\n update_order: t('inbox_ops.action_type.update_order', 'Update Order'),\n update_shipment: t('inbox_ops.action_type.update_shipment', 'Update Shipment'),\n create_contact: t('inbox_ops.action_type.create_contact', 'Create Contact'),\n create_product: t('inbox_ops.action_type.create_product', 'Create Product'),\n link_contact: t('inbox_ops.action_type.link_contact', 'Link Contact'),\n log_activity: t('inbox_ops.action_type.log_activity', 'Log Activity'),\n draft_reply: t('inbox_ops.action_type.draft_reply', 'Draft Reply'),\n }\n}\n\nexport function ConfidenceBadge({ value }: { value: string }) {\n const num = parseFloat(value)\n const pct = Math.round(num * 100)\n const color = num >= 0.8 ? 'text-green-600' : num >= 0.6 ? 'text-yellow-600' : 'text-red-600'\n const bgColor = num >= 0.8 ? 'bg-green-200' : num >= 0.6 ? 'bg-yellow-200' : 'bg-red-200'\n const width = Math.round(num * 100)\n return (\n <div className=\"flex items-center gap-2\">\n <span className={`text-sm font-medium ${color}`}>{pct}%</span>\n <div className=\"w-24 h-2 bg-muted rounded-full overflow-hidden\">\n <div className={`h-full ${bgColor} rounded-full`} style={{ width: `${width}%` }} />\n </div>\n </div>\n )\n}\n\nfunction OrderPreview({ payload }: { payload: Record<string, unknown> }) {\n const t = useT()\n const lineItems = (payload.lineItems as Record<string, unknown>[]) || []\n const customerName = (payload.customerName as string) || ''\n const currencyCode = (payload.currencyCode as string) || ''\n const notes = (payload.notes as string) || ''\n const deliveryDate = (payload.requestedDeliveryDate as string) || ''\n\n return (\n <div className=\"mt-2 space-y-2 text-xs\">\n {customerName && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.customer', 'Customer')}:</span>\n <span>{customerName}</span>\n {typeof payload.customerEmail === 'string' && <span className=\"text-muted-foreground\">({payload.customerEmail})</span>}\n </div>\n )}\n {lineItems.length > 0 && (\n <div className=\"border rounded overflow-hidden\">\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"bg-muted/50\">\n <th className=\"text-left px-2 py-1 font-medium\">{t('inbox_ops.preview.product', 'Product')}</th>\n <th className=\"text-right px-2 py-1 font-medium\">{t('inbox_ops.preview.qty', 'Qty')}</th>\n <th className=\"text-right px-2 py-1 font-medium\">{t('inbox_ops.preview.price', 'Price')}</th>\n </tr>\n </thead>\n <tbody>\n {lineItems.map((item, index) => (\n <tr key={index} className=\"border-t\">\n <td className=\"px-2 py-1\">{(item.productName as string) || '\u2014'}</td>\n <td className=\"px-2 py-1 text-right\">{String(item.quantity ?? '')}</td>\n <td className=\"px-2 py-1 text-right\">{item.unitPrice ? `${item.unitPrice} ${currencyCode}` : '\u2014'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n {(deliveryDate || notes) && (\n <div className=\"flex flex-wrap gap-3\">\n {deliveryDate && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.delivery', 'Delivery')}:</span>\n <span>{deliveryDate}</span>\n </div>\n )}\n {notes && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.notes', 'Notes')}:</span>\n <span className=\"truncate max-w-[200px]\">{notes}</span>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction ProductPreview({ payload }: { payload: Record<string, unknown> }) {\n const t = useT()\n const title = (payload.title as string) || ''\n const sku = (payload.sku as string) || ''\n const unitPrice = (payload.unitPrice as string) || ''\n const currencyCode = (payload.currencyCode as string) || ''\n const kind = (payload.kind as string) || 'product'\n\n return (\n <div className=\"mt-2 space-y-1 text-xs\">\n {title && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.product_title', 'Title')}:</span>\n <span className=\"font-medium\">{title}</span>\n </div>\n )}\n <div className=\"flex flex-wrap gap-3\">\n {sku && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.sku', 'SKU')}:</span>\n <span>{sku}</span>\n </div>\n )}\n {unitPrice && (\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.preview.price', 'Price')}:</span>\n <span>{unitPrice}{currencyCode ? ` ${currencyCode}` : ''}</span>\n </div>\n )}\n <div className=\"flex gap-1\">\n <span className=\"text-muted-foreground\">{t('inbox_ops.edit_dialog.kind', 'Kind')}:</span>\n <span>{kind}</span>\n </div>\n </div>\n </div>\n )\n}\n\nexport function ActionCard({\n action,\n discrepancies,\n actionTypeLabels,\n onAccept,\n onReject,\n onRetry,\n onEdit,\n translatedDescription,\n resolveDiscrepancyDescription,\n}: {\n action: ActionDetail\n discrepancies: DiscrepancyDetail[]\n actionTypeLabels: Record<string, string>\n onAccept: (id: string) => void\n onReject: (id: string) => void\n onRetry: (id: string) => void\n onEdit: (action: ActionDetail) => void\n translatedDescription?: string\n resolveDiscrepancyDescription?: (description: string, foundValue?: string | null) => string\n}) {\n const t = useT()\n const Icon = ACTION_TYPE_ICONS[action.actionType] || Package\n const label = actionTypeLabels[action.actionType] || action.actionType\n const resolveActionDescription = useActionDescriptionResolver()\n\n const actionDiscrepancies = discrepancies.filter((d) => d.actionId === action.id && !d.resolved)\n const hasBlockingDiscrepancies = actionDiscrepancies.some((d) => d.severity === 'error')\n const displayDescription = translatedDescription || resolveActionDescription(action.description, action.payload)\n\n if (action.status === 'executed') {\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-green-50 dark:bg-green-950/20\">\n <div className=\"flex items-center gap-2 mb-2\">\n <CheckCircle className=\"h-5 w-5 text-green-600 flex-shrink-0\" />\n <span className=\"text-sm font-medium\">{label}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{displayDescription}</p>\n {action.createdEntityId && (\n <div className=\"mt-2\">\n <span className=\"text-xs text-green-600\">\n {t('inbox_ops.action.created_entity', 'Created {type}').replace('{type}', action.createdEntityType || '')} \u00B7 {action.executedAt && new Date(action.executedAt).toLocaleString()}\n </span>\n </div>\n )}\n </div>\n )\n }\n\n if (action.status === 'rejected') {\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-muted/50 opacity-60\">\n <div className=\"flex items-center gap-2 mb-2\">\n <XCircle className=\"h-5 w-5 text-muted-foreground flex-shrink-0\" />\n <span className=\"text-sm font-medium line-through\">{label}</span>\n <span className=\"text-xs text-muted-foreground\">{t('inbox_ops.status.rejected', 'Rejected')}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{displayDescription}</p>\n </div>\n )\n }\n\n if (action.status === 'failed') {\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-red-50 dark:bg-red-950/20\">\n <div className=\"flex items-center gap-2 mb-2\">\n <AlertTriangle className=\"h-5 w-5 text-red-600 flex-shrink-0\" />\n <span className=\"text-sm font-medium\">{label}</span>\n <span className=\"text-xs text-red-600\">{t('inbox_ops.extraction_failed', 'Failed')}</span>\n </div>\n <p className=\"text-sm text-muted-foreground\">{displayDescription}</p>\n {action.executionError && (\n <p className=\"text-xs text-red-600 mt-1\">{action.executionError}</p>\n )}\n <div className=\"mt-3 flex items-center gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onRetry(action.id)}\n >\n <RefreshCw className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.retry', 'Retry')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onEdit(action)}\n >\n <Pencil className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.edit', 'Edit')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onReject(action.id)}\n >\n <XCircle className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.reject', 'Reject')}\n </Button>\n </div>\n </div>\n )\n }\n\n const hasNameIssue = hasContactNameIssue(action)\n\n return (\n <div className=\"border rounded-lg p-3 md:p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <Icon className=\"h-5 w-5 text-primary flex-shrink-0\" />\n <span className=\"text-sm font-medium\">{label}</span>\n <ConfidenceBadge value={action.confidence} />\n </div>\n <p className=\"text-sm text-foreground/80 mb-2\">{displayDescription}</p>\n\n {(action.actionType === 'create_order' || action.actionType === 'create_quote') && (\n <OrderPreview payload={action.payload} />\n )}\n\n {action.actionType === 'create_product' && (\n <ProductPreview payload={action.payload} />\n )}\n\n {actionDiscrepancies.length > 0 && (\n <div className=\"mb-3 space-y-1\">\n {actionDiscrepancies.map((d) => (\n <div key={d.id} className={`flex items-start gap-2 text-xs rounded px-2 py-1.5 ${\n d.severity === 'error' ? 'bg-red-50 text-red-700 dark:bg-red-950/20' : 'bg-yellow-50 text-yellow-700 dark:bg-yellow-950/20'\n }`}>\n <AlertTriangle className=\"h-3 w-3 mt-0.5 flex-shrink-0\" />\n <div>\n <span>{resolveDiscrepancyDescription ? resolveDiscrepancyDescription(d.description, d.foundValue) : d.description}</span>\n {(d.expectedValue || d.foundValue) && (\n <div className=\"mt-0.5 text-[11px] opacity-80\">\n {d.expectedValue && <span>{t('inbox_ops.discrepancy.expected', 'Expected')}: {d.expectedValue}</span>}\n {d.expectedValue && d.foundValue && <span> \u00B7 </span>}\n {d.foundValue && <span>{t('inbox_ops.discrepancy.found', 'Found')}: {d.foundValue}</span>}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {hasNameIssue && (\n <div className=\"mb-3 flex items-start gap-2 text-xs rounded px-2 py-1.5 bg-amber-50 text-amber-700 dark:bg-amber-950/20 dark:text-amber-300\">\n <AlertTriangle className=\"h-3 w-3 mt-0.5 flex-shrink-0\" />\n <span>{action.actionType === 'link_contact'\n ? t('inbox_ops.contact.link_name_missing_warning', 'Contact name is missing. Please edit and provide a name before accepting.')\n : t('inbox_ops.contact.name_missing_warning', 'First and last name could not be extracted. Please edit before accepting.')\n }</span>\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div title={\n hasNameIssue\n ? action.actionType === 'link_contact'\n ? t('inbox_ops.contact.link_name_missing_warning', 'Contact name is missing. Please edit and provide a name before accepting.')\n : t('inbox_ops.contact.name_missing_warning', 'First and last name could not be extracted. Please edit before accepting.')\n : hasBlockingDiscrepancies\n ? t('inbox_ops.action.accept_blocked', 'Resolve errors before accepting')\n : undefined\n }>\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onAccept(action.id)}\n disabled={hasBlockingDiscrepancies || hasNameIssue}\n >\n <CheckCircle className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.accept', 'Accept')}\n </Button>\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onEdit(action)}\n >\n <Pencil className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.edit', 'Edit')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9\"\n onClick={() => onReject(action.id)}\n >\n <XCircle className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.reject', 'Reject')}\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|