@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.
Files changed (211) hide show
  1. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +17 -2
  2. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  3. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
  4. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  5. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +30 -0
  6. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  7. package/dist/modules/catalog/inbox-actions.js +51 -0
  8. package/dist/modules/catalog/inbox-actions.js.map +7 -0
  9. package/dist/modules/catalog/lib/messageObjectPreviews.js +146 -0
  10. package/dist/modules/catalog/lib/messageObjectPreviews.js.map +7 -0
  11. package/dist/modules/catalog/message-objects.js +95 -0
  12. package/dist/modules/catalog/message-objects.js.map +7 -0
  13. package/dist/modules/currencies/backend/currencies/[id]/page.js +21 -0
  14. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  15. package/dist/modules/currencies/lib/messageObjectPreviews.js +51 -0
  16. package/dist/modules/currencies/lib/messageObjectPreviews.js.map +7 -0
  17. package/dist/modules/currencies/message-objects.js +41 -0
  18. package/dist/modules/currencies/message-objects.js.map +7 -0
  19. package/dist/modules/customers/backend/customers/companies/[id]/page.js +20 -0
  20. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  21. package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -1
  22. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  23. package/dist/modules/customers/backend/customers/people/[id]/page.js +20 -0
  24. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  25. package/dist/modules/customers/components/detail/CompanyHighlights.js +18 -14
  26. package/dist/modules/customers/components/detail/CompanyHighlights.js.map +2 -2
  27. package/dist/modules/customers/components/detail/PersonHighlights.js +18 -14
  28. package/dist/modules/customers/components/detail/PersonHighlights.js.map +2 -2
  29. package/dist/modules/customers/inbox-actions.js +230 -0
  30. package/dist/modules/customers/inbox-actions.js.map +7 -0
  31. package/dist/modules/customers/lib/messageObjectPreviews.js +41 -5
  32. package/dist/modules/customers/lib/messageObjectPreviews.js.map +2 -2
  33. package/dist/modules/customers/message-objects.js +31 -11
  34. package/dist/modules/customers/message-objects.js.map +2 -2
  35. package/dist/modules/inbox_ops/api/emails/[id]/route.js +40 -1
  36. package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
  37. package/dist/modules/inbox_ops/api/extract/route.js +87 -0
  38. package/dist/modules/inbox_ops/api/extract/route.js.map +7 -0
  39. package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js +6 -1
  40. package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js.map +2 -2
  41. package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
  42. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +40 -14
  43. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  44. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js +2 -2
  45. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js.map +2 -2
  46. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +161 -79
  47. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  48. package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js +2 -2
  49. package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js.map +2 -2
  50. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +109 -62
  51. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +3 -3
  52. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js +2 -2
  53. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js.map +2 -2
  54. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +36 -14
  55. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
  56. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js +2 -2
  57. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js.map +2 -2
  58. package/dist/modules/inbox_ops/components/proposals/ActionCard.js +65 -10
  59. package/dist/modules/inbox_ops/components/proposals/ActionCard.js.map +2 -2
  60. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +58 -10
  61. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  62. package/dist/modules/inbox_ops/lib/constants.js.map +2 -2
  63. package/dist/modules/inbox_ops/lib/contactValidation.js +40 -0
  64. package/dist/modules/inbox_ops/lib/contactValidation.js.map +7 -0
  65. package/dist/modules/inbox_ops/lib/executionEngine.js +31 -826
  66. package/dist/modules/inbox_ops/lib/executionEngine.js.map +3 -3
  67. package/dist/modules/inbox_ops/lib/executionHelpers.js +368 -0
  68. package/dist/modules/inbox_ops/lib/executionHelpers.js.map +7 -0
  69. package/dist/modules/inbox_ops/lib/extractionPrompt.js +28 -35
  70. package/dist/modules/inbox_ops/lib/extractionPrompt.js.map +3 -3
  71. package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js +1 -0
  72. package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js.map +7 -0
  73. package/dist/modules/inbox_ops/lib/translationProvider.js +15 -10
  74. package/dist/modules/inbox_ops/lib/translationProvider.js.map +2 -2
  75. package/dist/modules/inbox_ops/subscribers/extractionWorker.js +16 -16
  76. package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
  77. package/dist/modules/messages/commands/messages.js +3 -0
  78. package/dist/modules/messages/commands/messages.js.map +2 -2
  79. package/dist/modules/messages/components/message-detail/panels/objects-panel.js +6 -1
  80. package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +2 -2
  81. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +4 -1
  82. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
  83. package/dist/modules/messages/frontend/messages/view/[token]/page.js +1 -0
  84. package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +2 -2
  85. package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -7
  86. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  87. package/dist/modules/resources/lib/messageObjectPreviews.js +43 -0
  88. package/dist/modules/resources/lib/messageObjectPreviews.js.map +7 -0
  89. package/dist/modules/resources/message-objects.js +37 -0
  90. package/dist/modules/resources/message-objects.js.map +7 -0
  91. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +19 -0
  92. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  93. package/dist/modules/sales/backend/sales/documents/[id]/page.js +23 -2
  94. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  95. package/dist/modules/sales/backend/sales/quotes/[id]/page.js +1 -1
  96. package/dist/modules/sales/backend/sales/quotes/[id]/page.js.map +2 -2
  97. package/dist/modules/sales/inbox-actions.js +278 -0
  98. package/dist/modules/sales/inbox-actions.js.map +7 -0
  99. package/dist/modules/sales/lib/messageObjectPreviews.js +49 -4
  100. package/dist/modules/sales/lib/messageObjectPreviews.js.map +2 -2
  101. package/dist/modules/sales/message-objects.js +44 -2
  102. package/dist/modules/sales/message-objects.js.map +2 -2
  103. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +59 -30
  104. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +2 -2
  105. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +1 -1
  106. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +1 -1
  107. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +8 -30
  108. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  109. package/dist/modules/staff/backend/staff/my-availability/page.js +13 -0
  110. package/dist/modules/staff/backend/staff/my-availability/page.js.map +2 -2
  111. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +8 -31
  112. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  113. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +32 -10
  114. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  115. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +14 -1
  116. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  117. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -1
  118. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  119. package/dist/modules/staff/components/TeamForm.js +4 -2
  120. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  121. package/dist/modules/staff/components/TeamRoleForm.js +4 -2
  122. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  123. package/dist/modules/staff/lib/messageObjectPreviews.js +111 -2
  124. package/dist/modules/staff/lib/messageObjectPreviews.js.map +2 -2
  125. package/dist/modules/staff/message-objects.js +79 -8
  126. package/dist/modules/staff/message-objects.js.map +2 -2
  127. package/jest.config.cjs +1 -0
  128. package/jest.mocks/inbox-actions.generated.js +5 -0
  129. package/package.json +2 -2
  130. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +19 -5
  131. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +14 -0
  132. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +40 -0
  133. package/src/modules/catalog/inbox-actions.ts +60 -0
  134. package/src/modules/catalog/lib/messageObjectPreviews.ts +176 -0
  135. package/src/modules/catalog/message-objects.ts +102 -0
  136. package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -0
  137. package/src/modules/currencies/lib/messageObjectPreviews.ts +65 -0
  138. package/src/modules/currencies/message-objects.ts +40 -0
  139. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +19 -0
  140. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +13 -0
  141. package/src/modules/customers/backend/customers/people/[id]/page.tsx +19 -0
  142. package/src/modules/customers/components/detail/CompanyHighlights.tsx +14 -9
  143. package/src/modules/customers/components/detail/PersonHighlights.tsx +14 -9
  144. package/src/modules/customers/inbox-actions.ts +285 -0
  145. package/src/modules/customers/lib/messageObjectPreviews.ts +43 -3
  146. package/src/modules/customers/message-objects.ts +31 -11
  147. package/src/modules/inbox_ops/api/emails/[id]/route.ts +44 -0
  148. package/src/modules/inbox_ops/api/extract/route.ts +94 -0
  149. package/src/modules/inbox_ops/api/proposals/[id]/translate/route.ts +6 -1
  150. package/src/modules/inbox_ops/api/proposals/counts/route.ts +2 -0
  151. package/src/modules/inbox_ops/backend/inbox-ops/log/page.meta.ts +2 -2
  152. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +43 -13
  153. package/src/modules/inbox_ops/backend/inbox-ops/page.meta.ts +2 -2
  154. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +176 -81
  155. package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.ts +2 -2
  156. package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +122 -68
  157. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.meta.ts +2 -2
  158. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +36 -14
  159. package/src/modules/inbox_ops/components/proposals/ActionCard.tsx +91 -7
  160. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +64 -12
  161. package/src/modules/inbox_ops/lib/constants.ts +9 -0
  162. package/src/modules/inbox_ops/lib/contactValidation.ts +54 -0
  163. package/src/modules/inbox_ops/lib/executionEngine.ts +47 -1060
  164. package/src/modules/inbox_ops/lib/executionHelpers.ts +527 -0
  165. package/src/modules/inbox_ops/lib/extractionPrompt.ts +45 -34
  166. package/src/modules/inbox_ops/lib/inbox-actions-generated.d.ts +11 -0
  167. package/src/modules/inbox_ops/lib/translationProvider.ts +16 -10
  168. package/src/modules/inbox_ops/subscribers/extractionWorker.ts +16 -18
  169. package/src/modules/messages/commands/messages.ts +4 -0
  170. package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +8 -1
  171. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +3 -0
  172. package/src/modules/messages/frontend/messages/view/[token]/page.tsx +1 -0
  173. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +20 -4
  174. package/src/modules/resources/lib/messageObjectPreviews.ts +55 -0
  175. package/src/modules/resources/message-objects.ts +36 -0
  176. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +18 -0
  177. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -0
  178. package/src/modules/sales/backend/sales/quotes/[id]/page.tsx +1 -1
  179. package/src/modules/sales/inbox-actions.ts +359 -0
  180. package/src/modules/sales/lib/messageObjectPreviews.ts +54 -4
  181. package/src/modules/sales/message-objects.ts +44 -2
  182. package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +72 -34
  183. package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +1 -1
  184. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +7 -29
  185. package/src/modules/staff/backend/staff/my-availability/page.tsx +14 -0
  186. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +8 -30
  187. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +28 -7
  188. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +12 -0
  189. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +12 -0
  190. package/src/modules/staff/components/TeamForm.tsx +3 -0
  191. package/src/modules/staff/components/TeamRoleForm.tsx +3 -0
  192. package/src/modules/staff/lib/messageObjectPreviews.ts +133 -2
  193. package/src/modules/staff/message-objects.ts +79 -8
  194. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +0 -51
  195. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +0 -7
  196. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +0 -35
  197. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +0 -7
  198. package/dist/modules/customers/widgets/messages/index.js +0 -7
  199. package/dist/modules/customers/widgets/messages/index.js.map +0 -7
  200. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +0 -51
  201. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +0 -7
  202. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +0 -34
  203. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +0 -7
  204. package/dist/modules/staff/widgets/messages/index.js +0 -7
  205. package/dist/modules/staff/widgets/messages/index.js.map +0 -7
  206. package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +0 -57
  207. package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +0 -49
  208. package/src/modules/customers/widgets/messages/index.ts +0 -2
  209. package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +0 -57
  210. package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +0 -44
  211. package/src/modules/staff/widgets/messages/index.ts +0 -2
