@open-mercato/core 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2

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 (163) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +13 -1
  3. package/dist/helpers/integration/api.js +29 -16
  4. package/dist/helpers/integration/api.js.map +2 -2
  5. package/dist/helpers/integration/auth.js +11 -6
  6. package/dist/helpers/integration/auth.js.map +3 -3
  7. package/dist/modules/auth/commands/roles.js +9 -12
  8. package/dist/modules/auth/commands/roles.js.map +2 -2
  9. package/dist/modules/catalog/ai-agents-context.js +147 -0
  10. package/dist/modules/catalog/ai-agents-context.js.map +7 -0
  11. package/dist/modules/catalog/ai-agents.js +383 -0
  12. package/dist/modules/catalog/ai-agents.js.map +7 -0
  13. package/dist/modules/catalog/ai-tools/_shared.js +318 -0
  14. package/dist/modules/catalog/ai-tools/_shared.js.map +7 -0
  15. package/dist/modules/catalog/ai-tools/authoring-pack.js +391 -0
  16. package/dist/modules/catalog/ai-tools/authoring-pack.js.map +7 -0
  17. package/dist/modules/catalog/ai-tools/categories-pack.js +167 -0
  18. package/dist/modules/catalog/ai-tools/categories-pack.js.map +7 -0
  19. package/dist/modules/catalog/ai-tools/configuration-pack.js +120 -0
  20. package/dist/modules/catalog/ai-tools/configuration-pack.js.map +7 -0
  21. package/dist/modules/catalog/ai-tools/media-tags-pack.js +107 -0
  22. package/dist/modules/catalog/ai-tools/media-tags-pack.js.map +7 -0
  23. package/dist/modules/catalog/ai-tools/merchandising-pack.js +429 -0
  24. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +7 -0
  25. package/dist/modules/catalog/ai-tools/mutation-pack.js +576 -0
  26. package/dist/modules/catalog/ai-tools/mutation-pack.js.map +7 -0
  27. package/dist/modules/catalog/ai-tools/prices-offers-pack.js +208 -0
  28. package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +7 -0
  29. package/dist/modules/catalog/ai-tools/products-pack.js +298 -0
  30. package/dist/modules/catalog/ai-tools/products-pack.js.map +7 -0
  31. package/dist/modules/catalog/ai-tools/stats-pack.js +57 -0
  32. package/dist/modules/catalog/ai-tools/stats-pack.js.map +7 -0
  33. package/dist/modules/catalog/ai-tools/types.js +10 -0
  34. package/dist/modules/catalog/ai-tools/types.js.map +7 -0
  35. package/dist/modules/catalog/ai-tools/variants-pack.js +75 -0
  36. package/dist/modules/catalog/ai-tools/variants-pack.js.map +7 -0
  37. package/dist/modules/catalog/ai-tools.js +28 -0
  38. package/dist/modules/catalog/ai-tools.js.map +7 -0
  39. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +466 -0
  40. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +7 -0
  41. package/dist/modules/catalog/backend/catalog/products/page.js +7 -1
  42. package/dist/modules/catalog/backend/catalog/products/page.js.map +2 -2
  43. package/dist/modules/catalog/components/CatalogStatsCard.js +91 -0
  44. package/dist/modules/catalog/components/CatalogStatsCard.js.map +7 -0
  45. package/dist/modules/catalog/components/products/ProductsDataTable.js +23 -3
  46. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  47. package/dist/modules/catalog/events.js +7 -4
  48. package/dist/modules/catalog/events.js.map +2 -2
  49. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +59 -0
  50. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +7 -0
  51. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js +17 -0
  52. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js.map +7 -0
  53. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
  54. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
  55. package/dist/modules/catalog/widgets/injection-table.js +13 -1
  56. package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
  57. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +94 -0
  58. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +7 -0
  59. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js +17 -0
  60. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js.map +7 -0
  61. package/dist/modules/customer_accounts/widgets/injection-table.js +9 -0
  62. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  63. package/dist/modules/customers/ai-agents-context.js +96 -0
  64. package/dist/modules/customers/ai-agents-context.js.map +7 -0
  65. package/dist/modules/customers/ai-agents.js +244 -0
  66. package/dist/modules/customers/ai-agents.js.map +7 -0
  67. package/dist/modules/customers/ai-tools/activities-tasks-pack.js +1015 -0
  68. package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +7 -0
  69. package/dist/modules/customers/ai-tools/addresses-tags-pack.js +134 -0
  70. package/dist/modules/customers/ai-tools/addresses-tags-pack.js.map +7 -0
  71. package/dist/modules/customers/ai-tools/companies-pack.js +249 -0
  72. package/dist/modules/customers/ai-tools/companies-pack.js.map +7 -0
  73. package/dist/modules/customers/ai-tools/deals-pack.js +348 -0
  74. package/dist/modules/customers/ai-tools/deals-pack.js.map +7 -0
  75. package/dist/modules/customers/ai-tools/people-pack.js +261 -0
  76. package/dist/modules/customers/ai-tools/people-pack.js.map +7 -0
  77. package/dist/modules/customers/ai-tools/settings-pack.js +102 -0
  78. package/dist/modules/customers/ai-tools/settings-pack.js.map +7 -0
  79. package/dist/modules/customers/ai-tools/types.js +10 -0
  80. package/dist/modules/customers/ai-tools/types.js.map +7 -0
  81. package/dist/modules/customers/ai-tools.js +20 -0
  82. package/dist/modules/customers/ai-tools.js.map +7 -0
  83. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +469 -0
  84. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +7 -0
  85. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +17 -0
  86. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +7 -0
  87. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +117 -0
  88. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +7 -0
  89. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js +17 -0
  90. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js.map +7 -0
  91. package/dist/modules/customers/widgets/injection-table.js +26 -0
  92. package/dist/modules/customers/widgets/injection-table.js.map +7 -0
  93. package/dist/modules/inbox_ops/ai-tools.js +4 -0
  94. package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
  95. package/dist/modules/inbox_ops/lib/llmProvider.js +52 -7
  96. package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
  97. package/dist/modules/notifications/setup.js +13 -0
  98. package/dist/modules/notifications/setup.js.map +7 -0
  99. package/jest.config.cjs +1 -0
  100. package/jest.setup.ts +18 -0
  101. package/package.json +5 -3
  102. package/src/helpers/integration/api.ts +38 -16
  103. package/src/helpers/integration/auth.ts +13 -6
  104. package/src/modules/auth/commands/roles.ts +10 -12
  105. package/src/modules/catalog/AGENTS.md +11 -0
  106. package/src/modules/catalog/ai-agents-context.ts +239 -0
  107. package/src/modules/catalog/ai-agents.ts +525 -0
  108. package/src/modules/catalog/ai-tools/_shared.ts +487 -0
  109. package/src/modules/catalog/ai-tools/authoring-pack.ts +600 -0
  110. package/src/modules/catalog/ai-tools/categories-pack.ts +192 -0
  111. package/src/modules/catalog/ai-tools/configuration-pack.ts +218 -0
  112. package/src/modules/catalog/ai-tools/media-tags-pack.ts +127 -0
  113. package/src/modules/catalog/ai-tools/merchandising-pack.ts +608 -0
  114. package/src/modules/catalog/ai-tools/mutation-pack.ts +761 -0
  115. package/src/modules/catalog/ai-tools/prices-offers-pack.ts +376 -0
  116. package/src/modules/catalog/ai-tools/products-pack.ts +387 -0
  117. package/src/modules/catalog/ai-tools/stats-pack.ts +84 -0
  118. package/src/modules/catalog/ai-tools/types.ts +81 -0
  119. package/src/modules/catalog/ai-tools/variants-pack.ts +147 -0
  120. package/src/modules/catalog/ai-tools.ts +78 -0
  121. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +597 -0
  122. package/src/modules/catalog/backend/catalog/products/page.tsx +23 -2
  123. package/src/modules/catalog/components/CatalogStatsCard.tsx +118 -0
  124. package/src/modules/catalog/components/products/ProductsDataTable.tsx +54 -6
  125. package/src/modules/catalog/events.ts +7 -4
  126. package/src/modules/catalog/i18n/de.json +17 -0
  127. package/src/modules/catalog/i18n/en.json +17 -0
  128. package/src/modules/catalog/i18n/es.json +17 -0
  129. package/src/modules/catalog/i18n/pl.json +17 -0
  130. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +109 -0
  131. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.ts +29 -0
  132. package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
  133. package/src/modules/catalog/widgets/injection-table.ts +12 -0
  134. package/src/modules/customer_accounts/i18n/de.json +5 -0
  135. package/src/modules/customer_accounts/i18n/en.json +5 -0
  136. package/src/modules/customer_accounts/i18n/es.json +5 -0
  137. package/src/modules/customer_accounts/i18n/pl.json +5 -0
  138. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +136 -0
  139. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.ts +43 -0
  140. package/src/modules/customer_accounts/widgets/injection-table.ts +9 -0
  141. package/src/modules/customers/AGENTS.md +13 -0
  142. package/src/modules/customers/ai-agents-context.ts +150 -0
  143. package/src/modules/customers/ai-agents.ts +355 -0
  144. package/src/modules/customers/ai-tools/activities-tasks-pack.ts +1248 -0
  145. package/src/modules/customers/ai-tools/addresses-tags-pack.ts +145 -0
  146. package/src/modules/customers/ai-tools/companies-pack.ts +362 -0
  147. package/src/modules/customers/ai-tools/deals-pack.ts +505 -0
  148. package/src/modules/customers/ai-tools/people-pack.ts +369 -0
  149. package/src/modules/customers/ai-tools/settings-pack.ts +121 -0
  150. package/src/modules/customers/ai-tools/types.ts +76 -0
  151. package/src/modules/customers/ai-tools.ts +34 -0
  152. package/src/modules/customers/i18n/de.json +25 -0
  153. package/src/modules/customers/i18n/en.json +25 -0
  154. package/src/modules/customers/i18n/es.json +25 -0
  155. package/src/modules/customers/i18n/pl.json +25 -0
  156. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +580 -0
  157. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +36 -0
  158. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +191 -0
  159. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.ts +37 -0
  160. package/src/modules/customers/widgets/injection-table.ts +41 -0
  161. package/src/modules/inbox_ops/ai-tools.ts +4 -0
  162. package/src/modules/inbox_ops/lib/llmProvider.ts +83 -7
  163. package/src/modules/notifications/setup.ts +11 -0
