@open-mercato/core 0.4.8-develop-15259be22b → 0.4.8-develop-280c02b529

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 (110) hide show
  1. package/dist/generated/entities/inbox_proposal/index.js +2 -0
  2. package/dist/generated/entities/inbox_proposal/index.js.map +2 -2
  3. package/dist/modules/catalog/inbox-actions.js +49 -0
  4. package/dist/modules/catalog/inbox-actions.js.map +2 -2
  5. package/dist/modules/customers/inbox-actions.js +69 -27
  6. package/dist/modules/customers/inbox-actions.js.map +3 -3
  7. package/dist/modules/inbox_ops/ai-tools.js +346 -0
  8. package/dist/modules/inbox_ops/ai-tools.js.map +7 -0
  9. package/dist/modules/inbox_ops/api/extract/route.js +3 -2
  10. package/dist/modules/inbox_ops/api/extract/route.js.map +2 -2
  11. package/dist/modules/inbox_ops/api/proposals/[id]/accept-all/route.js +4 -0
  12. package/dist/modules/inbox_ops/api/proposals/[id]/accept-all/route.js.map +2 -2
  13. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/accept/route.js +4 -0
  14. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/accept/route.js.map +2 -2
  15. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/complete/route.js +4 -0
  16. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/complete/route.js.map +2 -2
  17. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/reject/route.js +4 -0
  18. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/reject/route.js.map +2 -2
  19. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js +4 -0
  20. package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js.map +2 -2
  21. package/dist/modules/inbox_ops/api/proposals/[id]/categorize/route.js +59 -0
  22. package/dist/modules/inbox_ops/api/proposals/[id]/categorize/route.js.map +7 -0
  23. package/dist/modules/inbox_ops/api/proposals/[id]/reject/route.js +4 -0
  24. package/dist/modules/inbox_ops/api/proposals/[id]/reject/route.js.map +2 -2
  25. package/dist/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.js +34 -14
  26. package/dist/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.js.map +2 -2
  27. package/dist/modules/inbox_ops/api/proposals/counts/route.js +49 -4
  28. package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
  29. package/dist/modules/inbox_ops/api/proposals/route.js +13 -0
  30. package/dist/modules/inbox_ops/api/proposals/route.js.map +2 -2
  31. package/dist/modules/inbox_ops/api/settings/route.js +33 -2
  32. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  33. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +28 -3
  34. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  35. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +103 -5
  36. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +2 -2
  37. package/dist/modules/inbox_ops/components/messages/InboxEmailContent.js +24 -0
  38. package/dist/modules/inbox_ops/components/messages/InboxEmailContent.js.map +7 -0
  39. package/dist/modules/inbox_ops/components/messages/InboxEmailPreview.js +29 -0
  40. package/dist/modules/inbox_ops/components/messages/InboxEmailPreview.js.map +7 -0
  41. package/dist/modules/inbox_ops/components/proposals/CategoryBadge.js +59 -0
  42. package/dist/modules/inbox_ops/components/proposals/CategoryBadge.js.map +7 -0
  43. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +3 -1
  44. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  45. package/dist/modules/inbox_ops/data/entities.js +4 -0
  46. package/dist/modules/inbox_ops/data/entities.js.map +2 -2
  47. package/dist/modules/inbox_ops/data/validators.js +30 -5
  48. package/dist/modules/inbox_ops/data/validators.js.map +2 -2
  49. package/dist/modules/inbox_ops/lib/cache.js +53 -0
  50. package/dist/modules/inbox_ops/lib/cache.js.map +7 -0
  51. package/dist/modules/inbox_ops/lib/contactValidation.js +38 -3
  52. package/dist/modules/inbox_ops/lib/contactValidation.js.map +2 -2
  53. package/dist/modules/inbox_ops/lib/executionHelpers.js +28 -1
  54. package/dist/modules/inbox_ops/lib/executionHelpers.js.map +2 -2
  55. package/dist/modules/inbox_ops/lib/extractionPrompt.js +2 -1
  56. package/dist/modules/inbox_ops/lib/extractionPrompt.js.map +2 -2
  57. package/dist/modules/inbox_ops/lib/messageObjectPreviews.js +52 -0
  58. package/dist/modules/inbox_ops/lib/messageObjectPreviews.js.map +7 -0
  59. package/dist/modules/inbox_ops/lib/messagesIntegration.js +155 -0
  60. package/dist/modules/inbox_ops/lib/messagesIntegration.js.map +7 -0
  61. package/dist/modules/inbox_ops/message-objects.js +36 -0
  62. package/dist/modules/inbox_ops/message-objects.js.map +7 -0
  63. package/dist/modules/inbox_ops/message-types.js +38 -0
  64. package/dist/modules/inbox_ops/message-types.js.map +7 -0
  65. package/dist/modules/inbox_ops/migrations/Migration20260303173020.js +13 -0
  66. package/dist/modules/inbox_ops/migrations/Migration20260303173020.js.map +7 -0
  67. package/dist/modules/inbox_ops/migrations/Migration20260303173215.js +15 -0
  68. package/dist/modules/inbox_ops/migrations/Migration20260303173215.js.map +7 -0
  69. package/dist/modules/inbox_ops/search.js +5 -3
  70. package/dist/modules/inbox_ops/search.js.map +2 -2
  71. package/dist/modules/inbox_ops/subscribers/extractionWorker.js +65 -3
  72. package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
  73. package/generated/entities/inbox_proposal/index.ts +1 -0
  74. package/package.json +3 -3
  75. package/src/modules/catalog/inbox-actions.ts +55 -0
  76. package/src/modules/customers/inbox-actions.ts +86 -27
  77. package/src/modules/inbox_ops/ai-tools.ts +451 -0
  78. package/src/modules/inbox_ops/api/extract/route.ts +3 -2
  79. package/src/modules/inbox_ops/api/proposals/[id]/accept-all/route.ts +5 -0
  80. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/accept/route.ts +5 -0
  81. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/complete/route.ts +5 -0
  82. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/reject/route.ts +5 -0
  83. package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.ts +5 -0
  84. package/src/modules/inbox_ops/api/proposals/[id]/categorize/route.ts +61 -0
  85. package/src/modules/inbox_ops/api/proposals/[id]/reject/route.ts +5 -0
  86. package/src/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.ts +36 -16
  87. package/src/modules/inbox_ops/api/proposals/counts/route.ts +60 -5
  88. package/src/modules/inbox_ops/api/proposals/route.ts +14 -1
  89. package/src/modules/inbox_ops/api/settings/route.ts +36 -2
  90. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +31 -3
  91. package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +103 -1
  92. package/src/modules/inbox_ops/components/messages/InboxEmailContent.tsx +45 -0
  93. package/src/modules/inbox_ops/components/messages/InboxEmailPreview.tsx +40 -0
  94. package/src/modules/inbox_ops/components/proposals/CategoryBadge.tsx +59 -0
  95. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +3 -1
  96. package/src/modules/inbox_ops/components/proposals/types.ts +1 -0
  97. package/src/modules/inbox_ops/data/entities.ts +14 -1
  98. package/src/modules/inbox_ops/data/validators.ts +41 -5
  99. package/src/modules/inbox_ops/lib/cache.ts +60 -0
  100. package/src/modules/inbox_ops/lib/contactValidation.ts +31 -2
  101. package/src/modules/inbox_ops/lib/executionHelpers.ts +40 -0
  102. package/src/modules/inbox_ops/lib/extractionPrompt.ts +2 -1
  103. package/src/modules/inbox_ops/lib/messageObjectPreviews.ts +61 -0
  104. package/src/modules/inbox_ops/lib/messagesIntegration.ts +231 -0
  105. package/src/modules/inbox_ops/message-objects.ts +34 -0
  106. package/src/modules/inbox_ops/message-types.ts +36 -0
  107. package/src/modules/inbox_ops/migrations/Migration20260303173020.ts +13 -0
  108. package/src/modules/inbox_ops/migrations/Migration20260303173215.ts +15 -0
  109. package/src/modules/inbox_ops/search.ts +5 -3
  110. package/src/modules/inbox_ops/subscribers/extractionWorker.ts +75 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/inbox_ops/api/settings/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { InboxSettings } from '../../data/entities'\nimport { updateSettingsSchema } from '../../data/validators'\nimport { resolveRequestContext, handleRouteError } from '../routeHelpers'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['inbox_ops.settings.manage'] },\n PATCH: { requireAuth: true, requireFeatures: ['inbox_ops.settings.manage'] },\n}\n\nexport async function GET(req: Request) {\n try {\n const ctx = await resolveRequestContext(req)\n\n const settings = await findOneWithDecryption(\n ctx.em,\n InboxSettings,\n {\n organizationId: ctx.organizationId,\n tenantId: ctx.tenantId,\n deletedAt: null,\n },\n undefined,\n ctx.scope,\n )\n\n return NextResponse.json({\n settings: settings ? {\n id: settings.id,\n inboxAddress: settings.inboxAddress,\n isActive: settings.isActive,\n workingLanguage: settings.workingLanguage,\n } : null,\n })\n } catch (err) {\n return handleRouteError(err, 'load settings')\n }\n}\n\nexport async function PATCH(req: Request) {\n try {\n const ctx = await resolveRequestContext(req)\n\n const body = await req.json()\n const parsed = updateSettingsSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request', details: parsed.error.issues }, { status: 400 })\n }\n\n const settings = await findOneWithDecryption(\n ctx.em,\n InboxSettings,\n {\n organizationId: ctx.organizationId,\n tenantId: ctx.tenantId,\n deletedAt: null,\n },\n undefined,\n ctx.scope,\n )\n\n if (!settings) {\n return NextResponse.json({ error: 'Settings not found' }, { status: 404 })\n }\n\n if (parsed.data.workingLanguage !== undefined) {\n settings.workingLanguage = parsed.data.workingLanguage\n }\n if (parsed.data.isActive !== undefined) {\n settings.isActive = parsed.data.isActive\n }\n\n await ctx.em.flush()\n\n return NextResponse.json({\n ok: true,\n settings: {\n id: settings.id,\n inboxAddress: settings.inboxAddress,\n isActive: settings.isActive,\n workingLanguage: settings.workingLanguage,\n },\n })\n } catch (err) {\n return handleRouteError(err, 'update settings')\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'InboxOps',\n summary: 'Settings',\n methods: {\n GET: {\n summary: 'Get tenant inbox configuration',\n description: 'Returns the forwarding address and configuration for this tenant',\n responses: [\n { status: 200, description: 'Inbox settings' },\n ],\n },\n PATCH: {\n summary: 'Update tenant inbox configuration',\n description: 'Updates working language and/or active status',\n responses: [\n { status: 200, description: 'Updated settings' },\n { status: 404, description: 'Settings not found' },\n ],\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,uBAAuB,wBAAwB;AAEjD,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,2BAA2B,EAAE;AAAA,EACzE,OAAO,EAAE,aAAa,MAAM,iBAAiB,CAAC,2BAA2B,EAAE;AAC7E;AAEA,eAAsB,IAAI,KAAc;AACtC,MAAI;AACF,UAAM,MAAM,MAAM,sBAAsB,GAAG;AAE3C,UAAM,WAAW,MAAM;AAAA,MACrB,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,QACE,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,QACd,WAAW;AAAA,MACb;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAEA,WAAO,aAAa,KAAK;AAAA,MACvB,UAAU,WAAW;AAAA,QACnB,IAAI,SAAS;AAAA,QACb,cAAc,SAAS;AAAA,QACvB,UAAU,SAAS;AAAA,QACnB,iBAAiB,SAAS;AAAA,MAC5B,IAAI;AAAA,IACN,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,iBAAiB,KAAK,eAAe;AAAA,EAC9C;AACF;AAEA,eAAsB,MAAM,KAAc;AACxC,MAAI;AACF,UAAM,MAAM,MAAM,sBAAsB,GAAG;AAE3C,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,SAAS,qBAAqB,UAAU,IAAI;AAClD,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,aAAa,KAAK,EAAE,OAAO,mBAAmB,SAAS,OAAO,MAAM,OAAO,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACtG;AAEA,UAAM,WAAW,MAAM;AAAA,MACrB,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,QACE,gBAAgB,IAAI;AAAA,QACpB,UAAU,IAAI;AAAA,QACd,WAAW;AAAA,MACb;AAAA,MACA;AAAA,MACA,IAAI;AAAA,IACN;AAEA,QAAI,CAAC,UAAU;AACb,aAAO,aAAa,KAAK,EAAE,OAAO,qBAAqB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC3E;AAEA,QAAI,OAAO,KAAK,oBAAoB,QAAW;AAC7C,eAAS,kBAAkB,OAAO,KAAK;AAAA,IACzC;AACA,QAAI,OAAO,KAAK,aAAa,QAAW;AACtC,eAAS,WAAW,OAAO,KAAK;AAAA,IAClC;AAEA,UAAM,IAAI,GAAG,MAAM;AAEnB,WAAO,aAAa,KAAK;AAAA,MACvB,IAAI;AAAA,MACJ,UAAU;AAAA,QACR,IAAI,SAAS;AAAA,QACb,cAAc,SAAS;AAAA,QACvB,UAAU,SAAS;AAAA,QACnB,iBAAiB,SAAS;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,iBAAiB,KAAK,iBAAiB;AAAA,EAChD;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,iBAAiB;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa;AAAA,MACb,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,mBAAmB;AAAA,QAC/C,EAAE,QAAQ,KAAK,aAAa,qBAAqB;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { runWithCacheTenant } from '@open-mercato/cache'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { InboxSettings } from '../../data/entities'\nimport { updateSettingsSchema } from '../../data/validators'\nimport { resolveRequestContext, handleRouteError } from '../routeHelpers'\nimport {\n resolveCache,\n createSettingsCacheKey,\n createSettingsCacheTag,\n invalidateSettingsCache,\n SETTINGS_CACHE_TTL_MS,\n} from '../../lib/cache'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['inbox_ops.settings.manage'] },\n PATCH: { requireAuth: true, requireFeatures: ['inbox_ops.settings.manage'] },\n}\n\nexport async function GET(req: Request) {\n try {\n const ctx = await resolveRequestContext(req)\n const cache = resolveCache(ctx.container)\n\n if (cache) {\n const cacheKey = createSettingsCacheKey(ctx.tenantId)\n const cached = await runWithCacheTenant(ctx.tenantId, () => cache.get(cacheKey))\n if (cached) {\n return NextResponse.json(cached)\n }\n }\n\n const settings = await findOneWithDecryption(\n ctx.em,\n InboxSettings,\n {\n organizationId: ctx.organizationId,\n tenantId: ctx.tenantId,\n deletedAt: null,\n },\n undefined,\n ctx.scope,\n )\n\n const responseBody = {\n settings: settings ? {\n id: settings.id,\n inboxAddress: settings.inboxAddress,\n isActive: settings.isActive,\n workingLanguage: settings.workingLanguage,\n } : null,\n }\n\n if (cache) {\n const cacheKey = createSettingsCacheKey(ctx.tenantId)\n const tag = createSettingsCacheTag(ctx.tenantId)\n try {\n await runWithCacheTenant(ctx.tenantId, () =>\n cache.set(cacheKey, responseBody, { ttl: SETTINGS_CACHE_TTL_MS, tags: [tag] }),\n )\n } catch (err) {\n console.warn('[inbox_ops:settings] Failed to set cache', err)\n }\n }\n\n return NextResponse.json(responseBody)\n } catch (err) {\n return handleRouteError(err, 'load settings')\n }\n}\n\nexport async function PATCH(req: Request) {\n try {\n const ctx = await resolveRequestContext(req)\n\n const body = await req.json()\n const parsed = updateSettingsSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request', details: parsed.error.issues }, { status: 400 })\n }\n\n const settings = await findOneWithDecryption(\n ctx.em,\n InboxSettings,\n {\n organizationId: ctx.organizationId,\n tenantId: ctx.tenantId,\n deletedAt: null,\n },\n undefined,\n ctx.scope,\n )\n\n if (!settings) {\n return NextResponse.json({ error: 'Settings not found' }, { status: 404 })\n }\n\n if (parsed.data.workingLanguage !== undefined) {\n settings.workingLanguage = parsed.data.workingLanguage\n }\n if (parsed.data.isActive !== undefined) {\n settings.isActive = parsed.data.isActive\n }\n\n await ctx.em.flush()\n\n const cache = resolveCache(ctx.container)\n await runWithCacheTenant(ctx.tenantId, () => invalidateSettingsCache(cache, ctx.tenantId))\n\n return NextResponse.json({\n ok: true,\n settings: {\n id: settings.id,\n inboxAddress: settings.inboxAddress,\n isActive: settings.isActive,\n workingLanguage: settings.workingLanguage,\n },\n })\n } catch (err) {\n return handleRouteError(err, 'update settings')\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'InboxOps',\n summary: 'Settings',\n methods: {\n GET: {\n summary: 'Get tenant inbox configuration',\n description: 'Returns the forwarding address and configuration for this tenant',\n responses: [\n { status: 200, description: 'Inbox settings' },\n ],\n },\n PATCH: {\n summary: 'Update tenant inbox configuration',\n description: 'Updates working language and/or active status',\n responses: [\n { status: 200, description: 'Updated settings' },\n { status: 404, description: 'Settings not found' },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -15,6 +15,7 @@ import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
15
15
  import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
16
16
  import { ErrorMessage } from "@open-mercato/ui/backend/detail";
17
17
  import { Settings, Inbox, Copy } from "lucide-react";
18
+ import { CategoryBadge, useCategoryLabels } from "../../components/proposals/CategoryBadge.js";
18
19
  const STATUS_COLORS = {
19
20
  pending: "bg-yellow-100 text-yellow-800",
20
21
  partial: "bg-blue-100 text-blue-800",
@@ -64,6 +65,7 @@ function InboxOpsProposalsPage() {
64
65
  const [settings, setSettings] = React.useState(null);
65
66
  const [copied, setCopied] = React.useState(false);
66
67
  const statusFilter = typeof filterValues.status === "string" ? filterValues.status : void 0;
68
+ const categoryFilter = typeof filterValues.category === "string" ? filterValues.category : void 0;
67
69
  const loadProposals = React.useCallback(async () => {
68
70
  setIsLoading(true);
69
71
  setError(null);
@@ -71,6 +73,7 @@ function InboxOpsProposalsPage() {
71
73
  params.set("page", String(page));
72
74
  params.set("pageSize", String(pageSize));
73
75
  if (statusFilter) params.set("status", statusFilter);
76
+ if (categoryFilter) params.set("category", categoryFilter);
74
77
  if (search.trim()) params.set("search", search.trim());
75
78
  try {
76
79
  const result = await apiCall(`/api/inbox_ops/proposals?${params}`);
@@ -84,7 +87,7 @@ function InboxOpsProposalsPage() {
84
87
  setError(t("inbox_ops.flash.load_failed", "Failed to load proposals"));
85
88
  }
86
89
  setIsLoading(false);
87
- }, [page, pageSize, statusFilter, search, scopeVersion, t]);
90
+ }, [page, pageSize, statusFilter, categoryFilter, search, scopeVersion, t]);
88
91
  const loadCounts = React.useCallback(async () => {
89
92
  const result = await apiCall("/api/inbox_ops/proposals/counts");
90
93
  if (result?.ok && result.result) setCounts(result.result);
@@ -100,7 +103,7 @@ function InboxOpsProposalsPage() {
100
103
  }, []);
101
104
  React.useEffect(() => {
102
105
  if (initialLoadComplete) loadProposals();
103
- }, [page, statusFilter, search, scopeVersion]);
106
+ }, [page, statusFilter, categoryFilter, search, scopeVersion]);
104
107
  const handleCopyAddress = React.useCallback(() => {
105
108
  if (settings?.inboxAddress) {
106
109
  navigator.clipboard.writeText(settings.inboxAddress);
@@ -141,6 +144,8 @@ function InboxOpsProposalsPage() {
141
144
  flash(t("inbox_ops.flash.action_reject_failed", "Failed to reject"), "error");
142
145
  }
143
146
  }, [confirm, t, loadProposals, loadCounts, runMutation]);
147
+ const categoryLabels = useCategoryLabels();
148
+ const byCategory = counts.byCategory || {};
144
149
  const filters = React.useMemo(() => [
145
150
  {
146
151
  id: "status",
@@ -152,8 +157,23 @@ function InboxOpsProposalsPage() {
152
157
  { value: "accepted", label: `${t("inbox_ops.status.accepted", "Accepted")} (${counts.accepted})` },
153
158
  { value: "rejected", label: `${t("inbox_ops.status.rejected", "Rejected")} (${counts.rejected})` }
154
159
  ]
160
+ },
161
+ {
162
+ id: "category",
163
+ label: t("inbox_ops.category", "Category"),
164
+ type: "select",
165
+ options: [
166
+ { value: "rfq", label: `${categoryLabels.rfq} (${byCategory.rfq || 0})` },
167
+ { value: "order", label: `${categoryLabels.order} (${byCategory.order || 0})` },
168
+ { value: "order_update", label: `${categoryLabels.order_update} (${byCategory.order_update || 0})` },
169
+ { value: "complaint", label: `${categoryLabels.complaint} (${byCategory.complaint || 0})` },
170
+ { value: "shipping_update", label: `${categoryLabels.shipping_update} (${byCategory.shipping_update || 0})` },
171
+ { value: "inquiry", label: `${categoryLabels.inquiry} (${byCategory.inquiry || 0})` },
172
+ { value: "payment", label: `${categoryLabels.payment} (${byCategory.payment || 0})` },
173
+ { value: "other", label: `${categoryLabels.other} (${byCategory.other || 0})` }
174
+ ]
155
175
  }
156
- ], [t, counts]);
176
+ ], [t, counts, categoryLabels, byCategory]);
157
177
  const columns = React.useMemo(() => [
158
178
  {
159
179
  accessorKey: "summary",
@@ -175,6 +195,11 @@ function InboxOpsProposalsPage() {
175
195
  header: t("inbox_ops.list.status", "Status"),
176
196
  cell: ({ row }) => /* @__PURE__ */ jsx(StatusBadge, { status: row.original.status })
177
197
  },
198
+ {
199
+ accessorKey: "category",
200
+ header: t("inbox_ops.category", "Category"),
201
+ cell: ({ row }) => /* @__PURE__ */ jsx(CategoryBadge, { category: row.original.category })
202
+ },
178
203
  {
179
204
  id: "actions_count",
180
205
  header: t("inbox_ops.list.progress", "Progress"),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/inbox_ops/backend/inbox-ops/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 { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\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 { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { Settings, Inbox, Copy } from 'lucide-react'\n\ntype ProposalRow = {\n id: string\n summary: string\n confidence: string\n status: string\n inboxEmailId: string\n createdAt: string\n participants?: { name: string; email: string }[]\n actionCount?: number\n pendingActionCount?: number\n discrepancyCount?: number\n emailSubject?: string | null\n emailFrom?: string | null\n receivedAt?: string | null\n}\n\ntype ProposalListResponse = {\n items?: ProposalRow[]\n total?: number\n page?: number\n totalPages?: number\n}\n\ntype StatusCounts = {\n pending: number\n partial: number\n accepted: number\n rejected: number\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n pending: 'bg-yellow-100 text-yellow-800',\n partial: 'bg-blue-100 text-blue-800',\n accepted: 'bg-green-100 text-green-800',\n rejected: 'bg-red-100 text-red-800',\n processing: 'bg-purple-100 text-purple-800',\n}\n\nfunction ConfidenceBadge({ value }: { value: string }) {\n const num = parseFloat(value)\n const pct = Math.round(num * 100)\n const color = num >= 0.8 ? 'bg-green-100 text-green-800' : num >= 0.6 ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{pct}%</span>\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const t = useT()\n const statusLabels: Record<string, string> = {\n pending: t('inbox_ops.status.pending', 'Pending'),\n partial: t('inbox_ops.status.partial', 'Partial'),\n accepted: t('inbox_ops.status.accepted', 'Accepted'),\n rejected: t('inbox_ops.status.rejected', 'Rejected'),\n processing: t('inbox_ops.status.processing', 'Processing'),\n }\n const color = STATUS_COLORS[status] || 'bg-gray-100 text-gray-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{statusLabels[status] || status}</span>\n}\n\nexport default function InboxOpsProposalsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-proposals',\n })\n\n const [items, setItems] = React.useState<ProposalRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [initialLoadComplete, setInitialLoadComplete] = React.useState(false)\n const [counts, setCounts] = React.useState<StatusCounts>({ pending: 0, partial: 0, accepted: 0, rejected: 0 })\n const [settings, setSettings] = React.useState<{ inboxAddress?: string } | null>(null)\n const [copied, setCopied] = React.useState(false)\n\n const statusFilter = typeof filterValues.status === 'string' ? filterValues.status : undefined\n\n const loadProposals = React.useCallback(async () => {\n setIsLoading(true)\n setError(null)\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (statusFilter) params.set('status', statusFilter)\n if (search.trim()) params.set('search', search.trim())\n\n try {\n const result = await apiCall<ProposalListResponse>(`/api/inbox_ops/proposals?${params}`)\n if (result?.ok && result.result?.items) {\n setItems(result.result.items)\n setTotal(result.result.total || 0)\n } else {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n } catch {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, search, scopeVersion, t])\n\n const loadCounts = React.useCallback(async () => {\n const result = await apiCall<StatusCounts>('/api/inbox_ops/proposals/counts')\n if (result?.ok && result.result) setCounts(result.result)\n }, [scopeVersion])\n\n const loadSettings = React.useCallback(async () => {\n const result = await apiCall<{ settings: { inboxAddress?: string } | null }>('/api/inbox_ops/settings')\n if (result?.ok && result.result?.settings) setSettings(result.result.settings)\n }, [scopeVersion])\n\n React.useEffect(() => {\n Promise.all([loadProposals(), loadCounts(), loadSettings()]).then(() => {\n setInitialLoadComplete(true)\n })\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n React.useEffect(() => {\n if (initialLoadComplete) loadProposals()\n }, [page, statusFilter, search, scopeVersion]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleCopyAddress = 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 handleRefresh = React.useCallback(() => {\n loadProposals()\n loadCounts()\n }, [loadProposals, loadCounts])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRejectProposal = React.useCallback(async (proposalId: string) => {\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 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 loadProposals()\n loadCounts()\n } else {\n flash(t('inbox_ops.flash.action_reject_failed', 'Failed to reject'), 'error')\n }\n }, [confirm, t, loadProposals, loadCounts, runMutation])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'status',\n label: t('inbox_ops.list.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'pending', label: `${t('inbox_ops.status.pending', 'Pending')} (${counts.pending})` },\n { value: 'partial', label: `${t('inbox_ops.status.partial', 'Partial')} (${counts.partial})` },\n { value: 'accepted', label: `${t('inbox_ops.status.accepted', 'Accepted')} (${counts.accepted})` },\n { value: 'rejected', label: `${t('inbox_ops.status.rejected', 'Rejected')} (${counts.rejected})` },\n ],\n },\n ], [t, counts])\n\n const columns: ColumnDef<ProposalRow>[] = React.useMemo(() => [\n {\n accessorKey: 'summary',\n header: t('inbox_ops.summary', 'Summary'),\n cell: ({ row }) => (\n <div className=\"min-w-0\">\n <Link\n href={`/backend/inbox-ops/proposals/${row.original.id}`}\n className=\"text-sm font-medium text-primary hover:underline truncate max-w-[300px] block\"\n >\n {row.original.emailSubject || row.original.summary?.slice(0, 80) || t('inbox_ops.untitled_proposal', 'Untitled proposal')}\n </Link>\n {row.original.emailFrom && (\n <span className=\"text-xs text-muted-foreground truncate block\">{row.original.emailFrom}</span>\n )}\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: t('inbox_ops.list.status', 'Status'),\n cell: ({ row }) => <StatusBadge status={row.original.status} />,\n },\n {\n id: 'actions_count',\n header: t('inbox_ops.list.progress', 'Progress'),\n cell: ({ row }) => {\n const pending = row.original.pendingActionCount ?? 0\n const total = row.original.actionCount ?? 0\n if (total === 0) return <span className=\"text-sm text-muted-foreground\">\u2014</span>\n return (\n <span className=\"text-sm text-muted-foreground\">\n {t('inbox_ops.list.action_summary', '{pending}/{total} actions')\n .replace('{pending}', String(pending))\n .replace('{total}', String(total))}\n </span>\n )\n },\n },\n {\n accessorKey: 'confidence',\n header: t('inbox_ops.confidence', 'Confidence'),\n cell: ({ row }) => <ConfidenceBadge value={row.original.confidence} />,\n },\n {\n accessorKey: 'receivedAt',\n header: t('inbox_ops.received_at', 'Received'),\n cell: ({ row }) => {\n const dateStr = row.original.receivedAt || row.original.createdAt\n const d = new Date(dateStr)\n return <span className=\"text-sm text-muted-foreground\">{d.toLocaleDateString()} {d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>\n },\n },\n ], [t])\n\n const totalCount = counts.pending + counts.partial + counts.accepted + counts.rejected\n\n const emptyStateContent = initialLoadComplete && totalCount === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <Inbox className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">{t('inbox_ops.empty.title', 'Forward emails to start')}</h2>\n {settings?.inboxAddress && (\n <div className=\"mt-4 flex items-center gap-2 bg-muted rounded-lg px-4 py-3\">\n <code className=\"text-sm font-mono\">{settings.inboxAddress}</code>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </Button>\n </div>\n )}\n <ol className=\"mt-6 text-sm text-muted-foreground text-left space-y-2\">\n <li>1. {t('inbox_ops.empty.step1', 'Forward any email thread to this address')}</li>\n <li>2. {t('inbox_ops.empty.step2', \"We'll analyze it and propose actions\")}</li>\n <li>3. {t('inbox_ops.empty.step3', 'Review and accept with one click')}</li>\n </ol>\n </div>\n ) : undefined\n\n if (error && !initialLoadComplete) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable<ProposalRow>\n title={t('inbox_ops.title', 'AI Inbox Actions')}\n refreshButton={{\n label: t('inbox_ops.list.actions.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n }}\n actions={(\n <div className=\"flex items-center gap-2\">\n {settings?.inboxAddress && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </span>\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" asChild>\n <Link href=\"/backend/inbox-ops/settings\">\n <Settings className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">{t('inbox_ops.list.actions.settings', 'Settings')}</span>\n </Link>\n </Button>\n </div>\n )}\n columns={columns}\n data={items}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('inbox_ops.list.searchPlaceholder', 'Search proposals...')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n onRowClick={(row) => router.push(`/backend/inbox-ops/proposals/${row.id}`)}\n rowActions={(row) => (\n <RowActions items={[\n {\n id: 'view',\n label: t('inbox_ops.list.actions.view', 'View'),\n onSelect: () => router.push(`/backend/inbox-ops/proposals/${row.id}`),\n },\n ...(row.status === 'pending' || row.status === 'partial' ? [{\n id: 'reject',\n label: t('inbox_ops.list.actions.reject', 'Reject'),\n destructive: true,\n onSelect: () => handleRejectProposal(row.id),\n }] : []),\n ]} />\n )}\n pagination={{\n page,\n pageSize,\n total,\n totalPages: Math.ceil(total / pageSize),\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n emptyState={emptyStateContent}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
- "mappings": "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",
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 { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\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 { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { Settings, Inbox, Copy } from 'lucide-react'\nimport { CategoryBadge, useCategoryLabels } from '../../components/proposals/CategoryBadge'\n\ntype ProposalRow = {\n id: string\n summary: string\n confidence: string\n status: string\n category?: string | null\n inboxEmailId: string\n createdAt: string\n participants?: { name: string; email: string }[]\n actionCount?: number\n pendingActionCount?: number\n discrepancyCount?: number\n emailSubject?: string | null\n emailFrom?: string | null\n receivedAt?: string | null\n}\n\ntype ProposalListResponse = {\n items?: ProposalRow[]\n total?: number\n page?: number\n totalPages?: number\n}\n\ntype StatusCounts = {\n pending: number\n partial: number\n accepted: number\n rejected: number\n byCategory?: Record<string, number>\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n pending: 'bg-yellow-100 text-yellow-800',\n partial: 'bg-blue-100 text-blue-800',\n accepted: 'bg-green-100 text-green-800',\n rejected: 'bg-red-100 text-red-800',\n processing: 'bg-purple-100 text-purple-800',\n}\n\nfunction ConfidenceBadge({ value }: { value: string }) {\n const num = parseFloat(value)\n const pct = Math.round(num * 100)\n const color = num >= 0.8 ? 'bg-green-100 text-green-800' : num >= 0.6 ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{pct}%</span>\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const t = useT()\n const statusLabels: Record<string, string> = {\n pending: t('inbox_ops.status.pending', 'Pending'),\n partial: t('inbox_ops.status.partial', 'Partial'),\n accepted: t('inbox_ops.status.accepted', 'Accepted'),\n rejected: t('inbox_ops.status.rejected', 'Rejected'),\n processing: t('inbox_ops.status.processing', 'Processing'),\n }\n const color = STATUS_COLORS[status] || 'bg-gray-100 text-gray-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{statusLabels[status] || status}</span>\n}\n\nexport default function InboxOpsProposalsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-proposals',\n })\n\n const [items, setItems] = React.useState<ProposalRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [initialLoadComplete, setInitialLoadComplete] = React.useState(false)\n const [counts, setCounts] = React.useState<StatusCounts>({ pending: 0, partial: 0, accepted: 0, rejected: 0 })\n const [settings, setSettings] = React.useState<{ inboxAddress?: string } | null>(null)\n const [copied, setCopied] = React.useState(false)\n\n const statusFilter = typeof filterValues.status === 'string' ? filterValues.status : undefined\n const categoryFilter = typeof filterValues.category === 'string' ? filterValues.category : undefined\n\n const loadProposals = React.useCallback(async () => {\n setIsLoading(true)\n setError(null)\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (statusFilter) params.set('status', statusFilter)\n if (categoryFilter) params.set('category', categoryFilter)\n if (search.trim()) params.set('search', search.trim())\n\n try {\n const result = await apiCall<ProposalListResponse>(`/api/inbox_ops/proposals?${params}`)\n if (result?.ok && result.result?.items) {\n setItems(result.result.items)\n setTotal(result.result.total || 0)\n } else {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n } catch {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, categoryFilter, search, scopeVersion, t])\n\n const loadCounts = React.useCallback(async () => {\n const result = await apiCall<StatusCounts>('/api/inbox_ops/proposals/counts')\n if (result?.ok && result.result) setCounts(result.result)\n }, [scopeVersion])\n\n const loadSettings = React.useCallback(async () => {\n const result = await apiCall<{ settings: { inboxAddress?: string } | null }>('/api/inbox_ops/settings')\n if (result?.ok && result.result?.settings) setSettings(result.result.settings)\n }, [scopeVersion])\n\n React.useEffect(() => {\n Promise.all([loadProposals(), loadCounts(), loadSettings()]).then(() => {\n setInitialLoadComplete(true)\n })\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n React.useEffect(() => {\n if (initialLoadComplete) loadProposals()\n }, [page, statusFilter, categoryFilter, search, scopeVersion]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleCopyAddress = 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 handleRefresh = React.useCallback(() => {\n loadProposals()\n loadCounts()\n }, [loadProposals, loadCounts])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRejectProposal = React.useCallback(async (proposalId: string) => {\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 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 loadProposals()\n loadCounts()\n } else {\n flash(t('inbox_ops.flash.action_reject_failed', 'Failed to reject'), 'error')\n }\n }, [confirm, t, loadProposals, loadCounts, runMutation])\n\n const categoryLabels = useCategoryLabels()\n const byCategory = counts.byCategory || {}\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'status',\n label: t('inbox_ops.list.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'pending', label: `${t('inbox_ops.status.pending', 'Pending')} (${counts.pending})` },\n { value: 'partial', label: `${t('inbox_ops.status.partial', 'Partial')} (${counts.partial})` },\n { value: 'accepted', label: `${t('inbox_ops.status.accepted', 'Accepted')} (${counts.accepted})` },\n { value: 'rejected', label: `${t('inbox_ops.status.rejected', 'Rejected')} (${counts.rejected})` },\n ],\n },\n {\n id: 'category',\n label: t('inbox_ops.category', 'Category'),\n type: 'select',\n options: [\n { value: 'rfq', label: `${categoryLabels.rfq} (${byCategory.rfq || 0})` },\n { value: 'order', label: `${categoryLabels.order} (${byCategory.order || 0})` },\n { value: 'order_update', label: `${categoryLabels.order_update} (${byCategory.order_update || 0})` },\n { value: 'complaint', label: `${categoryLabels.complaint} (${byCategory.complaint || 0})` },\n { value: 'shipping_update', label: `${categoryLabels.shipping_update} (${byCategory.shipping_update || 0})` },\n { value: 'inquiry', label: `${categoryLabels.inquiry} (${byCategory.inquiry || 0})` },\n { value: 'payment', label: `${categoryLabels.payment} (${byCategory.payment || 0})` },\n { value: 'other', label: `${categoryLabels.other} (${byCategory.other || 0})` },\n ],\n },\n ], [t, counts, categoryLabels, byCategory])\n\n const columns: ColumnDef<ProposalRow>[] = React.useMemo(() => [\n {\n accessorKey: 'summary',\n header: t('inbox_ops.summary', 'Summary'),\n cell: ({ row }) => (\n <div className=\"min-w-0\">\n <Link\n href={`/backend/inbox-ops/proposals/${row.original.id}`}\n className=\"text-sm font-medium text-primary hover:underline truncate max-w-[300px] block\"\n >\n {row.original.emailSubject || row.original.summary?.slice(0, 80) || t('inbox_ops.untitled_proposal', 'Untitled proposal')}\n </Link>\n {row.original.emailFrom && (\n <span className=\"text-xs text-muted-foreground truncate block\">{row.original.emailFrom}</span>\n )}\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: t('inbox_ops.list.status', 'Status'),\n cell: ({ row }) => <StatusBadge status={row.original.status} />,\n },\n {\n accessorKey: 'category',\n header: t('inbox_ops.category', 'Category'),\n cell: ({ row }) => <CategoryBadge category={row.original.category} />,\n },\n {\n id: 'actions_count',\n header: t('inbox_ops.list.progress', 'Progress'),\n cell: ({ row }) => {\n const pending = row.original.pendingActionCount ?? 0\n const total = row.original.actionCount ?? 0\n if (total === 0) return <span className=\"text-sm text-muted-foreground\">\u2014</span>\n return (\n <span className=\"text-sm text-muted-foreground\">\n {t('inbox_ops.list.action_summary', '{pending}/{total} actions')\n .replace('{pending}', String(pending))\n .replace('{total}', String(total))}\n </span>\n )\n },\n },\n {\n accessorKey: 'confidence',\n header: t('inbox_ops.confidence', 'Confidence'),\n cell: ({ row }) => <ConfidenceBadge value={row.original.confidence} />,\n },\n {\n accessorKey: 'receivedAt',\n header: t('inbox_ops.received_at', 'Received'),\n cell: ({ row }) => {\n const dateStr = row.original.receivedAt || row.original.createdAt\n const d = new Date(dateStr)\n return <span className=\"text-sm text-muted-foreground\">{d.toLocaleDateString()} {d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>\n },\n },\n ], [t])\n\n const totalCount = counts.pending + counts.partial + counts.accepted + counts.rejected\n\n const emptyStateContent = initialLoadComplete && totalCount === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <Inbox className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">{t('inbox_ops.empty.title', 'Forward emails to start')}</h2>\n {settings?.inboxAddress && (\n <div className=\"mt-4 flex items-center gap-2 bg-muted rounded-lg px-4 py-3\">\n <code className=\"text-sm font-mono\">{settings.inboxAddress}</code>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </Button>\n </div>\n )}\n <ol className=\"mt-6 text-sm text-muted-foreground text-left space-y-2\">\n <li>1. {t('inbox_ops.empty.step1', 'Forward any email thread to this address')}</li>\n <li>2. {t('inbox_ops.empty.step2', \"We'll analyze it and propose actions\")}</li>\n <li>3. {t('inbox_ops.empty.step3', 'Review and accept with one click')}</li>\n </ol>\n </div>\n ) : undefined\n\n if (error && !initialLoadComplete) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable<ProposalRow>\n title={t('inbox_ops.title', 'AI Inbox Actions')}\n refreshButton={{\n label: t('inbox_ops.list.actions.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n }}\n actions={(\n <div className=\"flex items-center gap-2\">\n {settings?.inboxAddress && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </span>\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" asChild>\n <Link href=\"/backend/inbox-ops/settings\">\n <Settings className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">{t('inbox_ops.list.actions.settings', 'Settings')}</span>\n </Link>\n </Button>\n </div>\n )}\n columns={columns}\n data={items}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('inbox_ops.list.searchPlaceholder', 'Search proposals...')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n onRowClick={(row) => router.push(`/backend/inbox-ops/proposals/${row.id}`)}\n rowActions={(row) => (\n <RowActions items={[\n {\n id: 'view',\n label: t('inbox_ops.list.actions.view', 'View'),\n onSelect: () => router.push(`/backend/inbox-ops/proposals/${row.id}`),\n },\n ...(row.status === 'pending' || row.status === 'partial' ? [{\n id: 'reject',\n label: t('inbox_ops.list.actions.reject', 'Reject'),\n destructive: true,\n onSelect: () => handleRejectProposal(row.id),\n }] : []),\n ]} />\n )}\n pagination={{\n page,\n pageSize,\n total,\n totalPages: Math.ceil(total / pageSize),\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n emptyState={emptyStateContent}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["total"]
7
7
  }
@@ -21,9 +21,11 @@ import {
21
21
  ExternalLink,
22
22
  RefreshCw,
23
23
  Users,
24
- Languages
24
+ Languages,
25
+ Pencil
25
26
  } from "lucide-react";
26
27
  import { ActionCard, ConfidenceBadge, useActionTypeLabels, useDiscrepancyDescriptions } from "../../../../components/proposals/ActionCard.js";
28
+ import { CategoryBadge, CATEGORY_CONFIG, ALL_CATEGORIES, useCategoryLabels } from "../../../../components/proposals/CategoryBadge.js";
27
29
  import { hasContactNameIssue } from "../../../../lib/contactValidation.js";
28
30
  import { EditActionDialog } from "../../../../components/proposals/EditActionDialog.js";
29
31
  function EmailThreadViewer({ email }) {
@@ -44,6 +46,74 @@ function EmailThreadViewer({ email }) {
44
46
  ] }, index)) : email.cleanedText ? /* @__PURE__ */ jsx("div", { className: "border rounded-lg p-3 md:p-4 bg-card", children: /* @__PURE__ */ jsx("div", { className: "text-sm whitespace-pre-wrap text-foreground/80", children: email.cleanedText }) }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("inbox_ops.no_email_content", "No email content available") })
45
47
  ] });
46
48
  }
49
+ function CategoryEditDropdown({
50
+ currentCategory,
51
+ onSelect,
52
+ disabled
53
+ }) {
54
+ const t = useT();
55
+ const labels = useCategoryLabels();
56
+ const [isOpen, setIsOpen] = React.useState(false);
57
+ const dropdownRef = React.useRef(null);
58
+ React.useEffect(() => {
59
+ function handleClickOutside(event) {
60
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
61
+ setIsOpen(false);
62
+ }
63
+ }
64
+ function handleEscape(event) {
65
+ if (event.key === "Escape") setIsOpen(false);
66
+ }
67
+ if (isOpen) {
68
+ document.addEventListener("mousedown", handleClickOutside);
69
+ document.addEventListener("keydown", handleEscape);
70
+ }
71
+ return () => {
72
+ document.removeEventListener("mousedown", handleClickOutside);
73
+ document.removeEventListener("keydown", handleEscape);
74
+ };
75
+ }, [isOpen]);
76
+ return /* @__PURE__ */ jsxs("div", { className: "relative inline-block", ref: dropdownRef, children: [
77
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
78
+ /* @__PURE__ */ jsx(CategoryBadge, { category: currentCategory }),
79
+ /* @__PURE__ */ jsx(
80
+ Button,
81
+ {
82
+ type: "button",
83
+ variant: "ghost",
84
+ size: "sm",
85
+ className: "h-6 w-6 p-0",
86
+ onClick: () => setIsOpen(!isOpen),
87
+ disabled,
88
+ title: t("inbox_ops.recategorize", "Change Category"),
89
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-3 w-3" })
90
+ }
91
+ )
92
+ ] }),
93
+ isOpen && /* @__PURE__ */ jsx("div", { className: "absolute top-full left-0 mt-1 z-50 w-48 rounded-md border bg-popover shadow-md", children: /* @__PURE__ */ jsx("div", { className: "p-1", children: ALL_CATEGORIES.map((cat) => {
94
+ const config = CATEGORY_CONFIG[cat];
95
+ const { Icon } = config;
96
+ return /* @__PURE__ */ jsxs(
97
+ Button,
98
+ {
99
+ type: "button",
100
+ variant: "ghost",
101
+ size: "sm",
102
+ className: `flex items-center gap-2 w-full justify-start rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground ${currentCategory === cat ? "bg-accent" : ""}`,
103
+ onClick: () => {
104
+ onSelect(cat);
105
+ setIsOpen(false);
106
+ },
107
+ children: [
108
+ /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
109
+ labels[cat] || cat
110
+ ]
111
+ },
112
+ cat
113
+ );
114
+ }) }) })
115
+ ] });
116
+ }
47
117
  function ProposalDetailPage({ params }) {
48
118
  const t = useT();
49
119
  const locale = useLocale();
@@ -120,6 +190,21 @@ function ProposalDetailPage({ params }) {
120
190
  }
121
191
  setIsTranslating(false);
122
192
  }, [proposalId, locale, t, runMutation]);
193
+ const handleCategorize = React.useCallback(async (category) => {
194
+ if (!proposalId) return;
195
+ const result = await runMutation({
196
+ operation: () => apiCall(
197
+ `/api/inbox_ops/proposals/${proposalId}/categorize`,
198
+ { method: "POST", body: JSON.stringify({ category }) }
199
+ ),
200
+ context: {}
201
+ });
202
+ if (result?.ok && result.result?.ok) {
203
+ setProposal((prev) => prev ? { ...prev, category: result.result.category } : prev);
204
+ } else {
205
+ flash(t("inbox_ops.flash.save_failed", "Failed to save"), "error");
206
+ }
207
+ }, [proposalId, t, runMutation]);
123
208
  const loadData = React.useCallback(async () => {
124
209
  if (!proposalId) return;
125
210
  setIsLoading(true);
@@ -342,10 +427,23 @@ function ProposalDetailPage({ params }) {
342
427
  )
343
428
  ] }),
344
429
  /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground/80 mb-3", children: showTranslation && translation ? translation.summary : proposal.summary }),
345
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 mb-3", children: /* @__PURE__ */ jsxs("div", { children: [
346
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("inbox_ops.confidence", "Confidence") }),
347
- /* @__PURE__ */ jsx(ConfidenceBadge, { value: proposal.confidence })
348
- ] }) }),
430
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 mb-3 flex-wrap", children: [
431
+ /* @__PURE__ */ jsxs("div", { children: [
432
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("inbox_ops.confidence", "Confidence") }),
433
+ /* @__PURE__ */ jsx(ConfidenceBadge, { value: proposal.confidence })
434
+ ] }),
435
+ /* @__PURE__ */ jsxs("div", { children: [
436
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground block", children: t("inbox_ops.category", "Category") }),
437
+ /* @__PURE__ */ jsx(
438
+ CategoryEditDropdown,
439
+ {
440
+ currentCategory: proposal.category,
441
+ onSelect: handleCategorize,
442
+ disabled: isProcessing
443
+ }
444
+ )
445
+ ] })
446
+ ] }),
349
447
  proposal.possiblyIncomplete && /* @__PURE__ */ jsxs("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", children: [
350
448
  /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3 w-3" }),
351
449
  t("inbox_ops.possibly_incomplete", "This thread appears to be a partial forward")
@@ -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, 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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",
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 Pencil,\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 { CategoryBadge, CATEGORY_CONFIG, ALL_CATEGORIES, useCategoryLabels } from '../../../../components/proposals/CategoryBadge'\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\nfunction CategoryEditDropdown({\n currentCategory,\n onSelect,\n disabled,\n}: {\n currentCategory: string | null | undefined\n onSelect: (category: string) => void\n disabled: boolean\n}) {\n const t = useT()\n const labels = useCategoryLabels()\n const [isOpen, setIsOpen] = React.useState(false)\n const dropdownRef = React.useRef<HTMLDivElement>(null)\n\n React.useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false)\n }\n }\n function handleEscape(event: KeyboardEvent) {\n if (event.key === 'Escape') setIsOpen(false)\n }\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleEscape)\n }\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleEscape)\n }\n }, [isOpen])\n\n return (\n <div className=\"relative inline-block\" ref={dropdownRef}>\n <div className=\"flex items-center gap-1\">\n <CategoryBadge category={currentCategory} />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-6 w-6 p-0\"\n onClick={() => setIsOpen(!isOpen)}\n disabled={disabled}\n title={t('inbox_ops.recategorize', 'Change Category')}\n >\n <Pencil className=\"h-3 w-3\" />\n </Button>\n </div>\n {isOpen && (\n <div className=\"absolute top-full left-0 mt-1 z-50 w-48 rounded-md border bg-popover shadow-md\">\n <div className=\"p-1\">\n {ALL_CATEGORIES.map((cat) => {\n const config = CATEGORY_CONFIG[cat]\n const { Icon } = config\n return (\n <Button\n key={cat}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={`flex items-center gap-2 w-full justify-start rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground ${currentCategory === cat ? 'bg-accent' : ''}`}\n onClick={() => { onSelect(cat); setIsOpen(false) }}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n {labels[cat] || cat}\n </Button>\n )\n })}\n </div>\n </div>\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 handleCategorize = React.useCallback(async (category: string) => {\n if (!proposalId) return\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; category: string; previousCategory: string | null }>(\n `/api/inbox_ops/proposals/${proposalId}/categorize`,\n { method: 'POST', body: JSON.stringify({ category }) },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n setProposal((prev) => prev ? { ...prev, category: result.result!.category } : prev)\n } else {\n flash(t('inbox_ops.flash.save_failed', 'Failed to save'), 'error')\n }\n }, [proposalId, 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 flex-wrap\">\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 <span className=\"text-xs text-muted-foreground block\">{t('inbox_ops.category', 'Category')}</span>\n <CategoryEditDropdown\n currentCategory={proposal.category}\n onSelect={handleCategorize}\n disabled={isProcessing}\n />\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
6
  "names": ["pendingActions"]
7
7
  }