@@ -7,9 +7,10 @@ import { Page, PageBody } from "@open-mercato/ui/backend/Page";
7
7
  import { Button } from "@open-mercato/ui/primitives/button";
8
8
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
9
9
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
10
- import { LoadingMessage } from "@open-mercato/ui/backend/detail";
10
+ import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
11
11
  import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
12
12
  import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
13
+ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
13
14
  import {
14
15
  ArrowLeft,
15
16
  CheckCircle,
@@ -22,7 +23,8 @@ import {
22
23
  Users,
23
24
  Languages
24
25
  } from "lucide-react";
25
- import { ActionCard, ConfidenceBadge, useActionTypeLabels } from "../../../../components/proposals/ActionCard.js";
26
+ import { ActionCard, ConfidenceBadge, useActionTypeLabels, useDiscrepancyDescriptions } from "../../../../components/proposals/ActionCard.js";
27
+ import { hasContactNameIssue } from "../../../../lib/contactValidation.js";
26
28
  import { EditActionDialog } from "../../../../components/proposals/EditActionDialog.js";
27
29
  function EmailThreadViewer({ email }) {
28
30
  const t = useT();
@@ -52,9 +54,14 @@ function ProposalDetailPage({ params }) {
52
54
  const [discrepancies, setDiscrepancies] = React.useState([]);
53
55
  const [email, setEmail] = React.useState(null);
54
56
  const [isLoading, setIsLoading] = React.useState(true);
57
+ const [error, setError] = React.useState(null);
55
58
  const [isProcessing, setIsProcessing] = React.useState(false);
56
59
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
60
+ const { runMutation } = useGuardedMutation({
61
+ contextId: "inbox-ops-proposal-detail"
62
+ });
57
63
  const actionTypeLabels = useActionTypeLabels();
64
+ const resolveDiscrepancyDescription = useDiscrepancyDescriptions();
58
65
  const [editingAction, setEditingAction] = React.useState(null);
59
66
  const [sendingReplyId, setSendingReplyId] = React.useState(null);
60
67
  const [translation, setTranslation] = React.useState(null);
@@ -97,39 +104,53 @@ function ProposalDetailPage({ params }) {
97
104
  const handleTranslate = React.useCallback(async () => {
98
105
  if (!proposalId) return;
99
106
  setIsTranslating(true);
100
- const result = await apiCall(
101
- `/api/inbox_ops/proposals/${proposalId}/translate`,
102
- { method: "POST", body: JSON.stringify({ targetLocale: locale }) }
103
- );
107
+ const result = await runMutation({
108
+ operation: () => apiCall(
109
+ `/api/inbox_ops/proposals/${proposalId}/translate`,
110
+ { method: "POST", body: JSON.stringify({ targetLocale: locale }) }
111
+ ),
112
+ context: {}
113
+ });
104
114
  if (result?.ok && result.result?.translation) {
105
115
  setTranslation(result.result.translation);
106
116
  setShowTranslation(true);
107
117
  } else {
108
- flash(t("inbox_ops.translate.failed", "Translation failed"), "error");
118
+ const detail = result?.result?.error;
119
+ flash(detail ? `${t("inbox_ops.translate.failed", "Translation failed")}: ${detail}` : t("inbox_ops.translate.failed", "Translation failed"), "error");
109
120
  }
110
121
  setIsTranslating(false);
111
- }, [proposalId, locale, t]);
122
+ }, [proposalId, locale, t, runMutation]);
112
123
  const loadData = React.useCallback(async () => {
113
124
  if (!proposalId) return;
114
125
  setIsLoading(true);
115
- const result = await apiCall(`/api/inbox_ops/proposals/${proposalId}`);
116
- if (result?.ok && result.result) {
117
- setProposal(result.result.proposal);
118
- setActions(result.result.actions || []);
119
- setDiscrepancies(result.result.discrepancies || []);
120
- setEmail(result.result.email);
126
+ setError(null);
127
+ try {
128
+ const result = await apiCall(`/api/inbox_ops/proposals/${proposalId}`);
129
+ if (result?.ok && result.result) {
130
+ setProposal(result.result.proposal);
131
+ setActions(result.result.actions || []);
132
+ setDiscrepancies(result.result.discrepancies || []);
133
+ setEmail(result.result.email);
134
+ } else {
135
+ setError(t("inbox_ops.flash.load_failed", "Failed to load proposal"));
136
+ }
137
+ } catch {
138
+ setError(t("inbox_ops.flash.load_failed", "Failed to load proposal"));
121
139
  }
122
140
  setIsLoading(false);
123
- }, [proposalId]);
141
+ }, [proposalId, t]);
124
142
  React.useEffect(() => {
125
143
  loadData();
126
144
  }, [loadData]);
127
145
  const handleAcceptAction = React.useCallback(async (actionId) => {
128
146
  setIsProcessing(true);
129
- const result = await apiCall(
130
- `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/accept`,
131
- { method: "POST" }
132
- );
147
+ const result = await runMutation({
148
+ operation: () => apiCall(
149
+ `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/accept`,
150
+ { method: "POST" }
151
+ ),
152
+ context: {}
153
+ });
133
154
  if (result?.ok && result.result?.ok) {
134
155
  flash(t("inbox_ops.flash.action_executed", "Action executed"), "success");
135
156
  await loadData();
@@ -137,13 +158,16 @@ function ProposalDetailPage({ params }) {
137
158
  flash(result?.result?.error || t("inbox_ops.flash.action_execute_failed", "Failed to execute action"), "error");
138
159
  }
139
160
  setIsProcessing(false);
140
- }, [proposalId, loadData, t]);
161
+ }, [proposalId, loadData, t, runMutation]);
141
162
  const handleRejectAction = React.useCallback(async (actionId) => {
142
163
  setIsProcessing(true);
143
- const result = await apiCall(
144
- `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/reject`,
145
- { method: "POST" }
146
- );
164
+ const result = await runMutation({
165
+ operation: () => apiCall(
166
+ `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/reject`,
167
+ { method: "POST" }
168
+ ),
169
+ context: {}
170
+ });
147
171
  if (result?.ok && result.result?.ok) {
148
172
  flash(t("inbox_ops.flash.action_rejected", "Action rejected"), "success");
149
173
  await loadData();
@@ -151,27 +175,34 @@ function ProposalDetailPage({ params }) {
151
175
  flash(t("inbox_ops.flash.action_reject_failed", "Failed to reject action"), "error");
152
176
  }
153
177
  setIsProcessing(false);
154
- }, [proposalId, loadData]);
178
+ }, [proposalId, loadData, runMutation]);
155
179
  const handleAcceptAll = React.useCallback(async () => {
156
- const pendingCount = actions.filter((a) => a.status === "pending").length;
180
+ const pendingActions2 = actions.filter((a) => a.status === "pending");
181
+ const pendingCount = pendingActions2.length;
182
+ const nameIssueCount = pendingActions2.filter((a) => hasContactNameIssue(a)).length;
183
+ const confirmText = nameIssueCount > 0 ? t("inbox_ops.action.accept_all_confirm_with_skip", "Execute {count} pending actions? {skipCount} contact actions will be skipped due to missing names.").replace("{count}", String(pendingCount)).replace("{skipCount}", String(nameIssueCount)) : t("inbox_ops.action.accept_all_confirm", "Execute {count} pending actions?").replace("{count}", String(pendingCount));
157
184
  const confirmed = await confirm({
158
185
  title: t("inbox_ops.action.accept_all", "Accept All"),
159
- text: t("inbox_ops.action.accept_all_confirm", `Execute ${pendingCount} pending actions?`).replace("{count}", String(pendingCount))
186
+ text: confirmText
160
187
  });
161
188
  if (!confirmed) return;
162
189
  setIsProcessing(true);
163
- const result = await apiCall(
164
- `/api/inbox_ops/proposals/${proposalId}/accept-all`,
165
- { method: "POST" }
166
- );
190
+ const result = await runMutation({
191
+ operation: () => apiCall(
192
+ `/api/inbox_ops/proposals/${proposalId}/accept-all`,
193
+ { method: "POST" }
194
+ ),
195
+ context: {}
196
+ });
167
197
  if (result?.ok && result.result?.ok) {
168
- flash(t("inbox_ops.flash.accept_all_success", "{succeeded} actions executed").replace("{succeeded}", String(result.result.succeeded)) + (result.result.failed > 0 ? `, ${result.result.failed} failed` : ""), "success");
198
+ const msg = result.result.failed > 0 ? t("inbox_ops.flash.accept_all_partial", "{succeeded} actions executed, {failed} failed").replace("{succeeded}", String(result.result.succeeded)).replace("{failed}", String(result.result.failed)) : t("inbox_ops.flash.accept_all_success", "{succeeded} actions executed").replace("{succeeded}", String(result.result.succeeded));
199
+ flash(msg, "success");
169
200
  await loadData();
170
201
  } else {
171
202
  flash(t("inbox_ops.flash.accept_all_failed", "Failed to accept all actions"), "error");
172
203
  }
173
204
  setIsProcessing(false);
174
- }, [proposalId, actions, confirm, t, loadData]);
205
+ }, [proposalId, actions, confirm, t, loadData, runMutation]);
175
206
  const handleRejectAll = React.useCallback(async () => {
176
207
  const confirmed = await confirm({
177
208
  title: t("inbox_ops.action.reject_all", "Reject Proposal"),
@@ -179,35 +210,44 @@ function ProposalDetailPage({ params }) {
179
210
  });
180
211
  if (!confirmed) return;
181
212
  setIsProcessing(true);
182
- const result = await apiCall(
183
- `/api/inbox_ops/proposals/${proposalId}/reject`,
184
- { method: "POST" }
185
- );
213
+ const result = await runMutation({
214
+ operation: () => apiCall(
215
+ `/api/inbox_ops/proposals/${proposalId}/reject`,
216
+ { method: "POST" }
217
+ ),
218
+ context: {}
219
+ });
186
220
  if (result?.ok && result.result?.ok) {
187
221
  flash(t("inbox_ops.action.proposal_rejected", "Proposal rejected"), "success");
188
222
  await loadData();
189
223
  }
190
224
  setIsProcessing(false);
191
- }, [proposalId, confirm, t, loadData]);
225
+ }, [proposalId, confirm, t, loadData, runMutation]);
192
226
  const handleRetryExtraction = React.useCallback(async () => {
193
227
  if (!email) return;
194
228
  setIsProcessing(true);
195
- const result = await apiCall(
196
- `/api/inbox_ops/emails/${email.id}/reprocess`,
197
- { method: "POST" }
198
- );
229
+ const result = await runMutation({
230
+ operation: () => apiCall(
231
+ `/api/inbox_ops/emails/${email.id}/reprocess`,
232
+ { method: "POST" }
233
+ ),
234
+ context: {}
235
+ });
199
236
  if (result?.ok && result.result?.ok) {
200
237
  flash(t("inbox_ops.flash.reprocessing_started", "Reprocessing started"), "success");
201
238
  await loadData();
202
239
  }
203
240
  setIsProcessing(false);
204
- }, [email, loadData]);
241
+ }, [email, loadData, runMutation]);
205
242
  const handleSendReply = React.useCallback(async (actionId) => {
206
243
  setSendingReplyId(actionId);
207
- const result = await apiCall(
208
- `/api/inbox_ops/proposals/${proposalId}/replies/${actionId}/send`,
209
- { method: "POST" }
210
- );
244
+ const result = await runMutation({
245
+ operation: () => apiCall(
246
+ `/api/inbox_ops/proposals/${proposalId}/replies/${actionId}/send`,
247
+ { method: "POST" }
248
+ ),
249
+ context: {}
250
+ });
211
251
  if (result?.ok && result.result?.ok) {
212
252
  flash(t("inbox_ops.reply.sent_success", "Reply sent successfully"), "success");
213
253
  await loadData();
@@ -215,8 +255,9 @@ function ProposalDetailPage({ params }) {
215
255
  flash(result?.result?.error || t("inbox_ops.flash.send_reply_failed", "Failed to send reply"), "error");
216
256
  }
217
257
  setSendingReplyId(null);
218
- }, [proposalId, t, loadData]);
258
+ }, [proposalId, t, loadData, runMutation]);
219
259
  if (isLoading) return /* @__PURE__ */ jsx(LoadingMessage, { label: t("inbox_ops.loading_proposal", "Loading proposal...") });