@@ -0,0 +1,469 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Building2, ChevronDown, Handshake, PanelRightOpen, Search, Sparkles, Users } from "lucide-react";
5
+ import { AiChat } from "@open-mercato/ui/ai/AiChat";
6
+ import { useAiDock } from "@open-mercato/ui/ai/AiDock";
7
+ import { useAiChatSessions } from "@open-mercato/ui/ai/AiChatSessions";
8
+ import { ChatPaneTabs } from "@open-mercato/ui/ai/ChatPaneTabs";
9
+ import { Button } from "@open-mercato/ui/primitives/button";
10
+ import { IconButton } from "@open-mercato/ui/primitives/icon-button";
11
+ import {
12
+ Dialog,
13
+ DialogContent,
14
+ DialogDescription,
15
+ DialogHeader,
16
+ DialogTitle
17
+ } from "@open-mercato/ui/primitives/dialog";
18
+ import { Popover, PopoverContent, PopoverTrigger } from "@open-mercato/ui/primitives/popover";
19
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
20
+ import { cn } from "@open-mercato/shared/lib/utils";
21
+ const CUSTOMERS_AI_INJECT_AGENT_ID = "customers.account_assistant";
22
+ function computeCustomersAiInjectPageContext(context) {
23
+ return buildPageContext(context);
24
+ }
25
+ function readString(value) {
26
+ return typeof value === "string" ? value : "";
27
+ }
28
+ function readNumber(value) {
29
+ if (typeof value === "number" && Number.isFinite(value)) return value;
30
+ if (typeof value === "string") {
31
+ const parsed = Number.parseInt(value, 10);
32
+ if (Number.isFinite(parsed)) return parsed;
33
+ }
34
+ return 0;
35
+ }
36
+ function resolveView(tableId) {
37
+ if (typeof tableId === "string" && tableId.includes("companies")) {
38
+ return "customers.companies.list";
39
+ }
40
+ return "customers.people.list";
41
+ }
42
+ function buildPageContext(context) {
43
+ const selectedIdsRaw = Array.isArray(context?.selectedRowIds) ? context?.selectedRowIds ?? [] : [];
44
+ const selectedIds = selectedIdsRaw.map(readString).filter((id) => id.length > 0);
45
+ const selectedCount = selectedIds.length > 0 ? selectedIds.length : readNumber(context?.selectedCount);
46
+ const totalMatching = readNumber(context?.totalMatching ?? context?.total ?? context?.rowCount);
47
+ const recordId = selectedIds.length > 0 ? selectedIds.join(",") : null;
48
+ return {
49
+ view: resolveView(context?.tableId),
50
+ recordType: null,
51
+ recordId,
52
+ extra: {
53
+ selectedCount,
54
+ totalMatching
55
+ }
56
+ };
57
+ }
58
+ function useCustomerSuggestions(view, hasSelection, selectedCount) {
59
+ const t = useT();
60
+ return React.useMemo(() => {
61
+ if (view === "customers.companies.list") {
62
+ if (hasSelection) {
63
+ return [
64
+ {
65
+ label: t(
66
+ "customers.ai_assistant.suggestions.summarizeSelectedCompanies",
67
+ "Summarize selected companies"
68
+ ),
69
+ prompt: `Give me a summary of my ${selectedCount} selected companies \u2014 size, industry, and recent activity`,
70
+ icon: /* @__PURE__ */ jsx(Building2, { className: "size-4" })
71
+ },
72
+ {
73
+ label: t(
74
+ "customers.ai_assistant.suggestions.dealsForSelectedCompanies",
75
+ "Show deals for selected companies"
76
+ ),
77
+ prompt: `Show me all deals associated with my ${selectedCount} selected companies`,
78
+ icon: /* @__PURE__ */ jsx(Handshake, { className: "size-4" })
79
+ },
80
+ {
81
+ label: t(
82
+ "customers.ai_assistant.suggestions.peopleAtSelectedCompanies",
83
+ "List people at selected companies"
84
+ ),
85
+ prompt: `List the contacts (people) associated with my ${selectedCount} selected companies`,
86
+ icon: /* @__PURE__ */ jsx(Users, { className: "size-4" })
87
+ }
88
+ ];
89
+ }
90
+ return [
91
+ {
92
+ label: t(
93
+ "customers.ai_assistant.suggestions.searchCompanies",
94
+ "Search for a company"
95
+ ),
96
+ prompt: "Search for companies by name, industry, or tax ID",
97
+ icon: /* @__PURE__ */ jsx(Search, { className: "size-4" })
98
+ },
99
+ {
100
+ label: t(
101
+ "customers.ai_assistant.suggestions.topCompaniesByDeals",
102
+ "Top companies by deal value"
103
+ ),
104
+ prompt: "Show me the companies with the highest open deal value",
105
+ icon: /* @__PURE__ */ jsx(Handshake, { className: "size-4" })
106
+ },
107
+ {
108
+ label: t(
109
+ "customers.ai_assistant.suggestions.companiesWithoutContacts",
110
+ "Companies missing contacts"
111
+ ),
112
+ prompt: "Find companies that have no associated people yet",
113
+ icon: /* @__PURE__ */ jsx(Users, { className: "size-4" })
114
+ },
115
+ {
116
+ label: t(
117
+ "customers.ai_assistant.suggestions.companiesActivityOverview",
118
+ "Activity overview"
119
+ ),
120
+ prompt: "Give me an overview of recent company-level activities and interactions",
121
+ icon: /* @__PURE__ */ jsx(Building2, { className: "size-4" })
122
+ }
123
+ ];
124
+ }
125
+ if (hasSelection) {
126
+ return [
127
+ {
128
+ label: t("customers.ai_assistant.suggestions.summarizeSelected", "Summarize selected contacts"),
129
+ prompt: `Give me a summary of my ${selectedCount} selected contacts \u2014 key details and recent activity`,
130
+ icon: /* @__PURE__ */ jsx(Users, { className: "size-4" })
131
+ },
132
+ {
133
+ label: t("customers.ai_assistant.suggestions.findDeals", "Show deals for selected people"),
134
+ prompt: `Show me all deals associated with my ${selectedCount} selected contacts`,
135
+ icon: /* @__PURE__ */ jsx(Handshake, { className: "size-4" })
136
+ },
137
+ {
138
+ label: t("customers.ai_assistant.suggestions.findCompanies", "Find related companies"),
139
+ prompt: `Find companies related to my ${selectedCount} selected contacts`,
140
+ icon: /* @__PURE__ */ jsx(Building2, { className: "size-4" })
141
+ }
142
+ ];
143
+ }
144
+ return [
145
+ {
146
+ label: t("customers.ai_assistant.suggestions.searchPeople", "Search for a contact"),
147
+ prompt: "Search for contacts by name, email, or company",
148
+ icon: /* @__PURE__ */ jsx(Search, { className: "size-4" })
149
+ },
150
+ {
151
+ label: t("customers.ai_assistant.suggestions.recentDeals", "Show recent deals"),
152
+ prompt: "Show me the most recent deals and their current stages",
153
+ icon: /* @__PURE__ */ jsx(Handshake, { className: "size-4" })
154
+ },
155
+ {
156
+ label: t("customers.ai_assistant.suggestions.topCompanies", "List top companies"),
157
+ prompt: "List companies with the most associated contacts and deals",
158
+ icon: /* @__PURE__ */ jsx(Building2, { className: "size-4" })
159
+ },
160
+ {
161
+ label: t("customers.ai_assistant.suggestions.activityOverview", "Activity overview"),
162
+ prompt: "Give me an overview of recent customer activities and interactions",
163
+ icon: /* @__PURE__ */ jsx(Users, { className: "size-4" })
164
+ }
165
+ ];
166
+ }, [view, hasSelection, selectedCount, t]);
167
+ }
168
+ function useCustomerContextItems(pageContext) {
169
+ const t = useT();
170
+ return React.useMemo(() => {
171
+ const items = [];
172
+ const { selectedCount, totalMatching } = pageContext.extra;
173
+ const isCompanies = pageContext.view === "customers.companies.list";
174
+ if (selectedCount > 0) {
175
+ const key = isCompanies ? "customers.ai_assistant.context.selectedCompanies" : "customers.ai_assistant.context.selectedPeople";
176
+ const fallback = isCompanies ? "{count} companies selected" : "{count} contacts selected";
177
+ items.push({ label: t(key, fallback).replace("{count}", String(selectedCount)) });
178
+ } else if (totalMatching > 0) {
179
+ const key = isCompanies ? "customers.ai_assistant.context.matchingCompanies" : "customers.ai_assistant.context.matchingPeople";
180
+ const fallback = isCompanies ? "{count} companies in view" : "{count} contacts in view";
181
+ items.push({ label: t(key, fallback).replace("{count}", String(totalMatching)) });
182
+ }
183
+ return items;
184
+ }, [pageContext, t]);
185
+ }
186
+ function useCustomerAgents() {
187
+ const t = useT();
188
+ return React.useMemo(
189
+ () => [
190
+ {
191
+ id: CUSTOMERS_AI_INJECT_AGENT_ID,
192
+ label: t("customers.ai_assistant.agents.account.label", "CRM Assistant"),
193
+ description: t(
194
+ "customers.ai_assistant.agents.account.description",
195
+ "Explore people, companies, deals, and activities."
196
+ ),
197
+ icon: /* @__PURE__ */ jsx(Sparkles, { className: "size-4" })
198
+ }
199
+ ],
200
+ [t]
201
+ );
202
+ }
203
+ function AiAssistantTriggerWidget({ context }) {
204
+ const t = useT();
205
+ const dock = useAiDock();
206
+ const [open, setOpen] = React.useState(false);
207
+ const [popoverOpen, setPopoverOpen] = React.useState(false);
208
+ const [activeAgent, setActiveAgent] = React.useState(CUSTOMERS_AI_INJECT_AGENT_ID);
209
+ const [lastAgent, setLastAgent] = React.useState(null);
210
+ const pageContext = React.useMemo(() => buildPageContext(context), [context]);
211
+ const agents = useCustomerAgents();
212
+ const selectedCount = pageContext.extra.selectedCount;
213
+ const hasSelection = selectedCount > 0;
214
+ const suggestions = useCustomerSuggestions(pageContext.view, hasSelection, selectedCount);
215
+ const contextItems = useCustomerContextItems(pageContext);
216
+ const openAgent = React.useCallback((agentId) => {
217
+ setActiveAgent(agentId);
218
+ setLastAgent(agentId);
219
+ setPopoverOpen(false);
220
+ if (dock.state.assistant?.agent === agentId) {
221
+ dock.dock(dock.state.assistant);
222
+ setOpen(false);
223
+ return;
224
+ }
225
+ setOpen(true);
226
+ }, [dock]);
227
+ const handleSelectAgent = React.useCallback((agentId) => {
228
+ openAgent(agentId);
229
+ }, [openAgent]);
230
+ const handleMainTriggerClick = React.useCallback(() => {
231
+ if (agents.length === 1) {
232
+ openAgent(agents[0].id);
233
+ return;
234
+ }
235
+ if (lastAgent && agents.some((a) => a.id === lastAgent)) {
236
+ openAgent(lastAgent);
237
+ return;
238
+ }
239
+ setPopoverOpen(true);
240
+ }, [agents, lastAgent, openAgent]);
241
+ const handleDock = React.useCallback(() => {
242
+ const agent = agents.find((a) => a.id === activeAgent) ?? agents[0];
243
+ if (!agent) return;
244
+ dock.dock({
245
+ agent: agent.id,
246
+ label: agent.label,
247
+ description: t("customers.ai_assistant.dock.subtitle", "Customers"),
248
+ pageContext,
249
+ placeholder: t(
250
+ "customers.ai_assistant.sheet.composerPlaceholder",
251
+ "Ask about people, companies, deals..."
252
+ ),
253
+ suggestions,
254
+ contextItems,
255
+ welcomeTitle: t("customers.ai_assistant.sheet.welcomeTitle", "CRM Assistant"),
256
+ welcomeDescription: hasSelection ? t(
257
+ "customers.ai_assistant.sheet.welcomeDescriptionSelection",
258
+ "Ready to explore your {count} selected contacts:"
259
+ ).replace("{count}", String(selectedCount)) : t(
260
+ "customers.ai_assistant.sheet.welcomeDescriptionAll",
261
+ "Ask me anything about your customers, companies, and deals:"
262
+ )
263
+ });
264
+ setOpen(false);
265
+ }, [
266
+ activeAgent,
267
+ agents,
268
+ contextItems,
269
+ dock,
270
+ hasSelection,
271
+ pageContext,
272
+ selectedCount,
273
+ suggestions,
274
+ t
275
+ ]);
276
+ const triggerLabel = t(
277
+ "customers.ai_assistant.trigger.ariaLabel",
278
+ "Open AI assistant for people"
279
+ );
280
+ const labelText = t("customers.ai_assistant.trigger.label", "AI");
281
+ const moreAgentsLabel = t(
282
+ "customers.ai_assistant.trigger.moreAgentsAriaLabel",
283
+ "Choose an AI assistant"
284
+ );
285
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
286
+ /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center", children: [
287
+ /* @__PURE__ */ jsxs(
288
+ Button,
289
+ {
290
+ type: "button",
291
+ variant: "outline",
292
+ onClick: handleMainTriggerClick,
293
+ "data-ai-customers-inject-trigger": "",
294
+ "aria-label": triggerLabel,
295
+ title: triggerLabel,
296
+ className: cn(
297
+ "relative",
298
+ agents.length > 1 && "rounded-r-none border-r-0"
299
+ ),
300
+ children: [
301
+ /* @__PURE__ */ jsx(Sparkles, { className: "size-4", "aria-hidden": true }),
302
+ /* @__PURE__ */ jsx("span", { children: labelText }),
303
+ hasSelection ? /* @__PURE__ */ jsx(
304
+ "span",
305
+ {
306
+ className: "absolute -top-1 -right-1 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-medium leading-none text-primary-foreground",
307
+ "data-ai-customers-inject-selected-count": selectedCount,
308
+ children: selectedCount
309
+ }
310
+ ) : null
311
+ ]
312
+ }
313
+ ),
314
+ agents.length > 1 ? /* @__PURE__ */ jsxs(Popover, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
315
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
316
+ IconButton,
317
+ {
318
+ type: "button",
319
+ variant: "outline",
320
+ size: "lg",
321
+ "aria-label": moreAgentsLabel,
322
+ title: moreAgentsLabel,
323
+ className: "rounded-l-none",
324
+ "data-ai-customers-inject-picker": "",
325
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4", "aria-hidden": true })
326
+ }
327
+ ) }),
328
+ /* @__PURE__ */ jsxs(PopoverContent, { align: "end", className: "w-72 p-1", children: [
329
+ /* @__PURE__ */ jsx("div", { className: "px-3 pt-2 pb-1 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: t("customers.ai_assistant.popover.heading", "AI assistants") }),
330
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: agents.map((agent) => /* @__PURE__ */ jsxs(
331
+ "button",
332
+ {
333
+ type: "button",
334
+ onClick: () => handleSelectAgent(agent.id),
335
+ "data-ai-customers-inject-agent-option": agent.id,
336
+ className: "flex items-start gap-2 rounded-sm px-2 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none",
337
+ children: [
338
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 inline-flex size-6 items-center justify-center rounded-full bg-secondary text-secondary-foreground", children: agent.icon }),
339
+ /* @__PURE__ */ jsxs("span", { className: "flex-1 min-w-0", children: [
340
+ /* @__PURE__ */ jsx("span", { className: "block font-medium leading-tight", children: agent.label }),
341
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground leading-snug", children: agent.description })
342
+ ] })
343
+ ]
344
+ },
345
+ agent.id
346
+ )) })
347
+ ] })
348
+ ] }) : null
349
+ ] }),
350
+ /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(
351
+ DialogContent,
352
+ {
353
+ className: cn(
354
+ // Mobile: full-screen sheet (no rounded corners, fills the
355
+ // viewport). Desktop (≥sm): right-anchored side sheet.
356
+ // The Dialog primitive ships a centering transform at the sm
357
+ // breakpoint (`sm:top-1/2 sm:left-1/2 sm:-translate-x-1/2
358
+ // sm:-translate-y-1/2 sm:inset-auto`); each must be overridden
359
+ // at the same `sm:` breakpoint or the panel renders half off
360
+ // the viewport.
361
+ "top-0 left-0 right-0 bottom-0 translate-x-0 translate-y-0 max-w-none w-screen h-svh max-h-svh rounded-none",
362
+ "sm:top-0 sm:bottom-0 sm:right-0 sm:left-auto sm:translate-x-0 sm:translate-y-0",
363
+ "sm:max-w-xl sm:w-[36rem] sm:rounded-l-2xl sm:h-screen sm:max-h-screen",
364
+ "flex flex-col gap-3 p-4 z-[70]"
365
+ ),
366
+ "data-ai-customers-inject-sheet": "",
367
+ children: [
368
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
369
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 pr-8", children: [
370
+ /* @__PURE__ */ jsx(
371
+ IconButton,
372
+ {
373
+ type: "button",
374
+ variant: "ghost",
375
+ size: "sm",
376
+ "aria-label": t("customers.ai_assistant.sheet.dock", "Dock to side"),
377
+ title: t("customers.ai_assistant.sheet.dock", "Dock to side"),
378
+ onClick: handleDock,
379
+ "data-ai-customers-inject-dock": "",
380
+ className: "hidden lg:inline-flex shrink-0",
381
+ children: /* @__PURE__ */ jsx(PanelRightOpen, { className: "size-4", "aria-hidden": true })
382
+ }
383
+ ),
384
+ /* @__PURE__ */ jsx(DialogTitle, { className: "flex-1 min-w-0 truncate", children: t("customers.ai_assistant.sheet.title", "Customers AI assistant") }),
385
+ hasSelection ? /* @__PURE__ */ jsx(
386
+ "span",
387
+ {
388
+ className: "shrink-0 inline-flex items-center rounded-full border border-border bg-secondary px-2 py-0.5 text-xs text-secondary-foreground",
389
+ "data-ai-customers-inject-selection-pill": "",
390
+ "data-ai-customers-inject-selected-count": selectedCount,
391
+ children: t(
392
+ "customers.ai_assistant.sheet.selectionPill",
393
+ "Acting on {count} selected"
394
+ ).replace("{count}", String(selectedCount))
395
+ }
396
+ ) : null
397
+ ] }),
398
+ /* @__PURE__ */ jsx(DialogDescription, { children: hasSelection ? t(
399
+ "customers.ai_assistant.sheet.descriptionWithSelection",
400
+ "Working with {count} selected contacts. Ask about their details, deals, companies, and activities."
401
+ ).replace("{count}", String(selectedCount)) : t(
402
+ "customers.ai_assistant.sheet.description",
403
+ "Your CRM assistant. Ask about people, companies, deals, and activities."
404
+ ) })
405
+ ] }),
406
+ /* @__PURE__ */ jsx(
407
+ CustomersChatBody,
408
+ {
409
+ activeAgent,
410
+ pageContext,
411
+ suggestions,
412
+ contextItems,
413
+ hasSelection,
414
+ selectedCount
415
+ }
416
+ )
417
+ ]
418
+ }
419
+ ) })
420
+ ] });
421
+ }
422
+ function CustomersChatBody({
423
+ activeAgent,
424
+ pageContext,
425
+ suggestions,
426
+ contextItems,
427
+ hasSelection,
428
+ selectedCount
429
+ }) {
430
+ const t = useT();
431
+ const sessions = useAiChatSessions();
432
+ const session = sessions.getActiveSession(activeAgent);
433
+ React.useEffect(() => {
434
+ if (!session) sessions.ensureSession(activeAgent);
435
+ }, [activeAgent, session, sessions]);
436
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
437
+ /* @__PURE__ */ jsx(ChatPaneTabs, { agentId: activeAgent, className: "border-b" }),
438
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", "data-ai-customers-inject-chat-container": "", children: session ? /* @__PURE__ */ jsx(
439
+ AiChat,
440
+ {
441
+ agent: activeAgent,
442
+ conversationId: session.conversationId,
443
+ pageContext,
444
+ className: "h-full",
445
+ placeholder: t(
446
+ "customers.ai_assistant.sheet.composerPlaceholder",
447
+ "Ask about people, companies, deals..."
448
+ ),
449
+ suggestions,
450
+ contextItems,
451
+ welcomeTitle: t("customers.ai_assistant.sheet.welcomeTitle", "CRM Assistant"),
452
+ welcomeDescription: hasSelection ? t(
453
+ "customers.ai_assistant.sheet.welcomeDescriptionSelection",
454
+ "Ready to explore your {count} selected contacts:"
455
+ ).replace("{count}", String(selectedCount)) : t(
456
+ "customers.ai_assistant.sheet.welcomeDescriptionAll",
457
+ "Ask me anything about your customers, companies, and deals:"
458
+ )
459
+ },
460
+ session.id
461
+ ) : null })
462
+ ] });
463
+ }
464
+ export {
465
+ CUSTOMERS_AI_INJECT_AGENT_ID,
466
+ computeCustomersAiInjectPageContext,
467
+ AiAssistantTriggerWidget as default
468
+ };
469
+ //# sourceMappingURL=widget.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\n/**\n * Step 4.10 \u2014 Backend AiChat injection widget (client).\n *\n * Renders a compact, round, icon-only trigger in the DataTable\n * `:search-trailing` injection slot (right next to the list search input).\n * Clicking the trigger opens a popover listing the AI agents this widget\n * exposes \u2014 currently `customers.account_assistant`, but the popover is\n * the agreed extension point for additional customers-domain agents\n * (selection digesters, deal-shapers, etc.). Picking an agent opens a\n * right-side sheet embedding `<AiChat>` for that agent.\n *\n * `pageContext` shape matches spec \u00A710.1 (view / recordType / recordId\n * / extra). The host DataTable provides selection + total information\n * through the `context` prop injected by `<InjectionSpot>`.\n */\n\nimport * as React from 'react'\nimport { Building2, ChevronDown, Handshake, PanelRightOpen, Search, Sparkles, Users } from 'lucide-react'\nimport { AiChat, type AiChatSuggestion, type AiChatContextItem } from '@open-mercato/ui/ai/AiChat'\nimport { useAiDock } from '@open-mercato/ui/ai/AiDock'\nimport { useAiChatSessions } from '@open-mercato/ui/ai/AiChatSessions'\nimport { ChatPaneTabs } from '@open-mercato/ui/ai/ChatPaneTabs'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nexport const CUSTOMERS_AI_INJECT_AGENT_ID = 'customers.account_assistant'\n\nexport type CustomersAiInjectView = 'customers.people.list' | 'customers.companies.list'\n\nexport interface CustomersAiInjectPageContext {\n view: CustomersAiInjectView\n recordType: null\n recordId: string | null\n extra: {\n selectedCount: number\n totalMatching: number\n }\n}\n\nexport function computeCustomersAiInjectPageContext(\n context: HostInjectionContext | undefined,\n): CustomersAiInjectPageContext {\n return buildPageContext(context)\n}\n\ninterface HostInjectionContext {\n tableId?: string | null\n title?: string\n selectedRowIds?: string[]\n selectedCount?: number\n total?: number\n totalMatching?: number\n rowCount?: number\n}\n\ninterface AiAssistantTriggerProps {\n context?: HostInjectionContext\n}\n\nfunction readString(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction readNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const parsed = Number.parseInt(value, 10)\n if (Number.isFinite(parsed)) return parsed\n }\n return 0\n}\n\nfunction resolveView(tableId: string | null | undefined): CustomersAiInjectView {\n if (typeof tableId === 'string' && tableId.includes('companies')) {\n return 'customers.companies.list'\n }\n return 'customers.people.list'\n}\n\nfunction buildPageContext(context: HostInjectionContext | undefined): CustomersAiInjectPageContext {\n const selectedIdsRaw = Array.isArray(context?.selectedRowIds) ? context?.selectedRowIds ?? [] : []\n const selectedIds = selectedIdsRaw.map(readString).filter((id) => id.length > 0)\n const selectedCount = selectedIds.length > 0\n ? selectedIds.length\n : readNumber(context?.selectedCount)\n const totalMatching = readNumber(context?.totalMatching ?? context?.total ?? context?.rowCount)\n const recordId = selectedIds.length > 0 ? selectedIds.join(',') : null\n return {\n view: resolveView(context?.tableId),\n recordType: null,\n recordId,\n extra: {\n selectedCount,\n totalMatching,\n },\n }\n}\n\nfunction useCustomerSuggestions(\n view: CustomersAiInjectView,\n hasSelection: boolean,\n selectedCount: number,\n): AiChatSuggestion[] {\n const t = useT()\n return React.useMemo(() => {\n if (view === 'customers.companies.list') {\n if (hasSelection) {\n return [\n {\n label: t(\n 'customers.ai_assistant.suggestions.summarizeSelectedCompanies',\n 'Summarize selected companies',\n ),\n prompt: `Give me a summary of my ${selectedCount} selected companies \u2014 size, industry, and recent activity`,\n icon: <Building2 className=\"size-4\" />,\n },\n {\n label: t(\n 'customers.ai_assistant.suggestions.dealsForSelectedCompanies',\n 'Show deals for selected companies',\n ),\n prompt: `Show me all deals associated with my ${selectedCount} selected companies`,\n icon: <Handshake className=\"size-4\" />,\n },\n {\n label: t(\n 'customers.ai_assistant.suggestions.peopleAtSelectedCompanies',\n 'List people at selected companies',\n ),\n prompt: `List the contacts (people) associated with my ${selectedCount} selected companies`,\n icon: <Users className=\"size-4\" />,\n },\n ]\n }\n return [\n {\n label: t(\n 'customers.ai_assistant.suggestions.searchCompanies',\n 'Search for a company',\n ),\n prompt: 'Search for companies by name, industry, or tax ID',\n icon: <Search className=\"size-4\" />,\n },\n {\n label: t(\n 'customers.ai_assistant.suggestions.topCompaniesByDeals',\n 'Top companies by deal value',\n ),\n prompt: 'Show me the companies with the highest open deal value',\n icon: <Handshake className=\"size-4\" />,\n },\n {\n label: t(\n 'customers.ai_assistant.suggestions.companiesWithoutContacts',\n 'Companies missing contacts',\n ),\n prompt: 'Find companies that have no associated people yet',\n icon: <Users className=\"size-4\" />,\n },\n {\n label: t(\n 'customers.ai_assistant.suggestions.companiesActivityOverview',\n 'Activity overview',\n ),\n prompt: 'Give me an overview of recent company-level activities and interactions',\n icon: <Building2 className=\"size-4\" />,\n },\n ]\n }\n if (hasSelection) {\n return [\n {\n label: t('customers.ai_assistant.suggestions.summarizeSelected', 'Summarize selected contacts'),\n prompt: `Give me a summary of my ${selectedCount} selected contacts \u2014 key details and recent activity`,\n icon: <Users className=\"size-4\" />,\n },\n {\n label: t('customers.ai_assistant.suggestions.findDeals', 'Show deals for selected people'),\n prompt: `Show me all deals associated with my ${selectedCount} selected contacts`,\n icon: <Handshake className=\"size-4\" />,\n },\n {\n label: t('customers.ai_assistant.suggestions.findCompanies', 'Find related companies'),\n prompt: `Find companies related to my ${selectedCount} selected contacts`,\n icon: <Building2 className=\"size-4\" />,\n },\n ]\n }\n return [\n {\n label: t('customers.ai_assistant.suggestions.searchPeople', 'Search for a contact'),\n prompt: 'Search for contacts by name, email, or company',\n icon: <Search className=\"size-4\" />,\n },\n {\n label: t('customers.ai_assistant.suggestions.recentDeals', 'Show recent deals'),\n prompt: 'Show me the most recent deals and their current stages',\n icon: <Handshake className=\"size-4\" />,\n },\n {\n label: t('customers.ai_assistant.suggestions.topCompanies', 'List top companies'),\n prompt: 'List companies with the most associated contacts and deals',\n icon: <Building2 className=\"size-4\" />,\n },\n {\n label: t('customers.ai_assistant.suggestions.activityOverview', 'Activity overview'),\n prompt: 'Give me an overview of recent customer activities and interactions',\n icon: <Users className=\"size-4\" />,\n },\n ]\n }, [view, hasSelection, selectedCount, t])\n}\n\nfunction useCustomerContextItems(pageContext: CustomersAiInjectPageContext): AiChatContextItem[] {\n const t = useT()\n return React.useMemo(() => {\n const items: AiChatContextItem[] = []\n const { selectedCount, totalMatching } = pageContext.extra\n const isCompanies = pageContext.view === 'customers.companies.list'\n if (selectedCount > 0) {\n const key = isCompanies\n ? 'customers.ai_assistant.context.selectedCompanies'\n : 'customers.ai_assistant.context.selectedPeople'\n const fallback = isCompanies ? '{count} companies selected' : '{count} contacts selected'\n items.push({ label: t(key, fallback).replace('{count}', String(selectedCount)) })\n } else if (totalMatching > 0) {\n const key = isCompanies\n ? 'customers.ai_assistant.context.matchingCompanies'\n : 'customers.ai_assistant.context.matchingPeople'\n const fallback = isCompanies ? '{count} companies in view' : '{count} contacts in view'\n items.push({ label: t(key, fallback).replace('{count}', String(totalMatching)) })\n }\n return items\n }, [pageContext, t])\n}\n\ninterface CustomerAgentDescriptor {\n id: string\n label: string\n description: string\n icon: React.ReactNode\n}\n\nfunction useCustomerAgents(): CustomerAgentDescriptor[] {\n const t = useT()\n return React.useMemo(\n () => [\n {\n id: CUSTOMERS_AI_INJECT_AGENT_ID,\n label: t('customers.ai_assistant.agents.account.label', 'CRM Assistant'),\n description: t(\n 'customers.ai_assistant.agents.account.description',\n 'Explore people, companies, deals, and activities.',\n ),\n icon: <Sparkles className=\"size-4\" />,\n },\n ],\n [t],\n )\n}\n\nexport default function AiAssistantTriggerWidget({ context }: AiAssistantTriggerProps) {\n const t = useT()\n const dock = useAiDock()\n const [open, setOpen] = React.useState(false)\n const [popoverOpen, setPopoverOpen] = React.useState(false)\n const [activeAgent, setActiveAgent] = React.useState<string>(CUSTOMERS_AI_INJECT_AGENT_ID)\n const [lastAgent, setLastAgent] = React.useState<string | null>(null)\n const pageContext = React.useMemo(() => buildPageContext(context), [context])\n const agents = useCustomerAgents()\n\n const selectedCount = pageContext.extra.selectedCount\n const hasSelection = selectedCount > 0\n const suggestions = useCustomerSuggestions(pageContext.view, hasSelection, selectedCount)\n const contextItems = useCustomerContextItems(pageContext)\n\n const openAgent = React.useCallback((agentId: string) => {\n setActiveAgent(agentId)\n setLastAgent(agentId)\n setPopoverOpen(false)\n if (dock.state.assistant?.agent === agentId) {\n dock.dock(dock.state.assistant)\n setOpen(false)\n return\n }\n setOpen(true)\n }, [dock])\n\n const handleSelectAgent = React.useCallback((agentId: string) => {\n openAgent(agentId)\n }, [openAgent])\n\n const handleMainTriggerClick = React.useCallback(() => {\n if (agents.length === 1) {\n openAgent(agents[0].id)\n return\n }\n if (lastAgent && agents.some((a) => a.id === lastAgent)) {\n openAgent(lastAgent)\n return\n }\n setPopoverOpen(true)\n }, [agents, lastAgent, openAgent])\n\n const handleDock = React.useCallback(() => {\n const agent = agents.find((a) => a.id === activeAgent) ?? agents[0]\n if (!agent) return\n dock.dock({\n agent: agent.id,\n label: agent.label,\n description: t('customers.ai_assistant.dock.subtitle', 'Customers'),\n pageContext: pageContext as unknown as Record<string, unknown>,\n placeholder: t(\n 'customers.ai_assistant.sheet.composerPlaceholder',\n 'Ask about people, companies, deals...',\n ),\n suggestions,\n contextItems,\n welcomeTitle: t('customers.ai_assistant.sheet.welcomeTitle', 'CRM Assistant'),\n welcomeDescription: hasSelection\n ? t(\n 'customers.ai_assistant.sheet.welcomeDescriptionSelection',\n 'Ready to explore your {count} selected contacts:',\n ).replace('{count}', String(selectedCount))\n : t(\n 'customers.ai_assistant.sheet.welcomeDescriptionAll',\n 'Ask me anything about your customers, companies, and deals:',\n ),\n })\n setOpen(false)\n }, [\n activeAgent,\n agents,\n contextItems,\n dock,\n hasSelection,\n pageContext,\n selectedCount,\n suggestions,\n t,\n ])\n\n const triggerLabel = t(\n 'customers.ai_assistant.trigger.ariaLabel',\n 'Open AI assistant for people',\n )\n\n const labelText = t('customers.ai_assistant.trigger.label', 'AI')\n const moreAgentsLabel = t(\n 'customers.ai_assistant.trigger.moreAgentsAriaLabel',\n 'Choose an AI assistant',\n )\n\n return (\n <>\n <div className=\"inline-flex items-center\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleMainTriggerClick}\n data-ai-customers-inject-trigger=\"\"\n aria-label={triggerLabel}\n title={triggerLabel}\n className={cn(\n 'relative',\n agents.length > 1 && 'rounded-r-none border-r-0',\n )}\n >\n <Sparkles className=\"size-4\" aria-hidden />\n <span>{labelText}</span>\n {hasSelection ? (\n <span\n className=\"absolute -top-1 -right-1 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-medium leading-none text-primary-foreground\"\n data-ai-customers-inject-selected-count={selectedCount}\n >\n {selectedCount}\n </span>\n ) : null}\n </Button>\n {agents.length > 1 ? (\n <Popover open={popoverOpen} onOpenChange={setPopoverOpen}>\n <PopoverTrigger asChild>\n <IconButton\n type=\"button\"\n variant=\"outline\"\n size=\"lg\"\n aria-label={moreAgentsLabel}\n title={moreAgentsLabel}\n className=\"rounded-l-none\"\n data-ai-customers-inject-picker=\"\"\n >\n <ChevronDown className=\"size-4\" aria-hidden />\n </IconButton>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-72 p-1\">\n <div className=\"px-3 pt-2 pb-1 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {t('customers.ai_assistant.popover.heading', 'AI assistants')}\n </div>\n <div className=\"flex flex-col gap-0.5\">\n {agents.map((agent) => (\n <button\n key={agent.id}\n type=\"button\"\n onClick={() => handleSelectAgent(agent.id)}\n data-ai-customers-inject-agent-option={agent.id}\n className=\"flex items-start gap-2 rounded-sm px-2 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none\"\n >\n <span className=\"mt-0.5 inline-flex size-6 items-center justify-center rounded-full bg-secondary text-secondary-foreground\">\n {agent.icon}\n </span>\n <span className=\"flex-1 min-w-0\">\n <span className=\"block font-medium leading-tight\">{agent.label}</span>\n <span className=\"block text-xs text-muted-foreground leading-snug\">\n {agent.description}\n </span>\n </span>\n </button>\n ))}\n </div>\n </PopoverContent>\n </Popover>\n ) : null}\n </div>\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogContent\n className={cn(\n // Mobile: full-screen sheet (no rounded corners, fills the\n // viewport). Desktop (\u2265sm): right-anchored side sheet.\n // The Dialog primitive ships a centering transform at the sm\n // breakpoint (`sm:top-1/2 sm:left-1/2 sm:-translate-x-1/2\n // sm:-translate-y-1/2 sm:inset-auto`); each must be overridden\n // at the same `sm:` breakpoint or the panel renders half off\n // the viewport.\n 'top-0 left-0 right-0 bottom-0 translate-x-0 translate-y-0 max-w-none w-screen h-svh max-h-svh rounded-none',\n 'sm:top-0 sm:bottom-0 sm:right-0 sm:left-auto sm:translate-x-0 sm:translate-y-0',\n 'sm:max-w-xl sm:w-[36rem] sm:rounded-l-2xl sm:h-screen sm:max-h-screen',\n 'flex flex-col gap-3 p-4 z-[70]',\n )}\n data-ai-customers-inject-sheet=\"\"\n >\n <DialogHeader>\n <div className=\"flex items-center gap-3 pr-8\">\n {/* Dock button lives on the LEFT \u2014 the Dialog primitive\n auto-renders an X close button absolutely positioned in\n the top-right corner, so anything we drop in the header's\n right side visually collides with it. Mobile hides the\n dock entirely (the side panel is desktop-only). */}\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={t('customers.ai_assistant.sheet.dock', 'Dock to side')}\n title={t('customers.ai_assistant.sheet.dock', 'Dock to side')}\n onClick={handleDock}\n data-ai-customers-inject-dock=\"\"\n className=\"hidden lg:inline-flex shrink-0\"\n >\n <PanelRightOpen className=\"size-4\" aria-hidden />\n </IconButton>\n <DialogTitle className=\"flex-1 min-w-0 truncate\">\n {t('customers.ai_assistant.sheet.title', 'Customers AI assistant')}\n </DialogTitle>\n {hasSelection ? (\n <span\n className=\"shrink-0 inline-flex items-center rounded-full border border-border bg-secondary px-2 py-0.5 text-xs text-secondary-foreground\"\n data-ai-customers-inject-selection-pill=\"\"\n data-ai-customers-inject-selected-count={selectedCount}\n >\n {t(\n 'customers.ai_assistant.sheet.selectionPill',\n 'Acting on {count} selected',\n ).replace('{count}', String(selectedCount))}\n </span>\n ) : null}\n </div>\n <DialogDescription>\n {hasSelection\n ? t(\n 'customers.ai_assistant.sheet.descriptionWithSelection',\n 'Working with {count} selected contacts. Ask about their details, deals, companies, and activities.',\n ).replace('{count}', String(selectedCount))\n : t(\n 'customers.ai_assistant.sheet.description',\n 'Your CRM assistant. Ask about people, companies, deals, and activities.',\n )}\n </DialogDescription>\n </DialogHeader>\n <CustomersChatBody\n activeAgent={activeAgent}\n pageContext={pageContext}\n suggestions={suggestions}\n contextItems={contextItems}\n hasSelection={hasSelection}\n selectedCount={selectedCount}\n />\n </DialogContent>\n </Dialog>\n </>\n )\n}\n\ninterface CustomersChatBodyProps {\n activeAgent: string\n pageContext: CustomersAiInjectPageContext\n suggestions: AiChatSuggestion[]\n contextItems: AiChatContextItem[]\n hasSelection: boolean\n selectedCount: number\n}\n\nfunction CustomersChatBody({\n activeAgent,\n pageContext,\n suggestions,\n contextItems,\n hasSelection,\n selectedCount,\n}: CustomersChatBodyProps) {\n const t = useT()\n const sessions = useAiChatSessions()\n const session = sessions.getActiveSession(activeAgent)\n\n // Lazily ensure an open session exists. Running `ensureSession` inside an\n // effect (not inline during render) keeps the provider's setState calls\n // outside of the render phase. The first frame may render without a\n // session \u2014 that's fine, we render the tab strip alone until the next\n // tick when the new session is committed and `getActiveSession` returns it.\n React.useEffect(() => {\n if (!session) sessions.ensureSession(activeAgent)\n }, [activeAgent, session, sessions])\n\n return (\n <>\n <ChatPaneTabs agentId={activeAgent} className=\"border-b\" />\n <div className=\"min-h-0 flex-1\" data-ai-customers-inject-chat-container=\"\">\n {session ? (\n <AiChat\n // `key` forces a fresh mount when the active tab changes so the\n // AI SDK's status doesn't leak across sessions.\n key={session.id}\n agent={activeAgent}\n conversationId={session.conversationId}\n pageContext={pageContext as unknown as Record<string, unknown>}\n className=\"h-full\"\n placeholder={t(\n 'customers.ai_assistant.sheet.composerPlaceholder',\n 'Ask about people, companies, deals...',\n )}\n suggestions={suggestions}\n contextItems={contextItems}\n welcomeTitle={t('customers.ai_assistant.sheet.welcomeTitle', 'CRM Assistant')}\n welcomeDescription={\n hasSelection\n ? t(\n 'customers.ai_assistant.sheet.welcomeDescriptionSelection',\n 'Ready to explore your {count} selected contacts:',\n ).replace('{count}', String(selectedCount))\n : t(\n 'customers.ai_assistant.sheet.welcomeDescriptionAll',\n 'Ask me anything about your customers, companies, and deals:',\n )\n }\n />\n ) : null}\n </div>\n </>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import AiAssistantTriggerWidget from "./widget.client.js";
2
+ const widget = {
3
+ metadata: {
4
+ id: "customers.injection.ai-assistant-trigger",
5
+ title: "Customers AI Assistant Trigger",
6
+ description: 'Renders an "Ask AI" button in the people list header that opens a sheet embedding the customers account assistant.',
7
+ features: ["customers.people.view", "ai_assistant.view"],
8
+ priority: 100,
9
+ enabled: true
10
+ },
11
+ Widget: AiAssistantTriggerWidget
12
+ };
13
+ var widget_default = widget;
14
+ export {
15
+ widget_default as default
16
+ };
17
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts"],
4
+ "sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport AiAssistantTriggerWidget from './widget.client'\n\n/**\n * Step 4.10 \u2014 Backend AiChat injection example.\n *\n * Demonstrates how a third-party module can drop `<AiChat>` onto a page\n * it does NOT own (the customers People list) via the existing widget\n * injection system. Targets spot `data-table:customers.people.list:header`,\n * which is owned by the `DataTable` primitive in `packages/ui`.\n *\n * The trigger button opens a right-side sheet embedding\n * `<AiChat agent=\"customers.account_assistant\" pageContext={...} />`.\n * `pageContext` follows the spec \u00A710.1 shape:\n *\n * { view: 'customers.people.list',\n * recordType: null,\n * recordId: string, // \"\" or comma-separated UUIDs\n * extra: { selectedCount, totalMatching } }\n *\n * Feature-gated behind `customers.people.view` + `ai_assistant.view`.\n */\nconst widget: InjectionWidgetModule<Record<string, unknown>, Record<string, unknown>> = {\n metadata: {\n id: 'customers.injection.ai-assistant-trigger',\n title: 'Customers AI Assistant Trigger',\n description:\n 'Renders an \"Ask AI\" button in the people list header that opens a sheet embedding the customers account assistant.',\n features: ['customers.people.view', 'ai_assistant.view'],\n priority: 100,\n enabled: true,\n },\n Widget: AiAssistantTriggerWidget,\n}\n\nexport default widget\n"],
5
+ "mappings": "AACA,OAAO,8BAA8B;AAqBrC,MAAM,SAAkF;AAAA,EACtF,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aACE;AAAA,IACF,UAAU,CAAC,yBAAyB,mBAAmB;AAAA,IACvD,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
6
+ "names": []
7
+ }