@kite-copilot/chat-panel 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -9
- package/dist/auto.cjs +3638 -0
- package/dist/auto.d.cts +60 -0
- package/dist/auto.d.ts +60 -0
- package/dist/auto.js +23 -0
- package/dist/chunk-R73Y24JS.js +3665 -0
- package/dist/createKiteChat-CFo7NUHz.d.cts +254 -0
- package/dist/createKiteChat-CFo7NUHz.d.ts +254 -0
- package/dist/embed.global.js +22 -23
- package/dist/index.cjs +3718 -0
- package/dist/index.d.cts +179 -0
- package/dist/index.d.ts +90 -287
- package/dist/index.js +67 -2737
- package/dist/styles.css +1 -1
- package/package.json +34 -23
- package/dist/index.d.mts +0 -376
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -2692
- package/dist/index.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,2738 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
69
|
-
icon: "size-9",
|
|
70
|
-
"icon-sm": "size-8",
|
|
71
|
-
"icon-lg": "size-10"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
defaultVariants: {
|
|
75
|
-
variant: "default",
|
|
76
|
-
size: "default"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
);
|
|
80
|
-
function Button({
|
|
81
|
-
className,
|
|
82
|
-
variant,
|
|
83
|
-
size,
|
|
84
|
-
asChild = false,
|
|
85
|
-
...props
|
|
86
|
-
}) {
|
|
87
|
-
const Comp = asChild ? reactSlot.Slot : "button";
|
|
88
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
89
|
-
Comp,
|
|
90
|
-
{
|
|
91
|
-
"data-slot": "button",
|
|
92
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
93
|
-
...props
|
|
94
|
-
}
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
var ScrollArea = React4__namespace.forwardRef(({ className, children, ...props }, ref) => {
|
|
98
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99
|
-
ScrollAreaPrimitive__namespace.Root,
|
|
100
|
-
{
|
|
101
|
-
"data-slot": "scroll-area",
|
|
102
|
-
className: cn("relative", className),
|
|
103
|
-
...props,
|
|
104
|
-
children: [
|
|
105
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
106
|
-
ScrollAreaPrimitive__namespace.Viewport,
|
|
107
|
-
{
|
|
108
|
-
ref,
|
|
109
|
-
"data-slot": "scroll-area-viewport",
|
|
110
|
-
className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
|
|
111
|
-
children
|
|
112
|
-
}
|
|
113
|
-
),
|
|
114
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
|
|
115
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.Corner, {})
|
|
116
|
-
]
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
});
|
|
120
|
-
ScrollArea.displayName = "ScrollArea";
|
|
121
|
-
function ScrollBar({
|
|
122
|
-
className,
|
|
123
|
-
orientation = "vertical",
|
|
124
|
-
...props
|
|
125
|
-
}) {
|
|
126
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
127
|
-
ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
|
|
128
|
-
{
|
|
129
|
-
"data-slot": "scroll-area-scrollbar",
|
|
130
|
-
orientation,
|
|
131
|
-
className: cn(
|
|
132
|
-
"flex touch-none p-px transition-colors select-none",
|
|
133
|
-
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
134
|
-
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
|
|
135
|
-
className
|
|
136
|
-
),
|
|
137
|
-
...props,
|
|
138
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
139
|
-
ScrollAreaPrimitive__namespace.ScrollAreaThumb,
|
|
140
|
-
{
|
|
141
|
-
"data-slot": "scroll-area-thumb",
|
|
142
|
-
className: "bg-border relative flex-1 rounded-full"
|
|
143
|
-
}
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
function AssistantActivity({
|
|
149
|
-
phase,
|
|
150
|
-
progressSteps = []
|
|
151
|
-
}) {
|
|
152
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 rounded-lg bg-muted/40 px-3 py-3 text-xs text-muted-foreground transition-colors", children: [
|
|
153
|
-
phase === "thinking" && progressSteps.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
154
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
155
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Thinking\u2026" })
|
|
156
|
-
] }),
|
|
157
|
-
phase === "searching" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 animate-in fade-in-0 duration-300", children: [
|
|
158
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
159
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "h-3.5 w-3.5 opacity-70" }),
|
|
160
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Searching across pages\u2026" })
|
|
161
|
-
] }),
|
|
162
|
-
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "ml-6 list-disc space-y-1", children: [
|
|
163
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { className: "opacity-90", children: "Checking recent changes" }),
|
|
164
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { className: "opacity-90", children: "Scanning documentation" }),
|
|
165
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { className: "opacity-90", children: "Summarizing relevant sections" })
|
|
166
|
-
] })
|
|
167
|
-
] }),
|
|
168
|
-
(phase === "thinking" || phase === "executing" || phase === "responding") && progressSteps.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 animate-in fade-in-0 duration-200", children: [
|
|
169
|
-
progressSteps.map((step, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
170
|
-
"div",
|
|
171
|
-
{
|
|
172
|
-
className: `flex items-center gap-2 transition-opacity duration-200 ${step.completed ? "opacity-60" : "opacity-100"}`,
|
|
173
|
-
children: [
|
|
174
|
-
step.completed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3.5 w-3.5 text-green-500 flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin flex-shrink-0" }),
|
|
175
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: step.completed ? "line-through" : "", children: step.message })
|
|
176
|
-
]
|
|
177
|
-
},
|
|
178
|
-
index
|
|
179
|
-
)),
|
|
180
|
-
phase === "responding" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 opacity-100 animate-in fade-in-0 duration-200", children: [
|
|
181
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin flex-shrink-0" }),
|
|
182
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Preparing response..." })
|
|
183
|
-
] })
|
|
184
|
-
] })
|
|
185
|
-
] });
|
|
186
|
-
}
|
|
187
|
-
function GuideCursor({ x, y, visible, onClick = false }) {
|
|
188
|
-
return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: visible && /* @__PURE__ */ jsxRuntime.jsx(
|
|
189
|
-
framerMotion.motion.div,
|
|
190
|
-
{
|
|
191
|
-
className: "fixed pointer-events-none z-[9999]",
|
|
192
|
-
initial: { opacity: 0, scale: 0.5 },
|
|
193
|
-
animate: {
|
|
194
|
-
opacity: 1,
|
|
195
|
-
scale: 1,
|
|
196
|
-
x,
|
|
197
|
-
y
|
|
198
|
-
},
|
|
199
|
-
exit: { opacity: 0, scale: 0.5 },
|
|
200
|
-
transition: {
|
|
201
|
-
type: "spring",
|
|
202
|
-
stiffness: 200,
|
|
203
|
-
damping: 20
|
|
204
|
-
},
|
|
205
|
-
style: {
|
|
206
|
-
left: 0,
|
|
207
|
-
top: 0
|
|
208
|
-
},
|
|
209
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
210
|
-
"svg",
|
|
211
|
-
{
|
|
212
|
-
width: "32",
|
|
213
|
-
height: "32",
|
|
214
|
-
viewBox: "0 0 24 24",
|
|
215
|
-
fill: "none",
|
|
216
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
217
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
218
|
-
"path",
|
|
219
|
-
{
|
|
220
|
-
d: "M3 3L10.07 19.97L12.58 12.58L19.97 10.07L3 3Z",
|
|
221
|
-
fill: "#C4B5FD"
|
|
222
|
-
}
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
)
|
|
226
|
-
}
|
|
227
|
-
) });
|
|
228
|
-
}
|
|
229
|
-
function useGuideCursor() {
|
|
230
|
-
const [cursorState, setCursorState] = React4__namespace.useState({
|
|
231
|
-
x: 0,
|
|
232
|
-
y: 0,
|
|
233
|
-
visible: false,
|
|
234
|
-
onClick: false
|
|
235
|
-
});
|
|
236
|
-
const moveTo = React4__namespace.useCallback((target) => {
|
|
237
|
-
const element = document.querySelector(target.selector);
|
|
238
|
-
if (element) {
|
|
239
|
-
const rect = element.getBoundingClientRect();
|
|
240
|
-
const offsetX = target.offset?.x || 0;
|
|
241
|
-
const offsetY = target.offset?.y || 0;
|
|
242
|
-
setCursorState({
|
|
243
|
-
x: rect.left + rect.width / 2 + offsetX,
|
|
244
|
-
y: rect.top + rect.height / 2 + offsetY,
|
|
245
|
-
visible: true,
|
|
246
|
-
onClick: target.onClick || false
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}, []);
|
|
250
|
-
const hide = React4__namespace.useCallback(() => {
|
|
251
|
-
setCursorState((prev) => ({ ...prev, visible: false }));
|
|
252
|
-
}, []);
|
|
253
|
-
const show = React4__namespace.useCallback(() => {
|
|
254
|
-
setCursorState((prev) => ({ ...prev, visible: true }));
|
|
255
|
-
}, []);
|
|
256
|
-
return {
|
|
257
|
-
cursorState,
|
|
258
|
-
moveTo,
|
|
259
|
-
hide,
|
|
260
|
-
show
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
function Card({ className, ...props }) {
|
|
264
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
265
|
-
"div",
|
|
266
|
-
{
|
|
267
|
-
"data-slot": "card",
|
|
268
|
-
className: cn(
|
|
269
|
-
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
270
|
-
className
|
|
271
|
-
),
|
|
272
|
-
...props
|
|
273
|
-
}
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
function CardHeader({ className, ...props }) {
|
|
277
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
278
|
-
"div",
|
|
279
|
-
{
|
|
280
|
-
"data-slot": "card-header",
|
|
281
|
-
className: cn(
|
|
282
|
-
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
283
|
-
className
|
|
284
|
-
),
|
|
285
|
-
...props
|
|
286
|
-
}
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
function CardTitle({ className, ...props }) {
|
|
290
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
291
|
-
"div",
|
|
292
|
-
{
|
|
293
|
-
"data-slot": "card-title",
|
|
294
|
-
className: cn("leading-none font-semibold", className),
|
|
295
|
-
...props
|
|
296
|
-
}
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
function CardDescription({ className, ...props }) {
|
|
300
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
301
|
-
"div",
|
|
302
|
-
{
|
|
303
|
-
"data-slot": "card-description",
|
|
304
|
-
className: cn("text-muted-foreground text-sm", className),
|
|
305
|
-
...props
|
|
306
|
-
}
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
function CardAction({ className, ...props }) {
|
|
310
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
311
|
-
"div",
|
|
312
|
-
{
|
|
313
|
-
"data-slot": "card-action",
|
|
314
|
-
className: cn(
|
|
315
|
-
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
316
|
-
className
|
|
317
|
-
),
|
|
318
|
-
...props
|
|
319
|
-
}
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
function CardContent({ className, ...props }) {
|
|
323
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
324
|
-
"div",
|
|
325
|
-
{
|
|
326
|
-
"data-slot": "card-content",
|
|
327
|
-
className: cn("px-6", className),
|
|
328
|
-
...props
|
|
329
|
-
}
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
function CardFooter({ className, ...props }) {
|
|
333
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
334
|
-
"div",
|
|
335
|
-
{
|
|
336
|
-
"data-slot": "card-footer",
|
|
337
|
-
className: cn("flex items-center px-6 [.border-t]:pt-6", className),
|
|
338
|
-
...props
|
|
339
|
-
}
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
var formatDate = (dateString) => {
|
|
343
|
-
const date = new Date(dateString);
|
|
344
|
-
return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
1
|
+
import {
|
|
2
|
+
ApiKeyList,
|
|
3
|
+
AssistantActivity,
|
|
4
|
+
AssistantSearchSummary,
|
|
5
|
+
Button,
|
|
6
|
+
Card,
|
|
7
|
+
CardAction,
|
|
8
|
+
CardContent,
|
|
9
|
+
CardDescription,
|
|
10
|
+
CardFooter,
|
|
11
|
+
CardHeader,
|
|
12
|
+
CardTitle,
|
|
13
|
+
ChatPanel,
|
|
14
|
+
ChatPanelWithToggle,
|
|
15
|
+
CustomerCard,
|
|
16
|
+
CustomerList,
|
|
17
|
+
DashboardStatsCard,
|
|
18
|
+
DataRenderer,
|
|
19
|
+
GuideCursor,
|
|
20
|
+
HelpButton,
|
|
21
|
+
Input,
|
|
22
|
+
PanelToggle,
|
|
23
|
+
ScrollArea,
|
|
24
|
+
ScrollBar,
|
|
25
|
+
SessionList,
|
|
26
|
+
SubscriptionCard,
|
|
27
|
+
SubscriptionList,
|
|
28
|
+
TopCustomersList,
|
|
29
|
+
TransactionList,
|
|
30
|
+
buttonVariants,
|
|
31
|
+
cn,
|
|
32
|
+
createKiteChat,
|
|
33
|
+
useGuideCursor
|
|
34
|
+
} from "./chunk-R73Y24JS.js";
|
|
35
|
+
export {
|
|
36
|
+
ApiKeyList,
|
|
37
|
+
AssistantActivity,
|
|
38
|
+
AssistantSearchSummary,
|
|
39
|
+
Button,
|
|
40
|
+
Card,
|
|
41
|
+
CardAction,
|
|
42
|
+
CardContent,
|
|
43
|
+
CardDescription,
|
|
44
|
+
CardFooter,
|
|
45
|
+
CardHeader,
|
|
46
|
+
CardTitle,
|
|
47
|
+
ChatPanel,
|
|
48
|
+
ChatPanelWithToggle,
|
|
49
|
+
CustomerCard,
|
|
50
|
+
CustomerList,
|
|
51
|
+
DashboardStatsCard,
|
|
52
|
+
DataRenderer,
|
|
53
|
+
GuideCursor,
|
|
54
|
+
HelpButton,
|
|
55
|
+
Input,
|
|
56
|
+
PanelToggle,
|
|
57
|
+
ScrollArea,
|
|
58
|
+
ScrollBar,
|
|
59
|
+
SessionList,
|
|
60
|
+
SubscriptionCard,
|
|
61
|
+
SubscriptionList,
|
|
62
|
+
TopCustomersList,
|
|
63
|
+
TransactionList,
|
|
64
|
+
buttonVariants,
|
|
65
|
+
cn,
|
|
66
|
+
createKiteChat,
|
|
67
|
+
useGuideCursor
|
|
345
68
|
};
|
|
346
|
-
var formatCurrency = (amount, currency = "USD") => {
|
|
347
|
-
return new Intl.NumberFormat("en-US", {
|
|
348
|
-
style: "currency",
|
|
349
|
-
currency
|
|
350
|
-
}).format(amount);
|
|
351
|
-
};
|
|
352
|
-
var getPlanIcon = (plan) => {
|
|
353
|
-
switch (plan) {
|
|
354
|
-
case "Enterprise":
|
|
355
|
-
return lucideReact.Crown;
|
|
356
|
-
case "Professional":
|
|
357
|
-
return lucideReact.Zap;
|
|
358
|
-
default:
|
|
359
|
-
return lucideReact.Activity;
|
|
360
|
-
}
|
|
361
|
-
};
|
|
362
|
-
var getPlanColor = (plan) => {
|
|
363
|
-
switch (plan) {
|
|
364
|
-
case "Enterprise":
|
|
365
|
-
return "bg-purple-50 text-purple-700 border-purple-200";
|
|
366
|
-
case "Professional":
|
|
367
|
-
return "bg-blue-50 text-blue-700 border-blue-200";
|
|
368
|
-
default:
|
|
369
|
-
return "bg-gray-50 text-gray-700 border-gray-200";
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
function StatusBadge({ status, type = "default" }) {
|
|
373
|
-
const getConfig = () => {
|
|
374
|
-
const statusLower = status.toLowerCase();
|
|
375
|
-
if (type === "transaction") {
|
|
376
|
-
switch (statusLower) {
|
|
377
|
-
case "paid":
|
|
378
|
-
return { color: "bg-emerald-50 text-emerald-700 border-emerald-200", icon: lucideReact.CheckCircle2 };
|
|
379
|
-
case "failed":
|
|
380
|
-
return { color: "bg-red-50 text-red-700 border-red-200", icon: lucideReact.XCircle };
|
|
381
|
-
case "pending":
|
|
382
|
-
return { color: "bg-amber-50 text-amber-700 border-amber-200", icon: lucideReact.Clock };
|
|
383
|
-
case "refunded":
|
|
384
|
-
return { color: "bg-slate-50 text-slate-700 border-slate-200", icon: lucideReact.RefreshCw };
|
|
385
|
-
default:
|
|
386
|
-
return { color: "bg-gray-50 text-gray-700 border-gray-200", icon: lucideReact.AlertCircle };
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
if (type === "subscription") {
|
|
390
|
-
switch (statusLower) {
|
|
391
|
-
case "active":
|
|
392
|
-
return { color: "bg-emerald-50 text-emerald-700 border-emerald-200", icon: lucideReact.CheckCircle2 };
|
|
393
|
-
case "cancelled":
|
|
394
|
-
return { color: "bg-slate-50 text-slate-700 border-slate-200", icon: lucideReact.XCircle };
|
|
395
|
-
case "past_due":
|
|
396
|
-
return { color: "bg-red-50 text-red-700 border-red-200", icon: lucideReact.AlertCircle };
|
|
397
|
-
case "trialing":
|
|
398
|
-
return { color: "bg-blue-50 text-blue-700 border-blue-200", icon: lucideReact.Clock };
|
|
399
|
-
default:
|
|
400
|
-
return { color: "bg-gray-50 text-gray-700 border-gray-200", icon: lucideReact.AlertCircle };
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
switch (statusLower) {
|
|
404
|
-
case "active":
|
|
405
|
-
return { color: "bg-emerald-50 text-emerald-700 border-emerald-200", icon: lucideReact.CheckCircle2 };
|
|
406
|
-
case "inactive":
|
|
407
|
-
return { color: "bg-slate-50 text-slate-700 border-slate-200", icon: lucideReact.XCircle };
|
|
408
|
-
default:
|
|
409
|
-
return { color: "bg-gray-50 text-gray-700 border-gray-200", icon: lucideReact.AlertCircle };
|
|
410
|
-
}
|
|
411
|
-
};
|
|
412
|
-
const config = getConfig();
|
|
413
|
-
const Icon = config.icon;
|
|
414
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium border ${config.color}`, children: [
|
|
415
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3 w-3" }),
|
|
416
|
-
status
|
|
417
|
-
] });
|
|
418
|
-
}
|
|
419
|
-
function SubscriptionCard({ subscription }) {
|
|
420
|
-
const PlanIcon = getPlanIcon(subscription.plan);
|
|
421
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
422
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-1 ${subscription.status === "active" ? "bg-emerald-500" : subscription.status === "past_due" ? "bg-red-500" : "bg-slate-300"}` }),
|
|
423
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
|
|
424
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
425
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-base font-semibold text-gray-900 flex items-center gap-2", children: [
|
|
426
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4 text-gray-500" }),
|
|
427
|
-
subscription.id
|
|
428
|
-
] }),
|
|
429
|
-
subscription.customer_email && /* @__PURE__ */ jsxRuntime.jsxs(CardDescription, { className: "text-sm text-gray-500 flex items-center gap-1.5", children: [
|
|
430
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "h-3 w-3" }),
|
|
431
|
-
subscription.customer_email
|
|
432
|
-
] })
|
|
433
|
-
] }),
|
|
434
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: subscription.status, type: "subscription" })
|
|
435
|
-
] }) }),
|
|
436
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "pt-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
437
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
438
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
439
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Plan" }),
|
|
440
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium border ${getPlanColor(subscription.plan)}`, children: [
|
|
441
|
-
/* @__PURE__ */ jsxRuntime.jsx(PlanIcon, { className: "h-3 w-3" }),
|
|
442
|
-
subscription.plan
|
|
443
|
-
] })
|
|
444
|
-
] }),
|
|
445
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
446
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Billing" }),
|
|
447
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-medium text-gray-900", children: [
|
|
448
|
-
formatCurrency(subscription.amount, subscription.currency),
|
|
449
|
-
" / ",
|
|
450
|
-
subscription.billing_cycle
|
|
451
|
-
] })
|
|
452
|
-
] })
|
|
453
|
-
] }),
|
|
454
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
455
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
456
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Current Period" }),
|
|
457
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-gray-700", children: [
|
|
458
|
-
formatDate(subscription.current_period_start),
|
|
459
|
-
" - ",
|
|
460
|
-
formatDate(subscription.current_period_end)
|
|
461
|
-
] })
|
|
462
|
-
] }),
|
|
463
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
464
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Created" }),
|
|
465
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-gray-700", children: formatDate(subscription.created_at) })
|
|
466
|
-
] })
|
|
467
|
-
] })
|
|
468
|
-
] }) })
|
|
469
|
-
] });
|
|
470
|
-
}
|
|
471
|
-
function SubscriptionList({ subscriptions, maxItems = 5 }) {
|
|
472
|
-
const displaySubs = subscriptions.slice(0, maxItems);
|
|
473
|
-
const hasMore = subscriptions.length > maxItems;
|
|
474
|
-
if (subscriptions.length === 0) {
|
|
475
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-gray-200 shadow-sm bg-white", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "py-8 text-center", children: [
|
|
476
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-10 w-10 text-gray-300 mx-auto mb-3" }),
|
|
477
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No subscriptions found" })
|
|
478
|
-
] }) });
|
|
479
|
-
}
|
|
480
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
481
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
482
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
|
|
483
|
-
subscriptions.length,
|
|
484
|
-
" Subscription",
|
|
485
|
-
subscriptions.length !== 1 ? "s" : ""
|
|
486
|
-
] }) }),
|
|
487
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-0", children: [
|
|
488
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: displaySubs.map((sub) => {
|
|
489
|
-
const PlanIcon = getPlanIcon(sub.plan);
|
|
490
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
491
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
492
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `p-2 rounded-lg ${getPlanColor(sub.plan).replace("text-", "text-").replace("border-", "bg-").split(" ")[0]}`, children: /* @__PURE__ */ jsxRuntime.jsx(PlanIcon, { className: "h-4 w-4" }) }),
|
|
493
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
494
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: sub.customer_email || sub.customer_id }),
|
|
495
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
496
|
-
sub.plan,
|
|
497
|
-
" \xB7 ",
|
|
498
|
-
formatCurrency(sub.amount, sub.currency),
|
|
499
|
-
"/",
|
|
500
|
-
sub.billing_cycle
|
|
501
|
-
] })
|
|
502
|
-
] })
|
|
503
|
-
] }),
|
|
504
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: sub.status, type: "subscription" })
|
|
505
|
-
] }) }, sub.id);
|
|
506
|
-
}) }),
|
|
507
|
-
hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 bg-gray-50 border-t border-gray-100 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
|
|
508
|
-
"+",
|
|
509
|
-
subscriptions.length - maxItems,
|
|
510
|
-
" more subscription",
|
|
511
|
-
subscriptions.length - maxItems !== 1 ? "s" : ""
|
|
512
|
-
] }) })
|
|
513
|
-
] })
|
|
514
|
-
] });
|
|
515
|
-
}
|
|
516
|
-
function CustomerCard({ customer }) {
|
|
517
|
-
const PlanIcon = getPlanIcon(customer.subscription);
|
|
518
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
519
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-1 ${customer.status === "active" ? "bg-emerald-500" : "bg-slate-300"}` }),
|
|
520
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
|
|
521
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
522
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base font-semibold text-gray-900", children: customer.name }),
|
|
523
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardDescription, { className: "text-sm text-gray-500 flex items-center gap-1", children: [
|
|
524
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "h-3 w-3" }),
|
|
525
|
-
customer.email
|
|
526
|
-
] })
|
|
527
|
-
] }) }),
|
|
528
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: customer.status, type: "customer" })
|
|
529
|
-
] }) }),
|
|
530
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "pt-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
531
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
532
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
533
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Plan" }),
|
|
534
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium border ${getPlanColor(customer.subscription)}`, children: [
|
|
535
|
-
/* @__PURE__ */ jsxRuntime.jsx(PlanIcon, { className: "h-3 w-3" }),
|
|
536
|
-
customer.subscription
|
|
537
|
-
] })
|
|
538
|
-
] }),
|
|
539
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
540
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Revenue" }),
|
|
541
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-medium text-gray-900 flex items-center gap-1", children: [
|
|
542
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DollarSign, { className: "h-3 w-3 text-emerald-500" }),
|
|
543
|
-
customer.revenue
|
|
544
|
-
] })
|
|
545
|
-
] })
|
|
546
|
-
] }),
|
|
547
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
548
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
549
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Location" }),
|
|
550
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-gray-700 flex items-center gap-1", children: [
|
|
551
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-3 w-3 text-gray-400" }),
|
|
552
|
-
customer.location || "Not specified"
|
|
553
|
-
] })
|
|
554
|
-
] }),
|
|
555
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
556
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 mb-1", children: "Customer Since" }),
|
|
557
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-gray-700 flex items-center gap-1", children: [
|
|
558
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-3 w-3 text-gray-400" }),
|
|
559
|
-
customer.joinDate
|
|
560
|
-
] })
|
|
561
|
-
] })
|
|
562
|
-
] })
|
|
563
|
-
] }) })
|
|
564
|
-
] });
|
|
565
|
-
}
|
|
566
|
-
function CustomerList({ customers, maxItems = 5 }) {
|
|
567
|
-
const displayCustomers = customers.slice(0, maxItems);
|
|
568
|
-
const hasMore = customers.length > maxItems;
|
|
569
|
-
if (customers.length === 0) {
|
|
570
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-gray-200 shadow-sm bg-white", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "py-8 text-center", children: [
|
|
571
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "h-10 w-10 text-gray-300 mx-auto mb-3" }),
|
|
572
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No customers found" })
|
|
573
|
-
] }) });
|
|
574
|
-
}
|
|
575
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
576
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
577
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "h-4 w-4" }),
|
|
578
|
-
customers.length,
|
|
579
|
-
" Customer",
|
|
580
|
-
customers.length !== 1 ? "s" : ""
|
|
581
|
-
] }) }),
|
|
582
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-0", children: [
|
|
583
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: displayCustomers.map((customer) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
584
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
585
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: customer.name }),
|
|
586
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 truncate", children: customer.email })
|
|
587
|
-
] }) }),
|
|
588
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
589
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-2 py-0.5 rounded text-xs font-medium ${getPlanColor(customer.subscription)}`, children: customer.subscription }),
|
|
590
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: customer.status, type: "customer" })
|
|
591
|
-
] })
|
|
592
|
-
] }) }, customer.id)) }),
|
|
593
|
-
hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 bg-gray-50 border-t border-gray-100 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
|
|
594
|
-
"+",
|
|
595
|
-
customers.length - maxItems,
|
|
596
|
-
" more customer",
|
|
597
|
-
customers.length - maxItems !== 1 ? "s" : ""
|
|
598
|
-
] }) })
|
|
599
|
-
] })
|
|
600
|
-
] });
|
|
601
|
-
}
|
|
602
|
-
function TransactionList({ transactions, maxItems = 5 }) {
|
|
603
|
-
const displayTransactions = transactions.slice(0, maxItems);
|
|
604
|
-
const hasMore = transactions.length > maxItems;
|
|
605
|
-
if (transactions.length === 0) {
|
|
606
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-gray-200 shadow-sm bg-white", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "py-8 text-center", children: [
|
|
607
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DollarSign, { className: "h-10 w-10 text-gray-300 mx-auto mb-3" }),
|
|
608
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No transactions found" })
|
|
609
|
-
] }) });
|
|
610
|
-
}
|
|
611
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
612
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
613
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DollarSign, { className: "h-4 w-4" }),
|
|
614
|
-
transactions.length,
|
|
615
|
-
" Transaction",
|
|
616
|
-
transactions.length !== 1 ? "s" : ""
|
|
617
|
-
] }) }),
|
|
618
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-0", children: [
|
|
619
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: displayTransactions.map((tx) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
620
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
621
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `p-2 rounded-lg ${tx.status === "paid" ? "bg-emerald-50" : tx.status === "failed" ? "bg-red-50" : tx.status === "refunded" ? "bg-slate-50" : "bg-amber-50"}`, children: tx.status === "paid" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-4 w-4 text-emerald-600" }) : tx.status === "failed" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-4 w-4 text-red-600" }) : tx.status === "refunded" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4 text-slate-600" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4 text-amber-600" }) }),
|
|
622
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
623
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: tx.customer }),
|
|
624
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
625
|
-
tx.date,
|
|
626
|
-
tx.decline_reason && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-red-500 ml-2", children: [
|
|
627
|
-
"\xB7 ",
|
|
628
|
-
tx.decline_reason
|
|
629
|
-
] })
|
|
630
|
-
] })
|
|
631
|
-
] })
|
|
632
|
-
] }),
|
|
633
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
634
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `text-sm font-semibold ${tx.status === "paid" ? "text-emerald-600" : tx.status === "failed" ? "text-red-600" : tx.status === "refunded" ? "text-slate-600" : "text-amber-600"}`, children: [
|
|
635
|
-
tx.status === "refunded" ? "-" : "",
|
|
636
|
-
tx.amount
|
|
637
|
-
] }),
|
|
638
|
-
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: tx.status, type: "transaction" })
|
|
639
|
-
] })
|
|
640
|
-
] }) }, tx.id)) }),
|
|
641
|
-
hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 bg-gray-50 border-t border-gray-100 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-500", children: [
|
|
642
|
-
"+",
|
|
643
|
-
transactions.length - maxItems,
|
|
644
|
-
" more transaction",
|
|
645
|
-
transactions.length - maxItems !== 1 ? "s" : ""
|
|
646
|
-
] }) })
|
|
647
|
-
] })
|
|
648
|
-
] });
|
|
649
|
-
}
|
|
650
|
-
function ApiKeyList({ apiKeys }) {
|
|
651
|
-
if (apiKeys.length === 0) {
|
|
652
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-gray-200 shadow-sm bg-white", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "py-8 text-center", children: [
|
|
653
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Key, { className: "h-10 w-10 text-gray-300 mx-auto mb-3" }),
|
|
654
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No API keys found" })
|
|
655
|
-
] }) });
|
|
656
|
-
}
|
|
657
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
658
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
659
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Key, { className: "h-4 w-4" }),
|
|
660
|
-
apiKeys.length,
|
|
661
|
-
" API Key",
|
|
662
|
-
apiKeys.length !== 1 ? "s" : ""
|
|
663
|
-
] }) }),
|
|
664
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: apiKeys.map((key, idx) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
665
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
666
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-900", children: key.name }),
|
|
667
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 font-mono", children: [
|
|
668
|
-
key.key.slice(0, 12),
|
|
669
|
-
"...",
|
|
670
|
-
key.key.slice(-4)
|
|
671
|
-
] })
|
|
672
|
-
] }),
|
|
673
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
674
|
-
"Last used: ",
|
|
675
|
-
key.lastUsed
|
|
676
|
-
] })
|
|
677
|
-
] }) }, idx)) }) })
|
|
678
|
-
] });
|
|
679
|
-
}
|
|
680
|
-
function SessionList({ sessions }) {
|
|
681
|
-
const getDeviceIcon = (device) => {
|
|
682
|
-
const deviceLower = device.toLowerCase();
|
|
683
|
-
if (deviceLower.includes("mobile") || deviceLower.includes("iphone") || deviceLower.includes("android")) {
|
|
684
|
-
return lucideReact.Smartphone;
|
|
685
|
-
}
|
|
686
|
-
return lucideReact.Laptop;
|
|
687
|
-
};
|
|
688
|
-
if (sessions.length === 0) {
|
|
689
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-gray-200 shadow-sm bg-white", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "py-8 text-center", children: [
|
|
690
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "h-10 w-10 text-gray-300 mx-auto mb-3" }),
|
|
691
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No active sessions" })
|
|
692
|
-
] }) });
|
|
693
|
-
}
|
|
694
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
695
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
696
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "h-4 w-4" }),
|
|
697
|
-
sessions.length,
|
|
698
|
-
" Active Session",
|
|
699
|
-
sessions.length !== 1 ? "s" : ""
|
|
700
|
-
] }) }),
|
|
701
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: sessions.map((session, idx) => {
|
|
702
|
-
const DeviceIcon = getDeviceIcon(session.device);
|
|
703
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
704
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
705
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 rounded-lg bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(DeviceIcon, { className: "h-4 w-4 text-gray-600" }) }),
|
|
706
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
707
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-900", children: session.device }),
|
|
708
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 flex items-center gap-1", children: [
|
|
709
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-3 w-3" }),
|
|
710
|
-
session.location
|
|
711
|
-
] })
|
|
712
|
-
] })
|
|
713
|
-
] }),
|
|
714
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500", children: session.time })
|
|
715
|
-
] }) }, idx);
|
|
716
|
-
}) }) })
|
|
717
|
-
] });
|
|
718
|
-
}
|
|
719
|
-
function DashboardStatsCard({ stats }) {
|
|
720
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
721
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
722
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-4 w-4" }),
|
|
723
|
-
"Dashboard Overview"
|
|
724
|
-
] }) }),
|
|
725
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
726
|
-
stats.revenue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 rounded-lg bg-emerald-50 border border-emerald-100", children: [
|
|
727
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-emerald-600 font-medium mb-1", children: "Revenue" }),
|
|
728
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-lg font-bold text-emerald-700", children: formatCurrency(stats.revenue.total) }),
|
|
729
|
-
stats.revenue.change !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `text-xs ${stats.revenue.change > 0 ? "text-emerald-600" : "text-red-600"}`, children: [
|
|
730
|
-
stats.revenue.change > 0 ? "+" : "",
|
|
731
|
-
stats.revenue.change,
|
|
732
|
-
"% from last period"
|
|
733
|
-
] })
|
|
734
|
-
] }),
|
|
735
|
-
stats.subscriptions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 rounded-lg bg-blue-50 border border-blue-100", children: [
|
|
736
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-blue-600 font-medium mb-1", children: "Subscriptions" }),
|
|
737
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-lg font-bold text-blue-700", children: [
|
|
738
|
-
stats.subscriptions.active,
|
|
739
|
-
" active"
|
|
740
|
-
] }),
|
|
741
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-blue-600", children: [
|
|
742
|
-
stats.subscriptions.total,
|
|
743
|
-
" total"
|
|
744
|
-
] })
|
|
745
|
-
] }),
|
|
746
|
-
stats.customers && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 rounded-lg bg-purple-50 border border-purple-100", children: [
|
|
747
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-purple-600 font-medium mb-1", children: "Customers" }),
|
|
748
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-lg font-bold text-purple-700", children: stats.customers.total }),
|
|
749
|
-
stats.customers.new > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-purple-600", children: [
|
|
750
|
-
"+",
|
|
751
|
-
stats.customers.new,
|
|
752
|
-
" new this period"
|
|
753
|
-
] })
|
|
754
|
-
] }),
|
|
755
|
-
stats.transactions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 rounded-lg bg-amber-50 border border-amber-100", children: [
|
|
756
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-amber-600 font-medium mb-1", children: "Transactions" }),
|
|
757
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-lg font-bold text-amber-700", children: [
|
|
758
|
-
stats.transactions.successful,
|
|
759
|
-
" successful"
|
|
760
|
-
] }),
|
|
761
|
-
stats.transactions.failed > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-red-600", children: [
|
|
762
|
-
stats.transactions.failed,
|
|
763
|
-
" failed"
|
|
764
|
-
] })
|
|
765
|
-
] })
|
|
766
|
-
] }) })
|
|
767
|
-
] });
|
|
768
|
-
}
|
|
769
|
-
function TopCustomersList({ customers }) {
|
|
770
|
-
if (customers.length === 0) {
|
|
771
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-gray-200 shadow-sm bg-white", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "py-8 text-center", children: [
|
|
772
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crown, { className: "h-10 w-10 text-gray-300 mx-auto mb-3" }),
|
|
773
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No top customers data" })
|
|
774
|
-
] }) });
|
|
775
|
-
}
|
|
776
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-gray-200 shadow-sm bg-white overflow-hidden", children: [
|
|
777
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "text-sm font-medium text-gray-700 flex items-center gap-2", children: [
|
|
778
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crown, { className: "h-4 w-4 text-amber-500" }),
|
|
779
|
-
"Top Customers"
|
|
780
|
-
] }) }),
|
|
781
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-gray-100", children: customers.map((customer, idx) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 hover:bg-gray-50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
782
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
783
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `h-6 w-6 rounded-full flex items-center justify-center text-xs font-bold ${idx === 0 ? "bg-amber-100 text-amber-700" : idx === 1 ? "bg-slate-100 text-slate-700" : idx === 2 ? "bg-orange-100 text-orange-700" : "bg-gray-100 text-gray-700"}`, children: idx + 1 }),
|
|
784
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
785
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-900 truncate", children: customer.name }),
|
|
786
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-500 truncate", children: customer.email })
|
|
787
|
-
] })
|
|
788
|
-
] }),
|
|
789
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-emerald-600", children: typeof customer.revenue === "number" ? formatCurrency(customer.revenue) : customer.revenue })
|
|
790
|
-
] }) }, idx)) }) })
|
|
791
|
-
] });
|
|
792
|
-
}
|
|
793
|
-
function DataRenderer({ type, data }) {
|
|
794
|
-
if (!data) return null;
|
|
795
|
-
const dataObj = data;
|
|
796
|
-
switch (type) {
|
|
797
|
-
case "subscription":
|
|
798
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SubscriptionCard, { subscription: dataObj });
|
|
799
|
-
case "subscriptions": {
|
|
800
|
-
const subs = dataObj.subscriptions || dataObj || [];
|
|
801
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SubscriptionList, { subscriptions: Array.isArray(subs) ? subs : [subs] });
|
|
802
|
-
}
|
|
803
|
-
case "customer":
|
|
804
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CustomerCard, { customer: dataObj.customer || dataObj });
|
|
805
|
-
case "customers": {
|
|
806
|
-
const custs = dataObj.customers || dataObj || [];
|
|
807
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CustomerList, { customers: Array.isArray(custs) ? custs : [custs] });
|
|
808
|
-
}
|
|
809
|
-
case "transactions": {
|
|
810
|
-
const txs = dataObj.transactions || dataObj || [];
|
|
811
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TransactionList, { transactions: Array.isArray(txs) ? txs : [txs] });
|
|
812
|
-
}
|
|
813
|
-
case "transaction":
|
|
814
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TransactionList, { transactions: [dataObj], maxItems: 1 });
|
|
815
|
-
case "dashboard_stats":
|
|
816
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DashboardStatsCard, { stats: dataObj });
|
|
817
|
-
case "top_customers": {
|
|
818
|
-
const topCustomers = dataObj.customers || dataObj || [];
|
|
819
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TopCustomersList, { customers: Array.isArray(topCustomers) ? topCustomers : [topCustomers] });
|
|
820
|
-
}
|
|
821
|
-
case "api_keys": {
|
|
822
|
-
const keys = dataObj.api_keys || dataObj || [];
|
|
823
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ApiKeyList, { apiKeys: Array.isArray(keys) ? keys : [keys] });
|
|
824
|
-
}
|
|
825
|
-
case "sessions": {
|
|
826
|
-
const sessions = dataObj.sessions || dataObj || [];
|
|
827
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SessionList, { sessions: Array.isArray(sessions) ? sessions : [sessions] });
|
|
828
|
-
}
|
|
829
|
-
default:
|
|
830
|
-
return null;
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
var defaultFolders = [
|
|
834
|
-
{
|
|
835
|
-
id: "customers",
|
|
836
|
-
title: "Customer Management",
|
|
837
|
-
topics: [
|
|
838
|
-
{ id: "add-customer", label: "Add a new customer", prompt: "How do I add a new customer to the system and what information is required?" },
|
|
839
|
-
{ id: "customer-details", label: "View customer details", prompt: "Show me how to view and edit customer information and their payment history." }
|
|
840
|
-
]
|
|
841
|
-
},
|
|
842
|
-
{
|
|
843
|
-
id: "payments",
|
|
844
|
-
title: "Payment Processing",
|
|
845
|
-
topics: [
|
|
846
|
-
{ id: "process-payment", label: "Process a payment", prompt: "How do I process a one-time payment for a customer?" },
|
|
847
|
-
{ id: "refund-payment", label: "Issue a refund", prompt: "Walk me through issuing a refund for a customer payment." }
|
|
848
|
-
]
|
|
849
|
-
},
|
|
850
|
-
{
|
|
851
|
-
id: "subscriptions",
|
|
852
|
-
title: "Subscription Management",
|
|
853
|
-
topics: [
|
|
854
|
-
{ id: "create-subscription", label: "Create a subscription", prompt: "How do I set up a new subscription plan for a customer?" },
|
|
855
|
-
{ id: "update-subscription", label: "Update subscription tier", prompt: "How can I change a customer's subscription plan or upgrade them?" }
|
|
856
|
-
]
|
|
857
|
-
},
|
|
858
|
-
{
|
|
859
|
-
id: "billing",
|
|
860
|
-
title: "Billing",
|
|
861
|
-
topics: [
|
|
862
|
-
{ id: "payment-methods", label: "Manage payment methods", prompt: "How do customers add or update their payment methods?" }
|
|
863
|
-
]
|
|
864
|
-
}
|
|
865
|
-
];
|
|
866
|
-
var defaultGuides = {
|
|
867
|
-
"getting-started": {
|
|
868
|
-
id: "getting-started",
|
|
869
|
-
title: "Getting started",
|
|
870
|
-
steps: [
|
|
871
|
-
{
|
|
872
|
-
text: "Step 1: Let's open the Customers page. This is where you'll manage all your customers - you can view, add, and edit customer information here.",
|
|
873
|
-
navigation: { page: "customers" },
|
|
874
|
-
cursorTarget: {
|
|
875
|
-
selector: '[data-page="customers"]',
|
|
876
|
-
offset: { x: 0, y: 0 },
|
|
877
|
-
onClick: true
|
|
878
|
-
}
|
|
879
|
-
},
|
|
880
|
-
{
|
|
881
|
-
text: "Step 2: Now let's open the Add customer dialog. This is where you'll enter information for your first customer, including their name, email, and other details.",
|
|
882
|
-
navigation: { page: "customers" },
|
|
883
|
-
cursorTarget: {
|
|
884
|
-
selector: '[data-testid="add-customer-button"]',
|
|
885
|
-
offset: { x: 0, y: 0 },
|
|
886
|
-
onClick: true
|
|
887
|
-
}
|
|
888
|
-
},
|
|
889
|
-
{
|
|
890
|
-
text: "Step 3: Let's open the Settings page. This is where you manage your account settings, company information, and preferences. We're going to verify your company address is correct.",
|
|
891
|
-
navigation: { page: "settings", subtab: "general" },
|
|
892
|
-
cursorTarget: {
|
|
893
|
-
selector: '[data-page="settings"]',
|
|
894
|
-
offset: { x: 0, y: 0 },
|
|
895
|
-
onClick: true
|
|
896
|
-
}
|
|
897
|
-
},
|
|
898
|
-
{
|
|
899
|
-
text: "Step 4: Here's the address field in the Company Information section. It's important to verify this address is accurate since it's used for billing and shipping purposes. Make sure it's up to date.",
|
|
900
|
-
navigation: { page: "settings", subtab: "general" },
|
|
901
|
-
cursorTarget: {
|
|
902
|
-
selector: '[data-testid="company-address-input"]',
|
|
903
|
-
offset: { x: 0, y: 0 },
|
|
904
|
-
onClick: false
|
|
905
|
-
}
|
|
906
|
-
},
|
|
907
|
-
{
|
|
908
|
-
text: "Step 5: Let's open the API Keys tab. This section shows all your API keys - you'll need these to connect your application to our services. We're going to create a production API key.",
|
|
909
|
-
navigation: { page: "settings", subtab: "api" },
|
|
910
|
-
cursorTarget: {
|
|
911
|
-
selector: '[data-settings-tab="api"]',
|
|
912
|
-
offset: { x: 0, y: 0 },
|
|
913
|
-
onClick: true
|
|
914
|
-
}
|
|
915
|
-
},
|
|
916
|
-
{
|
|
917
|
-
text: "Step 6: Let's open the Create API Key dialog. Here you can create a new API key for your application. You'll want to give it a descriptive name like 'Production Key' so you can easily identify it later.",
|
|
918
|
-
navigation: { page: "settings", subtab: "api" },
|
|
919
|
-
cursorTarget: {
|
|
920
|
-
selector: '[data-testid="create-api-key-button"]',
|
|
921
|
-
offset: { x: 0, y: 0 },
|
|
922
|
-
onClick: true
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
]
|
|
926
|
-
},
|
|
927
|
-
"add-api-key": {
|
|
928
|
-
id: "add-api-key",
|
|
929
|
-
title: "How to add an API key",
|
|
930
|
-
steps: [
|
|
931
|
-
{
|
|
932
|
-
text: "Step 1: Let's open the Settings page. This is where you manage your account settings and preferences. We need to go here to access the API Keys section.",
|
|
933
|
-
navigation: { page: "settings", subtab: "general" },
|
|
934
|
-
cursorTarget: {
|
|
935
|
-
selector: '[data-page="settings"]',
|
|
936
|
-
offset: { x: 0, y: 0 },
|
|
937
|
-
onClick: false
|
|
938
|
-
}
|
|
939
|
-
},
|
|
940
|
-
{
|
|
941
|
-
text: "Step 2: Let's open the API Keys tab. This section shows all your API keys and allows you to create new ones. You'll need API keys to connect your application to our services.",
|
|
942
|
-
navigation: { page: "settings", subtab: "api" },
|
|
943
|
-
cursorTarget: {
|
|
944
|
-
selector: '[data-settings-tab="api"]',
|
|
945
|
-
offset: { x: 0, y: 0 },
|
|
946
|
-
onClick: true
|
|
947
|
-
}
|
|
948
|
-
},
|
|
949
|
-
{
|
|
950
|
-
text: "Step 3: Let's open the Create API Key dialog. This is where you'll create your new API key - you can give it a name to help you identify it later, then click Create to generate it.",
|
|
951
|
-
navigation: { page: "settings", subtab: "api" },
|
|
952
|
-
cursorTarget: {
|
|
953
|
-
selector: '[data-testid="create-api-key-button"]',
|
|
954
|
-
offset: { x: 0, y: 0 },
|
|
955
|
-
onClick: true
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
]
|
|
959
|
-
},
|
|
960
|
-
"refund-payment": {
|
|
961
|
-
id: "refund-payment",
|
|
962
|
-
title: "How to refund a payment",
|
|
963
|
-
steps: [
|
|
964
|
-
{
|
|
965
|
-
text: "Step 1: Let's open the Home page. This is your dashboard where you can view today's activity, your payment overview, and recent transactions. We need to go here to find the payment you want to refund.",
|
|
966
|
-
navigation: { page: "dashboard" },
|
|
967
|
-
cursorTarget: {
|
|
968
|
-
selector: '[data-page="dashboard"]',
|
|
969
|
-
offset: { x: 0, y: 0 },
|
|
970
|
-
onClick: true
|
|
971
|
-
}
|
|
972
|
-
},
|
|
973
|
-
{
|
|
974
|
-
text: "Step 2: Scroll down to see the Recent transactions section at the bottom. This shows your latest payment transactions with their status. We're looking for a transaction with 'paid' status - only paid transactions can be refunded.",
|
|
975
|
-
navigation: { page: "dashboard" },
|
|
976
|
-
cursorTarget: {
|
|
977
|
-
selector: '[data-testid="recent-activity-card"]',
|
|
978
|
-
offset: { x: 0, y: 0 },
|
|
979
|
-
onClick: false
|
|
980
|
-
}
|
|
981
|
-
},
|
|
982
|
-
{
|
|
983
|
-
text: "Step 3: Let's open the dropdown menu for this paid transaction. Each transaction has a menu button (three dots) that gives you options like refunding. Click it to see the available actions, including the 'Refund payment' option.",
|
|
984
|
-
navigation: { page: "dashboard" },
|
|
985
|
-
cursorTarget: {
|
|
986
|
-
selector: '[data-testid="transaction-menu-button"]',
|
|
987
|
-
offset: { x: 0, y: 0 },
|
|
988
|
-
onClick: true
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
]
|
|
992
|
-
}
|
|
993
|
-
};
|
|
994
|
-
var BUILT_IN_AGENT_URL = process.env.AGENT_URL || "https://api.kite.com";
|
|
995
|
-
var defaultConfig = {
|
|
996
|
-
userId: "",
|
|
997
|
-
orgId: "",
|
|
998
|
-
agentUrl: BUILT_IN_AGENT_URL,
|
|
999
|
-
theme: "light",
|
|
1000
|
-
position: "bottom-right",
|
|
1001
|
-
showDefaultFolders: true,
|
|
1002
|
-
enableGuideCursor: true
|
|
1003
|
-
};
|
|
1004
|
-
var ChatPanelContext = React4__namespace.createContext(null);
|
|
1005
|
-
function ChatPanelProvider({ children, config }) {
|
|
1006
|
-
const value = React4__namespace.useMemo(() => {
|
|
1007
|
-
const mergedConfig = { ...defaultConfig, ...config };
|
|
1008
|
-
let folders = [];
|
|
1009
|
-
if (mergedConfig.showDefaultFolders !== false) {
|
|
1010
|
-
folders = [...defaultFolders];
|
|
1011
|
-
}
|
|
1012
|
-
if (mergedConfig.folders) {
|
|
1013
|
-
folders = [...folders, ...mergedConfig.folders];
|
|
1014
|
-
}
|
|
1015
|
-
const guides = {
|
|
1016
|
-
...mergedConfig.showDefaultFolders !== false ? defaultGuides : {},
|
|
1017
|
-
...mergedConfig.guides
|
|
1018
|
-
};
|
|
1019
|
-
return {
|
|
1020
|
-
config: mergedConfig,
|
|
1021
|
-
userId: mergedConfig.userId,
|
|
1022
|
-
orgId: mergedConfig.orgId,
|
|
1023
|
-
agentUrl: mergedConfig.agentUrl || BUILT_IN_AGENT_URL,
|
|
1024
|
-
folders,
|
|
1025
|
-
guides,
|
|
1026
|
-
theme: mergedConfig.theme || "light",
|
|
1027
|
-
position: mergedConfig.position || "bottom-right",
|
|
1028
|
-
enableGuideCursor: mergedConfig.enableGuideCursor !== false
|
|
1029
|
-
};
|
|
1030
|
-
}, [config]);
|
|
1031
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChatPanelContext.Provider, { value, children });
|
|
1032
|
-
}
|
|
1033
|
-
function useChatPanelConfig() {
|
|
1034
|
-
const context = React4__namespace.useContext(ChatPanelContext);
|
|
1035
|
-
if (!context) {
|
|
1036
|
-
return {
|
|
1037
|
-
config: defaultConfig,
|
|
1038
|
-
userId: defaultConfig.userId,
|
|
1039
|
-
orgId: defaultConfig.orgId,
|
|
1040
|
-
agentUrl: defaultConfig.agentUrl || BUILT_IN_AGENT_URL,
|
|
1041
|
-
folders: defaultFolders,
|
|
1042
|
-
guides: defaultGuides,
|
|
1043
|
-
theme: "light",
|
|
1044
|
-
position: "bottom-right",
|
|
1045
|
-
enableGuideCursor: true
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
return context;
|
|
1049
|
-
}
|
|
1050
|
-
function renderMarkdown(text) {
|
|
1051
|
-
if (!text) return null;
|
|
1052
|
-
const lines = text.split("\n");
|
|
1053
|
-
const elements = [];
|
|
1054
|
-
let currentList = null;
|
|
1055
|
-
let inCodeBlock = false;
|
|
1056
|
-
let codeContent = [];
|
|
1057
|
-
const processInlineFormatting = (line) => {
|
|
1058
|
-
const parts = [];
|
|
1059
|
-
let remaining = line;
|
|
1060
|
-
let keyIndex = 0;
|
|
1061
|
-
while (remaining.length > 0) {
|
|
1062
|
-
const codeMatch = remaining.match(/^`([^`]+)`/);
|
|
1063
|
-
if (codeMatch) {
|
|
1064
|
-
parts.push(
|
|
1065
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "bg-gray-100 px-1 py-0.5 rounded text-xs font-mono", children: codeMatch[1] }, keyIndex++)
|
|
1066
|
-
);
|
|
1067
|
-
remaining = remaining.slice(codeMatch[0].length);
|
|
1068
|
-
continue;
|
|
1069
|
-
}
|
|
1070
|
-
const boldMatch = remaining.match(/^\*\*([^*]+)\*\*/);
|
|
1071
|
-
if (boldMatch) {
|
|
1072
|
-
parts.push(/* @__PURE__ */ jsxRuntime.jsx("strong", { children: boldMatch[1] }, keyIndex++));
|
|
1073
|
-
remaining = remaining.slice(boldMatch[0].length);
|
|
1074
|
-
continue;
|
|
1075
|
-
}
|
|
1076
|
-
const italicMatch = remaining.match(/^\*([^*]+)\*/);
|
|
1077
|
-
if (italicMatch) {
|
|
1078
|
-
parts.push(/* @__PURE__ */ jsxRuntime.jsx("em", { children: italicMatch[1] }, keyIndex++));
|
|
1079
|
-
remaining = remaining.slice(italicMatch[0].length);
|
|
1080
|
-
continue;
|
|
1081
|
-
}
|
|
1082
|
-
const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)]+)\)/);
|
|
1083
|
-
if (linkMatch) {
|
|
1084
|
-
parts.push(
|
|
1085
|
-
/* @__PURE__ */ jsxRuntime.jsx("a", { href: linkMatch[2], className: "text-blue-600 hover:underline", target: "_blank", rel: "noopener noreferrer", children: linkMatch[1] }, keyIndex++)
|
|
1086
|
-
);
|
|
1087
|
-
remaining = remaining.slice(linkMatch[0].length);
|
|
1088
|
-
continue;
|
|
1089
|
-
}
|
|
1090
|
-
const nextSpecial = remaining.search(/[`*\[]/);
|
|
1091
|
-
if (nextSpecial === -1) {
|
|
1092
|
-
parts.push(remaining);
|
|
1093
|
-
break;
|
|
1094
|
-
} else if (nextSpecial === 0) {
|
|
1095
|
-
parts.push(remaining[0]);
|
|
1096
|
-
remaining = remaining.slice(1);
|
|
1097
|
-
} else {
|
|
1098
|
-
parts.push(remaining.slice(0, nextSpecial));
|
|
1099
|
-
remaining = remaining.slice(nextSpecial);
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
return parts.length === 1 ? parts[0] : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts });
|
|
1103
|
-
};
|
|
1104
|
-
const flushList = () => {
|
|
1105
|
-
if (currentList) {
|
|
1106
|
-
const ListTag = currentList.type === "ul" ? "ul" : "ol";
|
|
1107
|
-
elements.push(
|
|
1108
|
-
/* @__PURE__ */ jsxRuntime.jsx(ListTag, { className: `${currentList.type === "ul" ? "list-disc" : "list-decimal"} ml-4 my-1`, children: currentList.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "ml-2", children: item }, i)) }, elements.length)
|
|
1109
|
-
);
|
|
1110
|
-
currentList = null;
|
|
1111
|
-
}
|
|
1112
|
-
};
|
|
1113
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1114
|
-
const line = lines[i];
|
|
1115
|
-
if (line.startsWith("```")) {
|
|
1116
|
-
if (inCodeBlock) {
|
|
1117
|
-
elements.push(
|
|
1118
|
-
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "bg-gray-100 rounded p-2 my-1 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-xs font-mono", children: codeContent.join("\n") }) }, elements.length)
|
|
1119
|
-
);
|
|
1120
|
-
inCodeBlock = false;
|
|
1121
|
-
codeContent = [];
|
|
1122
|
-
} else {
|
|
1123
|
-
flushList();
|
|
1124
|
-
inCodeBlock = true;
|
|
1125
|
-
line.slice(3).trim();
|
|
1126
|
-
}
|
|
1127
|
-
continue;
|
|
1128
|
-
}
|
|
1129
|
-
if (inCodeBlock) {
|
|
1130
|
-
codeContent.push(line);
|
|
1131
|
-
continue;
|
|
1132
|
-
}
|
|
1133
|
-
const headerMatch = line.match(/^(#{1,6})\s+(.+)/);
|
|
1134
|
-
if (headerMatch) {
|
|
1135
|
-
flushList();
|
|
1136
|
-
const level = headerMatch[1].length;
|
|
1137
|
-
const content = processInlineFormatting(headerMatch[2]);
|
|
1138
|
-
const className = level === 1 ? "text-lg font-bold my-1" : level === 2 ? "text-base font-bold my-1" : "text-sm font-semibold my-1";
|
|
1139
|
-
elements.push(/* @__PURE__ */ jsxRuntime.jsx("div", { className, children: content }, elements.length));
|
|
1140
|
-
continue;
|
|
1141
|
-
}
|
|
1142
|
-
const ulMatch = line.match(/^[-*]\s+(.+)/);
|
|
1143
|
-
if (ulMatch) {
|
|
1144
|
-
if (!currentList || currentList.type !== "ul") {
|
|
1145
|
-
flushList();
|
|
1146
|
-
currentList = { type: "ul", items: [] };
|
|
1147
|
-
}
|
|
1148
|
-
currentList.items.push(processInlineFormatting(ulMatch[1]));
|
|
1149
|
-
continue;
|
|
1150
|
-
}
|
|
1151
|
-
const olMatch = line.match(/^\d+[.)]\s+(.+)/);
|
|
1152
|
-
if (olMatch) {
|
|
1153
|
-
if (!currentList || currentList.type !== "ol") {
|
|
1154
|
-
flushList();
|
|
1155
|
-
currentList = { type: "ol", items: [] };
|
|
1156
|
-
}
|
|
1157
|
-
currentList.items.push(processInlineFormatting(olMatch[1]));
|
|
1158
|
-
continue;
|
|
1159
|
-
}
|
|
1160
|
-
if (line.trim() === "") {
|
|
1161
|
-
flushList();
|
|
1162
|
-
elements.push(/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2" }, elements.length));
|
|
1163
|
-
continue;
|
|
1164
|
-
}
|
|
1165
|
-
if (line.match(/^[-*_]{3,}$/)) {
|
|
1166
|
-
flushList();
|
|
1167
|
-
elements.push(/* @__PURE__ */ jsxRuntime.jsx("hr", { className: "my-2 border-gray-200" }, elements.length));
|
|
1168
|
-
continue;
|
|
1169
|
-
}
|
|
1170
|
-
flushList();
|
|
1171
|
-
elements.push(/* @__PURE__ */ jsxRuntime.jsx("div", { children: processInlineFormatting(line) }, elements.length));
|
|
1172
|
-
}
|
|
1173
|
-
flushList();
|
|
1174
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: elements });
|
|
1175
|
-
}
|
|
1176
|
-
var initialMessages = [];
|
|
1177
|
-
function ChatPanel({
|
|
1178
|
-
onBack,
|
|
1179
|
-
onNavigate,
|
|
1180
|
-
onActionComplete,
|
|
1181
|
-
onAgentAction,
|
|
1182
|
-
currentPage,
|
|
1183
|
-
config: propConfig
|
|
1184
|
-
}) {
|
|
1185
|
-
const contextConfig = useChatPanelConfig();
|
|
1186
|
-
const { userId, orgId, agentUrl, folders, guides, enableGuideCursor } = propConfig ? { ...contextConfig, ...propConfig, userId: propConfig.userId || contextConfig.userId, orgId: propConfig.orgId || contextConfig.orgId, agentUrl: propConfig.agentUrl || contextConfig.agentUrl } : contextConfig;
|
|
1187
|
-
const [messages, setMessages] = React4__namespace.useState(initialMessages);
|
|
1188
|
-
const [input, setInput] = React4__namespace.useState("");
|
|
1189
|
-
const [sessionId] = React4__namespace.useState(() => crypto.randomUUID());
|
|
1190
|
-
const streamIntervals = React4__namespace.useRef({});
|
|
1191
|
-
const isEmpty = messages.length === 0;
|
|
1192
|
-
const [phase, setPhase] = React4__namespace.useState("idle");
|
|
1193
|
-
const [progressSteps, setProgressSteps] = React4__namespace.useState([]);
|
|
1194
|
-
const phaseTimers = React4__namespace.useRef([]);
|
|
1195
|
-
const lastRole = messages.length ? messages[messages.length - 1].role : void 0;
|
|
1196
|
-
const [panelView, setPanelView] = React4__namespace.useState("landing");
|
|
1197
|
-
const [currentFolderId, setCurrentFolderId] = React4__namespace.useState(void 0);
|
|
1198
|
-
const [activeGuide, setActiveGuide] = React4__namespace.useState(void 0);
|
|
1199
|
-
const activeGuideRef = React4__namespace.useRef(void 0);
|
|
1200
|
-
const latestBulkSummaryNavigationRef = React4__namespace.useRef(null);
|
|
1201
|
-
const [guideComplete, setGuideComplete] = React4__namespace.useState(false);
|
|
1202
|
-
React4__namespace.useEffect(() => {
|
|
1203
|
-
window.resetIntegrationNotification = () => {
|
|
1204
|
-
localStorage.removeItem("gmailNotificationSeen");
|
|
1205
|
-
console.log("Integration notification reset! Click the Integrations tab to see it again.");
|
|
1206
|
-
};
|
|
1207
|
-
const handleIntegrationTabClick = () => {
|
|
1208
|
-
const hasSeenNotification = localStorage.getItem("gmailNotificationSeen");
|
|
1209
|
-
if (!hasSeenNotification) {
|
|
1210
|
-
setPanelView("landing");
|
|
1211
|
-
setCurrentFolderId(void 0);
|
|
1212
|
-
const messageId = Date.now();
|
|
1213
|
-
const notificationText = "I see you're exploring integrations. Let me know if there are any other connections we should add.";
|
|
1214
|
-
const draftMessage = {
|
|
1215
|
-
id: messageId,
|
|
1216
|
-
role: "assistant",
|
|
1217
|
-
kind: "text",
|
|
1218
|
-
content: "",
|
|
1219
|
-
isNotificationMessage: true
|
|
1220
|
-
};
|
|
1221
|
-
setMessages((prev) => [...prev, draftMessage]);
|
|
1222
|
-
streamAssistantMessage(messageId, notificationText);
|
|
1223
|
-
localStorage.setItem("gmailNotificationSeen", "true");
|
|
1224
|
-
}
|
|
1225
|
-
};
|
|
1226
|
-
window.addEventListener("integrationTabClicked", handleIntegrationTabClick);
|
|
1227
|
-
return () => {
|
|
1228
|
-
window.removeEventListener("integrationTabClicked", handleIntegrationTabClick);
|
|
1229
|
-
};
|
|
1230
|
-
}, []);
|
|
1231
|
-
React4__namespace.useEffect(() => {
|
|
1232
|
-
if (activeGuide) {
|
|
1233
|
-
if (!activeGuideRef.current || activeGuideRef.current.id !== activeGuide.id || activeGuideRef.current.stepIndex !== activeGuide.stepIndex) {
|
|
1234
|
-
activeGuideRef.current = activeGuide;
|
|
1235
|
-
}
|
|
1236
|
-
} else {
|
|
1237
|
-
activeGuideRef.current = void 0;
|
|
1238
|
-
}
|
|
1239
|
-
}, [activeGuide]);
|
|
1240
|
-
const [pendingNavigation, setPendingNavigation] = React4__namespace.useState(null);
|
|
1241
|
-
const [pendingAction, setPendingAction] = React4__namespace.useState(null);
|
|
1242
|
-
const [actionFormData, setActionFormData] = React4__namespace.useState({});
|
|
1243
|
-
const messagesEndRef = React4__namespace.useRef(null);
|
|
1244
|
-
const messagesContainerRef = React4__namespace.useRef(null);
|
|
1245
|
-
const currentStepRef = React4__namespace.useRef(null);
|
|
1246
|
-
const { cursorState, moveTo, hide } = useGuideCursor();
|
|
1247
|
-
const [pendingFile, setPendingFile] = React4__namespace.useState(null);
|
|
1248
|
-
const [pendingBulkSession, setPendingBulkSession] = React4__namespace.useState(null);
|
|
1249
|
-
const [isCollapsed, setIsCollapsed] = React4__namespace.useState(false);
|
|
1250
|
-
const pendingBulkSessionRef = React4__namespace.useRef(null);
|
|
1251
|
-
const fileInputRef = React4__namespace.useRef(null);
|
|
1252
|
-
React4__namespace.useEffect(() => {
|
|
1253
|
-
if (!activeGuide || activeGuide.id !== "add-api-key" || activeGuide.stepIndex !== 2) {
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
const checkForDialogOpen = () => {
|
|
1257
|
-
const dialog = document.querySelector('[role="dialog"]');
|
|
1258
|
-
const currentGuide = activeGuideRef.current;
|
|
1259
|
-
if (dialog && currentGuide && currentGuide.id === "add-api-key" && currentGuide.stepIndex === 2) {
|
|
1260
|
-
hide();
|
|
1261
|
-
const id = Date.now() + 1;
|
|
1262
|
-
setMessages((prev) => [
|
|
1263
|
-
...prev,
|
|
1264
|
-
{ id, role: "assistant", kind: "guideComplete", content: "Perfect! The dialog is now open. You can enter a name and create your API key." }
|
|
1265
|
-
]);
|
|
1266
|
-
setActiveGuide(void 0);
|
|
1267
|
-
setGuideComplete(true);
|
|
1268
|
-
}
|
|
1269
|
-
};
|
|
1270
|
-
const interval = setInterval(checkForDialogOpen, 300);
|
|
1271
|
-
return () => clearInterval(interval);
|
|
1272
|
-
}, [activeGuide, hide]);
|
|
1273
|
-
React4__namespace.useEffect(() => {
|
|
1274
|
-
return () => {
|
|
1275
|
-
Object.values(streamIntervals.current).forEach((id) => window.clearInterval(id));
|
|
1276
|
-
streamIntervals.current = {};
|
|
1277
|
-
phaseTimers.current.forEach((id) => window.clearTimeout(id));
|
|
1278
|
-
phaseTimers.current = [];
|
|
1279
|
-
};
|
|
1280
|
-
}, []);
|
|
1281
|
-
React4__namespace.useEffect(() => {
|
|
1282
|
-
if (activeGuide && messages.length > 0) {
|
|
1283
|
-
const lastMessage = messages[messages.length - 1];
|
|
1284
|
-
if (lastMessage.kind === "guideStep" || lastMessage.kind === "guideComplete") {
|
|
1285
|
-
if (currentStepRef.current && messagesContainerRef.current) {
|
|
1286
|
-
const container = messagesContainerRef.current;
|
|
1287
|
-
const stepElement = currentStepRef.current;
|
|
1288
|
-
const containerRect = container.getBoundingClientRect();
|
|
1289
|
-
const stepRect = stepElement.getBoundingClientRect();
|
|
1290
|
-
const scrollTop = stepRect.top - containerRect.top + container.scrollTop;
|
|
1291
|
-
container.scrollTop = scrollTop;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
} else if (!activeGuide && messages.length > 0) {
|
|
1295
|
-
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1296
|
-
}
|
|
1297
|
-
}, [messages, phase, activeGuide]);
|
|
1298
|
-
const latestBulkSummaryNavigation = React4__namespace.useMemo(() => {
|
|
1299
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1300
|
-
const msg = messages[i];
|
|
1301
|
-
if (msg.kind === "bulkSummary" && msg.bulkSummary?.navigationPage && msg.bulkSummary.successes > 0) {
|
|
1302
|
-
return msg.bulkSummary.navigationPage;
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
return null;
|
|
1306
|
-
}, [messages]);
|
|
1307
|
-
React4__namespace.useEffect(() => {
|
|
1308
|
-
latestBulkSummaryNavigationRef.current = latestBulkSummaryNavigation;
|
|
1309
|
-
}, [latestBulkSummaryNavigation]);
|
|
1310
|
-
React4__namespace.useEffect(() => {
|
|
1311
|
-
pendingBulkSessionRef.current = pendingBulkSession;
|
|
1312
|
-
}, [pendingBulkSession]);
|
|
1313
|
-
React4__namespace.useEffect(() => {
|
|
1314
|
-
const handleKeyDown = (e) => {
|
|
1315
|
-
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
1316
|
-
const currentBulkSession = pendingBulkSessionRef.current;
|
|
1317
|
-
if (currentBulkSession) {
|
|
1318
|
-
e.preventDefault();
|
|
1319
|
-
e.stopPropagation();
|
|
1320
|
-
confirmBulkOperation(currentBulkSession);
|
|
1321
|
-
return;
|
|
1322
|
-
}
|
|
1323
|
-
if (pendingAction) {
|
|
1324
|
-
e.preventDefault();
|
|
1325
|
-
e.stopPropagation();
|
|
1326
|
-
handleActionSubmit();
|
|
1327
|
-
return;
|
|
1328
|
-
}
|
|
1329
|
-
if (pendingNavigation) {
|
|
1330
|
-
e.preventDefault();
|
|
1331
|
-
e.stopPropagation();
|
|
1332
|
-
handleConfirmNavigation(pendingNavigation);
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
const currentBulkNav = latestBulkSummaryNavigationRef.current;
|
|
1336
|
-
if (currentBulkNav && onNavigate) {
|
|
1337
|
-
e.preventDefault();
|
|
1338
|
-
e.stopPropagation();
|
|
1339
|
-
onNavigate(currentBulkNav.page, currentBulkNav.subtab);
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
if (guideComplete) {
|
|
1343
|
-
e.preventDefault();
|
|
1344
|
-
e.stopPropagation();
|
|
1345
|
-
handleBack();
|
|
1346
|
-
return;
|
|
1347
|
-
}
|
|
1348
|
-
const currentGuide = activeGuideRef.current;
|
|
1349
|
-
if (currentGuide) {
|
|
1350
|
-
e.preventDefault();
|
|
1351
|
-
e.stopPropagation();
|
|
1352
|
-
advanceGuide();
|
|
1353
|
-
return;
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
};
|
|
1357
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1358
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1359
|
-
}, [pendingAction, pendingNavigation, activeGuide, guideComplete, onNavigate]);
|
|
1360
|
-
function streamAssistantMessage(messageId, fullText, followups) {
|
|
1361
|
-
const tokens = fullText.split(" ");
|
|
1362
|
-
let i = 0;
|
|
1363
|
-
const intervalId = window.setInterval(() => {
|
|
1364
|
-
i += 1;
|
|
1365
|
-
setMessages(
|
|
1366
|
-
(prev) => prev.map((m) => m.id === messageId ? { ...m, content: tokens.slice(0, i).join(" ") } : m)
|
|
1367
|
-
);
|
|
1368
|
-
if (i >= tokens.length) {
|
|
1369
|
-
window.clearInterval(intervalId);
|
|
1370
|
-
delete streamIntervals.current[messageId];
|
|
1371
|
-
if (followups && followups.length > 0) {
|
|
1372
|
-
setMessages(
|
|
1373
|
-
(prev) => prev.map((m) => m.id === messageId ? { ...m, followups } : m)
|
|
1374
|
-
);
|
|
1375
|
-
}
|
|
1376
|
-
setPhase("idle");
|
|
1377
|
-
}
|
|
1378
|
-
}, 25);
|
|
1379
|
-
streamIntervals.current[messageId] = intervalId;
|
|
1380
|
-
}
|
|
1381
|
-
function handleFollowupClick(messageId, followup) {
|
|
1382
|
-
setMessages(
|
|
1383
|
-
(prev) => prev.map((m) => m.id === messageId ? { ...m, followupSelected: true } : m)
|
|
1384
|
-
);
|
|
1385
|
-
startChatFlow(followup.label);
|
|
1386
|
-
}
|
|
1387
|
-
function handleBack() {
|
|
1388
|
-
Object.values(streamIntervals.current).forEach((id) => window.clearInterval(id));
|
|
1389
|
-
streamIntervals.current = {};
|
|
1390
|
-
phaseTimers.current.forEach((id) => window.clearTimeout(id));
|
|
1391
|
-
phaseTimers.current = [];
|
|
1392
|
-
hide();
|
|
1393
|
-
setMessages([]);
|
|
1394
|
-
setInput("");
|
|
1395
|
-
setPhase("idle");
|
|
1396
|
-
setPanelView("landing");
|
|
1397
|
-
setCurrentFolderId(void 0);
|
|
1398
|
-
setActiveGuide(void 0);
|
|
1399
|
-
setGuideComplete(false);
|
|
1400
|
-
setPendingNavigation(null);
|
|
1401
|
-
setPendingAction(null);
|
|
1402
|
-
setActionFormData({});
|
|
1403
|
-
if (onBack) onBack();
|
|
1404
|
-
}
|
|
1405
|
-
function openFolder(folderId) {
|
|
1406
|
-
setPanelView("folder");
|
|
1407
|
-
setCurrentFolderId(folderId);
|
|
1408
|
-
}
|
|
1409
|
-
function closeFolder() {
|
|
1410
|
-
setPanelView("landing");
|
|
1411
|
-
setCurrentFolderId(void 0);
|
|
1412
|
-
}
|
|
1413
|
-
function handleSubmit(e) {
|
|
1414
|
-
e.preventDefault();
|
|
1415
|
-
const trimmed = input.trim();
|
|
1416
|
-
if (pendingFile) {
|
|
1417
|
-
if (!trimmed) {
|
|
1418
|
-
const errorMessage = {
|
|
1419
|
-
id: Date.now(),
|
|
1420
|
-
role: "assistant",
|
|
1421
|
-
kind: "text",
|
|
1422
|
-
content: "Please describe what you'd like to do with this CSV file. For example: 'Create customers from this file' or 'Add these subscriptions'."
|
|
1423
|
-
};
|
|
1424
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
startBulkUploadFlow(trimmed, pendingFile);
|
|
1428
|
-
setInput("");
|
|
1429
|
-
setPendingFile(null);
|
|
1430
|
-
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
1431
|
-
return;
|
|
1432
|
-
}
|
|
1433
|
-
if (!trimmed) return;
|
|
1434
|
-
startChatFlow(trimmed);
|
|
1435
|
-
setInput("");
|
|
1436
|
-
}
|
|
1437
|
-
function getPageDisplayName(target) {
|
|
1438
|
-
const pageNames = {
|
|
1439
|
-
dashboard: "dashboard",
|
|
1440
|
-
customers: "customers page",
|
|
1441
|
-
payments: "payments page",
|
|
1442
|
-
settings: "settings page",
|
|
1443
|
-
support: "support page",
|
|
1444
|
-
disputes: "disputes page",
|
|
1445
|
-
radar: "radar page"
|
|
1446
|
-
};
|
|
1447
|
-
if (target.page === "settings" && target.subtab) {
|
|
1448
|
-
const subtabNames = {
|
|
1449
|
-
general: "General",
|
|
1450
|
-
billing: "Billing",
|
|
1451
|
-
security: "Security",
|
|
1452
|
-
api: "API Keys",
|
|
1453
|
-
notifications: "Notifications",
|
|
1454
|
-
integrations: "Integrations"
|
|
1455
|
-
};
|
|
1456
|
-
return `${pageNames.settings} (${subtabNames[target.subtab] || target.subtab} tab)`;
|
|
1457
|
-
}
|
|
1458
|
-
return pageNames[target.page] || target.page;
|
|
1459
|
-
}
|
|
1460
|
-
function handleConfirmNavigation(target) {
|
|
1461
|
-
if (onNavigate) {
|
|
1462
|
-
onNavigate(target.page, target.subtab);
|
|
1463
|
-
}
|
|
1464
|
-
setPendingNavigation(null);
|
|
1465
|
-
setMessages(
|
|
1466
|
-
(prev) => prev.map(
|
|
1467
|
-
(msg) => msg.kind === "navigationAction" && msg.navigationTarget?.page === target.page && msg.navigationTarget?.subtab === target.subtab ? { ...msg, navigationTarget: void 0 } : msg
|
|
1468
|
-
)
|
|
1469
|
-
);
|
|
1470
|
-
}
|
|
1471
|
-
function handleActionSubmit() {
|
|
1472
|
-
if (!pendingAction) return;
|
|
1473
|
-
const data = actionFormData;
|
|
1474
|
-
if (pendingAction.type === "updateCompanyInfo") ; else if (pendingAction.type === "addApiKey") {
|
|
1475
|
-
const apiData = data;
|
|
1476
|
-
if (!apiData.name || !apiData.name.trim()) return;
|
|
1477
|
-
} else if (pendingAction.type === "addCustomer") {
|
|
1478
|
-
const customerData = data;
|
|
1479
|
-
if (!customerData.name || !customerData.name.trim() || !customerData.email || !customerData.email.trim()) return;
|
|
1480
|
-
} else if (pendingAction.type === "changePassword") {
|
|
1481
|
-
const passwordData = data;
|
|
1482
|
-
if (!passwordData.currentPassword || !passwordData.newPassword || !passwordData.confirmPassword) return;
|
|
1483
|
-
if (passwordData.newPassword !== passwordData.confirmPassword) return;
|
|
1484
|
-
} else if (pendingAction.type === "addWebhook") {
|
|
1485
|
-
const webhookData = data;
|
|
1486
|
-
if (!webhookData.url || !webhookData.url.trim()) return;
|
|
1487
|
-
} else if (pendingAction.type === "addPaymentMethod") {
|
|
1488
|
-
const paymentData = data;
|
|
1489
|
-
if (!paymentData.cardNumber || !paymentData.expiryDate) return;
|
|
1490
|
-
} else if (pendingAction.type === "deleteApiKey") {
|
|
1491
|
-
const apiData = data;
|
|
1492
|
-
if (!apiData.keyId && !apiData.name) return;
|
|
1493
|
-
} else if (pendingAction.type === "refundPayment") {
|
|
1494
|
-
const refundData = data;
|
|
1495
|
-
if (!refundData.transactionId && !refundData.customer) return;
|
|
1496
|
-
} else if (pendingAction.type === "createSubscription") {
|
|
1497
|
-
const subscriptionData = data;
|
|
1498
|
-
if (!subscriptionData.customerEmail && !subscriptionData.customerId) return;
|
|
1499
|
-
} else if (pendingAction.type === "toggleBlockRule" || pendingAction.type === "enableBlockRule" || pendingAction.type === "disableBlockRule") {
|
|
1500
|
-
const blockRuleData = data;
|
|
1501
|
-
if (!blockRuleData.ruleId) return;
|
|
1502
|
-
}
|
|
1503
|
-
if (onActionComplete) {
|
|
1504
|
-
onActionComplete(pendingAction.type, data);
|
|
1505
|
-
}
|
|
1506
|
-
setMessages(
|
|
1507
|
-
(prev) => prev.map(
|
|
1508
|
-
(msg) => msg.kind === "actionForm" && msg.actionType === pendingAction.type ? { ...msg, isSubmitted: true } : msg
|
|
1509
|
-
)
|
|
1510
|
-
);
|
|
1511
|
-
setPendingAction(null);
|
|
1512
|
-
setActionFormData({});
|
|
1513
|
-
}
|
|
1514
|
-
function dispatchAgentAction(result) {
|
|
1515
|
-
if (onAgentAction) {
|
|
1516
|
-
onAgentAction({ result });
|
|
1517
|
-
}
|
|
1518
|
-
window.dispatchEvent(new CustomEvent("agentActionComplete", {
|
|
1519
|
-
detail: { result }
|
|
1520
|
-
}));
|
|
1521
|
-
}
|
|
1522
|
-
async function startChatFlow(userText) {
|
|
1523
|
-
phaseTimers.current.forEach((id) => window.clearTimeout(id));
|
|
1524
|
-
phaseTimers.current = [];
|
|
1525
|
-
const lastAssistantMessage = [...messages].reverse().find((m) => m.role === "assistant");
|
|
1526
|
-
const isRespondingToNotification = lastAssistantMessage?.isNotificationMessage === true;
|
|
1527
|
-
const now = Date.now();
|
|
1528
|
-
const userMessage = { id: now, role: "user", content: userText };
|
|
1529
|
-
setMessages((prev) => [...prev, userMessage]);
|
|
1530
|
-
if (isRespondingToNotification) {
|
|
1531
|
-
const thankYouMessageId = Date.now() + 1;
|
|
1532
|
-
const thankYouMessage = {
|
|
1533
|
-
id: thankYouMessageId,
|
|
1534
|
-
role: "assistant",
|
|
1535
|
-
kind: "text",
|
|
1536
|
-
content: ""
|
|
1537
|
-
};
|
|
1538
|
-
setMessages((prev) => [...prev, thankYouMessage]);
|
|
1539
|
-
streamAssistantMessage(thankYouMessageId, "Thank you, your feedback is saved.");
|
|
1540
|
-
return;
|
|
1541
|
-
}
|
|
1542
|
-
setPendingNavigation(null);
|
|
1543
|
-
setPhase("thinking");
|
|
1544
|
-
setProgressSteps([]);
|
|
1545
|
-
let streamCompleted = false;
|
|
1546
|
-
try {
|
|
1547
|
-
const controller = new AbortController();
|
|
1548
|
-
const timeoutId = setTimeout(() => controller.abort(), 6e4);
|
|
1549
|
-
const response = await fetch(`${agentUrl}/chat/stream`, {
|
|
1550
|
-
method: "POST",
|
|
1551
|
-
headers: {
|
|
1552
|
-
"Content-Type": "application/json"
|
|
1553
|
-
},
|
|
1554
|
-
body: JSON.stringify({
|
|
1555
|
-
session_id: sessionId,
|
|
1556
|
-
user_id: userId,
|
|
1557
|
-
org_id: orgId,
|
|
1558
|
-
message: userText,
|
|
1559
|
-
current_page: currentPage || "dashboard"
|
|
1560
|
-
}),
|
|
1561
|
-
signal: controller.signal
|
|
1562
|
-
});
|
|
1563
|
-
clearTimeout(timeoutId);
|
|
1564
|
-
if (!response.ok) {
|
|
1565
|
-
throw new Error(`Agent request failed: ${response.status}`);
|
|
1566
|
-
}
|
|
1567
|
-
const reader = response.body?.getReader();
|
|
1568
|
-
if (!reader) throw new Error("No response body");
|
|
1569
|
-
const decoder = new TextDecoder();
|
|
1570
|
-
let buffer = "";
|
|
1571
|
-
while (true) {
|
|
1572
|
-
const { done, value } = await reader.read();
|
|
1573
|
-
if (done) break;
|
|
1574
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1575
|
-
const events = buffer.split("\n\n");
|
|
1576
|
-
buffer = events.pop() || "";
|
|
1577
|
-
for (const eventStr of events) {
|
|
1578
|
-
if (!eventStr.trim()) continue;
|
|
1579
|
-
const lines = eventStr.split("\n");
|
|
1580
|
-
let eventType = "";
|
|
1581
|
-
let eventData = "";
|
|
1582
|
-
for (const line of lines) {
|
|
1583
|
-
if (line.startsWith("event: ")) {
|
|
1584
|
-
eventType = line.slice(7);
|
|
1585
|
-
} else if (line.startsWith("data: ")) {
|
|
1586
|
-
eventData = line.slice(6);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
if (!eventType || !eventData) continue;
|
|
1590
|
-
try {
|
|
1591
|
-
const data = JSON.parse(eventData);
|
|
1592
|
-
if (eventType === "progress") {
|
|
1593
|
-
if (data.status === "thinking") {
|
|
1594
|
-
setPhase("thinking");
|
|
1595
|
-
setProgressSteps([{ message: data.message, completed: false }]);
|
|
1596
|
-
} else if (data.status === "executing") {
|
|
1597
|
-
setPhase("executing");
|
|
1598
|
-
setProgressSteps((prev) => {
|
|
1599
|
-
const updated = prev.map((step) => ({ ...step, completed: true }));
|
|
1600
|
-
const lastStep = updated[updated.length - 1];
|
|
1601
|
-
if (!lastStep || lastStep.message !== data.message) {
|
|
1602
|
-
updated.push({ message: data.message, completed: false });
|
|
1603
|
-
}
|
|
1604
|
-
return updated;
|
|
1605
|
-
});
|
|
1606
|
-
} else if (data.status === "responding") {
|
|
1607
|
-
setPhase("responding");
|
|
1608
|
-
setProgressSteps((prev) => prev.map((step) => ({ ...step, completed: true })));
|
|
1609
|
-
}
|
|
1610
|
-
} else if (eventType === "response") {
|
|
1611
|
-
setProgressSteps([]);
|
|
1612
|
-
streamCompleted = true;
|
|
1613
|
-
const agentResponse = data;
|
|
1614
|
-
if (agentResponse.action === "navigate" && agentResponse.navigation) {
|
|
1615
|
-
const navTarget = {
|
|
1616
|
-
page: agentResponse.navigation.page,
|
|
1617
|
-
subtab: agentResponse.navigation.subtab
|
|
1618
|
-
};
|
|
1619
|
-
setPendingNavigation(navTarget);
|
|
1620
|
-
const navigationMessage = {
|
|
1621
|
-
id: now + 1,
|
|
1622
|
-
role: "assistant",
|
|
1623
|
-
kind: "navigationAction",
|
|
1624
|
-
content: agentResponse.response || `I can take you to the ${getPageDisplayName(navTarget)}.`,
|
|
1625
|
-
navigationTarget: navTarget
|
|
1626
|
-
};
|
|
1627
|
-
setMessages((prev) => [...prev, navigationMessage]);
|
|
1628
|
-
setPhase("idle");
|
|
1629
|
-
} else if (agentResponse.action === "show_form" && agentResponse.actionType) {
|
|
1630
|
-
setPendingAction({
|
|
1631
|
-
type: agentResponse.actionType,
|
|
1632
|
-
data: agentResponse.actionData || {}
|
|
1633
|
-
});
|
|
1634
|
-
setActionFormData(agentResponse.actionData || {});
|
|
1635
|
-
const actionMessage = {
|
|
1636
|
-
id: now + 1,
|
|
1637
|
-
role: "assistant",
|
|
1638
|
-
kind: "actionForm",
|
|
1639
|
-
content: agentResponse.response || agentResponse.message || "Please fill in the details below:",
|
|
1640
|
-
actionType: agentResponse.actionType,
|
|
1641
|
-
actionData: agentResponse.actionData || {}
|
|
1642
|
-
};
|
|
1643
|
-
setMessages((prev) => [...prev, actionMessage]);
|
|
1644
|
-
setPhase("idle");
|
|
1645
|
-
} else if (agentResponse.action === "suggest_bulk") {
|
|
1646
|
-
const assistantMessageId = now + 1;
|
|
1647
|
-
const assistantMessage = {
|
|
1648
|
-
id: assistantMessageId,
|
|
1649
|
-
role: "assistant",
|
|
1650
|
-
kind: "text",
|
|
1651
|
-
content: ""
|
|
1652
|
-
};
|
|
1653
|
-
setMessages((prev) => [...prev, assistantMessage]);
|
|
1654
|
-
streamAssistantMessage(assistantMessageId, agentResponse.response || agentResponse.message || "For bulk operations, you can upload a CSV file - just click the \u{1F4CE} button!", agentResponse.followups);
|
|
1655
|
-
streamCompleted = true;
|
|
1656
|
-
} else if (agentResponse.action === "bulk_preview") {
|
|
1657
|
-
setPendingBulkSession(agentResponse.bulk_session_id);
|
|
1658
|
-
const previewMessage = {
|
|
1659
|
-
id: now + 1,
|
|
1660
|
-
role: "assistant",
|
|
1661
|
-
kind: "bulkPreview",
|
|
1662
|
-
content: agentResponse.message || `I found ${agentResponse.csv_data?.rowCount || 0} items. Here's a preview:`,
|
|
1663
|
-
csvData: agentResponse.csv_data ? {
|
|
1664
|
-
rowCount: agentResponse.csv_data.rowCount,
|
|
1665
|
-
columns: agentResponse.csv_data.columns,
|
|
1666
|
-
sampleRows: agentResponse.csv_data.sampleRows,
|
|
1667
|
-
fileName: "From context"
|
|
1668
|
-
} : void 0,
|
|
1669
|
-
suggestedAction: agentResponse.suggested_action,
|
|
1670
|
-
bulkSessionId: agentResponse.bulk_session_id
|
|
1671
|
-
};
|
|
1672
|
-
setMessages((prev) => [...prev, previewMessage]);
|
|
1673
|
-
setPhase("idle");
|
|
1674
|
-
streamCompleted = true;
|
|
1675
|
-
} else if (agentResponse.action === "execute" && agentResponse.executionResult) {
|
|
1676
|
-
const assistantMessageId = now + 1;
|
|
1677
|
-
const assistantMessage = {
|
|
1678
|
-
id: assistantMessageId,
|
|
1679
|
-
role: "assistant",
|
|
1680
|
-
kind: "text",
|
|
1681
|
-
content: "",
|
|
1682
|
-
structuredData: agentResponse.structuredData || void 0
|
|
1683
|
-
};
|
|
1684
|
-
setMessages((prev) => [...prev, assistantMessage]);
|
|
1685
|
-
streamAssistantMessage(assistantMessageId, agentResponse.response, agentResponse.followups);
|
|
1686
|
-
streamCompleted = true;
|
|
1687
|
-
setTimeout(() => {
|
|
1688
|
-
dispatchAgentAction(agentResponse.executionResult);
|
|
1689
|
-
}, 100);
|
|
1690
|
-
} else {
|
|
1691
|
-
const assistantMessageId = now + 1;
|
|
1692
|
-
const assistantMessage = {
|
|
1693
|
-
id: assistantMessageId,
|
|
1694
|
-
role: "assistant",
|
|
1695
|
-
kind: "text",
|
|
1696
|
-
content: ""
|
|
1697
|
-
};
|
|
1698
|
-
setMessages((prev) => [...prev, assistantMessage]);
|
|
1699
|
-
streamAssistantMessage(assistantMessageId, agentResponse.response, agentResponse.followups);
|
|
1700
|
-
streamCompleted = true;
|
|
1701
|
-
}
|
|
1702
|
-
} else if (eventType === "error") {
|
|
1703
|
-
setPhase("idle");
|
|
1704
|
-
setProgressSteps([]);
|
|
1705
|
-
streamCompleted = true;
|
|
1706
|
-
const errorMessageId = now + 1;
|
|
1707
|
-
const errorMessage = {
|
|
1708
|
-
id: errorMessageId,
|
|
1709
|
-
role: "assistant",
|
|
1710
|
-
kind: "text",
|
|
1711
|
-
content: ""
|
|
1712
|
-
};
|
|
1713
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1714
|
-
streamAssistantMessage(errorMessageId, data.message || "An error occurred processing your request.");
|
|
1715
|
-
} else if (eventType === "done") {
|
|
1716
|
-
setProgressSteps([]);
|
|
1717
|
-
setPhase("idle");
|
|
1718
|
-
streamCompleted = true;
|
|
1719
|
-
}
|
|
1720
|
-
} catch (parseError) {
|
|
1721
|
-
console.error("Failed to parse SSE event:", parseError);
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
setProgressSteps([]);
|
|
1726
|
-
if (!streamCompleted) {
|
|
1727
|
-
setPhase("idle");
|
|
1728
|
-
}
|
|
1729
|
-
} catch (error) {
|
|
1730
|
-
console.error("Agent request failed:", error);
|
|
1731
|
-
setProgressSteps([]);
|
|
1732
|
-
const errorMessageId = now + 1;
|
|
1733
|
-
const errorMessage = {
|
|
1734
|
-
id: errorMessageId,
|
|
1735
|
-
role: "assistant",
|
|
1736
|
-
kind: "text",
|
|
1737
|
-
content: ""
|
|
1738
|
-
};
|
|
1739
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1740
|
-
streamAssistantMessage(errorMessageId, "I'm having trouble connecting to my backend. Please make sure the agent server is running.");
|
|
1741
|
-
} finally {
|
|
1742
|
-
setProgressSteps([]);
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
async function startBulkUploadFlow(userText, file) {
|
|
1746
|
-
phaseTimers.current.forEach((id) => window.clearTimeout(id));
|
|
1747
|
-
phaseTimers.current = [];
|
|
1748
|
-
const now = Date.now();
|
|
1749
|
-
const userMessage = {
|
|
1750
|
-
id: now,
|
|
1751
|
-
role: "user",
|
|
1752
|
-
content: `\u{1F4CE} ${file.name}
|
|
1753
|
-
|
|
1754
|
-
${userText}`
|
|
1755
|
-
};
|
|
1756
|
-
setMessages((prev) => [...prev, userMessage]);
|
|
1757
|
-
setPhase("thinking");
|
|
1758
|
-
setProgressSteps([{ message: "Analyzing CSV file...", completed: false }]);
|
|
1759
|
-
try {
|
|
1760
|
-
const formData = new FormData();
|
|
1761
|
-
formData.append("file", file);
|
|
1762
|
-
formData.append("message", userText);
|
|
1763
|
-
formData.append("session_id", sessionId);
|
|
1764
|
-
formData.append("user_id", userId);
|
|
1765
|
-
formData.append("org_id", orgId);
|
|
1766
|
-
formData.append("current_page", currentPage || "dashboard");
|
|
1767
|
-
const controller = new AbortController();
|
|
1768
|
-
const timeoutId = setTimeout(() => controller.abort(), 12e4);
|
|
1769
|
-
const response = await fetch(`${agentUrl}/chat/bulk/stream`, {
|
|
1770
|
-
method: "POST",
|
|
1771
|
-
body: formData,
|
|
1772
|
-
signal: controller.signal
|
|
1773
|
-
});
|
|
1774
|
-
clearTimeout(timeoutId);
|
|
1775
|
-
if (!response.ok) {
|
|
1776
|
-
throw new Error(`Bulk upload failed: ${response.status}`);
|
|
1777
|
-
}
|
|
1778
|
-
const reader = response.body?.getReader();
|
|
1779
|
-
if (!reader) throw new Error("No response body");
|
|
1780
|
-
const decoder = new TextDecoder();
|
|
1781
|
-
let buffer = "";
|
|
1782
|
-
let bulkSessionId = null;
|
|
1783
|
-
while (true) {
|
|
1784
|
-
const { done, value } = await reader.read();
|
|
1785
|
-
if (done) break;
|
|
1786
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1787
|
-
const events = buffer.split("\n\n");
|
|
1788
|
-
buffer = events.pop() || "";
|
|
1789
|
-
for (const eventStr of events) {
|
|
1790
|
-
if (!eventStr.trim()) continue;
|
|
1791
|
-
const lines = eventStr.split("\n");
|
|
1792
|
-
let eventType = "";
|
|
1793
|
-
let eventData = "";
|
|
1794
|
-
for (const line of lines) {
|
|
1795
|
-
if (line.startsWith("event: ")) {
|
|
1796
|
-
eventType = line.slice(7);
|
|
1797
|
-
} else if (line.startsWith("data: ")) {
|
|
1798
|
-
eventData = line.slice(6);
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
if (!eventType || !eventData) continue;
|
|
1802
|
-
try {
|
|
1803
|
-
const data = JSON.parse(eventData);
|
|
1804
|
-
if (eventType === "preview") {
|
|
1805
|
-
setPhase("idle");
|
|
1806
|
-
setProgressSteps([]);
|
|
1807
|
-
bulkSessionId = data.bulk_session_id;
|
|
1808
|
-
setPendingBulkSession(bulkSessionId);
|
|
1809
|
-
const previewMessage = {
|
|
1810
|
-
id: now + 1,
|
|
1811
|
-
role: "assistant",
|
|
1812
|
-
kind: "bulkPreview",
|
|
1813
|
-
content: data.message || `I found ${data.csv_data?.rowCount || 0} items. Here's a preview:`,
|
|
1814
|
-
csvData: data.csv_data ? {
|
|
1815
|
-
rowCount: data.csv_data.rowCount,
|
|
1816
|
-
columns: data.csv_data.columns,
|
|
1817
|
-
sampleRows: data.csv_data.sampleRows,
|
|
1818
|
-
fileName: file.name
|
|
1819
|
-
} : void 0,
|
|
1820
|
-
suggestedAction: data.suggested_action,
|
|
1821
|
-
bulkSessionId: bulkSessionId || void 0
|
|
1822
|
-
};
|
|
1823
|
-
setMessages((prev) => [...prev, previewMessage]);
|
|
1824
|
-
} else if (eventType === "error") {
|
|
1825
|
-
setPhase("idle");
|
|
1826
|
-
setProgressSteps([]);
|
|
1827
|
-
const errorMessage = {
|
|
1828
|
-
id: Date.now(),
|
|
1829
|
-
role: "assistant",
|
|
1830
|
-
kind: "text",
|
|
1831
|
-
content: data.message || "An error occurred processing the CSV file."
|
|
1832
|
-
};
|
|
1833
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1834
|
-
}
|
|
1835
|
-
} catch (parseError) {
|
|
1836
|
-
console.error("Failed to parse SSE event:", parseError);
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
} catch (error) {
|
|
1841
|
-
console.error("Bulk upload failed:", error);
|
|
1842
|
-
setPhase("idle");
|
|
1843
|
-
setProgressSteps([]);
|
|
1844
|
-
const errorMessage = {
|
|
1845
|
-
id: Date.now(),
|
|
1846
|
-
role: "assistant",
|
|
1847
|
-
kind: "text",
|
|
1848
|
-
content: "Failed to process CSV file. Please try again."
|
|
1849
|
-
};
|
|
1850
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
async function confirmBulkOperation(bulkSessionId) {
|
|
1854
|
-
setPhase("executing");
|
|
1855
|
-
setProgressSteps([{ message: "Starting bulk operation...", completed: false }]);
|
|
1856
|
-
setPendingBulkSession(null);
|
|
1857
|
-
try {
|
|
1858
|
-
const response = await fetch(`${agentUrl}/chat/bulk/confirm`, {
|
|
1859
|
-
method: "POST",
|
|
1860
|
-
headers: {
|
|
1861
|
-
"Content-Type": "application/json"
|
|
1862
|
-
},
|
|
1863
|
-
body: JSON.stringify({
|
|
1864
|
-
session_id: sessionId,
|
|
1865
|
-
user_id: userId,
|
|
1866
|
-
org_id: orgId,
|
|
1867
|
-
bulk_session_id: bulkSessionId
|
|
1868
|
-
})
|
|
1869
|
-
});
|
|
1870
|
-
if (!response.ok) {
|
|
1871
|
-
throw new Error(`Bulk confirm failed: ${response.status}`);
|
|
1872
|
-
}
|
|
1873
|
-
const reader = response.body?.getReader();
|
|
1874
|
-
if (!reader) throw new Error("No response body");
|
|
1875
|
-
const decoder = new TextDecoder();
|
|
1876
|
-
let buffer = "";
|
|
1877
|
-
while (true) {
|
|
1878
|
-
const { done, value } = await reader.read();
|
|
1879
|
-
if (done) break;
|
|
1880
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1881
|
-
const events = buffer.split("\n\n");
|
|
1882
|
-
buffer = events.pop() || "";
|
|
1883
|
-
for (const eventStr of events) {
|
|
1884
|
-
if (!eventStr.trim()) continue;
|
|
1885
|
-
const lines = eventStr.split("\n");
|
|
1886
|
-
let eventType = "";
|
|
1887
|
-
let eventData = "";
|
|
1888
|
-
for (const line of lines) {
|
|
1889
|
-
if (line.startsWith("event: ")) {
|
|
1890
|
-
eventType = line.slice(7);
|
|
1891
|
-
} else if (line.startsWith("data: ")) {
|
|
1892
|
-
eventData = line.slice(6);
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
|
-
if (!eventType || !eventData) continue;
|
|
1896
|
-
try {
|
|
1897
|
-
const data = JSON.parse(eventData);
|
|
1898
|
-
if (eventType === "progress") {
|
|
1899
|
-
setMessages((prev) => {
|
|
1900
|
-
const existing = prev.find((m) => m.kind === "bulkProgress");
|
|
1901
|
-
if (existing) {
|
|
1902
|
-
return prev.map(
|
|
1903
|
-
(m) => m.kind === "bulkProgress" ? { ...m, bulkProgress: { processed: data.row, total: data.total, successes: data.successes || 0, failures: data.failures || 0 } } : m
|
|
1904
|
-
);
|
|
1905
|
-
} else {
|
|
1906
|
-
return [...prev, {
|
|
1907
|
-
id: Date.now(),
|
|
1908
|
-
role: "assistant",
|
|
1909
|
-
kind: "bulkProgress",
|
|
1910
|
-
bulkProgress: {
|
|
1911
|
-
processed: data.row,
|
|
1912
|
-
total: data.total,
|
|
1913
|
-
successes: data.successes || 0,
|
|
1914
|
-
failures: data.failures || 0
|
|
1915
|
-
}
|
|
1916
|
-
}];
|
|
1917
|
-
}
|
|
1918
|
-
});
|
|
1919
|
-
} else if (eventType === "summary") {
|
|
1920
|
-
setPhase("idle");
|
|
1921
|
-
setProgressSteps([]);
|
|
1922
|
-
setPendingBulkSession(null);
|
|
1923
|
-
setMessages((prev) => {
|
|
1924
|
-
const filtered = prev.filter((m) => m.kind !== "bulkProgress" && m.kind !== "bulkPreview");
|
|
1925
|
-
const newMsg = {
|
|
1926
|
-
id: Date.now(),
|
|
1927
|
-
role: "assistant",
|
|
1928
|
-
kind: "bulkSummary",
|
|
1929
|
-
content: data.message,
|
|
1930
|
-
bulkSummary: {
|
|
1931
|
-
total: data.total,
|
|
1932
|
-
successes: data.successes,
|
|
1933
|
-
failures: data.failures || [],
|
|
1934
|
-
navigationPage: data.navigationPage
|
|
1935
|
-
}
|
|
1936
|
-
};
|
|
1937
|
-
return [...filtered, newMsg];
|
|
1938
|
-
});
|
|
1939
|
-
setTimeout(() => {
|
|
1940
|
-
dispatchAgentAction({ bulk: true, total: data.total, successes: data.successes });
|
|
1941
|
-
}, 100);
|
|
1942
|
-
} else if (eventType === "error") {
|
|
1943
|
-
setPhase("idle");
|
|
1944
|
-
setProgressSteps([]);
|
|
1945
|
-
setPendingBulkSession(null);
|
|
1946
|
-
const errorMessage = {
|
|
1947
|
-
id: Date.now(),
|
|
1948
|
-
role: "assistant",
|
|
1949
|
-
kind: "text",
|
|
1950
|
-
content: data.message || "An error occurred during bulk processing."
|
|
1951
|
-
};
|
|
1952
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1953
|
-
}
|
|
1954
|
-
} catch (parseError) {
|
|
1955
|
-
console.error("Failed to parse confirm SSE event:", parseError);
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
} catch (error) {
|
|
1960
|
-
console.error("Bulk confirm failed:", error);
|
|
1961
|
-
setPhase("idle");
|
|
1962
|
-
setProgressSteps([]);
|
|
1963
|
-
setPendingBulkSession(null);
|
|
1964
|
-
const errorMessage = {
|
|
1965
|
-
id: Date.now(),
|
|
1966
|
-
role: "assistant",
|
|
1967
|
-
kind: "text",
|
|
1968
|
-
content: "Failed to start bulk operation. Please try again."
|
|
1969
|
-
};
|
|
1970
|
-
setMessages((prev) => [...prev, errorMessage]);
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
function cancelBulkOperation() {
|
|
1974
|
-
setPendingBulkSession(null);
|
|
1975
|
-
setMessages((prev) => prev.filter((m) => m.kind !== "bulkPreview"));
|
|
1976
|
-
}
|
|
1977
|
-
function sendTopic(prompt) {
|
|
1978
|
-
startChatFlow(prompt);
|
|
1979
|
-
}
|
|
1980
|
-
function appendAssistantText(text) {
|
|
1981
|
-
const id = Date.now() + Math.floor(Math.random() * 1e3);
|
|
1982
|
-
setMessages((prev) => [...prev, { id, role: "assistant", kind: "text", content: text }]);
|
|
1983
|
-
}
|
|
1984
|
-
function startGuide(guideId) {
|
|
1985
|
-
const guide = guides[guideId];
|
|
1986
|
-
if (!guide) return;
|
|
1987
|
-
setPanelView("landing");
|
|
1988
|
-
setCurrentFolderId(void 0);
|
|
1989
|
-
const initialGuideState = { id: guideId, stepIndex: 0 };
|
|
1990
|
-
setActiveGuide(initialGuideState);
|
|
1991
|
-
activeGuideRef.current = initialGuideState;
|
|
1992
|
-
appendAssistantText(`I'll help you with ${guide.title}.`);
|
|
1993
|
-
const firstStep = guide.steps[0];
|
|
1994
|
-
const isNavigationButton = firstStep.cursorTarget?.selector.includes("[data-page=");
|
|
1995
|
-
const isTabButton = firstStep.cursorTarget?.selector.includes("[data-settings-tab=");
|
|
1996
|
-
if (firstStep.cursorTarget && (isNavigationButton || isTabButton)) {
|
|
1997
|
-
const cursorTarget = firstStep.cursorTarget;
|
|
1998
|
-
if (isTabButton && firstStep.navigation && onNavigate) {
|
|
1999
|
-
onNavigate(firstStep.navigation.page, void 0);
|
|
2000
|
-
}
|
|
2001
|
-
const initialDelay = isTabButton ? 800 : 400;
|
|
2002
|
-
setTimeout(() => {
|
|
2003
|
-
const waitForElement = () => {
|
|
2004
|
-
const element = document.querySelector(cursorTarget.selector);
|
|
2005
|
-
if (element && element.offsetParent !== null) {
|
|
2006
|
-
moveTo(cursorTarget);
|
|
2007
|
-
if (cursorTarget.onClick) {
|
|
2008
|
-
setTimeout(() => {
|
|
2009
|
-
element.click();
|
|
2010
|
-
}, 1200);
|
|
2011
|
-
}
|
|
2012
|
-
} else {
|
|
2013
|
-
setTimeout(waitForElement, 200);
|
|
2014
|
-
}
|
|
2015
|
-
};
|
|
2016
|
-
waitForElement();
|
|
2017
|
-
}, initialDelay);
|
|
2018
|
-
} else {
|
|
2019
|
-
if (firstStep.navigation && onNavigate) {
|
|
2020
|
-
onNavigate(firstStep.navigation.page, firstStep.navigation.subtab);
|
|
2021
|
-
}
|
|
2022
|
-
if (firstStep.cursorTarget) {
|
|
2023
|
-
const cursorTarget = firstStep.cursorTarget;
|
|
2024
|
-
const isSettingsTab = cursorTarget.selector.includes("data-settings-tab");
|
|
2025
|
-
const isDialogElement = cursorTarget.selector.includes("dialog") || cursorTarget.selector.includes("api-key-name-input");
|
|
2026
|
-
const initialDelay = isDialogElement ? 700 : isSettingsTab ? 600 : 400;
|
|
2027
|
-
setTimeout(() => {
|
|
2028
|
-
const waitForElement = () => {
|
|
2029
|
-
const element = document.querySelector(cursorTarget.selector);
|
|
2030
|
-
if (element && element.offsetParent !== null) {
|
|
2031
|
-
moveTo(cursorTarget);
|
|
2032
|
-
if (cursorTarget.onClick) {
|
|
2033
|
-
setTimeout(() => {
|
|
2034
|
-
element.click();
|
|
2035
|
-
}, 1e3);
|
|
2036
|
-
}
|
|
2037
|
-
} else if (isSettingsTab || isDialogElement) {
|
|
2038
|
-
setTimeout(waitForElement, 200);
|
|
2039
|
-
} else {
|
|
2040
|
-
moveTo(cursorTarget);
|
|
2041
|
-
if (cursorTarget.onClick) {
|
|
2042
|
-
setTimeout(() => {
|
|
2043
|
-
const el = document.querySelector(cursorTarget.selector);
|
|
2044
|
-
if (el) el.click();
|
|
2045
|
-
}, 1e3);
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
};
|
|
2049
|
-
waitForElement();
|
|
2050
|
-
}, initialDelay);
|
|
2051
|
-
}
|
|
2052
|
-
}
|
|
2053
|
-
const draft = {
|
|
2054
|
-
id: Date.now() + 1,
|
|
2055
|
-
role: "assistant",
|
|
2056
|
-
kind: "guideStep",
|
|
2057
|
-
content: "",
|
|
2058
|
-
guideStepIndex: 0
|
|
2059
|
-
};
|
|
2060
|
-
setMessages((prev) => [...prev, draft]);
|
|
2061
|
-
streamAssistantMessage(draft.id, firstStep.text);
|
|
2062
|
-
}
|
|
2063
|
-
function advanceGuide() {
|
|
2064
|
-
if (!activeGuide) return;
|
|
2065
|
-
const guide = guides[activeGuide.id];
|
|
2066
|
-
if (!guide) return;
|
|
2067
|
-
let currentGuide = activeGuideRef.current;
|
|
2068
|
-
if (!currentGuide || currentGuide.id !== activeGuide.id) {
|
|
2069
|
-
currentGuide = activeGuide;
|
|
2070
|
-
activeGuideRef.current = activeGuide;
|
|
2071
|
-
}
|
|
2072
|
-
const currentStepIndex = currentGuide.stepIndex;
|
|
2073
|
-
const nextIndex = currentStepIndex + 1;
|
|
2074
|
-
if (nextIndex >= guide.steps.length) {
|
|
2075
|
-
hide();
|
|
2076
|
-
const id = Date.now() + 1;
|
|
2077
|
-
setMessages((prev) => [
|
|
2078
|
-
...prev,
|
|
2079
|
-
{ id, role: "assistant", kind: "guideComplete", content: "Guide Complete" }
|
|
2080
|
-
]);
|
|
2081
|
-
setActiveGuide(void 0);
|
|
2082
|
-
setGuideComplete(true);
|
|
2083
|
-
return;
|
|
2084
|
-
}
|
|
2085
|
-
const nextStep = guide.steps[nextIndex];
|
|
2086
|
-
const newGuideState = { id: activeGuide.id, stepIndex: nextIndex };
|
|
2087
|
-
setActiveGuide(newGuideState);
|
|
2088
|
-
activeGuideRef.current = newGuideState;
|
|
2089
|
-
const draft = {
|
|
2090
|
-
id: Date.now() + 1,
|
|
2091
|
-
role: "assistant",
|
|
2092
|
-
kind: "guideStep",
|
|
2093
|
-
content: "",
|
|
2094
|
-
guideStepIndex: nextIndex
|
|
2095
|
-
};
|
|
2096
|
-
setMessages((prev) => [...prev, draft]);
|
|
2097
|
-
const isNavigationButton = nextStep.cursorTarget?.selector.includes("[data-page=");
|
|
2098
|
-
const isTabButton = nextStep.cursorTarget?.selector.includes("[data-settings-tab=");
|
|
2099
|
-
if (nextStep.cursorTarget && (isNavigationButton || isTabButton)) {
|
|
2100
|
-
const cursorTarget = nextStep.cursorTarget;
|
|
2101
|
-
if (isTabButton && nextStep.navigation && onNavigate) {
|
|
2102
|
-
onNavigate(nextStep.navigation.page, void 0);
|
|
2103
|
-
}
|
|
2104
|
-
const initialDelay = isTabButton ? 800 : 400;
|
|
2105
|
-
setTimeout(() => {
|
|
2106
|
-
const currentGuideCheck = activeGuideRef.current;
|
|
2107
|
-
if (!currentGuideCheck || currentGuideCheck.id !== guide.id || currentGuideCheck.stepIndex !== nextIndex) {
|
|
2108
|
-
return;
|
|
2109
|
-
}
|
|
2110
|
-
const waitForElement = () => {
|
|
2111
|
-
const currentGuideCheck2 = activeGuideRef.current;
|
|
2112
|
-
if (!currentGuideCheck2 || currentGuideCheck2.id !== guide.id || currentGuideCheck2.stepIndex !== nextIndex) {
|
|
2113
|
-
return;
|
|
2114
|
-
}
|
|
2115
|
-
const element = document.querySelector(cursorTarget.selector);
|
|
2116
|
-
if (element && element.offsetParent !== null) {
|
|
2117
|
-
moveTo(cursorTarget);
|
|
2118
|
-
if (cursorTarget.onClick) {
|
|
2119
|
-
setTimeout(() => {
|
|
2120
|
-
const currentGuideCheck3 = activeGuideRef.current;
|
|
2121
|
-
if (!currentGuideCheck3 || currentGuideCheck3.id !== guide.id || currentGuideCheck3.stepIndex !== nextIndex) {
|
|
2122
|
-
return;
|
|
2123
|
-
}
|
|
2124
|
-
element.click();
|
|
2125
|
-
}, 1200);
|
|
2126
|
-
}
|
|
2127
|
-
} else {
|
|
2128
|
-
setTimeout(waitForElement, 200);
|
|
2129
|
-
}
|
|
2130
|
-
};
|
|
2131
|
-
waitForElement();
|
|
2132
|
-
}, initialDelay);
|
|
2133
|
-
} else {
|
|
2134
|
-
if (nextStep.navigation && onNavigate) {
|
|
2135
|
-
onNavigate(nextStep.navigation.page, nextStep.navigation.subtab);
|
|
2136
|
-
}
|
|
2137
|
-
if (nextStep.cursorTarget) {
|
|
2138
|
-
const cursorTarget = nextStep.cursorTarget;
|
|
2139
|
-
const isDialogElement = cursorTarget.selector.includes("dialog") || cursorTarget.selector.includes("api-key-name-input");
|
|
2140
|
-
const isSettingsTab = cursorTarget.selector.includes("data-settings-tab");
|
|
2141
|
-
const navigationSetTab = nextStep.navigation?.subtab && isSettingsTab && cursorTarget.selector.includes(`data-settings-tab="${nextStep.navigation.subtab}"`);
|
|
2142
|
-
const shouldAutoClick = cursorTarget.onClick && !navigationSetTab;
|
|
2143
|
-
const hasNavigation = !!nextStep.navigation;
|
|
2144
|
-
const hasSubtab = !!nextStep.navigation?.subtab;
|
|
2145
|
-
const navigationDelay = hasSubtab ? 700 : hasNavigation ? 400 : 0;
|
|
2146
|
-
const initialDelay = navigationDelay + (isDialogElement ? 700 : isSettingsTab ? 600 : 400);
|
|
2147
|
-
setTimeout(() => {
|
|
2148
|
-
const currentGuideCheck = activeGuideRef.current;
|
|
2149
|
-
if (!currentGuideCheck || currentGuideCheck.id !== guide.id || currentGuideCheck.stepIndex !== nextIndex) {
|
|
2150
|
-
return;
|
|
2151
|
-
}
|
|
2152
|
-
const waitForElement = () => {
|
|
2153
|
-
const currentGuideCheck2 = activeGuideRef.current;
|
|
2154
|
-
if (!currentGuideCheck2 || currentGuideCheck2.id !== guide.id || currentGuideCheck2.stepIndex !== nextIndex) {
|
|
2155
|
-
return;
|
|
2156
|
-
}
|
|
2157
|
-
const element = document.querySelector(cursorTarget.selector);
|
|
2158
|
-
if (element && element.offsetParent !== null) {
|
|
2159
|
-
moveTo(cursorTarget);
|
|
2160
|
-
if (shouldAutoClick) {
|
|
2161
|
-
setTimeout(() => {
|
|
2162
|
-
const currentGuideCheck3 = activeGuideRef.current;
|
|
2163
|
-
if (!currentGuideCheck3 || currentGuideCheck3.id !== guide.id || currentGuideCheck3.stepIndex !== nextIndex) {
|
|
2164
|
-
return;
|
|
2165
|
-
}
|
|
2166
|
-
element.click();
|
|
2167
|
-
}, 1e3);
|
|
2168
|
-
}
|
|
2169
|
-
} else if (isDialogElement || isSettingsTab || cursorTarget.selector.includes("data-testid")) {
|
|
2170
|
-
setTimeout(waitForElement, 200);
|
|
2171
|
-
} else {
|
|
2172
|
-
moveTo(cursorTarget);
|
|
2173
|
-
if (shouldAutoClick) {
|
|
2174
|
-
setTimeout(() => {
|
|
2175
|
-
const currentGuideCheck3 = activeGuideRef.current;
|
|
2176
|
-
if (!currentGuideCheck3 || currentGuideCheck3.id !== guide.id || currentGuideCheck3.stepIndex !== nextIndex) {
|
|
2177
|
-
return;
|
|
2178
|
-
}
|
|
2179
|
-
const el = document.querySelector(cursorTarget.selector);
|
|
2180
|
-
if (el) el.click();
|
|
2181
|
-
}, 1e3);
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
};
|
|
2185
|
-
waitForElement();
|
|
2186
|
-
}, initialDelay);
|
|
2187
|
-
} else {
|
|
2188
|
-
hide();
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
streamAssistantMessage(draft.id, nextStep.text);
|
|
2192
|
-
}
|
|
2193
|
-
function goBackGuide() {
|
|
2194
|
-
if (!activeGuide) return;
|
|
2195
|
-
const guide = guides[activeGuide.id];
|
|
2196
|
-
if (!guide) return;
|
|
2197
|
-
const prevIndex = activeGuide.stepIndex - 1;
|
|
2198
|
-
if (prevIndex >= 0) {
|
|
2199
|
-
setActiveGuide({ id: activeGuide.id, stepIndex: prevIndex });
|
|
2200
|
-
activeGuideRef.current = { id: activeGuide.id, stepIndex: prevIndex };
|
|
2201
|
-
const prevStep = guide.steps[prevIndex];
|
|
2202
|
-
if (prevStep.navigation && onNavigate) {
|
|
2203
|
-
onNavigate(prevStep.navigation.page, prevStep.navigation.subtab);
|
|
2204
|
-
}
|
|
2205
|
-
if (prevStep.cursorTarget) {
|
|
2206
|
-
moveTo(prevStep.cursorTarget);
|
|
2207
|
-
} else {
|
|
2208
|
-
hide();
|
|
2209
|
-
}
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
const currentFolder = folders.find((f) => f.id === currentFolderId);
|
|
2213
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "fixed bottom-6 right-6 z-50 flex flex-col w-[380px] max-h-[600px] rounded-2xl border border-gray-200 bg-white shadow-2xl overflow-hidden", children: [
|
|
2214
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-white", children: [
|
|
2215
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2216
|
-
(!isEmpty || panelView === "folder") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2217
|
-
Button,
|
|
2218
|
-
{
|
|
2219
|
-
type: "button",
|
|
2220
|
-
size: "icon",
|
|
2221
|
-
variant: "ghost",
|
|
2222
|
-
className: "h-7 w-7 rounded-full",
|
|
2223
|
-
onClick: panelView === "folder" ? closeFolder : handleBack,
|
|
2224
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "h-4 w-4" })
|
|
2225
|
-
}
|
|
2226
|
-
),
|
|
2227
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-700", children: panelView === "folder" && currentFolder ? currentFolder.title : "AI Assistant" })
|
|
2228
|
-
] }),
|
|
2229
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
2230
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2231
|
-
Button,
|
|
2232
|
-
{
|
|
2233
|
-
type: "button",
|
|
2234
|
-
size: "icon",
|
|
2235
|
-
variant: "ghost",
|
|
2236
|
-
className: "h-7 w-7 rounded-full",
|
|
2237
|
-
onClick: () => setIsCollapsed(!isCollapsed),
|
|
2238
|
-
children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })
|
|
2239
|
-
}
|
|
2240
|
-
),
|
|
2241
|
-
!isEmpty && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2242
|
-
Button,
|
|
2243
|
-
{
|
|
2244
|
-
type: "button",
|
|
2245
|
-
size: "icon",
|
|
2246
|
-
variant: "ghost",
|
|
2247
|
-
className: "h-7 w-7 rounded-full",
|
|
2248
|
-
onClick: handleBack,
|
|
2249
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SquarePen, { className: "h-4 w-4" })
|
|
2250
|
-
}
|
|
2251
|
-
)
|
|
2252
|
-
] })
|
|
2253
|
-
] }),
|
|
2254
|
-
!isCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 flex flex-col overflow-hidden", children: isEmpty && panelView === "landing" ? (
|
|
2255
|
-
// Landing view
|
|
2256
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: [
|
|
2257
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: folders.map((folder) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2258
|
-
"button",
|
|
2259
|
-
{
|
|
2260
|
-
type: "button",
|
|
2261
|
-
onClick: () => openFolder(folder.id),
|
|
2262
|
-
className: "w-full text-left px-3 py-2.5 rounded-lg hover:bg-gray-50 transition-colors border border-gray-100",
|
|
2263
|
-
children: [
|
|
2264
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-gray-800", children: folder.title }),
|
|
2265
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 mt-0.5", children: [
|
|
2266
|
-
folder.topics.length,
|
|
2267
|
-
" topics"
|
|
2268
|
-
] })
|
|
2269
|
-
]
|
|
2270
|
-
},
|
|
2271
|
-
folder.id
|
|
2272
|
-
)) }),
|
|
2273
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 pt-4 border-t border-gray-100", children: [
|
|
2274
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs uppercase tracking-wider text-gray-400 mb-2", children: "Interactive Guides" }),
|
|
2275
|
-
Object.values(guides).map((guide) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2276
|
-
"button",
|
|
2277
|
-
{
|
|
2278
|
-
type: "button",
|
|
2279
|
-
onClick: () => startGuide(guide.id),
|
|
2280
|
-
className: "w-full text-left px-3 py-2 rounded-lg hover:bg-gray-50 transition-colors text-sm text-gray-700",
|
|
2281
|
-
children: guide.title
|
|
2282
|
-
},
|
|
2283
|
-
guide.id
|
|
2284
|
-
))
|
|
2285
|
-
] })
|
|
2286
|
-
] })
|
|
2287
|
-
) : isEmpty && panelView === "folder" && currentFolder ? (
|
|
2288
|
-
// Folder view
|
|
2289
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: currentFolder.topics.map((topic) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2290
|
-
"button",
|
|
2291
|
-
{
|
|
2292
|
-
type: "button",
|
|
2293
|
-
onClick: () => sendTopic(topic.prompt),
|
|
2294
|
-
className: "w-full text-left px-3 py-2 rounded-lg hover:bg-gray-50 transition-colors text-sm text-gray-700",
|
|
2295
|
-
children: topic.label
|
|
2296
|
-
},
|
|
2297
|
-
topic.id
|
|
2298
|
-
)) }) })
|
|
2299
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { ref: messagesContainerRef, className: "h-full px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
2300
|
-
messages.map((message, idx) => {
|
|
2301
|
-
const prevMessage = idx > 0 ? messages[idx - 1] : null;
|
|
2302
|
-
const isRoleChange = !prevMessage || prevMessage.role !== message.role;
|
|
2303
|
-
const isCurrentGuideStep = message.kind === "guideStep" && activeGuide && message.guideStepIndex === activeGuide.stepIndex;
|
|
2304
|
-
if (message.role === "user") {
|
|
2305
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-6 text-gray-900 whitespace-pre-wrap", children: message.content }) }, message.id);
|
|
2306
|
-
}
|
|
2307
|
-
if (message.kind === "navigationAction" && message.navigationTarget) {
|
|
2308
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${isRoleChange ? "mt-3" : ""}`, children: [
|
|
2309
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-6 text-gray-700 mb-2", children: message.content }),
|
|
2310
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2311
|
-
Button,
|
|
2312
|
-
{
|
|
2313
|
-
type: "button",
|
|
2314
|
-
size: "sm",
|
|
2315
|
-
variant: "secondary",
|
|
2316
|
-
className: "h-8 rounded-xl px-3 text-xs gap-1.5 bg-gray-100 hover:bg-gray-200 border border-gray-200",
|
|
2317
|
-
onClick: () => message.navigationTarget && handleConfirmNavigation(message.navigationTarget),
|
|
2318
|
-
children: [
|
|
2319
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2320
|
-
"Go to ",
|
|
2321
|
-
getPageDisplayName(message.navigationTarget)
|
|
2322
|
-
] }),
|
|
2323
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 text-gray-400", children: [
|
|
2324
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Command, { className: "h-3 w-3" }),
|
|
2325
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { className: "h-3 w-3" })
|
|
2326
|
-
] })
|
|
2327
|
-
]
|
|
2328
|
-
}
|
|
2329
|
-
)
|
|
2330
|
-
] }, message.id);
|
|
2331
|
-
}
|
|
2332
|
-
if (message.kind === "actionForm" && message.actionType && !message.isSubmitted) {
|
|
2333
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${isRoleChange ? "mt-3" : ""}`, children: [
|
|
2334
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-6 text-gray-700 mb-3", children: message.content }),
|
|
2335
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 mb-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
2336
|
-
"Form for: ",
|
|
2337
|
-
message.actionType
|
|
2338
|
-
] }) }),
|
|
2339
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2340
|
-
Button,
|
|
2341
|
-
{
|
|
2342
|
-
type: "button",
|
|
2343
|
-
size: "sm",
|
|
2344
|
-
variant: "secondary",
|
|
2345
|
-
className: "h-8 rounded-xl px-3 text-xs gap-1.5 bg-gray-100 hover:bg-gray-200 border border-gray-200",
|
|
2346
|
-
onClick: handleActionSubmit,
|
|
2347
|
-
children: [
|
|
2348
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Submit" }),
|
|
2349
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 text-gray-400", children: [
|
|
2350
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Command, { className: "h-3 w-3" }),
|
|
2351
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { className: "h-3 w-3" })
|
|
2352
|
-
] })
|
|
2353
|
-
]
|
|
2354
|
-
}
|
|
2355
|
-
)
|
|
2356
|
-
] }, message.id);
|
|
2357
|
-
}
|
|
2358
|
-
if (message.kind === "bulkPreview" && message.csvData) {
|
|
2359
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${isRoleChange ? "mt-3" : ""}`, children: [
|
|
2360
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-6 text-gray-700 mb-2", children: message.content }),
|
|
2361
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-gray-50 rounded-lg border border-gray-200 overflow-hidden", children: [
|
|
2362
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 border-b border-gray-200 flex items-center gap-2", children: [
|
|
2363
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSpreadsheet, { className: "h-4 w-4 text-gray-500" }),
|
|
2364
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: message.csvData.fileName }),
|
|
2365
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-gray-400 ml-auto", children: [
|
|
2366
|
-
message.csvData.rowCount,
|
|
2367
|
-
" rows"
|
|
2368
|
-
] })
|
|
2369
|
-
] }),
|
|
2370
|
-
message.csvData.sampleRows && message.csvData.sampleRows.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: message.csvData.sampleRows.slice(0, 3).map((row, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-gray-600 bg-white rounded px-2 py-1 border border-gray-100", children: [
|
|
2371
|
-
Object.entries(row).slice(0, 3).map(([key, val], j) => /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2372
|
-
j > 0 && " \u2022 ",
|
|
2373
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400", children: [
|
|
2374
|
-
key,
|
|
2375
|
-
":"
|
|
2376
|
-
] }),
|
|
2377
|
-
" ",
|
|
2378
|
-
val
|
|
2379
|
-
] }, key)),
|
|
2380
|
-
Object.keys(row).length > 3 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400", children: " ..." })
|
|
2381
|
-
] }, i)) }) }),
|
|
2382
|
-
message.suggestedAction && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 bg-blue-50 border-t border-blue-100", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-blue-700", children: [
|
|
2383
|
-
"Suggested action: ",
|
|
2384
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: message.suggestedAction.replace(/_/g, " ") })
|
|
2385
|
-
] }) })
|
|
2386
|
-
] }),
|
|
2387
|
-
message.bulkSessionId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center gap-2", children: [
|
|
2388
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2389
|
-
Button,
|
|
2390
|
-
{
|
|
2391
|
-
type: "button",
|
|
2392
|
-
size: "sm",
|
|
2393
|
-
variant: "secondary",
|
|
2394
|
-
className: "h-8 rounded-xl px-3 text-xs gap-1.5 bg-gray-100 hover:bg-gray-200 border border-gray-200",
|
|
2395
|
-
onClick: () => message.bulkSessionId && confirmBulkOperation(message.bulkSessionId),
|
|
2396
|
-
children: [
|
|
2397
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2398
|
-
"Process ",
|
|
2399
|
-
message.csvData.rowCount,
|
|
2400
|
-
" rows"
|
|
2401
|
-
] }),
|
|
2402
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 text-gray-400", children: [
|
|
2403
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Command, { className: "h-3 w-3" }),
|
|
2404
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { className: "h-3 w-3" })
|
|
2405
|
-
] })
|
|
2406
|
-
]
|
|
2407
|
-
}
|
|
2408
|
-
),
|
|
2409
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2410
|
-
Button,
|
|
2411
|
-
{
|
|
2412
|
-
type: "button",
|
|
2413
|
-
size: "sm",
|
|
2414
|
-
variant: "ghost",
|
|
2415
|
-
className: "h-8 rounded-xl px-3 text-xs text-gray-500 hover:text-gray-700 hover:bg-gray-100",
|
|
2416
|
-
onClick: cancelBulkOperation,
|
|
2417
|
-
children: "Cancel"
|
|
2418
|
-
}
|
|
2419
|
-
)
|
|
2420
|
-
] })
|
|
2421
|
-
] }, message.id);
|
|
2422
|
-
}
|
|
2423
|
-
if (message.kind === "bulkProgress" && message.bulkProgress) {
|
|
2424
|
-
const { processed, total, successes, failures } = message.bulkProgress;
|
|
2425
|
-
const percentage = Math.round(processed / total * 100);
|
|
2426
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-gray-50 rounded-lg border border-gray-200 p-3", children: [
|
|
2427
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
2428
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-blue-600" }),
|
|
2429
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-gray-700", children: [
|
|
2430
|
-
"Processing... ",
|
|
2431
|
-
processed,
|
|
2432
|
-
" of ",
|
|
2433
|
-
total
|
|
2434
|
-
] })
|
|
2435
|
-
] }),
|
|
2436
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 bg-gray-200 rounded-full overflow-hidden mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2437
|
-
"div",
|
|
2438
|
-
{
|
|
2439
|
-
className: "h-full bg-blue-600 transition-all duration-300",
|
|
2440
|
-
style: { width: `${percentage}%` }
|
|
2441
|
-
}
|
|
2442
|
-
) }),
|
|
2443
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-xs text-gray-600", children: [
|
|
2444
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
|
|
2445
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3 w-3 text-green-600" }),
|
|
2446
|
-
successes,
|
|
2447
|
-
" successful"
|
|
2448
|
-
] }),
|
|
2449
|
-
failures > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-red-600", children: [
|
|
2450
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }),
|
|
2451
|
-
failures,
|
|
2452
|
-
" failed"
|
|
2453
|
-
] })
|
|
2454
|
-
] })
|
|
2455
|
-
] }) }, message.id);
|
|
2456
|
-
}
|
|
2457
|
-
if (message.kind === "bulkSummary" && message.bulkSummary) {
|
|
2458
|
-
const { total, successes, failures, navigationPage } = message.bulkSummary;
|
|
2459
|
-
const hasFailures = failures.length > 0;
|
|
2460
|
-
const pageLabel = navigationPage?.page === "customers" ? "Customers" : navigationPage?.page === "dashboard" ? "Dashboard" : navigationPage?.page === "settings" ? "Settings" : "Results";
|
|
2461
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `rounded-lg border p-3 ${hasFailures ? "bg-amber-50 border-amber-200" : "bg-green-50 border-green-200"}`, children: [
|
|
2462
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
2463
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: `h-5 w-5 ${hasFailures ? "text-amber-600" : "text-green-600"}` }),
|
|
2464
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-800", children: "Bulk operation complete" })
|
|
2465
|
-
] }),
|
|
2466
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-gray-600 mb-2", children: message.content || `Processed ${total} rows: ${successes} successful${hasFailures ? `, ${failures.length} failed` : ""}.` }),
|
|
2467
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 text-xs", children: [
|
|
2468
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-green-700", children: [
|
|
2469
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3 w-3" }),
|
|
2470
|
-
successes,
|
|
2471
|
-
" successful"
|
|
2472
|
-
] }),
|
|
2473
|
-
hasFailures && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-red-600", children: [
|
|
2474
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }),
|
|
2475
|
-
failures.length,
|
|
2476
|
-
" failed"
|
|
2477
|
-
] })
|
|
2478
|
-
] }),
|
|
2479
|
-
hasFailures && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 pt-2 border-t border-amber-200", children: [
|
|
2480
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] uppercase tracking-wider text-amber-700 mb-1", children: "Failed Rows" }),
|
|
2481
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 max-h-32 overflow-y-auto", children: [
|
|
2482
|
-
failures.slice(0, 5).map((failure, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-red-700 bg-red-50 rounded px-2 py-1", children: [
|
|
2483
|
-
"Row ",
|
|
2484
|
-
failure.row,
|
|
2485
|
-
": ",
|
|
2486
|
-
failure.error || "Unknown error"
|
|
2487
|
-
] }, i)),
|
|
2488
|
-
failures.length > 5 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-amber-600", children: [
|
|
2489
|
-
"...and ",
|
|
2490
|
-
failures.length - 5,
|
|
2491
|
-
" more"
|
|
2492
|
-
] })
|
|
2493
|
-
] })
|
|
2494
|
-
] }),
|
|
2495
|
-
navigationPage && successes > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 pt-2 border-t border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2496
|
-
"button",
|
|
2497
|
-
{
|
|
2498
|
-
type: "button",
|
|
2499
|
-
onClick: () => {
|
|
2500
|
-
if (onNavigate && navigationPage.page) {
|
|
2501
|
-
onNavigate(navigationPage.page, navigationPage.subtab);
|
|
2502
|
-
}
|
|
2503
|
-
},
|
|
2504
|
-
className: "flex items-center gap-2 text-xs text-gray-500 hover:text-gray-700 transition-colors group cursor-pointer",
|
|
2505
|
-
children: [
|
|
2506
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 px-1.5 py-0.5 bg-gray-100 rounded text-[10px] font-medium text-gray-600 group-hover:bg-gray-200", children: [
|
|
2507
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Command, { className: "h-2.5 w-2.5" }),
|
|
2508
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "+" }),
|
|
2509
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { className: "h-2.5 w-2.5" })
|
|
2510
|
-
] }),
|
|
2511
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2512
|
-
"View ",
|
|
2513
|
-
pageLabel
|
|
2514
|
-
] })
|
|
2515
|
-
]
|
|
2516
|
-
}
|
|
2517
|
-
) })
|
|
2518
|
-
] }) }, message.id);
|
|
2519
|
-
}
|
|
2520
|
-
return /* @__PURE__ */ jsxRuntime.jsx(React4__namespace.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2521
|
-
"div",
|
|
2522
|
-
{
|
|
2523
|
-
ref: isCurrentGuideStep ? currentStepRef : null,
|
|
2524
|
-
className: `${isRoleChange ? "mt-3" : ""}`,
|
|
2525
|
-
children: [
|
|
2526
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-6 text-gray-700", children: (() => {
|
|
2527
|
-
const text = message.content || "";
|
|
2528
|
-
if (message.kind === "guideStep") {
|
|
2529
|
-
const m = text.match(/^(Step\s+\d+:)([\s\S]*)/);
|
|
2530
|
-
if (m) {
|
|
2531
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2532
|
-
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: m[1] }),
|
|
2533
|
-
m[2]
|
|
2534
|
-
] });
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
if (message.role === "assistant" && text) {
|
|
2538
|
-
return renderMarkdown(text);
|
|
2539
|
-
}
|
|
2540
|
-
return text || /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-70", children: "Thinking\u2026" });
|
|
2541
|
-
})() }),
|
|
2542
|
-
message.role === "assistant" && message.structuredData && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2543
|
-
DataRenderer,
|
|
2544
|
-
{
|
|
2545
|
-
type: message.structuredData.type,
|
|
2546
|
-
data: message.structuredData.data
|
|
2547
|
-
}
|
|
2548
|
-
) }),
|
|
2549
|
-
message.role === "assistant" && message.followups && message.followups.length > 0 && !message.followupSelected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-1.5", children: message.followups.map((followup) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2550
|
-
"button",
|
|
2551
|
-
{
|
|
2552
|
-
type: "button",
|
|
2553
|
-
onClick: () => handleFollowupClick(message.id, followup),
|
|
2554
|
-
className: "inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-xl\n bg-white hover:bg-gray-50 text-gray-600 hover:text-gray-800\n border border-gray-200 hover:border-gray-300 shadow-sm\n transition-all duration-150 ease-in-out",
|
|
2555
|
-
children: followup.label
|
|
2556
|
-
},
|
|
2557
|
-
followup.id
|
|
2558
|
-
)) })
|
|
2559
|
-
]
|
|
2560
|
-
}
|
|
2561
|
-
) }, message.id);
|
|
2562
|
-
}),
|
|
2563
|
-
(activeGuide || guideComplete) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center gap-2", children: [
|
|
2564
|
-
activeGuide && activeGuide.stepIndex > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2565
|
-
Button,
|
|
2566
|
-
{
|
|
2567
|
-
type: "button",
|
|
2568
|
-
size: "sm",
|
|
2569
|
-
variant: "secondary",
|
|
2570
|
-
className: "h-7 w-7 rounded-full p-0 bg-gray-100 hover:bg-gray-200 border border-gray-200",
|
|
2571
|
-
onClick: goBackGuide,
|
|
2572
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "h-3.5 w-3.5 text-gray-600" })
|
|
2573
|
-
}
|
|
2574
|
-
),
|
|
2575
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2576
|
-
Button,
|
|
2577
|
-
{
|
|
2578
|
-
type: "button",
|
|
2579
|
-
size: "sm",
|
|
2580
|
-
variant: "secondary",
|
|
2581
|
-
className: "h-8 rounded-xl px-3 text-xs gap-1.5 bg-gray-100 hover:bg-gray-200 border border-gray-200",
|
|
2582
|
-
onClick: guideComplete ? handleBack : advanceGuide,
|
|
2583
|
-
children: [
|
|
2584
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: guideComplete ? "Done" : "Next" }),
|
|
2585
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 text-gray-400", children: [
|
|
2586
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Command, { className: "h-3 w-3" }),
|
|
2587
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { className: "h-3 w-3" })
|
|
2588
|
-
] })
|
|
2589
|
-
]
|
|
2590
|
-
}
|
|
2591
|
-
)
|
|
2592
|
-
] }),
|
|
2593
|
-
(phase === "thinking" || phase === "searching" || phase === "executing" || phase === "responding") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${lastRole === "user" ? "mt-3" : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2594
|
-
AssistantActivity,
|
|
2595
|
-
{
|
|
2596
|
-
phase,
|
|
2597
|
-
progressSteps
|
|
2598
|
-
}
|
|
2599
|
-
) }),
|
|
2600
|
-
!activeGuide && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
2601
|
-
] }) }) }) }) }),
|
|
2602
|
-
!isCollapsed && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 border-t border-gray-100 bg-gray-50/50 shrink-0", children: [
|
|
2603
|
-
pendingFile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-2 rounded-xl bg-blue-50 border border-blue-200 px-3 py-2", children: [
|
|
2604
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSpreadsheet, { className: "h-4 w-4 text-blue-600" }),
|
|
2605
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-blue-700 flex-1 truncate", children: pendingFile.name }),
|
|
2606
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2607
|
-
"button",
|
|
2608
|
-
{
|
|
2609
|
-
type: "button",
|
|
2610
|
-
onClick: () => {
|
|
2611
|
-
setPendingFile(null);
|
|
2612
|
-
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2613
|
-
},
|
|
2614
|
-
className: "text-blue-600 hover:text-blue-800",
|
|
2615
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
|
|
2616
|
-
}
|
|
2617
|
-
)
|
|
2618
|
-
] }),
|
|
2619
|
-
/* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "w-full", children: [
|
|
2620
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2621
|
-
"input",
|
|
2622
|
-
{
|
|
2623
|
-
ref: fileInputRef,
|
|
2624
|
-
type: "file",
|
|
2625
|
-
accept: ".csv",
|
|
2626
|
-
className: "hidden",
|
|
2627
|
-
onChange: (e) => {
|
|
2628
|
-
const file = e.target.files?.[0];
|
|
2629
|
-
if (file) {
|
|
2630
|
-
setPendingFile(file);
|
|
2631
|
-
}
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
),
|
|
2635
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 rounded-2xl border border-gray-200 bg-white px-3 py-2 shadow-sm", children: [
|
|
2636
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2637
|
-
Button,
|
|
2638
|
-
{
|
|
2639
|
-
type: "button",
|
|
2640
|
-
size: "icon",
|
|
2641
|
-
variant: "ghost",
|
|
2642
|
-
onClick: () => fileInputRef.current?.click(),
|
|
2643
|
-
className: "h-8 w-8 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
2644
|
-
title: "Upload CSV for bulk operations",
|
|
2645
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" })
|
|
2646
|
-
}
|
|
2647
|
-
),
|
|
2648
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2649
|
-
Input,
|
|
2650
|
-
{
|
|
2651
|
-
placeholder: pendingFile ? "Describe what to do with this CSV..." : "Ask anything...",
|
|
2652
|
-
value: input,
|
|
2653
|
-
onChange: (e) => setInput(e.target.value),
|
|
2654
|
-
className: "flex-1 border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 text-sm placeholder:text-gray-400"
|
|
2655
|
-
}
|
|
2656
|
-
),
|
|
2657
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2658
|
-
Button,
|
|
2659
|
-
{
|
|
2660
|
-
type: "submit",
|
|
2661
|
-
size: "icon",
|
|
2662
|
-
disabled: !input.trim() && !pendingFile,
|
|
2663
|
-
className: "h-8 w-8 rounded-full bg-gray-900 hover:bg-gray-800 disabled:bg-gray-300",
|
|
2664
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4" })
|
|
2665
|
-
}
|
|
2666
|
-
)
|
|
2667
|
-
] })
|
|
2668
|
-
] })
|
|
2669
|
-
] }),
|
|
2670
|
-
enableGuideCursor && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2671
|
-
GuideCursor,
|
|
2672
|
-
{
|
|
2673
|
-
x: cursorState.x,
|
|
2674
|
-
y: cursorState.y,
|
|
2675
|
-
visible: cursorState.visible,
|
|
2676
|
-
onClick: cursorState.onClick
|
|
2677
|
-
}
|
|
2678
|
-
)
|
|
2679
|
-
] });
|
|
2680
|
-
}
|
|
2681
|
-
function AssistantSearchSummary({
|
|
2682
|
-
title,
|
|
2683
|
-
links
|
|
2684
|
-
}) {
|
|
2685
|
-
const [open, setOpen] = React4__namespace.useState(false);
|
|
2686
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
2687
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2688
|
-
"button",
|
|
2689
|
-
{
|
|
2690
|
-
type: "button",
|
|
2691
|
-
onClick: () => setOpen((v) => !v),
|
|
2692
|
-
className: "flex w-full items-center gap-2 px-0 py-0",
|
|
2693
|
-
"aria-expanded": open,
|
|
2694
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
2695
|
-
open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3 w-3 opacity-70" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "h-3 w-3 opacity-70" }),
|
|
2696
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: title })
|
|
2697
|
-
] })
|
|
2698
|
-
}
|
|
2699
|
-
),
|
|
2700
|
-
open && links.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "ml-5 mt-1 space-y-0.5", children: links.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2701
|
-
"a",
|
|
2702
|
-
{
|
|
2703
|
-
href: link.href,
|
|
2704
|
-
target: "_blank",
|
|
2705
|
-
rel: "noreferrer",
|
|
2706
|
-
className: "text-primary hover:underline",
|
|
2707
|
-
children: link.label
|
|
2708
|
-
}
|
|
2709
|
-
) }, link.href)) })
|
|
2710
|
-
] });
|
|
2711
|
-
}
|
|
2712
|
-
|
|
2713
|
-
exports.AssistantActivity = AssistantActivity;
|
|
2714
|
-
exports.AssistantSearchSummary = AssistantSearchSummary;
|
|
2715
|
-
exports.Button = Button;
|
|
2716
|
-
exports.Card = Card;
|
|
2717
|
-
exports.CardAction = CardAction;
|
|
2718
|
-
exports.CardContent = CardContent;
|
|
2719
|
-
exports.CardDescription = CardDescription;
|
|
2720
|
-
exports.CardFooter = CardFooter;
|
|
2721
|
-
exports.CardHeader = CardHeader;
|
|
2722
|
-
exports.CardTitle = CardTitle;
|
|
2723
|
-
exports.ChatPanel = ChatPanel;
|
|
2724
|
-
exports.ChatPanelProvider = ChatPanelProvider;
|
|
2725
|
-
exports.DataRenderer = DataRenderer;
|
|
2726
|
-
exports.GuideCursor = GuideCursor;
|
|
2727
|
-
exports.Input = Input;
|
|
2728
|
-
exports.ScrollArea = ScrollArea;
|
|
2729
|
-
exports.ScrollBar = ScrollBar;
|
|
2730
|
-
exports.buttonVariants = buttonVariants;
|
|
2731
|
-
exports.cn = cn;
|
|
2732
|
-
exports.defaultConfig = defaultConfig;
|
|
2733
|
-
exports.defaultFolders = defaultFolders;
|
|
2734
|
-
exports.defaultGuides = defaultGuides;
|
|
2735
|
-
exports.useChatPanelConfig = useChatPanelConfig;
|
|
2736
|
-
exports.useGuideCursor = useGuideCursor;
|
|
2737
|
-
//# sourceMappingURL=index.js.map
|
|
2738
|
-
//# sourceMappingURL=index.js.map
|