260
+ if (error) return /* @__PURE__ */ jsx(ErrorMessage, { label: error });
220
261
  const pendingActions = actions.filter((a) => a.status === "pending");
221
262
  const emailIsProcessing = email?.status === "processing";
222
263
  const emailFailed = email?.status === "failed";
@@ -231,22 +272,23 @@ function ProposalDetailPage({ params }) {
231
272
  onSaved: loadData
232
273
  }
233
274
  ),
234
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-3 md:px-6 md:py-4 border-b", children: [
235
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
236
- /* @__PURE__ */ jsx(Link, { href: "/backend/inbox-ops", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }) }) }),
237
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
238
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold truncate", children: email?.subject || t("inbox_ops.proposal", "Proposal") }),
239
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
275
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 md:px-6 md:py-4 border-b bg-background", children: [
276
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 md:gap-3 min-w-0", children: [
277
+ /* @__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" }) }) }),
278
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
279
+ /* @__PURE__ */ jsx("h1", { className: "text-base md:text-lg font-semibold truncate", children: email?.subject || t("inbox_ops.proposal", "Proposal") }),
280
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground truncate", children: [
240
281
  email?.forwardedByName || email?.forwardedByAddress,
241
282
  " \xB7 ",
242
283
  email?.receivedAt && new Date(email.receivedAt).toLocaleString()
