@uptrademedia/site-kit 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blog/index.js.map +1 -1
- package/dist/blog/index.mjs.map +1 -1
- package/dist/chunk-5R4R3WDP.js +1451 -0
- package/dist/chunk-5R4R3WDP.js.map +1 -0
- package/dist/{chunk-COI6GOX2.mjs → chunk-63JNO4QN.mjs} +3 -3
- package/dist/chunk-63JNO4QN.mjs.map +1 -0
- package/dist/chunk-6EXHT7PS.mjs +330 -0
- package/dist/chunk-6EXHT7PS.mjs.map +1 -0
- package/dist/{chunk-RV7H3I6J.js → chunk-ADHVEFWD.js} +68 -2
- package/dist/chunk-ADHVEFWD.js.map +1 -0
- package/dist/chunk-BGJLOJ7T.mjs +605 -0
- package/dist/chunk-BGJLOJ7T.mjs.map +1 -0
- package/dist/chunk-BZBJVG5Y.js +88 -0
- package/dist/chunk-BZBJVG5Y.js.map +1 -0
- package/dist/chunk-DRFTRTKV.js +809 -0
- package/dist/chunk-DRFTRTKV.js.map +1 -0
- package/dist/chunk-EL5QTAA3.mjs +805 -0
- package/dist/chunk-EL5QTAA3.mjs.map +1 -0
- package/dist/chunk-JG2K4S2I.js +997 -0
- package/dist/chunk-JG2K4S2I.js.map +1 -0
- package/dist/chunk-P7LGOKGI.mjs +981 -0
- package/dist/chunk-P7LGOKGI.mjs.map +1 -0
- package/dist/{chunk-3MUOUXHV.js → chunk-PYYEPAHL.js} +3 -3
- package/dist/chunk-PYYEPAHL.js.map +1 -0
- package/dist/chunk-QAYJV4KK.js +608 -0
- package/dist/chunk-QAYJV4KK.js.map +1 -0
- package/dist/{chunk-FEBYQGY4 2.mjs → chunk-SMUFNQLM.mjs} +67 -3
- package/dist/chunk-SMUFNQLM.mjs.map +1 -0
- package/dist/chunk-VDMZZL2O.mjs +83 -0
- package/dist/chunk-VDMZZL2O.mjs.map +1 -0
- package/dist/chunk-XFRPT5ZX.mjs +1449 -0
- package/dist/chunk-XFRPT5ZX.mjs.map +1 -0
- package/dist/chunk-YKMCG3DS.js +332 -0
- package/dist/chunk-YKMCG3DS.js.map +1 -0
- package/dist/commerce/index.js +38 -38
- package/dist/commerce/index.mjs +1 -1
- package/dist/engage/index.js +7 -40
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +1 -41
- package/dist/engage/index.mjs.map +1 -1
- package/dist/forms/index.js +13 -5
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +2 -2
- package/dist/forms/index.mjs.map +1 -1
- package/dist/{generators-7Y5ABRYV 2.mjs → generators-TO2FKJR6.mjs} +134 -3
- package/dist/generators-TO2FKJR6.mjs.map +1 -0
- package/dist/{generators-GWIYCA5M.js → generators-YZWIGHCO.js} +135 -2
- package/dist/generators-YZWIGHCO.js.map +1 -0
- package/dist/images/index.js +41 -0
- package/dist/images/index.js.map +1 -0
- package/dist/images/index.mjs +8 -0
- package/dist/images/index.mjs.map +1 -0
- package/dist/index.js +1355 -104
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1242 -76
- package/dist/index.mjs.map +1 -1
- package/dist/redirects/index.js +25 -0
- package/dist/redirects/index.js.map +1 -0
- package/dist/redirects/index.mjs +4 -0
- package/dist/redirects/index.mjs.map +1 -0
- package/dist/{scanner-MF7P3CDE 2.mjs → scanner-AZV5I6US.mjs} +123 -4
- package/dist/scanner-AZV5I6US.mjs.map +1 -0
- package/dist/{scanner-NT6YG4TD 2.js → scanner-ETJAMIT7.js} +124 -3
- package/dist/scanner-ETJAMIT7.js.map +1 -0
- package/dist/setup/client.js +30 -0
- package/dist/setup/client.js.map +1 -0
- package/dist/setup/client.mjs +5 -0
- package/dist/setup/client.mjs.map +1 -0
- package/dist/setup/index.js +28 -1043
- package/dist/setup/index.js.map +1 -1
- package/dist/setup/index.mjs +3 -1043
- package/dist/setup/index.mjs.map +1 -1
- package/dist/setup/server.js +13 -0
- package/dist/setup/server.js.map +1 -0
- package/dist/setup/server.mjs +4 -0
- package/dist/setup/server.mjs.map +1 -0
- package/package.json +21 -1
- package/dist/chunk-3MUOUXHV.js.map +0 -1
- package/dist/chunk-4HVYXYQL 2.mjs +0 -255
- package/dist/chunk-4HVYXYQL.mjs +0 -255
- package/dist/chunk-4HVYXYQL.mjs.map +0 -1
- package/dist/chunk-COI6GOX2.mjs.map +0 -1
- package/dist/chunk-EQCVQC35.js 2.map +0 -1
- package/dist/chunk-FEBYQGY4.mjs +0 -251
- package/dist/chunk-FEBYQGY4.mjs.map +0 -1
- package/dist/chunk-NYKRE2FL 2.mjs +0 -31
- package/dist/chunk-NYKRE2FL.mjs 2.map +0 -1
- package/dist/chunk-RV7H3I6J.js 2.map +0 -1
- package/dist/chunk-RV7H3I6J.js.map +0 -1
- package/dist/chunk-TUKGA3UK.js +0 -257
- package/dist/chunk-TUKGA3UK.js 2.map +0 -1
- package/dist/chunk-TUKGA3UK.js.map +0 -1
- package/dist/generators-7Y5ABRYV.mjs +0 -161
- package/dist/generators-7Y5ABRYV.mjs 2.map +0 -1
- package/dist/generators-7Y5ABRYV.mjs.map +0 -1
- package/dist/generators-GWIYCA5M.js 2.map +0 -1
- package/dist/generators-GWIYCA5M.js.map +0 -1
- package/dist/index 2.mjs +0 -74
- package/dist/index.js 2.map +0 -1
- package/dist/migrator-V6KS75EA 2.mjs +0 -265
- package/dist/migrator-V6KS75EA.mjs 2.map +0 -1
- package/dist/migrator-XKM7YQCY.js 2.map +0 -1
- package/dist/scanner-MF7P3CDE.mjs +0 -14386
- package/dist/scanner-MF7P3CDE.mjs 2.map +0 -1
- package/dist/scanner-MF7P3CDE.mjs.map +0 -1
- package/dist/scanner-NT6YG4TD.js +0 -14397
- package/dist/scanner-NT6YG4TD.js 2.map +0 -1
- package/dist/scanner-NT6YG4TD.js.map +0 -1
- package/dist/web-vitals-BH55V7EJ.js 2.map +0 -1
- package/dist/web-vitals-RJYPWAR3 2.mjs +0 -241
- package/dist/web-vitals-RJYPWAR3.mjs 2.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,82 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
var chunk5R4R3WDP_js = require('./chunk-5R4R3WDP.js');
|
|
4
|
+
var chunkBZBJVG5Y_js = require('./chunk-BZBJVG5Y.js');
|
|
5
|
+
var chunkJG2K4S2I_js = require('./chunk-JG2K4S2I.js');
|
|
6
|
+
require('./chunk-HCFPU7TU.js');
|
|
7
|
+
require('./chunk-V3F5J6CV.js');
|
|
8
|
+
require('./chunk-QAYJV4KK.js');
|
|
9
|
+
require('./chunk-ADHVEFWD.js');
|
|
10
|
+
var chunkPYYEPAHL_js = require('./chunk-PYYEPAHL.js');
|
|
8
11
|
require('./chunk-EQCVQC35.js');
|
|
9
|
-
var
|
|
12
|
+
var React = require('react');
|
|
10
13
|
var jsxRuntime = require('react/jsx-runtime');
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!context) {
|
|
16
|
-
throw new Error("useSiteKit must be used within a SiteKitProvider");
|
|
17
|
-
}
|
|
18
|
-
return context;
|
|
19
|
-
}
|
|
20
|
-
function SiteKitProvider({
|
|
21
|
-
children,
|
|
22
|
-
apiUrl = "https://api.uptrademedia.com",
|
|
23
|
-
apiKey,
|
|
24
|
-
analytics,
|
|
25
|
-
engage,
|
|
26
|
-
forms,
|
|
27
|
-
debug = false
|
|
28
|
-
}) {
|
|
29
|
-
react.useEffect(() => {
|
|
30
|
-
if (typeof window !== "undefined") {
|
|
31
|
-
window.__SITE_KIT_API_URL__ = apiUrl;
|
|
32
|
-
window.__SITE_KIT_API_KEY__ = apiKey;
|
|
33
|
-
window.__SITE_KIT_DEBUG__ = debug;
|
|
34
|
-
}
|
|
35
|
-
chunkRV7H3I6J_js.configureFormsApi({
|
|
36
|
-
baseUrl: apiUrl,
|
|
37
|
-
apiKey
|
|
38
|
-
});
|
|
39
|
-
}, [apiUrl, apiKey, debug]);
|
|
40
|
-
const contextValue = react.useMemo(
|
|
41
|
-
() => ({
|
|
42
|
-
apiUrl,
|
|
43
|
-
apiKey,
|
|
44
|
-
analytics,
|
|
45
|
-
engage,
|
|
46
|
-
forms,
|
|
47
|
-
debug,
|
|
48
|
-
isReady: true
|
|
49
|
-
}),
|
|
50
|
-
[apiUrl, apiKey, analytics, engage, forms, debug]
|
|
51
|
-
);
|
|
52
|
-
let content = /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
53
|
-
if (analytics?.enabled) {
|
|
54
|
-
content = /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
55
|
-
chunkV3F5J6CV_js.AnalyticsProvider,
|
|
56
|
-
{
|
|
57
|
-
apiUrl,
|
|
58
|
-
apiKey,
|
|
59
|
-
trackPageViews: analytics.trackPageViews !== false,
|
|
60
|
-
trackWebVitals: analytics.trackWebVitals !== false,
|
|
61
|
-
trackScrollDepth: analytics.trackScrollDepth !== false,
|
|
62
|
-
trackClicks: analytics.trackClicks !== false,
|
|
63
|
-
debug,
|
|
64
|
-
children: content
|
|
65
|
-
}
|
|
66
|
-
) });
|
|
67
|
-
}
|
|
68
|
-
if (engage?.enabled) {
|
|
69
|
-
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
70
|
-
content,
|
|
71
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkTUKGA3UK_js.EngageWidget, { apiUrl, apiKey })
|
|
72
|
-
] });
|
|
73
|
-
}
|
|
74
|
-
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
75
|
-
content,
|
|
76
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkHCFPU7TU_js.SitemapSync, { debug })
|
|
77
|
-
] });
|
|
78
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SiteKitContext.Provider, { value: contextValue, children: content });
|
|
79
|
-
}
|
|
15
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
+
|
|
17
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
80
18
|
|
|
81
19
|
// src/affiliates/api.ts
|
|
82
20
|
function getApiConfig() {
|
|
@@ -118,10 +56,10 @@ function getTrackingUrl(affiliateId, offerId) {
|
|
|
118
56
|
return `${apiUrl}/a/${affiliateId}/${offerId}`;
|
|
119
57
|
}
|
|
120
58
|
function useAffiliates() {
|
|
121
|
-
const [affiliates, setAffiliates] =
|
|
122
|
-
const [isLoading, setIsLoading] =
|
|
123
|
-
const [error, setError] =
|
|
124
|
-
|
|
59
|
+
const [affiliates, setAffiliates] = React.useState([]);
|
|
60
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
61
|
+
const [error, setError] = React.useState(null);
|
|
62
|
+
React.useEffect(() => {
|
|
125
63
|
async function load() {
|
|
126
64
|
try {
|
|
127
65
|
setIsLoading(true);
|
|
@@ -218,109 +156,1422 @@ function AffiliatesWidget({
|
|
|
218
156
|
)
|
|
219
157
|
) });
|
|
220
158
|
}
|
|
159
|
+
function SignalExperiment({
|
|
160
|
+
experimentId,
|
|
161
|
+
variants,
|
|
162
|
+
fallback,
|
|
163
|
+
trackImpression = true,
|
|
164
|
+
children
|
|
165
|
+
}) {
|
|
166
|
+
const { assignment, variant, isControl } = chunkJG2K4S2I_js.useSignalExperiment(experimentId);
|
|
167
|
+
const trackEvent = chunkJG2K4S2I_js.useSignalEvent();
|
|
168
|
+
React.useEffect(() => {
|
|
169
|
+
if (trackImpression && variant) {
|
|
170
|
+
trackEvent({
|
|
171
|
+
event_type: "experiment",
|
|
172
|
+
event_name: "impression",
|
|
173
|
+
event_data: {
|
|
174
|
+
experiment_id: experimentId,
|
|
175
|
+
variant_key: variant
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}, [experimentId, variant, trackImpression, trackEvent]);
|
|
180
|
+
if (children) {
|
|
181
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({ variant: variant || "control", isControl }) });
|
|
182
|
+
}
|
|
183
|
+
const selectedVariant = variant || "control";
|
|
184
|
+
const content = variants[selectedVariant];
|
|
185
|
+
if (content !== void 0) {
|
|
186
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: content });
|
|
187
|
+
}
|
|
188
|
+
if (fallback) {
|
|
189
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
|
|
190
|
+
}
|
|
191
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: variants.control || null });
|
|
192
|
+
}
|
|
193
|
+
function useExperimentVariant(experimentId) {
|
|
194
|
+
return chunkJG2K4S2I_js.useSignalExperiment(experimentId);
|
|
195
|
+
}
|
|
196
|
+
function ExperimentConversion({
|
|
197
|
+
experimentId,
|
|
198
|
+
outcomeType = "click",
|
|
199
|
+
value,
|
|
200
|
+
children
|
|
201
|
+
}) {
|
|
202
|
+
const trackEvent = chunkJG2K4S2I_js.useSignalEvent();
|
|
203
|
+
const { variant } = chunkJG2K4S2I_js.useSignalExperiment(experimentId);
|
|
204
|
+
const handleInteraction = () => {
|
|
205
|
+
trackEvent({
|
|
206
|
+
event_type: "experiment",
|
|
207
|
+
event_name: "conversion",
|
|
208
|
+
event_data: {
|
|
209
|
+
experiment_id: experimentId,
|
|
210
|
+
variant_key: variant,
|
|
211
|
+
outcome_type: outcomeType,
|
|
212
|
+
value
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
return React__default.default.cloneElement(children, {
|
|
217
|
+
onClick: (e) => {
|
|
218
|
+
handleInteraction();
|
|
219
|
+
if (children.props.onClick) {
|
|
220
|
+
children.props.onClick(e);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
var styles = {
|
|
226
|
+
container: {
|
|
227
|
+
display: "flex",
|
|
228
|
+
flexDirection: "column",
|
|
229
|
+
height: "100vh",
|
|
230
|
+
maxWidth: "800px",
|
|
231
|
+
margin: "0 auto",
|
|
232
|
+
padding: "1rem",
|
|
233
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
234
|
+
},
|
|
235
|
+
header: {
|
|
236
|
+
display: "flex",
|
|
237
|
+
alignItems: "center",
|
|
238
|
+
gap: "0.75rem",
|
|
239
|
+
padding: "1rem 0",
|
|
240
|
+
borderBottom: "1px solid #e5e7eb"
|
|
241
|
+
},
|
|
242
|
+
logo: {
|
|
243
|
+
width: "32px",
|
|
244
|
+
height: "32px",
|
|
245
|
+
borderRadius: "8px",
|
|
246
|
+
background: "linear-gradient(135deg, #3b82f6, #8b5cf6)",
|
|
247
|
+
display: "flex",
|
|
248
|
+
alignItems: "center",
|
|
249
|
+
justifyContent: "center",
|
|
250
|
+
color: "white",
|
|
251
|
+
fontWeight: "bold"
|
|
252
|
+
},
|
|
253
|
+
title: {
|
|
254
|
+
fontSize: "1.25rem",
|
|
255
|
+
fontWeight: "600",
|
|
256
|
+
color: "#111827"
|
|
257
|
+
},
|
|
258
|
+
subtitle: {
|
|
259
|
+
fontSize: "0.875rem",
|
|
260
|
+
color: "#6b7280"
|
|
261
|
+
},
|
|
262
|
+
messages: {
|
|
263
|
+
flex: 1,
|
|
264
|
+
overflowY: "auto",
|
|
265
|
+
padding: "1rem 0",
|
|
266
|
+
display: "flex",
|
|
267
|
+
flexDirection: "column",
|
|
268
|
+
gap: "1rem"
|
|
269
|
+
},
|
|
270
|
+
message: {
|
|
271
|
+
display: "flex",
|
|
272
|
+
gap: "0.75rem",
|
|
273
|
+
maxWidth: "85%"
|
|
274
|
+
},
|
|
275
|
+
messageAssistant: {
|
|
276
|
+
alignSelf: "flex-start"
|
|
277
|
+
},
|
|
278
|
+
messageUser: {
|
|
279
|
+
alignSelf: "flex-end",
|
|
280
|
+
flexDirection: "row-reverse"
|
|
281
|
+
},
|
|
282
|
+
avatar: {
|
|
283
|
+
width: "32px",
|
|
284
|
+
height: "32px",
|
|
285
|
+
borderRadius: "50%",
|
|
286
|
+
display: "flex",
|
|
287
|
+
alignItems: "center",
|
|
288
|
+
justifyContent: "center",
|
|
289
|
+
fontSize: "0.875rem",
|
|
290
|
+
flexShrink: 0
|
|
291
|
+
},
|
|
292
|
+
avatarAssistant: {
|
|
293
|
+
background: "linear-gradient(135deg, #3b82f6, #8b5cf6)",
|
|
294
|
+
color: "white"
|
|
295
|
+
},
|
|
296
|
+
avatarUser: {
|
|
297
|
+
background: "#e5e7eb",
|
|
298
|
+
color: "#374151"
|
|
299
|
+
},
|
|
300
|
+
bubble: {
|
|
301
|
+
padding: "0.75rem 1rem",
|
|
302
|
+
borderRadius: "1rem",
|
|
303
|
+
fontSize: "0.9375rem",
|
|
304
|
+
lineHeight: "1.5"
|
|
305
|
+
},
|
|
306
|
+
bubbleAssistant: {
|
|
307
|
+
background: "#f3f4f6",
|
|
308
|
+
color: "#111827",
|
|
309
|
+
borderTopLeftRadius: "4px"
|
|
310
|
+
},
|
|
311
|
+
bubbleUser: {
|
|
312
|
+
background: "#3b82f6",
|
|
313
|
+
color: "white",
|
|
314
|
+
borderTopRightRadius: "4px"
|
|
315
|
+
},
|
|
316
|
+
actions: {
|
|
317
|
+
display: "flex",
|
|
318
|
+
flexWrap: "wrap",
|
|
319
|
+
gap: "0.5rem",
|
|
320
|
+
marginTop: "0.75rem"
|
|
321
|
+
},
|
|
322
|
+
actionButton: {
|
|
323
|
+
padding: "0.5rem 1rem",
|
|
324
|
+
borderRadius: "0.5rem",
|
|
325
|
+
fontSize: "0.875rem",
|
|
326
|
+
fontWeight: "500",
|
|
327
|
+
cursor: "pointer",
|
|
328
|
+
border: "none",
|
|
329
|
+
transition: "all 0.15s"
|
|
330
|
+
},
|
|
331
|
+
actionPrimary: {
|
|
332
|
+
background: "#3b82f6",
|
|
333
|
+
color: "white"
|
|
334
|
+
},
|
|
335
|
+
actionSecondary: {
|
|
336
|
+
background: "#e5e7eb",
|
|
337
|
+
color: "#374151"
|
|
338
|
+
},
|
|
339
|
+
actionOutline: {
|
|
340
|
+
background: "transparent",
|
|
341
|
+
color: "#3b82f6",
|
|
342
|
+
border: "1px solid #3b82f6"
|
|
343
|
+
},
|
|
344
|
+
inputContainer: {
|
|
345
|
+
display: "flex",
|
|
346
|
+
gap: "0.5rem",
|
|
347
|
+
padding: "1rem 0",
|
|
348
|
+
borderTop: "1px solid #e5e7eb"
|
|
349
|
+
},
|
|
350
|
+
input: {
|
|
351
|
+
flex: 1,
|
|
352
|
+
padding: "0.75rem 1rem",
|
|
353
|
+
borderRadius: "0.75rem",
|
|
354
|
+
border: "1px solid #d1d5db",
|
|
355
|
+
fontSize: "0.9375rem",
|
|
356
|
+
outline: "none"
|
|
357
|
+
},
|
|
358
|
+
sendButton: {
|
|
359
|
+
padding: "0.75rem 1.5rem",
|
|
360
|
+
borderRadius: "0.75rem",
|
|
361
|
+
background: "#3b82f6",
|
|
362
|
+
color: "white",
|
|
363
|
+
border: "none",
|
|
364
|
+
fontWeight: "500",
|
|
365
|
+
cursor: "pointer"
|
|
366
|
+
},
|
|
367
|
+
typing: {
|
|
368
|
+
display: "flex",
|
|
369
|
+
gap: "4px",
|
|
370
|
+
padding: "0.75rem 1rem",
|
|
371
|
+
background: "#f3f4f6",
|
|
372
|
+
borderRadius: "1rem",
|
|
373
|
+
width: "fit-content"
|
|
374
|
+
},
|
|
375
|
+
typingDot: {
|
|
376
|
+
width: "8px",
|
|
377
|
+
height: "8px",
|
|
378
|
+
borderRadius: "50%",
|
|
379
|
+
background: "#9ca3af",
|
|
380
|
+
animation: "typing 1.4s infinite"
|
|
381
|
+
},
|
|
382
|
+
moduleCard: {
|
|
383
|
+
display: "flex",
|
|
384
|
+
alignItems: "center",
|
|
385
|
+
gap: "0.75rem",
|
|
386
|
+
padding: "0.75rem",
|
|
387
|
+
background: "white",
|
|
388
|
+
border: "1px solid #e5e7eb",
|
|
389
|
+
borderRadius: "0.5rem",
|
|
390
|
+
cursor: "pointer",
|
|
391
|
+
transition: "all 0.15s"
|
|
392
|
+
},
|
|
393
|
+
moduleCardSelected: {
|
|
394
|
+
borderColor: "#3b82f6",
|
|
395
|
+
background: "#eff6ff"
|
|
396
|
+
},
|
|
397
|
+
moduleIcon: {
|
|
398
|
+
fontSize: "1.5rem"
|
|
399
|
+
},
|
|
400
|
+
moduleInfo: {
|
|
401
|
+
flex: 1
|
|
402
|
+
},
|
|
403
|
+
moduleName: {
|
|
404
|
+
fontWeight: "500",
|
|
405
|
+
color: "#111827"
|
|
406
|
+
},
|
|
407
|
+
moduleDesc: {
|
|
408
|
+
fontSize: "0.75rem",
|
|
409
|
+
color: "#6b7280"
|
|
410
|
+
},
|
|
411
|
+
checkbox: {
|
|
412
|
+
width: "20px",
|
|
413
|
+
height: "20px",
|
|
414
|
+
accentColor: "#3b82f6"
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
var MODULES = [
|
|
418
|
+
{ id: "analytics", name: "Analytics", icon: "\u{1F4CA}", description: "Page views, events, sessions, web vitals", recommended: true },
|
|
419
|
+
{ id: "seo", name: "SEO", icon: "\u{1F50D}", description: "Managed FAQs, meta tags, schema markup", recommended: true },
|
|
420
|
+
{ id: "forms", name: "Forms", icon: "\u{1F4DD}", description: "Portal-managed forms with submissions", recommended: true },
|
|
421
|
+
{ id: "engage", name: "Engage", icon: "\u{1F4AC}", description: "Live chat, popups, nudges, banners", recommended: false },
|
|
422
|
+
{ id: "commerce", name: "Commerce", icon: "\u{1F6D2}", description: "Products, services, checkout", recommended: false },
|
|
423
|
+
{ id: "signal", name: "Signal AI", icon: "\u{1F916}", description: "Autonomous optimization & A/B testing", recommended: false }
|
|
424
|
+
];
|
|
425
|
+
function SetupAssistant({
|
|
426
|
+
apiUrl = "https://api.uptrademedia.com",
|
|
427
|
+
signalUrl = "https://signal.uptrademedia.com",
|
|
428
|
+
supabaseUrl,
|
|
429
|
+
supabaseKey,
|
|
430
|
+
projectId,
|
|
431
|
+
orgId,
|
|
432
|
+
authToken,
|
|
433
|
+
onComplete,
|
|
434
|
+
welcomeMessage
|
|
435
|
+
}) {
|
|
436
|
+
const [messages, setMessages] = React.useState([]);
|
|
437
|
+
const [input, setInput] = React.useState("");
|
|
438
|
+
const [isTyping, setIsTyping] = React.useState(false);
|
|
439
|
+
const [isExtracting, setIsExtracting] = React.useState(false);
|
|
440
|
+
const [state, setState] = React.useState({
|
|
441
|
+
step: "welcome",
|
|
442
|
+
isAuthenticated: !!authToken,
|
|
443
|
+
selectedModules: ["analytics", "seo", "forms"],
|
|
444
|
+
config: {},
|
|
445
|
+
errors: [],
|
|
446
|
+
context: {
|
|
447
|
+
flow: null,
|
|
448
|
+
step: "welcome",
|
|
449
|
+
project_id: projectId,
|
|
450
|
+
org_id: orgId
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
const messagesEndRef = React.useRef(null);
|
|
454
|
+
const inputRef = React.useRef(null);
|
|
455
|
+
const streamingMessageRef = React.useRef(null);
|
|
456
|
+
const sendToSignalStreaming = React.useCallback(async (message, context, onToken, onComplete2) => {
|
|
457
|
+
try {
|
|
458
|
+
const response = await fetch(`${signalUrl}/api/skills/setup/chat/stream`, {
|
|
459
|
+
method: "POST",
|
|
460
|
+
headers: {
|
|
461
|
+
"Content-Type": "application/json",
|
|
462
|
+
...authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
463
|
+
},
|
|
464
|
+
body: JSON.stringify({
|
|
465
|
+
message,
|
|
466
|
+
context,
|
|
467
|
+
project_id: projectId,
|
|
468
|
+
org_id: orgId
|
|
469
|
+
})
|
|
470
|
+
});
|
|
471
|
+
if (!response.ok) {
|
|
472
|
+
throw new Error("Signal API error");
|
|
473
|
+
}
|
|
474
|
+
const reader = response.body?.getReader();
|
|
475
|
+
if (!reader) throw new Error("No response body");
|
|
476
|
+
const decoder = new TextDecoder();
|
|
477
|
+
let buffer = "";
|
|
478
|
+
let actions = [];
|
|
479
|
+
let updatedContext = {};
|
|
480
|
+
while (true) {
|
|
481
|
+
const { done, value } = await reader.read();
|
|
482
|
+
if (done) break;
|
|
483
|
+
buffer += decoder.decode(value, { stream: true });
|
|
484
|
+
const lines = buffer.split("\n");
|
|
485
|
+
buffer = lines.pop() || "";
|
|
486
|
+
for (const line of lines) {
|
|
487
|
+
if (line.startsWith("data: ")) {
|
|
488
|
+
const data = line.slice(6);
|
|
489
|
+
if (data === "[DONE]") continue;
|
|
490
|
+
try {
|
|
491
|
+
const event = JSON.parse(data);
|
|
492
|
+
if (event.type === "token") {
|
|
493
|
+
onToken(event.content);
|
|
494
|
+
} else if (event.type === "actions") {
|
|
495
|
+
actions = event.actions;
|
|
496
|
+
} else if (event.type === "context") {
|
|
497
|
+
updatedContext = event.context;
|
|
498
|
+
}
|
|
499
|
+
} catch {
|
|
500
|
+
onToken(data);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
onComplete2({ actions, updated_context: updatedContext });
|
|
506
|
+
} catch (error) {
|
|
507
|
+
console.error("Signal streaming error:", error);
|
|
508
|
+
const result = await sendToSignal(message, context);
|
|
509
|
+
onToken(result.response);
|
|
510
|
+
onComplete2({ actions: result.actions, updated_context: result.updated_context });
|
|
511
|
+
}
|
|
512
|
+
}, [signalUrl, authToken, projectId, orgId]);
|
|
513
|
+
const sendToSignal = React.useCallback(async (message, context) => {
|
|
514
|
+
try {
|
|
515
|
+
const response = await fetch(`${signalUrl}/api/skills/setup/chat`, {
|
|
516
|
+
method: "POST",
|
|
517
|
+
headers: {
|
|
518
|
+
"Content-Type": "application/json",
|
|
519
|
+
...authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
520
|
+
},
|
|
521
|
+
body: JSON.stringify({
|
|
522
|
+
message,
|
|
523
|
+
context,
|
|
524
|
+
project_id: projectId,
|
|
525
|
+
org_id: orgId
|
|
526
|
+
})
|
|
527
|
+
});
|
|
528
|
+
if (!response.ok) {
|
|
529
|
+
throw new Error("Signal API error");
|
|
530
|
+
}
|
|
531
|
+
return await response.json();
|
|
532
|
+
} catch (error) {
|
|
533
|
+
console.error("Signal API error:", error);
|
|
534
|
+
return {
|
|
535
|
+
response: "I had trouble connecting to Signal. Let me help you locally.",
|
|
536
|
+
actions: [
|
|
537
|
+
{ id: "1", label: "Continue", action: "continue_local", variant: "primary" }
|
|
538
|
+
]
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
}, [signalUrl, authToken, projectId, orgId]);
|
|
542
|
+
const extractBrandFromDomain = React.useCallback(async (domain) => {
|
|
543
|
+
setIsExtracting(true);
|
|
544
|
+
try {
|
|
545
|
+
const response = await fetch(`${apiUrl}/site-scrape/brand-only`, {
|
|
546
|
+
method: "POST",
|
|
547
|
+
headers: {
|
|
548
|
+
"Content-Type": "application/json",
|
|
549
|
+
...authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
550
|
+
},
|
|
551
|
+
body: JSON.stringify({ domain })
|
|
552
|
+
});
|
|
553
|
+
if (!response.ok) {
|
|
554
|
+
throw new Error("Brand extraction failed");
|
|
555
|
+
}
|
|
556
|
+
const data = await response.json();
|
|
557
|
+
return {
|
|
558
|
+
business_name: data.business_name,
|
|
559
|
+
tagline: data.tagline,
|
|
560
|
+
primary_color: data.primary_color,
|
|
561
|
+
secondary_color: data.secondary_color,
|
|
562
|
+
logo_url: data.logo_url,
|
|
563
|
+
phone_numbers: data.phone_numbers,
|
|
564
|
+
email_addresses: data.email_addresses,
|
|
565
|
+
social_profiles: data.social_profiles
|
|
566
|
+
};
|
|
567
|
+
} catch (error) {
|
|
568
|
+
console.error("Brand extraction error:", error);
|
|
569
|
+
return null;
|
|
570
|
+
} finally {
|
|
571
|
+
setIsExtracting(false);
|
|
572
|
+
}
|
|
573
|
+
}, [apiUrl, authToken]);
|
|
574
|
+
const addMessage = React.useCallback((message) => {
|
|
575
|
+
const newMessage = {
|
|
576
|
+
...message,
|
|
577
|
+
id: crypto.randomUUID(),
|
|
578
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
579
|
+
};
|
|
580
|
+
setMessages((prev) => [...prev, newMessage]);
|
|
581
|
+
return newMessage;
|
|
582
|
+
}, []);
|
|
583
|
+
React.useCallback((id, update) => {
|
|
584
|
+
setMessages((prev) => prev.map(
|
|
585
|
+
(m) => m.id === id ? { ...m, ...update } : m
|
|
586
|
+
));
|
|
587
|
+
}, []);
|
|
588
|
+
const addStreamingMessage = React.useCallback(() => {
|
|
589
|
+
const id = crypto.randomUUID();
|
|
590
|
+
const newMessage = {
|
|
591
|
+
id,
|
|
592
|
+
role: "assistant",
|
|
593
|
+
content: "",
|
|
594
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
595
|
+
isStreaming: true
|
|
596
|
+
};
|
|
597
|
+
setMessages((prev) => [...prev, newMessage]);
|
|
598
|
+
streamingMessageRef.current = id;
|
|
599
|
+
return id;
|
|
600
|
+
}, []);
|
|
601
|
+
const appendToStreamingMessage = React.useCallback((token) => {
|
|
602
|
+
const id = streamingMessageRef.current;
|
|
603
|
+
if (!id) return;
|
|
604
|
+
setMessages((prev) => prev.map(
|
|
605
|
+
(m) => m.id === id ? { ...m, content: m.content + token } : m
|
|
606
|
+
));
|
|
607
|
+
}, []);
|
|
608
|
+
const finalizeStreamingMessage = React.useCallback((actions) => {
|
|
609
|
+
const id = streamingMessageRef.current;
|
|
610
|
+
if (!id) return;
|
|
611
|
+
setMessages((prev) => prev.map(
|
|
612
|
+
(m) => m.id === id ? { ...m, isStreaming: false, actions } : m
|
|
613
|
+
));
|
|
614
|
+
streamingMessageRef.current = null;
|
|
615
|
+
}, []);
|
|
616
|
+
const addAssistantMessage = React.useCallback((content, actions, component) => {
|
|
617
|
+
setIsTyping(true);
|
|
618
|
+
setTimeout(() => {
|
|
619
|
+
setIsTyping(false);
|
|
620
|
+
addMessage({ role: "assistant", content, actions, component });
|
|
621
|
+
}, 500 + Math.random() * 500);
|
|
622
|
+
}, [addMessage]);
|
|
623
|
+
const scrollToBottom = React.useCallback(() => {
|
|
624
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
625
|
+
}, []);
|
|
626
|
+
React.useEffect(() => {
|
|
627
|
+
scrollToBottom();
|
|
628
|
+
}, [messages, isTyping, scrollToBottom]);
|
|
629
|
+
React.useEffect(() => {
|
|
630
|
+
const welcome = welcomeMessage || `Hey! \u{1F44B} I'm Signal, your AI setup assistant.
|
|
631
|
+
|
|
632
|
+
I'll help you integrate Uptrade Site-Kit into your project. What are we working with today?`;
|
|
633
|
+
setTimeout(() => {
|
|
634
|
+
addAssistantMessage(welcome, [
|
|
635
|
+
{ id: "1", label: "\u{1F195} New Site", action: "set_flow_new", variant: "primary" },
|
|
636
|
+
{ id: "2", label: "\u{1F4C1} Existing Project", action: "set_flow_existing", variant: "secondary" },
|
|
637
|
+
{ id: "3", label: "\u{1F504} Rebuild from Live Site", action: "set_flow_rebuild", variant: "outline" }
|
|
638
|
+
]);
|
|
639
|
+
}, 500);
|
|
640
|
+
}, []);
|
|
641
|
+
const handleAction = React.useCallback(async (action, data) => {
|
|
642
|
+
switch (action) {
|
|
643
|
+
case "start":
|
|
644
|
+
addMessage({ role: "user", content: "Let's do it!" });
|
|
645
|
+
setState((prev) => ({ ...prev, step: "auth" }));
|
|
646
|
+
addAssistantMessage(
|
|
647
|
+
`Great! First, let's connect to your Uptrade Portal account.
|
|
648
|
+
|
|
649
|
+
You can sign in with your existing Portal credentials:`,
|
|
650
|
+
[
|
|
651
|
+
{ id: "1", label: "Sign in with Email", action: "auth_email", variant: "primary" },
|
|
652
|
+
{ id: "2", label: "Sign in with Google", action: "auth_google", variant: "secondary" },
|
|
653
|
+
{ id: "3", label: "I don't have an account", action: "auth_signup", variant: "outline" }
|
|
654
|
+
]
|
|
655
|
+
);
|
|
656
|
+
break;
|
|
657
|
+
case "explain":
|
|
658
|
+
addMessage({ role: "user", content: "Tell me more first" });
|
|
659
|
+
addAssistantMessage(
|
|
660
|
+
`Uptrade Site-Kit is a lightweight package that connects your site to the Uptrade Portal.
|
|
661
|
+
|
|
662
|
+
Here's what you can enable:
|
|
663
|
+
|
|
664
|
+
\u{1F4CA} **Analytics** - Track page views, events, and Core Web Vitals
|
|
665
|
+
\u{1F50D} **SEO** - Managed meta tags, FAQs, and schema markup
|
|
666
|
+
\u{1F4DD} **Forms** - Portal-managed forms with spam protection
|
|
667
|
+
\u{1F4AC} **Engage** - Live chat, popups, and nudges
|
|
668
|
+
\u{1F6D2} **Commerce** - Products, services, and checkout
|
|
669
|
+
\u{1F916} **Signal AI** - Autonomous optimization and A/B testing
|
|
670
|
+
|
|
671
|
+
You only pay for what you use, and everything is managed from your Portal dashboard.`,
|
|
672
|
+
[
|
|
673
|
+
{ id: "1", label: "Sounds good, let's set it up", action: "start", variant: "primary" }
|
|
674
|
+
]
|
|
675
|
+
);
|
|
676
|
+
break;
|
|
677
|
+
case "auth_email":
|
|
678
|
+
addMessage({ role: "user", content: "Sign in with Email" });
|
|
679
|
+
addAssistantMessage(
|
|
680
|
+
`What's your Portal email address?`
|
|
681
|
+
);
|
|
682
|
+
setState((prev) => ({ ...prev, step: "auth" }));
|
|
683
|
+
setTimeout(() => inputRef.current?.focus(), 600);
|
|
684
|
+
break;
|
|
685
|
+
case "auth_google":
|
|
686
|
+
addMessage({ role: "user", content: "Sign in with Google" });
|
|
687
|
+
addAssistantMessage(
|
|
688
|
+
`Opening Google sign-in... (In a real implementation, this would trigger OAuth)`
|
|
689
|
+
);
|
|
690
|
+
setTimeout(() => {
|
|
691
|
+
setState((prev) => ({
|
|
692
|
+
...prev,
|
|
693
|
+
step: "project",
|
|
694
|
+
isAuthenticated: true,
|
|
695
|
+
userEmail: "user@example.com"
|
|
696
|
+
}));
|
|
697
|
+
handleAuthSuccess("user@example.com");
|
|
698
|
+
}, 1500);
|
|
699
|
+
break;
|
|
700
|
+
case "select_project":
|
|
701
|
+
addMessage({ role: "user", content: `Selected: ${data?.name}` });
|
|
702
|
+
setState((prev) => ({
|
|
703
|
+
...prev,
|
|
704
|
+
step: "modules",
|
|
705
|
+
selectedProject: data
|
|
706
|
+
}));
|
|
707
|
+
showModuleSelection();
|
|
708
|
+
break;
|
|
709
|
+
case "confirm_modules":
|
|
710
|
+
addMessage({ role: "user", content: `Selected ${state.selectedModules.length} modules` });
|
|
711
|
+
setState((prev) => ({ ...prev, step: "config" }));
|
|
712
|
+
showConfigGeneration();
|
|
713
|
+
break;
|
|
714
|
+
case "copy_code":
|
|
715
|
+
addMessage({ role: "user", content: "Copy integration code" });
|
|
716
|
+
addAssistantMessage(
|
|
717
|
+
`\u2705 Code copied to clipboard!
|
|
718
|
+
|
|
719
|
+
Paste this in your root layout file (e.g., \`app/layout.tsx\` or \`pages/_app.tsx\`).
|
|
720
|
+
|
|
721
|
+
Want me to help you verify the integration?`,
|
|
722
|
+
[
|
|
723
|
+
{ id: "1", label: "Yes, verify my setup", action: "verify", variant: "primary" },
|
|
724
|
+
{ id: "2", label: "I'm all set, thanks!", action: "complete", variant: "outline" }
|
|
725
|
+
]
|
|
726
|
+
);
|
|
727
|
+
break;
|
|
728
|
+
case "verify":
|
|
729
|
+
addMessage({ role: "user", content: "Verify my setup" });
|
|
730
|
+
setState((prev) => ({ ...prev, step: "verify" }));
|
|
731
|
+
addAssistantMessage(
|
|
732
|
+
`To verify your setup, start your dev server and visit any page.
|
|
733
|
+
|
|
734
|
+
I'll check for:
|
|
735
|
+
\u2022 \u2713 SiteKitProvider is loading
|
|
736
|
+
\u2022 \u2713 API key is valid
|
|
737
|
+
\u2022 \u2713 Analytics events are sending
|
|
738
|
+
\u2022 \u2713 Modules are initializing
|
|
739
|
+
|
|
740
|
+
Run \`npm run dev\` and let me know when you're ready:`,
|
|
741
|
+
[
|
|
742
|
+
{ id: "1", label: "My dev server is running", action: "check_connection", variant: "primary" }
|
|
743
|
+
]
|
|
744
|
+
);
|
|
745
|
+
break;
|
|
746
|
+
case "check_connection":
|
|
747
|
+
addMessage({ role: "user", content: "My dev server is running" });
|
|
748
|
+
setIsTyping(true);
|
|
749
|
+
setTimeout(() => {
|
|
750
|
+
setIsTyping(false);
|
|
751
|
+
addAssistantMessage(
|
|
752
|
+
`\u{1F389} **Everything looks great!**
|
|
753
|
+
|
|
754
|
+
I detected your site at \`localhost:3000\` and verified:
|
|
755
|
+
|
|
756
|
+
\u2705 SiteKitProvider initialized
|
|
757
|
+
\u2705 API key authenticated
|
|
758
|
+
\u2705 Analytics tracking active
|
|
759
|
+
\u2705 SEO components ready
|
|
760
|
+
|
|
761
|
+
You're all set! Your data will start appearing in your Portal dashboard within a few minutes.`,
|
|
762
|
+
[
|
|
763
|
+
{ id: "1", label: "Open Portal Dashboard", action: "open_dashboard", variant: "primary" },
|
|
764
|
+
{ id: "2", label: "Enable Signal AI", action: "enable_signal", variant: "secondary" }
|
|
765
|
+
]
|
|
766
|
+
);
|
|
767
|
+
setState((prev) => ({ ...prev, step: "complete" }));
|
|
768
|
+
}, 2e3);
|
|
769
|
+
break;
|
|
770
|
+
case "complete":
|
|
771
|
+
addMessage({ role: "user", content: "I'm all set, thanks!" });
|
|
772
|
+
addAssistantMessage(
|
|
773
|
+
`Awesome! \u{1F680}
|
|
774
|
+
|
|
775
|
+
Your site-kit integration is ready. Here's what happens next:
|
|
776
|
+
|
|
777
|
+
\u2022 Analytics data will appear in Portal within ~5 minutes
|
|
778
|
+
\u2022 You can manage SEO, forms, and engage from the dashboard
|
|
779
|
+
\u2022 If you enabled Signal, it'll start learning from your traffic
|
|
780
|
+
|
|
781
|
+
Need help anytime? Just come back to \`/_uptrade/setup\` or ping us in Portal.
|
|
782
|
+
|
|
783
|
+
Happy building! \u{1F3A8}`
|
|
784
|
+
);
|
|
785
|
+
onComplete?.(state);
|
|
786
|
+
break;
|
|
787
|
+
case "enable_signal":
|
|
788
|
+
addMessage({ role: "user", content: "Enable Signal AI" });
|
|
789
|
+
addAssistantMessage(
|
|
790
|
+
`Great choice! \u{1F916}
|
|
791
|
+
|
|
792
|
+
Signal AI will:
|
|
793
|
+
\u2022 Monitor your site for SEO issues
|
|
794
|
+
\u2022 Run A/B tests on CTAs and content
|
|
795
|
+
\u2022 Optimize popups and engagement timing
|
|
796
|
+
\u2022 Learn from user behavior to improve conversions
|
|
797
|
+
|
|
798
|
+
To enable Signal, add \`signal={{ enabled: true }}\` to your SiteKitProvider:
|
|
799
|
+
|
|
800
|
+
\`\`\`tsx
|
|
801
|
+
<SiteKitProvider
|
|
802
|
+
apiKey={process.env.NEXT_PUBLIC_UPTRADE_API_KEY!}
|
|
803
|
+
analytics={{ enabled: true }}
|
|
804
|
+
signal={{ enabled: true }} // Add this
|
|
805
|
+
>
|
|
806
|
+
\`\`\`
|
|
807
|
+
|
|
808
|
+
Signal requires the Business plan. Want me to check your plan?`,
|
|
809
|
+
[
|
|
810
|
+
{ id: "1", label: "Check my plan", action: "check_plan", variant: "primary" },
|
|
811
|
+
{ id: "2", label: "I'll do this later", action: "complete", variant: "outline" }
|
|
812
|
+
]
|
|
813
|
+
);
|
|
814
|
+
break;
|
|
815
|
+
case "confirm_brand":
|
|
816
|
+
addMessage({ role: "user", content: "Brand info confirmed" });
|
|
817
|
+
setState((prev) => ({ ...prev, step: "modules" }));
|
|
818
|
+
showModuleSelectionWithRecommendations();
|
|
819
|
+
break;
|
|
820
|
+
case "edit_brand":
|
|
821
|
+
addMessage({ role: "user", content: "Edit brand info" });
|
|
822
|
+
addAssistantMessage(
|
|
823
|
+
`No problem! Let me know what to change:
|
|
824
|
+
|
|
825
|
+
\u2022 Business name
|
|
826
|
+
\u2022 Primary color (hex like #3b82f6)
|
|
827
|
+
\u2022 Tagline
|
|
828
|
+
|
|
829
|
+
Just type what you'd like to update.`
|
|
830
|
+
);
|
|
831
|
+
break;
|
|
832
|
+
case "manual_brand":
|
|
833
|
+
addMessage({ role: "user", content: "Enter brand manually" });
|
|
834
|
+
addAssistantMessage(
|
|
835
|
+
`Sure! What's your business name?`
|
|
836
|
+
);
|
|
837
|
+
setState((prev) => ({
|
|
838
|
+
...prev,
|
|
839
|
+
context: { ...prev.context, step: "brand_manual" }
|
|
840
|
+
}));
|
|
841
|
+
break;
|
|
842
|
+
case "skip_brand":
|
|
843
|
+
addMessage({ role: "user", content: "Skip brand for now" });
|
|
844
|
+
setState((prev) => ({ ...prev, step: "modules" }));
|
|
845
|
+
showModuleSelection();
|
|
846
|
+
break;
|
|
847
|
+
case "extract_brand":
|
|
848
|
+
addMessage({ role: "user", content: "Extract from website" });
|
|
849
|
+
addAssistantMessage(
|
|
850
|
+
`What's the website URL? I'll extract the brand colors, name, and logo.`
|
|
851
|
+
);
|
|
852
|
+
break;
|
|
853
|
+
case "set_flow_new":
|
|
854
|
+
addMessage({ role: "user", content: "New Site" });
|
|
855
|
+
setState((prev) => ({
|
|
856
|
+
...prev,
|
|
857
|
+
context: { ...prev.context, flow: "new", step: "brand" }
|
|
858
|
+
}));
|
|
859
|
+
addAssistantMessage(
|
|
860
|
+
`Great! For a new site, I'll help you:
|
|
861
|
+
|
|
862
|
+
1. Set up your brand (colors, name)
|
|
863
|
+
2. Choose which modules to enable
|
|
864
|
+
3. Generate integration code
|
|
865
|
+
|
|
866
|
+
Do you have an existing website I can extract brand info from? Or would you prefer to enter it manually?`,
|
|
867
|
+
[
|
|
868
|
+
{ id: "1", label: "Extract from website", action: "extract_brand", variant: "primary" },
|
|
869
|
+
{ id: "2", label: "Enter manually", action: "manual_brand", variant: "outline" },
|
|
870
|
+
{ id: "3", label: "Skip for now", action: "skip_brand", variant: "outline" }
|
|
871
|
+
]
|
|
872
|
+
);
|
|
873
|
+
break;
|
|
874
|
+
case "set_flow_existing":
|
|
875
|
+
addMessage({ role: "user", content: "Existing Project" });
|
|
876
|
+
setState((prev) => ({
|
|
877
|
+
...prev,
|
|
878
|
+
context: { ...prev.context, flow: "existing", step: "scan" }
|
|
879
|
+
}));
|
|
880
|
+
addAssistantMessage(
|
|
881
|
+
`For an existing project, I can scan your codebase to find:
|
|
882
|
+
|
|
883
|
+
\u2022 Forms to migrate (contact forms, newsletter signups)
|
|
884
|
+
\u2022 Chat widgets to replace (Intercom, Crisp, etc.)
|
|
885
|
+
\u2022 Metadata patterns to enhance
|
|
886
|
+
\u2022 Sitemap configuration
|
|
887
|
+
|
|
888
|
+
Run this in your project root:
|
|
889
|
+
|
|
890
|
+
\`\`\`bash
|
|
891
|
+
npx @uptrade/site-kit scan
|
|
892
|
+
\`\`\`
|
|
893
|
+
|
|
894
|
+
Then paste the output here, or tell me about your project.`,
|
|
895
|
+
[
|
|
896
|
+
{ id: "1", label: "I ran the scan", action: "show_scan_results", variant: "primary" },
|
|
897
|
+
{ id: "2", label: "Skip scan", action: "skip_scan", variant: "outline" }
|
|
898
|
+
]
|
|
899
|
+
);
|
|
900
|
+
break;
|
|
901
|
+
case "set_flow_rebuild":
|
|
902
|
+
addMessage({ role: "user", content: "Rebuild from Live Site" });
|
|
903
|
+
setState((prev) => ({
|
|
904
|
+
...prev,
|
|
905
|
+
context: { ...prev.context, flow: "rebuild", step: "scrape" }
|
|
906
|
+
}));
|
|
907
|
+
addAssistantMessage(
|
|
908
|
+
`I'll help you rebuild with site-kit. Enter the live site URL and I'll:
|
|
909
|
+
|
|
910
|
+
\u2022 Extract brand colors and business info
|
|
911
|
+
\u2022 Import FAQs with schema markup
|
|
912
|
+
\u2022 Suggest redirect mappings
|
|
913
|
+
\u2022 Generate copilot-instructions.md
|
|
914
|
+
|
|
915
|
+
What's the website URL?`
|
|
916
|
+
);
|
|
917
|
+
break;
|
|
918
|
+
case "show_scan_results":
|
|
919
|
+
addMessage({ role: "user", content: "I ran the scan" });
|
|
920
|
+
addAssistantMessage(
|
|
921
|
+
`Great! Paste the scan output here, or describe what you found.
|
|
922
|
+
|
|
923
|
+
I'll analyze the results and recommend a migration plan.`
|
|
924
|
+
);
|
|
925
|
+
break;
|
|
926
|
+
case "skip_scan":
|
|
927
|
+
addMessage({ role: "user", content: "Skip scan" });
|
|
928
|
+
setState((prev) => ({ ...prev, step: "modules" }));
|
|
929
|
+
showModuleSelection();
|
|
930
|
+
break;
|
|
931
|
+
case "generate_redirects":
|
|
932
|
+
addMessage({ role: "user", content: "Generate redirects" });
|
|
933
|
+
if (state.context.scrape_results?.routes) {
|
|
934
|
+
addStreamingMessage();
|
|
935
|
+
await sendToSignalStreaming(
|
|
936
|
+
`Generate SEO-optimized redirects for these routes: ${JSON.stringify(state.context.scrape_results.routes)}`,
|
|
937
|
+
state.context,
|
|
938
|
+
(token) => appendToStreamingMessage(token),
|
|
939
|
+
(result) => finalizeStreamingMessage(result.actions)
|
|
940
|
+
);
|
|
941
|
+
} else {
|
|
942
|
+
addAssistantMessage(
|
|
943
|
+
`I need a list of routes to generate redirects. Would you like to:
|
|
944
|
+
|
|
945
|
+
1. Scrape a website for routes
|
|
946
|
+
2. Paste a list of URLs
|
|
947
|
+
|
|
948
|
+
What's easier?`,
|
|
949
|
+
[
|
|
950
|
+
{ id: "1", label: "Scrape website", action: "set_flow_rebuild", variant: "primary" },
|
|
951
|
+
{ id: "2", label: "Paste URLs", action: "paste_urls", variant: "outline" }
|
|
952
|
+
]
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
break;
|
|
956
|
+
case "generate_copilot_instructions":
|
|
957
|
+
addMessage({ role: "user", content: "Generate Copilot instructions" });
|
|
958
|
+
addStreamingMessage();
|
|
959
|
+
await sendToSignalStreaming(
|
|
960
|
+
`Generate copilot-instructions.md for project with modules: ${state.selectedModules.join(", ")} and brand: ${state.context.brand?.business_name || "Unknown"}`,
|
|
961
|
+
state.context,
|
|
962
|
+
(token) => appendToStreamingMessage(token),
|
|
963
|
+
(result) => {
|
|
964
|
+
finalizeStreamingMessage([
|
|
965
|
+
{ id: "1", label: "\u{1F4CB} Copy to clipboard", action: "copy_copilot_instructions", variant: "primary" },
|
|
966
|
+
{ id: "2", label: "Continue", action: "complete", variant: "outline" }
|
|
967
|
+
]);
|
|
968
|
+
}
|
|
969
|
+
);
|
|
970
|
+
break;
|
|
971
|
+
case "verify_now":
|
|
972
|
+
addMessage({ role: "user", content: "Verify integration" });
|
|
973
|
+
verifyIntegration();
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
}, [addMessage, addAssistantMessage, addStreamingMessage, appendToStreamingMessage, finalizeStreamingMessage, sendToSignalStreaming, state, onComplete]);
|
|
977
|
+
const handleAuthSuccess = React.useCallback((email) => {
|
|
978
|
+
addAssistantMessage(
|
|
979
|
+
`Welcome back, ${email.split("@")[0]}! \u{1F44B}
|
|
221
980
|
|
|
981
|
+
I found these projects in your account. Which one are we setting up?`,
|
|
982
|
+
[
|
|
983
|
+
{ id: "1", label: "MyCompany.com", action: "select_project", variant: "secondary", data: { id: "1", name: "MyCompany.com", domain: "mycompany.com" } },
|
|
984
|
+
{ id: "2", label: "Blog Project", action: "select_project", variant: "secondary", data: { id: "2", name: "Blog Project", domain: "blog.mycompany.com" } },
|
|
985
|
+
{ id: "3", label: "+ Create new project", action: "create_project", variant: "outline" }
|
|
986
|
+
]
|
|
987
|
+
);
|
|
988
|
+
}, [addAssistantMessage]);
|
|
989
|
+
const verifyIntegration = React.useCallback(async () => {
|
|
990
|
+
setState((prev) => ({ ...prev, step: "verify" }));
|
|
991
|
+
setIsTyping(true);
|
|
992
|
+
try {
|
|
993
|
+
const response = await fetch(`${signalUrl}/api/skills/setup/verify`, {
|
|
994
|
+
method: "POST",
|
|
995
|
+
headers: {
|
|
996
|
+
"Content-Type": "application/json",
|
|
997
|
+
...authToken ? { Authorization: `Bearer ${authToken}` } : {}
|
|
998
|
+
},
|
|
999
|
+
body: JSON.stringify({
|
|
1000
|
+
project_id: projectId || state.context.project_id,
|
|
1001
|
+
dev_url: "http://localhost:3000"
|
|
1002
|
+
})
|
|
1003
|
+
});
|
|
1004
|
+
setIsTyping(false);
|
|
1005
|
+
if (!response.ok) {
|
|
1006
|
+
throw new Error("Verification failed");
|
|
1007
|
+
}
|
|
1008
|
+
const result = await response.json();
|
|
1009
|
+
if (result.overall_status === "success") {
|
|
1010
|
+
const checkList = result.checks.map(
|
|
1011
|
+
(c) => `${c.passed ? "\u2705" : "\u274C"} ${c.check.replace(/_/g, " ")}`
|
|
1012
|
+
).join("\n");
|
|
1013
|
+
addAssistantMessage(
|
|
1014
|
+
`\u{1F389} **Integration Verified!**
|
|
1015
|
+
|
|
1016
|
+
${checkList}
|
|
1017
|
+
|
|
1018
|
+
Your site-kit integration is working perfectly. Data will start appearing in Portal shortly.`,
|
|
1019
|
+
[
|
|
1020
|
+
{ id: "1", label: "Open Portal Dashboard", action: "open_dashboard", variant: "primary" },
|
|
1021
|
+
{ id: "2", label: "Generate Copilot Instructions", action: "generate_copilot_instructions", variant: "secondary" }
|
|
1022
|
+
]
|
|
1023
|
+
);
|
|
1024
|
+
setState((prev) => ({ ...prev, step: "complete" }));
|
|
1025
|
+
} else {
|
|
1026
|
+
const issues = result.issues?.join("\n\u2022 ") || "Unknown issue";
|
|
1027
|
+
addAssistantMessage(
|
|
1028
|
+
`\u26A0\uFE0F **Verification Found Issues**
|
|
1029
|
+
|
|
1030
|
+
\u2022 ${issues}
|
|
1031
|
+
|
|
1032
|
+
Would you like help troubleshooting?`,
|
|
1033
|
+
[
|
|
1034
|
+
{ id: "1", label: "Help me fix this", action: "troubleshoot", variant: "primary" },
|
|
1035
|
+
{ id: "2", label: "Skip for now", action: "complete", variant: "outline" }
|
|
1036
|
+
]
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
setIsTyping(false);
|
|
1041
|
+
addAssistantMessage(
|
|
1042
|
+
`I couldn't verify the integration automatically. Make sure your dev server is running.
|
|
1043
|
+
|
|
1044
|
+
You can manually verify by:
|
|
1045
|
+
1. Opening your site in the browser
|
|
1046
|
+
2. Checking the Network tab for requests to api.uptrademedia.com
|
|
1047
|
+
3. Looking for analytics events in your Portal dashboard`,
|
|
1048
|
+
[
|
|
1049
|
+
{ id: "1", label: "Try again", action: "verify_now", variant: "primary" },
|
|
1050
|
+
{ id: "2", label: "Continue anyway", action: "complete", variant: "outline" }
|
|
1051
|
+
]
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
}, [signalUrl, authToken, projectId, state.context.project_id, addAssistantMessage]);
|
|
1055
|
+
const showModuleSelectionWithRecommendations = React.useCallback(async () => {
|
|
1056
|
+
const { brand, business_type, scan_results } = state.context;
|
|
1057
|
+
if (brand || business_type) {
|
|
1058
|
+
try {
|
|
1059
|
+
const result = await sendToSignal(
|
|
1060
|
+
`Recommend modules for: ${brand?.business_name || "Unknown"}, type: ${business_type || "general"}`,
|
|
1061
|
+
{ ...state.context, step: "recommend_modules" }
|
|
1062
|
+
);
|
|
1063
|
+
addAssistantMessage(
|
|
1064
|
+
result.response,
|
|
1065
|
+
void 0,
|
|
1066
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1067
|
+
ModuleSelector,
|
|
1068
|
+
{
|
|
1069
|
+
modules: MODULES,
|
|
1070
|
+
selected: state.selectedModules,
|
|
1071
|
+
onChange: (modules) => setState((prev) => ({ ...prev, selectedModules: modules })),
|
|
1072
|
+
onConfirm: () => handleAction("confirm_modules")
|
|
1073
|
+
}
|
|
1074
|
+
)
|
|
1075
|
+
);
|
|
1076
|
+
return;
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
showModuleSelection();
|
|
1081
|
+
}, [state.context, state.selectedModules, sendToSignal, handleAction]);
|
|
1082
|
+
const showModuleSelection = React.useCallback(() => {
|
|
1083
|
+
addAssistantMessage(
|
|
1084
|
+
`Perfect! Now let's choose which features to enable.
|
|
1085
|
+
|
|
1086
|
+
I've pre-selected the essentials, but you can customize:`,
|
|
1087
|
+
void 0,
|
|
1088
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1089
|
+
ModuleSelector,
|
|
1090
|
+
{
|
|
1091
|
+
modules: MODULES,
|
|
1092
|
+
selected: state.selectedModules,
|
|
1093
|
+
onChange: (modules) => setState((prev) => ({ ...prev, selectedModules: modules })),
|
|
1094
|
+
onConfirm: () => handleAction("confirm_modules")
|
|
1095
|
+
}
|
|
1096
|
+
)
|
|
1097
|
+
);
|
|
1098
|
+
}, [addAssistantMessage, state.selectedModules, handleAction]);
|
|
1099
|
+
const showConfigGeneration = React.useCallback(() => {
|
|
1100
|
+
const code = generateIntegrationCode(state);
|
|
1101
|
+
addAssistantMessage(
|
|
1102
|
+
`Here's your integration code! \u{1F389}
|
|
1103
|
+
|
|
1104
|
+
Add this to your root layout:`,
|
|
1105
|
+
[
|
|
1106
|
+
{ id: "1", label: "\u{1F4CB} Copy Code", action: "copy_code", variant: "primary" }
|
|
1107
|
+
],
|
|
1108
|
+
/* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code })
|
|
1109
|
+
);
|
|
1110
|
+
}, [addAssistantMessage, state]);
|
|
1111
|
+
const handleSubmit = React.useCallback(async (e) => {
|
|
1112
|
+
e.preventDefault();
|
|
1113
|
+
if (!input.trim()) return;
|
|
1114
|
+
const userInput = input.trim();
|
|
1115
|
+
setInput("");
|
|
1116
|
+
addMessage({ role: "user", content: userInput });
|
|
1117
|
+
if (state.step === "auth" && userInput.includes("@")) {
|
|
1118
|
+
setState((prev) => ({
|
|
1119
|
+
...prev,
|
|
1120
|
+
isAuthenticated: true,
|
|
1121
|
+
userEmail: userInput,
|
|
1122
|
+
step: "project"
|
|
1123
|
+
}));
|
|
1124
|
+
addAssistantMessage(
|
|
1125
|
+
`Sending magic link to ${userInput}...
|
|
1126
|
+
|
|
1127
|
+
(In production, you'd receive an email. For now, I'll simulate a successful login.)`
|
|
1128
|
+
);
|
|
1129
|
+
setTimeout(() => handleAuthSuccess(userInput), 1500);
|
|
1130
|
+
} else if (userInput.toLowerCase().includes("http") || userInput.match(/^[\w.-]+\.[a-z]{2,}$/i)) {
|
|
1131
|
+
const domain = userInput.replace(/^https?:\/\//, "").split("/")[0];
|
|
1132
|
+
setIsTyping(true);
|
|
1133
|
+
addAssistantMessage(`Analyzing ${domain} to extract brand information...`);
|
|
1134
|
+
const brand = await extractBrandFromDomain(domain);
|
|
1135
|
+
setIsTyping(false);
|
|
1136
|
+
if (brand) {
|
|
1137
|
+
setState((prev) => ({
|
|
1138
|
+
...prev,
|
|
1139
|
+
context: { ...prev.context, brand, domain }
|
|
1140
|
+
}));
|
|
1141
|
+
const brandSummary = [
|
|
1142
|
+
brand.business_name && `**Business:** ${brand.business_name}`,
|
|
1143
|
+
brand.tagline && `**Tagline:** ${brand.tagline}`,
|
|
1144
|
+
brand.primary_color && `**Primary Color:** ${brand.primary_color}`,
|
|
1145
|
+
brand.phone_numbers?.length && `**Phone:** ${brand.phone_numbers[0]}`
|
|
1146
|
+
].filter(Boolean).join("\n");
|
|
1147
|
+
addAssistantMessage(
|
|
1148
|
+
`Found brand information:
|
|
1149
|
+
|
|
1150
|
+
${brandSummary}
|
|
1151
|
+
|
|
1152
|
+
Does this look right?`,
|
|
1153
|
+
[
|
|
1154
|
+
{ id: "1", label: "Yes, looks good!", action: "confirm_brand", variant: "primary" },
|
|
1155
|
+
{ id: "2", label: "Edit brand info", action: "edit_brand", variant: "outline" }
|
|
1156
|
+
]
|
|
1157
|
+
);
|
|
1158
|
+
} else {
|
|
1159
|
+
addAssistantMessage(
|
|
1160
|
+
`I couldn't extract brand info from ${domain}. You can enter it manually, or we can continue without it.`,
|
|
1161
|
+
[
|
|
1162
|
+
{ id: "1", label: "Enter manually", action: "manual_brand", variant: "primary" },
|
|
1163
|
+
{ id: "2", label: "Skip for now", action: "skip_brand", variant: "outline" }
|
|
1164
|
+
]
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
} else {
|
|
1168
|
+
addStreamingMessage();
|
|
1169
|
+
try {
|
|
1170
|
+
await sendToSignalStreaming(
|
|
1171
|
+
userInput,
|
|
1172
|
+
state.context,
|
|
1173
|
+
(token) => appendToStreamingMessage(token),
|
|
1174
|
+
(result) => {
|
|
1175
|
+
if (result.updated_context) {
|
|
1176
|
+
setState((prev) => ({
|
|
1177
|
+
...prev,
|
|
1178
|
+
context: { ...prev.context, ...result.updated_context }
|
|
1179
|
+
}));
|
|
1180
|
+
}
|
|
1181
|
+
finalizeStreamingMessage(result.actions);
|
|
1182
|
+
}
|
|
1183
|
+
);
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
finalizeStreamingMessage();
|
|
1186
|
+
addAssistantMessage(
|
|
1187
|
+
`I understand you said: "${userInput}"
|
|
1188
|
+
|
|
1189
|
+
Let me help you with that. What would you like to do?`,
|
|
1190
|
+
[
|
|
1191
|
+
{ id: "1", label: "Continue setup", action: "start", variant: "primary" },
|
|
1192
|
+
{ id: "2", label: "Ask a question", action: "help", variant: "outline" }
|
|
1193
|
+
]
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}, [input, state.step, state.context, addMessage, addAssistantMessage, handleAuthSuccess, sendToSignalStreaming, appendToStreamingMessage, finalizeStreamingMessage, addStreamingMessage, extractBrandFromDomain]);
|
|
1198
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.container, children: [
|
|
1199
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.header, children: [
|
|
1200
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.logo, children: "U" }),
|
|
1201
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1202
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.title, children: "Uptrade Setup" }),
|
|
1203
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.subtitle, children: "Site-Kit Integration Wizard" })
|
|
1204
|
+
] })
|
|
1205
|
+
] }),
|
|
1206
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.messages, children: [
|
|
1207
|
+
messages.map((message) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1208
|
+
"div",
|
|
1209
|
+
{
|
|
1210
|
+
style: {
|
|
1211
|
+
...styles.message,
|
|
1212
|
+
...message.role === "assistant" ? styles.messageAssistant : styles.messageUser
|
|
1213
|
+
},
|
|
1214
|
+
children: [
|
|
1215
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1216
|
+
"div",
|
|
1217
|
+
{
|
|
1218
|
+
style: {
|
|
1219
|
+
...styles.avatar,
|
|
1220
|
+
...message.role === "assistant" ? styles.avatarAssistant : styles.avatarUser
|
|
1221
|
+
},
|
|
1222
|
+
children: message.role === "assistant" ? "\u2728" : "\u{1F464}"
|
|
1223
|
+
}
|
|
1224
|
+
),
|
|
1225
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1226
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1227
|
+
"div",
|
|
1228
|
+
{
|
|
1229
|
+
style: {
|
|
1230
|
+
...styles.bubble,
|
|
1231
|
+
...message.role === "assistant" ? styles.bubbleAssistant : styles.bubbleUser
|
|
1232
|
+
},
|
|
1233
|
+
children: message.content.split("\n").map((line, i) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
1234
|
+
line,
|
|
1235
|
+
i < message.content.split("\n").length - 1 && /* @__PURE__ */ jsxRuntime.jsx("br", {})
|
|
1236
|
+
] }, i))
|
|
1237
|
+
}
|
|
1238
|
+
),
|
|
1239
|
+
message.component,
|
|
1240
|
+
message.actions && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.actions, children: message.actions.map((action) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1241
|
+
"button",
|
|
1242
|
+
{
|
|
1243
|
+
onClick: () => handleAction(action.action, action.data),
|
|
1244
|
+
style: {
|
|
1245
|
+
...styles.actionButton,
|
|
1246
|
+
...action.variant === "primary" ? styles.actionPrimary : action.variant === "outline" ? styles.actionOutline : styles.actionSecondary
|
|
1247
|
+
},
|
|
1248
|
+
children: action.label
|
|
1249
|
+
},
|
|
1250
|
+
action.id
|
|
1251
|
+
)) })
|
|
1252
|
+
] })
|
|
1253
|
+
]
|
|
1254
|
+
},
|
|
1255
|
+
message.id
|
|
1256
|
+
)),
|
|
1257
|
+
isTyping && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles.message, ...styles.messageAssistant }, children: [
|
|
1258
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles.avatar, ...styles.avatarAssistant }, children: "\u2728" }),
|
|
1259
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.typing, children: [
|
|
1260
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles.typingDot, animationDelay: "0s" } }),
|
|
1261
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles.typingDot, animationDelay: "0.2s" } }),
|
|
1262
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles.typingDot, animationDelay: "0.4s" } })
|
|
1263
|
+
] })
|
|
1264
|
+
] }),
|
|
1265
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
|
|
1266
|
+
] }),
|
|
1267
|
+
/* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: styles.inputContainer, children: [
|
|
1268
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1269
|
+
"input",
|
|
1270
|
+
{
|
|
1271
|
+
ref: inputRef,
|
|
1272
|
+
type: "text",
|
|
1273
|
+
value: input,
|
|
1274
|
+
onChange: (e) => setInput(e.target.value),
|
|
1275
|
+
placeholder: "Type a message...",
|
|
1276
|
+
style: styles.input
|
|
1277
|
+
}
|
|
1278
|
+
),
|
|
1279
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", style: styles.sendButton, children: "Send" })
|
|
1280
|
+
] }),
|
|
1281
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
1282
|
+
@keyframes typing {
|
|
1283
|
+
0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
|
|
1284
|
+
30% { transform: translateY(-4px); opacity: 1; }
|
|
1285
|
+
}
|
|
1286
|
+
` })
|
|
1287
|
+
] });
|
|
1288
|
+
}
|
|
1289
|
+
function ModuleSelector({
|
|
1290
|
+
modules,
|
|
1291
|
+
selected,
|
|
1292
|
+
onChange,
|
|
1293
|
+
onConfirm
|
|
1294
|
+
}) {
|
|
1295
|
+
const toggle = (id) => {
|
|
1296
|
+
onChange(
|
|
1297
|
+
selected.includes(id) ? selected.filter((m) => m !== id) : [...selected, id]
|
|
1298
|
+
);
|
|
1299
|
+
};
|
|
1300
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "0.75rem", display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
1301
|
+
modules.map((module) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1302
|
+
"div",
|
|
1303
|
+
{
|
|
1304
|
+
onClick: () => toggle(module.id),
|
|
1305
|
+
style: {
|
|
1306
|
+
...styles.moduleCard,
|
|
1307
|
+
...selected.includes(module.id) ? styles.moduleCardSelected : {}
|
|
1308
|
+
},
|
|
1309
|
+
children: [
|
|
1310
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.moduleIcon, children: module.icon }),
|
|
1311
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.moduleInfo, children: [
|
|
1312
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.moduleName, children: [
|
|
1313
|
+
module.name,
|
|
1314
|
+
module.recommended && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: "0.5rem", fontSize: "0.625rem", background: "#dbeafe", color: "#1d4ed8", padding: "2px 6px", borderRadius: "4px" }, children: "Recommended" })
|
|
1315
|
+
] }),
|
|
1316
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.moduleDesc, children: module.description })
|
|
1317
|
+
] }),
|
|
1318
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1319
|
+
"input",
|
|
1320
|
+
{
|
|
1321
|
+
type: "checkbox",
|
|
1322
|
+
checked: selected.includes(module.id),
|
|
1323
|
+
onChange: () => toggle(module.id),
|
|
1324
|
+
style: styles.checkbox
|
|
1325
|
+
}
|
|
1326
|
+
)
|
|
1327
|
+
]
|
|
1328
|
+
},
|
|
1329
|
+
module.id
|
|
1330
|
+
)),
|
|
1331
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1332
|
+
"button",
|
|
1333
|
+
{
|
|
1334
|
+
onClick: onConfirm,
|
|
1335
|
+
style: { ...styles.actionButton, ...styles.actionPrimary, marginTop: "0.5rem" },
|
|
1336
|
+
children: [
|
|
1337
|
+
"Continue with ",
|
|
1338
|
+
selected.length,
|
|
1339
|
+
" modules"
|
|
1340
|
+
]
|
|
1341
|
+
}
|
|
1342
|
+
)
|
|
1343
|
+
] });
|
|
1344
|
+
}
|
|
1345
|
+
function CodeBlock({ code }) {
|
|
1346
|
+
return /* @__PURE__ */ jsxRuntime.jsx("pre", { style: {
|
|
1347
|
+
marginTop: "0.75rem",
|
|
1348
|
+
padding: "1rem",
|
|
1349
|
+
background: "#1f2937",
|
|
1350
|
+
color: "#e5e7eb",
|
|
1351
|
+
borderRadius: "0.5rem",
|
|
1352
|
+
fontSize: "0.8125rem",
|
|
1353
|
+
overflowX: "auto",
|
|
1354
|
+
fontFamily: "monospace"
|
|
1355
|
+
}, children: code });
|
|
1356
|
+
}
|
|
1357
|
+
function generateIntegrationCode(state) {
|
|
1358
|
+
const { selectedModules } = state;
|
|
1359
|
+
const moduleConfigs = [];
|
|
1360
|
+
if (selectedModules.includes("analytics")) {
|
|
1361
|
+
moduleConfigs.push(` analytics={{ enabled: true }}`);
|
|
1362
|
+
}
|
|
1363
|
+
if (selectedModules.includes("engage")) {
|
|
1364
|
+
moduleConfigs.push(` engage={{ enabled: true }}`);
|
|
1365
|
+
}
|
|
1366
|
+
if (selectedModules.includes("forms")) {
|
|
1367
|
+
moduleConfigs.push(` forms={{ enabled: true }}`);
|
|
1368
|
+
}
|
|
1369
|
+
if (selectedModules.includes("signal")) {
|
|
1370
|
+
moduleConfigs.push(` signal={{ enabled: true, realtime: true }}`);
|
|
1371
|
+
}
|
|
1372
|
+
return `// app/layout.tsx (or pages/_app.tsx)
|
|
1373
|
+
import { SiteKitProvider } from '@uptrade/site-kit'
|
|
1374
|
+
|
|
1375
|
+
export default function RootLayout({ children }) {
|
|
1376
|
+
return (
|
|
1377
|
+
<html>
|
|
1378
|
+
<body>
|
|
1379
|
+
<SiteKitProvider
|
|
1380
|
+
apiKey={process.env.NEXT_PUBLIC_UPTRADE_API_KEY!}
|
|
1381
|
+
${moduleConfigs.join("\n")}
|
|
1382
|
+
>
|
|
1383
|
+
{children}
|
|
1384
|
+
</SiteKitProvider>
|
|
1385
|
+
</body>
|
|
1386
|
+
</html>
|
|
1387
|
+
)
|
|
1388
|
+
}`;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
Object.defineProperty(exports, "SetupWizard", {
|
|
1392
|
+
enumerable: true,
|
|
1393
|
+
get: function () { return chunk5R4R3WDP_js.SetupWizard; }
|
|
1394
|
+
});
|
|
1395
|
+
Object.defineProperty(exports, "clearRedirectCache", {
|
|
1396
|
+
enumerable: true,
|
|
1397
|
+
get: function () { return chunkBZBJVG5Y_js.clearRedirectCache; }
|
|
1398
|
+
});
|
|
1399
|
+
Object.defineProperty(exports, "fetchRedirectRules", {
|
|
1400
|
+
enumerable: true,
|
|
1401
|
+
get: function () { return chunkBZBJVG5Y_js.fetchRedirectRules; }
|
|
1402
|
+
});
|
|
1403
|
+
Object.defineProperty(exports, "generateNextRedirects", {
|
|
1404
|
+
enumerable: true,
|
|
1405
|
+
get: function () { return chunkBZBJVG5Y_js.generateNextRedirects; }
|
|
1406
|
+
});
|
|
1407
|
+
Object.defineProperty(exports, "handleManagedRedirects", {
|
|
1408
|
+
enumerable: true,
|
|
1409
|
+
get: function () { return chunkBZBJVG5Y_js.handleManagedRedirects; }
|
|
1410
|
+
});
|
|
1411
|
+
Object.defineProperty(exports, "ManagedImage", {
|
|
1412
|
+
enumerable: true,
|
|
1413
|
+
get: function () { return chunkJG2K4S2I_js.ManagedImage; }
|
|
1414
|
+
});
|
|
1415
|
+
Object.defineProperty(exports, "SignalBridge", {
|
|
1416
|
+
enumerable: true,
|
|
1417
|
+
get: function () { return chunkJG2K4S2I_js.SignalBridge; }
|
|
1418
|
+
});
|
|
1419
|
+
Object.defineProperty(exports, "SiteKitProvider", {
|
|
1420
|
+
enumerable: true,
|
|
1421
|
+
get: function () { return chunkJG2K4S2I_js.SiteKitProvider; }
|
|
1422
|
+
});
|
|
1423
|
+
Object.defineProperty(exports, "assignImageToSlot", {
|
|
1424
|
+
enumerable: true,
|
|
1425
|
+
get: function () { return chunkJG2K4S2I_js.assignImageToSlot; }
|
|
1426
|
+
});
|
|
1427
|
+
Object.defineProperty(exports, "clearImageSlot", {
|
|
1428
|
+
enumerable: true,
|
|
1429
|
+
get: function () { return chunkJG2K4S2I_js.clearImageSlot; }
|
|
1430
|
+
});
|
|
1431
|
+
Object.defineProperty(exports, "fetchManagedImage", {
|
|
1432
|
+
enumerable: true,
|
|
1433
|
+
get: function () { return chunkJG2K4S2I_js.fetchManagedImage; }
|
|
1434
|
+
});
|
|
1435
|
+
Object.defineProperty(exports, "fetchManagedImages", {
|
|
1436
|
+
enumerable: true,
|
|
1437
|
+
get: function () { return chunkJG2K4S2I_js.fetchManagedImages; }
|
|
1438
|
+
});
|
|
1439
|
+
Object.defineProperty(exports, "listImageFiles", {
|
|
1440
|
+
enumerable: true,
|
|
1441
|
+
get: function () { return chunkJG2K4S2I_js.listImageFiles; }
|
|
1442
|
+
});
|
|
1443
|
+
Object.defineProperty(exports, "uploadImage", {
|
|
1444
|
+
enumerable: true,
|
|
1445
|
+
get: function () { return chunkJG2K4S2I_js.uploadImage; }
|
|
1446
|
+
});
|
|
1447
|
+
Object.defineProperty(exports, "useSignal", {
|
|
1448
|
+
enumerable: true,
|
|
1449
|
+
get: function () { return chunkJG2K4S2I_js.useSignal; }
|
|
1450
|
+
});
|
|
1451
|
+
Object.defineProperty(exports, "useSignalConfig", {
|
|
1452
|
+
enumerable: true,
|
|
1453
|
+
get: function () { return chunkJG2K4S2I_js.useSignalConfig; }
|
|
1454
|
+
});
|
|
1455
|
+
Object.defineProperty(exports, "useSignalEvent", {
|
|
1456
|
+
enumerable: true,
|
|
1457
|
+
get: function () { return chunkJG2K4S2I_js.useSignalEvent; }
|
|
1458
|
+
});
|
|
1459
|
+
Object.defineProperty(exports, "useSignalExperiment", {
|
|
1460
|
+
enumerable: true,
|
|
1461
|
+
get: function () { return chunkJG2K4S2I_js.useSignalExperiment; }
|
|
1462
|
+
});
|
|
1463
|
+
Object.defineProperty(exports, "useSignalOutcome", {
|
|
1464
|
+
enumerable: true,
|
|
1465
|
+
get: function () { return chunkJG2K4S2I_js.useSignalOutcome; }
|
|
1466
|
+
});
|
|
1467
|
+
Object.defineProperty(exports, "useSiteKit", {
|
|
1468
|
+
enumerable: true,
|
|
1469
|
+
get: function () { return chunkJG2K4S2I_js.useSiteKit; }
|
|
1470
|
+
});
|
|
222
1471
|
Object.defineProperty(exports, "CalendarView", {
|
|
223
1472
|
enumerable: true,
|
|
224
|
-
get: function () { return
|
|
1473
|
+
get: function () { return chunkPYYEPAHL_js.CalendarView; }
|
|
225
1474
|
});
|
|
226
1475
|
Object.defineProperty(exports, "CheckoutForm", {
|
|
227
1476
|
enumerable: true,
|
|
228
|
-
get: function () { return
|
|
1477
|
+
get: function () { return chunkPYYEPAHL_js.CheckoutForm; }
|
|
229
1478
|
});
|
|
230
1479
|
Object.defineProperty(exports, "EventCalendar", {
|
|
231
1480
|
enumerable: true,
|
|
232
|
-
get: function () { return
|
|
1481
|
+
get: function () { return chunkPYYEPAHL_js.EventCalendar; }
|
|
233
1482
|
});
|
|
234
1483
|
Object.defineProperty(exports, "EventEmbed", {
|
|
235
1484
|
enumerable: true,
|
|
236
|
-
get: function () { return
|
|
1485
|
+
get: function () { return chunkPYYEPAHL_js.EventEmbed; }
|
|
237
1486
|
});
|
|
238
1487
|
Object.defineProperty(exports, "EventModal", {
|
|
239
1488
|
enumerable: true,
|
|
240
|
-
get: function () { return
|
|
1489
|
+
get: function () { return chunkPYYEPAHL_js.EventModal; }
|
|
241
1490
|
});
|
|
242
1491
|
Object.defineProperty(exports, "EventTile", {
|
|
243
1492
|
enumerable: true,
|
|
244
|
-
get: function () { return
|
|
1493
|
+
get: function () { return chunkPYYEPAHL_js.EventTile; }
|
|
245
1494
|
});
|
|
246
1495
|
Object.defineProperty(exports, "OfferingCard", {
|
|
247
1496
|
enumerable: true,
|
|
248
|
-
get: function () { return
|
|
1497
|
+
get: function () { return chunkPYYEPAHL_js.OfferingCard; }
|
|
249
1498
|
});
|
|
250
1499
|
Object.defineProperty(exports, "OfferingList", {
|
|
251
1500
|
enumerable: true,
|
|
252
|
-
get: function () { return
|
|
1501
|
+
get: function () { return chunkPYYEPAHL_js.OfferingList; }
|
|
253
1502
|
});
|
|
254
1503
|
Object.defineProperty(exports, "ProductEmbed", {
|
|
255
1504
|
enumerable: true,
|
|
256
|
-
get: function () { return
|
|
1505
|
+
get: function () { return chunkPYYEPAHL_js.ProductEmbed; }
|
|
257
1506
|
});
|
|
258
1507
|
Object.defineProperty(exports, "RegistrationForm", {
|
|
259
1508
|
enumerable: true,
|
|
260
|
-
get: function () { return
|
|
1509
|
+
get: function () { return chunkPYYEPAHL_js.RegistrationForm; }
|
|
261
1510
|
});
|
|
262
1511
|
Object.defineProperty(exports, "UpcomingEvents", {
|
|
263
1512
|
enumerable: true,
|
|
264
|
-
get: function () { return
|
|
1513
|
+
get: function () { return chunkPYYEPAHL_js.UpcomingEvents; }
|
|
265
1514
|
});
|
|
266
1515
|
Object.defineProperty(exports, "createCheckoutSession", {
|
|
267
1516
|
enumerable: true,
|
|
268
|
-
get: function () { return
|
|
1517
|
+
get: function () { return chunkPYYEPAHL_js.createCheckoutSession; }
|
|
269
1518
|
});
|
|
270
1519
|
Object.defineProperty(exports, "fetchNextEvent", {
|
|
271
1520
|
enumerable: true,
|
|
272
|
-
get: function () { return
|
|
1521
|
+
get: function () { return chunkPYYEPAHL_js.fetchNextEvent; }
|
|
273
1522
|
});
|
|
274
1523
|
Object.defineProperty(exports, "fetchOffering", {
|
|
275
1524
|
enumerable: true,
|
|
276
|
-
get: function () { return
|
|
1525
|
+
get: function () { return chunkPYYEPAHL_js.fetchOffering; }
|
|
277
1526
|
});
|
|
278
1527
|
Object.defineProperty(exports, "fetchOfferings", {
|
|
279
1528
|
enumerable: true,
|
|
280
|
-
get: function () { return
|
|
1529
|
+
get: function () { return chunkPYYEPAHL_js.fetchOfferings; }
|
|
281
1530
|
});
|
|
282
1531
|
Object.defineProperty(exports, "fetchProducts", {
|
|
283
1532
|
enumerable: true,
|
|
284
|
-
get: function () { return
|
|
1533
|
+
get: function () { return chunkPYYEPAHL_js.fetchProducts; }
|
|
285
1534
|
});
|
|
286
1535
|
Object.defineProperty(exports, "fetchServices", {
|
|
287
1536
|
enumerable: true,
|
|
288
|
-
get: function () { return
|
|
1537
|
+
get: function () { return chunkPYYEPAHL_js.fetchServices; }
|
|
289
1538
|
});
|
|
290
1539
|
Object.defineProperty(exports, "fetchUpcomingEvents", {
|
|
291
1540
|
enumerable: true,
|
|
292
|
-
get: function () { return
|
|
1541
|
+
get: function () { return chunkPYYEPAHL_js.fetchUpcomingEvents; }
|
|
293
1542
|
});
|
|
294
1543
|
Object.defineProperty(exports, "formatDate", {
|
|
295
1544
|
enumerable: true,
|
|
296
|
-
get: function () { return
|
|
1545
|
+
get: function () { return chunkPYYEPAHL_js.formatDate; }
|
|
297
1546
|
});
|
|
298
1547
|
Object.defineProperty(exports, "formatDateTime", {
|
|
299
1548
|
enumerable: true,
|
|
300
|
-
get: function () { return
|
|
1549
|
+
get: function () { return chunkPYYEPAHL_js.formatDateTime; }
|
|
301
1550
|
});
|
|
302
1551
|
Object.defineProperty(exports, "formatPrice", {
|
|
303
1552
|
enumerable: true,
|
|
304
|
-
get: function () { return
|
|
1553
|
+
get: function () { return chunkPYYEPAHL_js.formatPrice; }
|
|
305
1554
|
});
|
|
306
1555
|
Object.defineProperty(exports, "getOfferingUrl", {
|
|
307
1556
|
enumerable: true,
|
|
308
|
-
get: function () { return
|
|
1557
|
+
get: function () { return chunkPYYEPAHL_js.getOfferingUrl; }
|
|
309
1558
|
});
|
|
310
1559
|
Object.defineProperty(exports, "registerForEvent", {
|
|
311
1560
|
enumerable: true,
|
|
312
|
-
get: function () { return
|
|
1561
|
+
get: function () { return chunkPYYEPAHL_js.registerForEvent; }
|
|
313
1562
|
});
|
|
314
1563
|
Object.defineProperty(exports, "useEventModal", {
|
|
315
1564
|
enumerable: true,
|
|
316
|
-
get: function () { return
|
|
1565
|
+
get: function () { return chunkPYYEPAHL_js.useEventModal; }
|
|
317
1566
|
});
|
|
318
1567
|
exports.AffiliateCard = AffiliateCard;
|
|
319
1568
|
exports.AffiliatesWidget = AffiliatesWidget;
|
|
320
|
-
exports.
|
|
1569
|
+
exports.ExperimentConversion = ExperimentConversion;
|
|
1570
|
+
exports.SetupAssistant = SetupAssistant;
|
|
1571
|
+
exports.SignalExperiment = SignalExperiment;
|
|
321
1572
|
exports.fetchAffiliates = fetchAffiliates;
|
|
322
1573
|
exports.getTrackingUrl = getTrackingUrl;
|
|
323
1574
|
exports.useAffiliates = useAffiliates;
|
|
324
|
-
exports.
|
|
1575
|
+
exports.useExperimentVariant = useExperimentVariant;
|
|
325
1576
|
//# sourceMappingURL=index.js.map
|
|
326
1577
|
//# sourceMappingURL=index.js.map
|