243
284
  ] })
244
285
  ] })
245
286
  ] }),
246
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
287
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
247
288
  pendingActions.length > 0 && /* @__PURE__ */ jsxs(
248
289
  Button,
249
290
  {
291
+ type: "button",
250
292
  variant: "outline",
251
293
  size: "sm",
252
294
  className: "h-11 md:h-9 text-destructive border-destructive/30 hover:bg-destructive/10",
@@ -258,7 +300,7 @@ function ProposalDetailPage({ params }) {
258
300
  ]
259
301
  }
260
302
  ),
261
- pendingActions.length > 1 && /* @__PURE__ */ jsxs(Button, { size: "sm", className: "h-11 md:h-9", onClick: handleAcceptAll, disabled: isProcessing, children: [
303
+ pendingActions.length > 1 && /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", className: "h-11 md:h-9", onClick: handleAcceptAll, disabled: isProcessing, children: [
262
304
  isProcessing ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin mr-1" }) : /* @__PURE__ */ jsx(CheckCheck, { className: "h-4 w-4 mr-1" }),
263
305
  /* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: t("inbox_ops.action.accept_all", "Accept All") })
264
306
  ] })
@@ -275,7 +317,7 @@ function ProposalDetailPage({ params }) {
275
317
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-red-700", children: t("inbox_ops.extraction_failed", "Extraction failed") })
276
318
  ] }),
277
319
  email?.processingError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600 mb-3", children: email.processingError }),
278
- /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "outline", onClick: handleRetryExtraction, disabled: isProcessing, children: [
320
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: handleRetryExtraction, disabled: isProcessing, children: [
279
321
  /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-1" }),
280
322
  t("inbox_ops.action.retry", "Retry")
281
323
  ] })
@@ -283,9 +325,10 @@ function ProposalDetailPage({ params }) {
283
325
  /* @__PURE__ */ jsxs("div", { className: "border rounded-lg p-3 md:p-4", children: [
284
326
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
285
327
  /* @__PURE__ */ jsx("h3", { className: "font-semibold text-sm", children: t("inbox_ops.summary", "Summary") }),
286
- proposal.workingLanguage && proposal.workingLanguage !== locale && /* @__PURE__ */ jsxs(
328
+ (proposal.workingLanguage || "en") !== locale && /* @__PURE__ */ jsxs(
287
329
  Button,
288
330
  {
331
+ type: "button",
289
332
  variant: "ghost",
290
333
  size: "sm",
291
334
  className: "h-8 text-xs",
@@ -333,15 +376,17 @@ function ProposalDetailPage({ params }) {
333
376
  /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: general.map((d) => /* @__PURE__ */ jsxs("div", { className: `flex items-start gap-2 text-xs rounded px-2 py-1.5 ${d.severity === "error" ? "bg-red-100 text-red-700 dark:bg-red-950/30" : "bg-yellow-100 text-yellow-700 dark:bg-yellow-950/30"}`, children: [
334
377
  /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3 mt-0.5 flex-shrink-0" }),
335
378
  /* @__PURE__ */ jsxs("div", { children: [
336
- /* @__PURE__ */ jsx("span", { children: d.description }),
379
+ /* @__PURE__ */ jsx("span", { children: resolveDiscrepancyDescription(d.description, d.foundValue) }),
337
380
  (d.expectedValue || d.foundValue) && /* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-[11px] opacity-80", children: [
338
381
  d.expectedValue && /* @__PURE__ */ jsxs("span", { children: [
339
- "Expected: ",
382
+ t("inbox_ops.discrepancy.expected", "Expected"),
383
+ ": ",
340
384
  d.expectedValue
341
385
  ] }),
342
386
  d.expectedValue && d.foundValue && /* @__PURE__ */ jsx("span", { children: " \xB7 " }),
343
387
  d.foundValue && /* @__PURE__ */ jsxs("span", { children: [
344
- "Found: ",
388
+ t("inbox_ops.discrepancy.found", "Found"),
389
+ ": ",
345
390
  d.foundValue
346
391
  ] })
347
392
  ] })
@@ -362,12 +407,14 @@ function ProposalDetailPage({ params }) {
362
407
  onReject: handleRejectAction,
363
408
  onRetry: handleAcceptAction,
364
409
  onEdit: handleEditAction,
365
- translatedDescription: showTranslation ? translation?.actions[action.id] : void 0
410
+ translatedDescription: showTranslation ? translation?.actions[action.id] : void 0,
411
+ resolveDiscrepancyDescription
366
412
  }
367
413
  ),
368
414
  action.actionType === "draft_reply" && (action.status === "executed" || action.status === "accepted") && /* @__PURE__ */ jsx("div", { className: "mt-2 pl-7", children: /* @__PURE__ */ jsxs(
369
415
  Button,
370
416
  {
417
+ type: "button",
371
418
  size: "sm",
372
419
  variant: "outline",
373
420
  className: "h-11 md:h-9",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/inbox_ops/backend/inbox-ops/proposals/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\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 } from '@open-mercato/ui/backend/detail'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n ArrowLeft,\n CheckCircle,\n XCircle,\n AlertTriangle,\n CheckCheck,\n Loader2,\n ExternalLink,\n RefreshCw,\n Users,\n Languages,\n} from 'lucide-react'\nimport type { ProposalTranslationEntry } from '../../../../data/entities'\nimport type { ProposalDetail, ActionDetail, DiscrepancyDetail, EmailDetail } from '../../../../components/proposals/types'\nimport { ActionCard, ConfidenceBadge, useActionTypeLabels } from '../../../../components/proposals/ActionCard'\nimport { EditActionDialog } from '../../../../components/proposals/EditActionDialog'\n\nfunction EmailThreadViewer({ email }: { email: EmailDetail | null }) {\n const t = useT()\n if (!email) return null\n\n const messages = email.threadMessages || []\n\n return (\n <div className=\"space-y-3\">\n <h3 className=\"font-semibold text-sm\">{t('inbox_ops.email_thread', 'Email Thread')}</h3>\n {messages.length > 0 ? (\n messages.map((msg, index) => (\n <div key={index} className=\"border rounded-lg p-3 md:p-4 bg-card\">\n <div className=\"flex items-center gap-2 mb-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">\n {msg.from?.name || msg.from?.email || t('inbox_ops.sender_unknown', 'Unknown')}\n </div>\n <div className=\"text-xs text-muted-foreground truncate\">{msg.from?.email}</div>\n </div>\n <span className=\"text-xs text-muted-foreground whitespace-nowrap\">\n {msg.date ? new Date(msg.date).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : ''}\n </span>\n </div>\n <div className=\"text-sm whitespace-pre-wrap text-foreground/80\">{msg.body}</div>\n </div>\n ))\n ) : email.cleanedText ? (\n <div className=\"border rounded-lg p-3 md:p-4 bg-card\">\n <div className=\"text-sm whitespace-pre-wrap text-foreground/80\">{email.cleanedText}</div>\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.no_email_content', 'No email content available')}</p>\n )}\n </div>\n )\n}\n\nexport default function ProposalDetailPage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const locale = useLocale()\n const router = useRouter()\n const proposalId = params?.id\n\n const [proposal, setProposal] = React.useState<ProposalDetail | null>(null)\n const [actions, setActions] = React.useState<ActionDetail[]>([])\n const [discrepancies, setDiscrepancies] = React.useState<DiscrepancyDetail[]>([])\n const [email, setEmail] = React.useState<EmailDetail | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [isProcessing, setIsProcessing] = React.useState(false)\n\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const actionTypeLabels = useActionTypeLabels()\n const [editingAction, setEditingAction] = React.useState<ActionDetail | null>(null)\n const [sendingReplyId, setSendingReplyId] = React.useState<string | null>(null)\n\n const [translation, setTranslation] = React.useState<ProposalTranslationEntry | null>(null)\n const [isTranslating, setIsTranslating] = React.useState(false)\n const [showTranslation, setShowTranslation] = React.useState(false)\n\n const handleEditAction = React.useCallback((action: ActionDetail) => {\n if (action.actionType === 'create_order' || action.actionType === 'create_quote') {\n const kind = action.actionType === 'create_order' ? 'order' : 'quote'\n try {\n sessionStorage.setItem(\n 'inbox_ops.orderDraft',\n JSON.stringify({\n actionId: action.id,\n proposalId: action.proposalId,\n payload: action.payload,\n }),\n )\n } catch { /* sessionStorage unavailable */ }\n router.push(`/backend/sales/documents/create?kind=${kind}&fromInboxAction=${encodeURIComponent(action.id)}`)\n return\n }\n if (action.actionType === 'create_product') {\n try {\n sessionStorage.setItem(\n 'inbox_ops.productDraft',\n JSON.stringify({\n actionId: action.id,\n proposalId: action.proposalId,\n payload: action.payload,\n }),\n )\n } catch { /* sessionStorage unavailable */ }\n router.push(`/backend/catalog/products/create?fromInboxAction=${encodeURIComponent(action.id)}`)\n return\n }\n setEditingAction(action)\n }, [router])\n\n const handleTranslate = React.useCallback(async () => {\n if (!proposalId) return\n setIsTranslating(true)\n const result = await apiCall<{ translation: ProposalTranslationEntry; cached: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/translate`,\n { method: 'POST', body: JSON.stringify({ targetLocale: locale }) },\n )\n if (result?.ok && result.result?.translation) {\n setTranslation(result.result.translation)\n setShowTranslation(true)\n } else {\n flash(t('inbox_ops.translate.failed', 'Translation failed'), 'error')\n }\n setIsTranslating(false)\n }, [proposalId, locale, t])\n\n const loadData = React.useCallback(async () => {\n if (!proposalId) return\n setIsLoading(true)\n const result = await apiCall<{\n proposal: ProposalDetail\n actions: ActionDetail[]\n discrepancies: DiscrepancyDetail[]\n email: EmailDetail\n }>(`/api/inbox_ops/proposals/${proposalId}`)\n if (result?.ok && result.result) {\n setProposal(result.result.proposal)\n setActions(result.result.actions || [])\n setDiscrepancies(result.result.discrepancies || [])\n setEmail(result.result.email)\n }\n setIsLoading(false)\n }, [proposalId])\n\n React.useEffect(() => { loadData() }, [loadData])\n\n const handleAcceptAction = React.useCallback(async (actionId: string) => {\n setIsProcessing(true)\n const result = await apiCall<{ ok: boolean; error?: string }>(\n `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/accept`,\n { method: 'POST' },\n )\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.action_executed', 'Action executed'), 'success')\n await loadData()\n } else {\n flash(result?.result?.error || t('inbox_ops.flash.action_execute_failed', 'Failed to execute action'), 'error')\n }\n setIsProcessing(false)\n }, [proposalId, loadData, t])\n\n const handleRejectAction = React.useCallback(async (actionId: string) => {\n setIsProcessing(true)\n const result = await apiCall<{ ok: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/reject`,\n { method: 'POST' },\n )\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.action_rejected', 'Action rejected'), 'success')\n await loadData()\n } else {\n flash(t('inbox_ops.flash.action_reject_failed', 'Failed to reject action'), 'error')\n }\n setIsProcessing(false)\n }, [proposalId, loadData])\n\n const handleAcceptAll = React.useCallback(async () => {\n const pendingCount = actions.filter((a) => a.status === 'pending').length\n const confirmed = await confirm({\n title: t('inbox_ops.action.accept_all', 'Accept All'),\n text: t('inbox_ops.action.accept_all_confirm', `Execute ${pendingCount} pending actions?`).replace('{count}', String(pendingCount)),\n })\n if (!confirmed) return\n\n setIsProcessing(true)\n const result = await apiCall<{ ok: boolean; succeeded: number; failed: number }>(\n `/api/inbox_ops/proposals/${proposalId}/accept-all`,\n { method: 'POST' },\n )\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.accept_all_success', '{succeeded} actions executed')\n .replace('{succeeded}', String(result.result.succeeded))\n + (result.result.failed > 0 ? `, ${result.result.failed} failed` : ''), 'success')\n await loadData()\n } else {\n flash(t('inbox_ops.flash.accept_all_failed', 'Failed to accept all actions'), 'error')\n }\n setIsProcessing(false)\n }, [proposalId, actions, confirm, t, loadData])\n\n const handleRejectAll = React.useCallback(async () => {\n const confirmed = await confirm({\n title: t('inbox_ops.action.reject_all', 'Reject Proposal'),\n text: t('inbox_ops.action.reject_all_confirm', 'Reject all pending actions in this proposal?'),\n })\n if (!confirmed) return\n\n setIsProcessing(true)\n const result = await apiCall<{ ok: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/reject`,\n { method: 'POST' },\n )\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.action.proposal_rejected', 'Proposal rejected'), 'success')\n await loadData()\n }\n setIsProcessing(false)\n }, [proposalId, confirm, t, loadData])\n\n const handleRetryExtraction = React.useCallback(async () => {\n if (!email) return\n setIsProcessing(true)\n const result = await apiCall<{ ok: boolean }>(\n `/api/inbox_ops/emails/${email.id}/reprocess`,\n { method: 'POST' },\n )\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.reprocessing_started', 'Reprocessing started'), 'success')\n await loadData()\n }\n setIsProcessing(false)\n }, [email, loadData])\n\n const handleSendReply = React.useCallback(async (actionId: string) => {\n setSendingReplyId(actionId)\n const result = await apiCall<{ ok: boolean; error?: string }>(\n `/api/inbox_ops/proposals/${proposalId}/replies/${actionId}/send`,\n { method: 'POST' },\n )\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.reply.sent_success', 'Reply sent successfully'), 'success')\n await loadData()\n } else {\n flash(result?.result?.error || t('inbox_ops.flash.send_reply_failed', 'Failed to send reply'), 'error')\n }\n setSendingReplyId(null)\n }, [proposalId, t, loadData])\n\n if (isLoading) return <LoadingMessage label={t('inbox_ops.loading_proposal', 'Loading proposal...')} />\n\n const pendingActions = actions.filter((a) => a.status === 'pending')\n const emailIsProcessing = email?.status === 'processing'\n const emailFailed = email?.status === 'failed'\n\n return (\n <Page>\n {ConfirmDialogElement}\n {editingAction && (\n <EditActionDialog\n action={editingAction}\n actionTypeLabels={actionTypeLabels}\n onClose={() => setEditingAction(null)}\n onSaved={loadData}\n />\n )}\n\n <div className=\"flex items-center justify-between px-3 py-3 md:px-6 md:py-4 border-b\">\n <div className=\"flex items-center gap-3\">\n <Link href=\"/backend/inbox-ops\">\n <Button variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n </Link>\n <div className=\"min-w-0\">\n <h1 className=\"text-lg font-semibold truncate\">{email?.subject || t('inbox_ops.proposal', 'Proposal')}</h1>\n <p className=\"text-xs text-muted-foreground\">\n {email?.forwardedByName || email?.forwardedByAddress} \u00B7 {email?.receivedAt && new Date(email.receivedAt).toLocaleString()}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {pendingActions.length > 0 && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9 text-destructive border-destructive/30 hover:bg-destructive/10\"\n onClick={handleRejectAll}\n disabled={isProcessing}\n >\n <XCircle className=\"h-4 w-4 mr-1\" />\n <span className=\"hidden md:inline\">{t('inbox_ops.action.reject_all', 'Reject Proposal')}</span>\n </Button>\n )}\n {pendingActions.length > 1 && (\n <Button size=\"sm\" className=\"h-11 md:h-9\" onClick={handleAcceptAll} disabled={isProcessing}>\n {isProcessing ? <Loader2 className=\"h-4 w-4 animate-spin mr-1\" /> : <CheckCheck className=\"h-4 w-4 mr-1\" />}\n <span className=\"hidden md:inline\">{t('inbox_ops.action.accept_all', 'Accept All')}</span>\n </Button>\n )}\n </div>\n </div>\n\n <PageBody>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6\">\n {/* Left panel: Email Thread */}\n <div>\n <EmailThreadViewer email={email} />\n </div>\n\n {/* Right panel: Summary + Actions */}\n <div className=\"space-y-4\">\n {emailIsProcessing ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary mb-3\" />\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.extraction_loading', 'AI is analyzing this thread...')}</p>\n </div>\n ) : emailFailed ? (\n <div className=\"border rounded-lg 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\" />\n <span className=\"text-sm font-medium text-red-700\">{t('inbox_ops.extraction_failed', 'Extraction failed')}</span>\n </div>\n {email?.processingError && (\n <p className=\"text-xs text-red-600 mb-3\">{email.processingError}</p>\n )}\n <Button size=\"sm\" variant=\"outline\" onClick={handleRetryExtraction} disabled={isProcessing}>\n <RefreshCw className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.retry', 'Retry')}\n </Button>\n </div>\n ) : proposal ? (\n <>\n {/* Summary */}\n <div className=\"border rounded-lg p-3 md:p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h3 className=\"font-semibold text-sm\">{t('inbox_ops.summary', 'Summary')}</h3>\n {proposal.workingLanguage && proposal.workingLanguage !== locale && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs\"\n onClick={showTranslation ? () => setShowTranslation(false) : handleTranslate}\n disabled={isTranslating}\n >\n {isTranslating ? (\n <Loader2 className=\"h-3 w-3 animate-spin mr-1\" />\n ) : (\n <Languages className=\"h-3 w-3 mr-1\" />\n )}\n {showTranslation\n ? t('inbox_ops.translate.show_original', 'Show original')\n : t('inbox_ops.translate.translate', 'Translate')}\n </Button>\n )}\n </div>\n <p className=\"text-sm text-foreground/80 mb-3\">\n {showTranslation && translation ? translation.summary : proposal.summary}\n </p>\n\n <div className=\"flex items-center gap-4 mb-3\">\n <div>\n <span className=\"text-xs text-muted-foreground\">{t('inbox_ops.confidence', 'Confidence')}</span>\n <ConfidenceBadge value={proposal.confidence} />\n </div>\n </div>\n\n {proposal.possiblyIncomplete && (\n <div className=\"flex items-center gap-2 text-xs text-yellow-600 bg-yellow-50 dark:bg-yellow-950/20 rounded px-2 py-1 mb-3\">\n <AlertTriangle className=\"h-3 w-3\" />\n {t('inbox_ops.possibly_incomplete', 'This thread appears to be a partial forward')}\n </div>\n )}\n\n {/* Participants */}\n {proposal.participants.length > 0 && (\n <div>\n <h4 className=\"text-xs font-medium text-muted-foreground mb-1\">{t('inbox_ops.participants', 'Participants')}</h4>\n <div className=\"space-y-1\">\n {proposal.participants.map((p, idx) => (\n <div key={idx} className=\"flex items-center gap-2 text-sm\">\n <Users className=\"h-3 w-3 text-muted-foreground\" />\n <span>{p.name}</span>\n <span className=\"text-xs text-muted-foreground\">({p.role})</span>\n {p.matchedContactId && <CheckCircle className=\"h-3 w-3 text-green-500\" />}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Discrepancies not tied to a specific action */}\n {(() => {\n const actionIds = new Set(actions.map((a) => a.id))\n const general = discrepancies.filter((d) => !d.resolved && (!d.actionId || !actionIds.has(d.actionId)))\n if (general.length === 0) return null\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-yellow-50 dark:bg-yellow-950/20\">\n <div className=\"flex items-center gap-2 mb-2\">\n <AlertTriangle className=\"h-4 w-4 text-yellow-600\" />\n <h3 className=\"font-semibold text-sm text-yellow-800 dark:text-yellow-300\">{t('inbox_ops.discrepancies', 'Issues Detected')}</h3>\n </div>\n <div className=\"space-y-1.5\">\n {general.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-100 text-red-700 dark:bg-red-950/30' : 'bg-yellow-100 text-yellow-700 dark:bg-yellow-950/30'\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 </div>\n )\n })()}\n\n {/* Actions */}\n <div>\n <h3 className=\"font-semibold text-sm mb-2\">{t('inbox_ops.actions', 'Proposed Actions')}</h3>\n {actions.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.no_actions', 'No actionable items detected in this thread')}</p>\n ) : (\n <div className=\"space-y-3\">\n {actions.map((action) => (\n <div key={action.id}>\n <ActionCard\n action={action}\n discrepancies={discrepancies}\n actionTypeLabels={actionTypeLabels}\n onAccept={handleAcceptAction}\n onReject={handleRejectAction}\n onRetry={handleAcceptAction}\n onEdit={handleEditAction}\n translatedDescription={showTranslation ? translation?.actions[action.id] : undefined}\n />\n {action.actionType === 'draft_reply' && (action.status === 'executed' || action.status === 'accepted') && (\n <div className=\"mt-2 pl-7\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-11 md:h-9\"\n disabled={sendingReplyId === action.id}\n onClick={() => handleSendReply(action.id)}\n >\n {sendingReplyId === action.id ? (\n <Loader2 className=\"h-4 w-4 animate-spin mr-1\" />\n ) : (\n <ExternalLink className=\"h-4 w-4 mr-1\" />\n )}\n {sendingReplyId === action.id\n ? t('inbox_ops.reply.sending', 'Sending...')\n : t('inbox_ops.reply.send', 'Send Reply')}\n </Button>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n </>\n ) : null}\n </div>\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\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, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport {\n ArrowLeft,\n CheckCircle,\n XCircle,\n AlertTriangle,\n CheckCheck,\n Loader2,\n ExternalLink,\n RefreshCw,\n Users,\n Languages,\n} from 'lucide-react'\nimport type { ProposalTranslationEntry } from '../../../../data/entities'\nimport type { ProposalDetail, ActionDetail, DiscrepancyDetail, EmailDetail } from '../../../../components/proposals/types'\nimport { ActionCard, ConfidenceBadge, useActionTypeLabels, useDiscrepancyDescriptions } from '../../../../components/proposals/ActionCard'\nimport { hasContactNameIssue } from '../../../../lib/contactValidation'\nimport { EditActionDialog } from '../../../../components/proposals/EditActionDialog'\n\nfunction EmailThreadViewer({ email }: { email: EmailDetail | null }) {\n const t = useT()\n if (!email) return null\n\n const messages = email.threadMessages || []\n\n return (\n <div className=\"space-y-3\">\n <h3 className=\"font-semibold text-sm\">{t('inbox_ops.email_thread', 'Email Thread')}</h3>\n {messages.length > 0 ? (\n messages.map((msg, index) => (\n <div key={index} className=\"border rounded-lg p-3 md:p-4 bg-card\">\n <div className=\"flex items-center gap-2 mb-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium truncate\">\n {msg.from?.name || msg.from?.email || t('inbox_ops.sender_unknown', 'Unknown')}\n </div>\n <div className=\"text-xs text-muted-foreground truncate\">{msg.from?.email}</div>\n </div>\n <span className=\"text-xs text-muted-foreground whitespace-nowrap\">\n {msg.date ? new Date(msg.date).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : ''}\n </span>\n </div>\n <div className=\"text-sm whitespace-pre-wrap text-foreground/80\">{msg.body}</div>\n </div>\n ))\n ) : email.cleanedText ? (\n <div className=\"border rounded-lg p-3 md:p-4 bg-card\">\n <div className=\"text-sm whitespace-pre-wrap text-foreground/80\">{email.cleanedText}</div>\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.no_email_content', 'No email content available')}</p>\n )}\n </div>\n )\n}\n\nexport default function ProposalDetailPage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const locale = useLocale()\n const router = useRouter()\n const proposalId = params?.id\n\n const [proposal, setProposal] = React.useState<ProposalDetail | null>(null)\n const [actions, setActions] = React.useState<ActionDetail[]>([])\n const [discrepancies, setDiscrepancies] = React.useState<DiscrepancyDetail[]>([])\n const [email, setEmail] = React.useState<EmailDetail | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isProcessing, setIsProcessing] = React.useState(false)\n\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-proposal-detail',\n })\n const actionTypeLabels = useActionTypeLabels()\n const resolveDiscrepancyDescription = useDiscrepancyDescriptions()\n const [editingAction, setEditingAction] = React.useState<ActionDetail | null>(null)\n const [sendingReplyId, setSendingReplyId] = React.useState<string | null>(null)\n\n const [translation, setTranslation] = React.useState<ProposalTranslationEntry | null>(null)\n const [isTranslating, setIsTranslating] = React.useState(false)\n const [showTranslation, setShowTranslation] = React.useState(false)\n\n const handleEditAction = React.useCallback((action: ActionDetail) => {\n if (action.actionType === 'create_order' || action.actionType === 'create_quote') {\n const kind = action.actionType === 'create_order' ? 'order' : 'quote'\n try {\n sessionStorage.setItem(\n 'inbox_ops.orderDraft',\n JSON.stringify({\n actionId: action.id,\n proposalId: action.proposalId,\n payload: action.payload,\n }),\n )\n } catch { /* sessionStorage unavailable */ }\n router.push(`/backend/sales/documents/create?kind=${kind}&fromInboxAction=${encodeURIComponent(action.id)}`)\n return\n }\n if (action.actionType === 'create_product') {\n try {\n sessionStorage.setItem(\n 'inbox_ops.productDraft',\n JSON.stringify({\n actionId: action.id,\n proposalId: action.proposalId,\n payload: action.payload,\n }),\n )\n } catch { /* sessionStorage unavailable */ }\n router.push(`/backend/catalog/products/create?fromInboxAction=${encodeURIComponent(action.id)}`)\n return\n }\n setEditingAction(action)\n }, [router])\n\n const handleTranslate = React.useCallback(async () => {\n if (!proposalId) return\n setIsTranslating(true)\n const result = await runMutation({\n operation: () => apiCall<{ translation: ProposalTranslationEntry; cached: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/translate`,\n { method: 'POST', body: JSON.stringify({ targetLocale: locale }) },\n ),\n context: {},\n })\n if (result?.ok && result.result?.translation) {\n setTranslation(result.result.translation)\n setShowTranslation(true)\n } else {\n const detail = (result?.result as Record<string, unknown> | null)?.error\n flash(detail ? `${t('inbox_ops.translate.failed', 'Translation failed')}: ${detail}` : t('inbox_ops.translate.failed', 'Translation failed'), 'error')\n }\n setIsTranslating(false)\n }, [proposalId, locale, t, runMutation])\n\n const loadData = React.useCallback(async () => {\n if (!proposalId) return\n setIsLoading(true)\n setError(null)\n try {\n const result = await apiCall<{\n proposal: ProposalDetail\n actions: ActionDetail[]\n discrepancies: DiscrepancyDetail[]\n email: EmailDetail\n }>(`/api/inbox_ops/proposals/${proposalId}`)\n if (result?.ok && result.result) {\n setProposal(result.result.proposal)\n setActions(result.result.actions || [])\n setDiscrepancies(result.result.discrepancies || [])\n setEmail(result.result.email)\n } else {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposal'))\n }\n } catch {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposal'))\n }\n setIsLoading(false)\n }, [proposalId, t])\n\n React.useEffect(() => { loadData() }, [loadData])\n\n const handleAcceptAction = React.useCallback(async (actionId: string) => {\n setIsProcessing(true)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; error?: string }>(\n `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/accept`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.action_executed', 'Action executed'), 'success')\n await loadData()\n } else {\n flash(result?.result?.error || t('inbox_ops.flash.action_execute_failed', 'Failed to execute action'), 'error')\n }\n setIsProcessing(false)\n }, [proposalId, loadData, t, runMutation])\n\n const handleRejectAction = React.useCallback(async (actionId: string) => {\n setIsProcessing(true)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/actions/${actionId}/reject`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.action_rejected', 'Action rejected'), 'success')\n await loadData()\n } else {\n flash(t('inbox_ops.flash.action_reject_failed', 'Failed to reject action'), 'error')\n }\n setIsProcessing(false)\n }, [proposalId, loadData, runMutation])\n\n const handleAcceptAll = React.useCallback(async () => {\n const pendingActions = actions.filter((a) => a.status === 'pending')\n const pendingCount = pendingActions.length\n const nameIssueCount = pendingActions.filter((a) => hasContactNameIssue(a)).length\n\n const confirmText = nameIssueCount > 0\n ? t('inbox_ops.action.accept_all_confirm_with_skip', 'Execute {count} pending actions? {skipCount} contact actions will be skipped due to missing names.')\n .replace('{count}', String(pendingCount))\n .replace('{skipCount}', String(nameIssueCount))\n : t('inbox_ops.action.accept_all_confirm', 'Execute {count} pending actions?').replace('{count}', String(pendingCount))\n\n const confirmed = await confirm({\n title: t('inbox_ops.action.accept_all', 'Accept All'),\n text: confirmText,\n })\n if (!confirmed) return\n\n setIsProcessing(true)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; succeeded: number; failed: number }>(\n `/api/inbox_ops/proposals/${proposalId}/accept-all`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n const msg = result.result.failed > 0\n ? t('inbox_ops.flash.accept_all_partial', '{succeeded} actions executed, {failed} failed')\n .replace('{succeeded}', String(result.result.succeeded))\n .replace('{failed}', String(result.result.failed))\n : t('inbox_ops.flash.accept_all_success', '{succeeded} actions executed')\n .replace('{succeeded}', String(result.result.succeeded))\n flash(msg, 'success')\n await loadData()\n } else {\n flash(t('inbox_ops.flash.accept_all_failed', 'Failed to accept all actions'), 'error')\n }\n setIsProcessing(false)\n }, [proposalId, actions, confirm, t, loadData, runMutation])\n\n const handleRejectAll = React.useCallback(async () => {\n const confirmed = await confirm({\n title: t('inbox_ops.action.reject_all', 'Reject Proposal'),\n text: t('inbox_ops.action.reject_all_confirm', 'Reject all pending actions in this proposal?'),\n })\n if (!confirmed) return\n\n setIsProcessing(true)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/reject`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.action.proposal_rejected', 'Proposal rejected'), 'success')\n await loadData()\n }\n setIsProcessing(false)\n }, [proposalId, confirm, t, loadData, runMutation])\n\n const handleRetryExtraction = React.useCallback(async () => {\n if (!email) return\n setIsProcessing(true)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean }>(\n `/api/inbox_ops/emails/${email.id}/reprocess`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.reprocessing_started', 'Reprocessing started'), 'success')\n await loadData()\n }\n setIsProcessing(false)\n }, [email, loadData, runMutation])\n\n const handleSendReply = React.useCallback(async (actionId: string) => {\n setSendingReplyId(actionId)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; error?: string }>(\n `/api/inbox_ops/proposals/${proposalId}/replies/${actionId}/send`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.reply.sent_success', 'Reply sent successfully'), 'success')\n await loadData()\n } else {\n flash(result?.result?.error || t('inbox_ops.flash.send_reply_failed', 'Failed to send reply'), 'error')\n }\n setSendingReplyId(null)\n }, [proposalId, t, loadData, runMutation])\n\n if (isLoading) return <LoadingMessage label={t('inbox_ops.loading_proposal', 'Loading proposal...')} />\n if (error) return <ErrorMessage label={error} />\n\n const pendingActions = actions.filter((a) => a.status === 'pending')\n const emailIsProcessing = email?.status === 'processing'\n const emailFailed = email?.status === 'failed'\n\n return (\n <Page>\n {ConfirmDialogElement}\n {editingAction && (\n <EditActionDialog\n action={editingAction}\n actionTypeLabels={actionTypeLabels}\n onClose={() => setEditingAction(null)}\n onSaved={loadData}\n />\n )}\n\n <div className=\"flex items-center justify-between px-4 py-3 md:px-6 md:py-4 border-b bg-background\">\n <div className=\"flex items-center gap-2 md:gap-3 min-w-0\">\n <Link href=\"/backend/inbox-ops\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n </Link>\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"text-base md:text-lg font-semibold truncate\">{email?.subject || t('inbox_ops.proposal', 'Proposal')}</h1>\n <p className=\"text-xs text-muted-foreground truncate\">\n {email?.forwardedByName || email?.forwardedByAddress} \u00B7 {email?.receivedAt && new Date(email.receivedAt).toLocaleString()}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n {pendingActions.length > 0 && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-9 text-destructive border-destructive/30 hover:bg-destructive/10\"\n onClick={handleRejectAll}\n disabled={isProcessing}\n >\n <XCircle className=\"h-4 w-4 mr-1\" />\n <span className=\"hidden md:inline\">{t('inbox_ops.action.reject_all', 'Reject Proposal')}</span>\n </Button>\n )}\n {pendingActions.length > 1 && (\n <Button type=\"button\" size=\"sm\" className=\"h-11 md:h-9\" onClick={handleAcceptAll} disabled={isProcessing}>\n {isProcessing ? <Loader2 className=\"h-4 w-4 animate-spin mr-1\" /> : <CheckCheck className=\"h-4 w-4 mr-1\" />}\n <span className=\"hidden md:inline\">{t('inbox_ops.action.accept_all', 'Accept All')}</span>\n </Button>\n )}\n </div>\n </div>\n\n <PageBody>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6\">\n {/* Left panel: Email Thread */}\n <div>\n <EmailThreadViewer email={email} />\n </div>\n\n {/* Right panel: Summary + Actions */}\n <div className=\"space-y-4\">\n {emailIsProcessing ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary mb-3\" />\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.extraction_loading', 'AI is analyzing this thread...')}</p>\n </div>\n ) : emailFailed ? (\n <div className=\"border rounded-lg 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\" />\n <span className=\"text-sm font-medium text-red-700\">{t('inbox_ops.extraction_failed', 'Extraction failed')}</span>\n </div>\n {email?.processingError && (\n <p className=\"text-xs text-red-600 mb-3\">{email.processingError}</p>\n )}\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={handleRetryExtraction} disabled={isProcessing}>\n <RefreshCw className=\"h-4 w-4 mr-1\" />\n {t('inbox_ops.action.retry', 'Retry')}\n </Button>\n </div>\n ) : proposal ? (\n <>\n {/* Summary */}\n <div className=\"border rounded-lg p-3 md:p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <h3 className=\"font-semibold text-sm\">{t('inbox_ops.summary', 'Summary')}</h3>\n {(proposal.workingLanguage || 'en') !== locale && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 text-xs\"\n onClick={showTranslation ? () => setShowTranslation(false) : handleTranslate}\n disabled={isTranslating}\n >\n {isTranslating ? (\n <Loader2 className=\"h-3 w-3 animate-spin mr-1\" />\n ) : (\n <Languages className=\"h-3 w-3 mr-1\" />\n )}\n {showTranslation\n ? t('inbox_ops.translate.show_original', 'Show original')\n : t('inbox_ops.translate.translate', 'Translate')}\n </Button>\n )}\n </div>\n <p className=\"text-sm text-foreground/80 mb-3\">\n {showTranslation && translation ? translation.summary : proposal.summary}\n </p>\n\n <div className=\"flex items-center gap-4 mb-3\">\n <div>\n <span className=\"text-xs text-muted-foreground\">{t('inbox_ops.confidence', 'Confidence')}</span>\n <ConfidenceBadge value={proposal.confidence} />\n </div>\n </div>\n\n {proposal.possiblyIncomplete && (\n <div className=\"flex items-center gap-2 text-xs text-yellow-600 bg-yellow-50 dark:bg-yellow-950/20 rounded px-2 py-1 mb-3\">\n <AlertTriangle className=\"h-3 w-3\" />\n {t('inbox_ops.possibly_incomplete', 'This thread appears to be a partial forward')}\n </div>\n )}\n\n {/* Participants */}\n {proposal.participants.length > 0 && (\n <div>\n <h4 className=\"text-xs font-medium text-muted-foreground mb-1\">{t('inbox_ops.participants', 'Participants')}</h4>\n <div className=\"space-y-1\">\n {proposal.participants.map((p, idx) => (\n <div key={idx} className=\"flex items-center gap-2 text-sm\">\n <Users className=\"h-3 w-3 text-muted-foreground\" />\n <span>{p.name}</span>\n <span className=\"text-xs text-muted-foreground\">({p.role})</span>\n {p.matchedContactId && <CheckCircle className=\"h-3 w-3 text-green-500\" />}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Discrepancies not tied to a specific action */}\n {(() => {\n const actionIds = new Set(actions.map((a) => a.id))\n const general = discrepancies.filter((d) => !d.resolved && (!d.actionId || !actionIds.has(d.actionId)))\n if (general.length === 0) return null\n return (\n <div className=\"border rounded-lg p-3 md:p-4 bg-yellow-50 dark:bg-yellow-950/20\">\n <div className=\"flex items-center gap-2 mb-2\">\n <AlertTriangle className=\"h-4 w-4 text-yellow-600\" />\n <h3 className=\"font-semibold text-sm text-yellow-800 dark:text-yellow-300\">{t('inbox_ops.discrepancies', 'Issues Detected')}</h3>\n </div>\n <div className=\"space-y-1.5\">\n {general.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-100 text-red-700 dark:bg-red-950/30' : 'bg-yellow-100 text-yellow-700 dark:bg-yellow-950/30'\n }`}>\n <AlertTriangle className=\"h-3 w-3 mt-0.5 flex-shrink-0\" />\n <div>\n <span>{resolveDiscrepancyDescription(d.description, d.foundValue)}</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 </div>\n )\n })()}\n\n {/* Actions */}\n <div>\n <h3 className=\"font-semibold text-sm mb-2\">{t('inbox_ops.actions', 'Proposed Actions')}</h3>\n {actions.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('inbox_ops.no_actions', 'No actionable items detected in this thread')}</p>\n ) : (\n <div className=\"space-y-3\">\n {actions.map((action) => (\n <div key={action.id}>\n <ActionCard\n action={action}\n discrepancies={discrepancies}\n actionTypeLabels={actionTypeLabels}\n onAccept={handleAcceptAction}\n onReject={handleRejectAction}\n onRetry={handleAcceptAction}\n onEdit={handleEditAction}\n translatedDescription={showTranslation ? translation?.actions[action.id] : undefined}\n resolveDiscrepancyDescription={resolveDiscrepancyDescription}\n />\n {action.actionType === 'draft_reply' && (action.status === 'executed' || action.status === 'accepted') && (\n <div className=\"mt-2 pl-7\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-11 md:h-9\"\n disabled={sendingReplyId === action.id}\n onClick={() => handleSendReply(action.id)}\n >\n {sendingReplyId === action.id ? (\n <Loader2 className=\"h-4 w-4 animate-spin mr-1\" />\n ) : (\n <ExternalLink className=\"h-4 w-4 mr-1\" />\n )}\n {sendingReplyId === action.id\n ? t('inbox_ops.reply.sending', 'Sending...')\n : t('inbox_ops.reply.send', 'Send Reply')}\n </Button>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n </>\n ) : null}\n </div>\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["pendingActions"]
7
7
  }
@@ -3,11 +3,11 @@ const metadata = {
3
3
  requireFeatures: ["inbox_ops.proposals.view"],
4
4
  pageTitle: "Proposal",
5
5
  pageTitleKey: "inbox_ops.nav.proposal_detail",
6
- pageGroup: "InboxOps",
6
+ pageGroup: "AI Inbox Actions",
7
7
  pageGroupKey: "inbox_ops.nav.group",
8
8
  navHidden: true,
9
9
  breadcrumb: [
10
- { label: "InboxOps", labelKey: "inbox_ops.nav.group", href: "/backend/inbox-ops" },
10
+ { label: "AI Inbox Actions", labelKey: "inbox_ops.nav.group", href: "/backend/inbox-ops" },
11
11
  { label: "Proposal", labelKey: "inbox_ops.nav.proposal_detail" }
12
12
  ]
13
13
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/inbox_ops/backend/inbox-ops/proposals/%5Bid%5D/page.meta.ts"],
4
- "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.proposals.view'],\n pageTitle: 'Proposal',\n pageTitleKey: 'inbox_ops.nav.proposal_detail',\n pageGroup: 'InboxOps',\n pageGroupKey: 'inbox_ops.nav.group',\n navHidden: true,\n breadcrumb: [\n { label: 'InboxOps', labelKey: 'inbox_ops.nav.group', href: '/backend/inbox-ops' },\n { label: 'Proposal', labelKey: 'inbox_ops.nav.proposal_detail' },\n ],\n}\n"],
5
- "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,0BAA0B;AAAA,EAC5C,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,YAAY,UAAU,uBAAuB,MAAM,qBAAqB;AAAA,IACjF,EAAE,OAAO,YAAY,UAAU,gCAAgC;AAAA,EACjE;AACF;",
4
+ "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.proposals.view'],\n pageTitle: 'Proposal',\n pageTitleKey: 'inbox_ops.nav.proposal_detail',\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: 'Proposal', labelKey: 'inbox_ops.nav.proposal_detail' },\n ],\n}\n"],
5
+ "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,0BAA0B;AAAA,EAC5C,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,gCAAgC;AAAA,EACjE;AACF;",
6
6
  "names": []
7
7
  }