@elevasis/ui 2.59.0 → 2.60.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.
|
@@ -82,6 +82,25 @@ type MessageEvent = {
|
|
|
82
82
|
error?: string;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* A single intake field definition stored in agent_access_grants.capture_fields.
|
|
87
|
+
*
|
|
88
|
+
* - key: machine identifier (e.g. "name", "company")
|
|
89
|
+
* - label: display label shown to the visitor
|
|
90
|
+
* - type: input type hint; defaults to "text" when absent
|
|
91
|
+
* - required: whether the visitor must fill this field; defaults to false
|
|
92
|
+
*/
|
|
93
|
+
declare const CaptureFieldSchema: z.ZodObject<{
|
|
94
|
+
key: z.ZodString;
|
|
95
|
+
label: z.ZodString;
|
|
96
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
97
|
+
email: "email";
|
|
98
|
+
text: "text";
|
|
99
|
+
tel: "tel";
|
|
100
|
+
}>>;
|
|
101
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
102
|
+
}, z.core.$strict>;
|
|
103
|
+
type CaptureField = z.infer<typeof CaptureFieldSchema>;
|
|
85
104
|
/**
|
|
86
105
|
* The public-facing grant shape returned by /authorize and /metadata endpoints.
|
|
87
106
|
*
|
|
@@ -162,7 +181,32 @@ interface PublicAgentChatConnectionState {
|
|
|
162
181
|
|
|
163
182
|
/**
|
|
164
183
|
* Context passed to the `renderIntro` render-prop. Provides the start action,
|
|
165
|
-
* loading state, resolved display strings, raw branding,
|
|
184
|
+
* loading state, resolved display strings, raw branding, the agent slug, and the
|
|
185
|
+
* grant's intake (`captureFields`) surface so a custom intro can render the same
|
|
186
|
+
* welcome form the default intro draws.
|
|
187
|
+
*
|
|
188
|
+
* A minimal custom intro that renders the intake form looks like:
|
|
189
|
+
*
|
|
190
|
+
* ```tsx
|
|
191
|
+
* renderIntro={({ start, starting, captureFields, intakeValues, setIntakeValue }) => (
|
|
192
|
+
* <Stack>
|
|
193
|
+
* <Title>Welcome!</Title>
|
|
194
|
+
* {captureFields.map((field) => (
|
|
195
|
+
* <TextInput
|
|
196
|
+
* key={field.key}
|
|
197
|
+
* label={field.label}
|
|
198
|
+
* required={field.required ?? false}
|
|
199
|
+
* value={intakeValues[field.key] ?? ''}
|
|
200
|
+
* onChange={(e) => setIntakeValue(field.key, e.currentTarget.value)}
|
|
201
|
+
* />
|
|
202
|
+
* ))}
|
|
203
|
+
* <Button onClick={start} loading={starting}>Start</Button>
|
|
204
|
+
* </Stack>
|
|
205
|
+
* )}
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* Values written via `setIntakeValue` flow into the session `metadata` on `start()`
|
|
209
|
+
* exactly as the default intro's form does (so `name` titles the session).
|
|
166
210
|
*/
|
|
167
211
|
interface PublicAgentIntroRenderContext {
|
|
168
212
|
/** Begins the authorize → session flow (the same action the default CTA runs). */
|
|
@@ -175,6 +219,12 @@ interface PublicAgentIntroRenderContext {
|
|
|
175
219
|
/** Raw grant branding record, so a custom intro can still read intro/instructions/etc. if it wants. */
|
|
176
220
|
branding: Record<string, unknown>;
|
|
177
221
|
slug: string;
|
|
222
|
+
/** The grant's resolved, validated intake fields (`[]` when none). Map these to inputs. */
|
|
223
|
+
captureFields: CaptureField[];
|
|
224
|
+
/** Current collected intake values, keyed by `CaptureField.key`. */
|
|
225
|
+
intakeValues: Record<string, string>;
|
|
226
|
+
/** Writes a single intake value; flows into session metadata on `start()`. */
|
|
227
|
+
setIntakeValue: (key: string, value: string) => void;
|
|
178
228
|
}
|
|
179
229
|
interface PublicAgentChatProps {
|
|
180
230
|
apiUrl: string;
|
|
@@ -232,4 +282,4 @@ declare const publicAgentChatKeys: {
|
|
|
232
282
|
};
|
|
233
283
|
|
|
234
284
|
export { PublicAgentChat, PublicAgentChatRoutePage, publicAgentChatKeys, usePublicAgentChatMessages, usePublicAgentChatWebSocket };
|
|
235
|
-
export type { PublicAgentChatAuthorizeResponse, PublicAgentChatConnectionState, PublicAgentChatGrant, PublicAgentChatMessagesResponse, PublicAgentChatMetadataResponse, PublicAgentChatProps, PublicAgentChatRoutePageProps, PublicAgentChatSessionResponse, PublicAgentIntroRenderContext };
|
|
285
|
+
export type { CaptureField, PublicAgentChatAuthorizeResponse, PublicAgentChatConnectionState, PublicAgentChatGrant, PublicAgentChatMessagesResponse, PublicAgentChatMetadataResponse, PublicAgentChatProps, PublicAgentChatRoutePageProps, PublicAgentChatSessionResponse, PublicAgentIntroRenderContext };
|
|
@@ -462,6 +462,9 @@ function PublicAgentChatFrame({
|
|
|
462
462
|
}
|
|
463
463
|
);
|
|
464
464
|
}
|
|
465
|
+
function mergeIntakeMetadata(metadata, intakeValues) {
|
|
466
|
+
return Object.keys(intakeValues).length > 0 ? { ...intakeValues, ...metadata } : metadata;
|
|
467
|
+
}
|
|
465
468
|
function PublicAgentChat({
|
|
466
469
|
apiUrl,
|
|
467
470
|
slug,
|
|
@@ -483,6 +486,9 @@ function PublicAgentChat({
|
|
|
483
486
|
const [input, setInput] = useState("");
|
|
484
487
|
const [isCreatingSession, setIsCreatingSession] = useState(false);
|
|
485
488
|
const [intakeValues, setIntakeValues] = useState({});
|
|
489
|
+
const setIntakeValue = useCallback((key, value) => {
|
|
490
|
+
setIntakeValues((prev) => ({ ...prev, [key]: value }));
|
|
491
|
+
}, []);
|
|
486
492
|
const autoStartedRef = useRef(false);
|
|
487
493
|
const greetingTimeRef = useRef(/* @__PURE__ */ new Date());
|
|
488
494
|
const displayTitle = resolveAgentTitle(title, slug, grant);
|
|
@@ -525,7 +531,7 @@ function PublicAgentChat({
|
|
|
525
531
|
}, [apiUrl, slug, renderIntro]);
|
|
526
532
|
const pendingFirstMessageRef = useRef(null);
|
|
527
533
|
const authorize = useCallback(
|
|
528
|
-
async (code) => {
|
|
534
|
+
async (code, onSuccessStatus = "ready") => {
|
|
529
535
|
if (!grant) return;
|
|
530
536
|
try {
|
|
531
537
|
setError(null);
|
|
@@ -542,7 +548,7 @@ function PublicAgentChat({
|
|
|
542
548
|
}
|
|
543
549
|
);
|
|
544
550
|
setCapabilityToken(authorization.capabilityToken);
|
|
545
|
-
setStatus(
|
|
551
|
+
setStatus(onSuccessStatus);
|
|
546
552
|
} catch (requestError) {
|
|
547
553
|
setError(requestError instanceof Error ? requestError.message : "Unable to start agent chat");
|
|
548
554
|
setStatus(grant.requiresCode ? "code-required" : "error");
|
|
@@ -552,6 +558,7 @@ function PublicAgentChat({
|
|
|
552
558
|
);
|
|
553
559
|
const createSession = useCallback(
|
|
554
560
|
async (boundCapabilityToken) => {
|
|
561
|
+
const mergedMetadata = mergeIntakeMetadata(metadata, intakeValues);
|
|
555
562
|
const createdSession = await fetchJson(
|
|
556
563
|
`${apiUrl}/api/public/agent-chat/${encodeURIComponent(slug)}/sessions`,
|
|
557
564
|
{
|
|
@@ -559,7 +566,7 @@ function PublicAgentChat({
|
|
|
559
566
|
headers: { "Content-Type": "application/json" },
|
|
560
567
|
body: JSON.stringify({
|
|
561
568
|
capabilityToken: boundCapabilityToken,
|
|
562
|
-
...
|
|
569
|
+
...mergedMetadata ? { metadata: mergedMetadata } : {}
|
|
563
570
|
})
|
|
564
571
|
}
|
|
565
572
|
);
|
|
@@ -568,7 +575,7 @@ function PublicAgentChat({
|
|
|
568
575
|
onSessionReady?.(createdSession);
|
|
569
576
|
return createdSession;
|
|
570
577
|
},
|
|
571
|
-
[apiUrl, slug, metadata, onSessionReady]
|
|
578
|
+
[apiUrl, slug, metadata, intakeValues, onSessionReady]
|
|
572
579
|
);
|
|
573
580
|
const startSession = useCallback(
|
|
574
581
|
async (code) => {
|
|
@@ -588,7 +595,7 @@ function PublicAgentChat({
|
|
|
588
595
|
}
|
|
589
596
|
);
|
|
590
597
|
setCapabilityToken(authorization.capabilityToken);
|
|
591
|
-
const mergedMetadata =
|
|
598
|
+
const mergedMetadata = mergeIntakeMetadata(metadata, intakeValues);
|
|
592
599
|
const createdSession = await fetchJson(
|
|
593
600
|
`${apiUrl}/api/public/agent-chat/${encodeURIComponent(slug)}/sessions`,
|
|
594
601
|
{
|
|
@@ -611,6 +618,21 @@ function PublicAgentChat({
|
|
|
611
618
|
},
|
|
612
619
|
[apiUrl, grant, intakeValues, metadata, onSessionReady, slug, visitorId]
|
|
613
620
|
);
|
|
621
|
+
const beginSession = useCallback(async () => {
|
|
622
|
+
if (capabilityToken) {
|
|
623
|
+
try {
|
|
624
|
+
setError(null);
|
|
625
|
+
setStatus("authorizing");
|
|
626
|
+
await createSession(capabilityToken);
|
|
627
|
+
setStatus("ready");
|
|
628
|
+
} catch (requestError) {
|
|
629
|
+
setError(requestError instanceof Error ? requestError.message : "Unable to start agent chat");
|
|
630
|
+
setStatus(grant?.requiresCode ? "code-required" : "error");
|
|
631
|
+
}
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
await startSession();
|
|
635
|
+
}, [capabilityToken, createSession, startSession, grant]);
|
|
614
636
|
useEffect(() => {
|
|
615
637
|
if (!grant || grant.requiresCode || renderIntro || hasIntroContent(grant) || resolveCaptureFields(grant).length > 0 || autoStartedRef.current) {
|
|
616
638
|
return;
|
|
@@ -696,7 +718,9 @@ function PublicAgentChat({
|
|
|
696
718
|
{
|
|
697
719
|
onSubmit: (event) => {
|
|
698
720
|
event.preventDefault();
|
|
699
|
-
|
|
721
|
+
if (!grant) return;
|
|
722
|
+
const next = renderIntro || hasIntroContent(grant) || resolveCaptureFields(grant).length > 0 ? "intro" : "ready";
|
|
723
|
+
void authorize(accessCode, next);
|
|
700
724
|
},
|
|
701
725
|
children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
702
726
|
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
@@ -728,13 +752,16 @@ function PublicAgentChat({
|
|
|
728
752
|
if (renderIntro) {
|
|
729
753
|
const ctx = {
|
|
730
754
|
start: () => {
|
|
731
|
-
void
|
|
755
|
+
void beginSession();
|
|
732
756
|
},
|
|
733
757
|
starting: status === "authorizing",
|
|
734
758
|
title: displayTitle,
|
|
735
759
|
subtitle: displaySubtitle,
|
|
736
760
|
branding,
|
|
737
|
-
slug
|
|
761
|
+
slug,
|
|
762
|
+
captureFields: resolveCaptureFields(grant),
|
|
763
|
+
intakeValues,
|
|
764
|
+
setIntakeValue
|
|
738
765
|
};
|
|
739
766
|
return /* @__PURE__ */ jsx(
|
|
740
767
|
PublicAgentChatFrame,
|
|
@@ -784,10 +811,7 @@ function PublicAgentChat({
|
|
|
784
811
|
type: field.type ?? "text",
|
|
785
812
|
required: field.required ?? false,
|
|
786
813
|
value: intakeValues[field.key] ?? "",
|
|
787
|
-
onChange: (event) =>
|
|
788
|
-
const value = event.currentTarget.value;
|
|
789
|
-
setIntakeValues((prev) => ({ ...prev, [field.key]: value }));
|
|
790
|
-
},
|
|
814
|
+
onChange: (event) => setIntakeValue(field.key, event.currentTarget.value),
|
|
791
815
|
autoComplete: field.type === "email" ? "email" : field.type === "tel" ? "tel" : "off"
|
|
792
816
|
},
|
|
793
817
|
field.key
|
|
@@ -796,7 +820,7 @@ function PublicAgentChat({
|
|
|
796
820
|
Button,
|
|
797
821
|
{
|
|
798
822
|
onClick: () => {
|
|
799
|
-
void
|
|
823
|
+
void beginSession();
|
|
800
824
|
},
|
|
801
825
|
leftSection: /* @__PURE__ */ jsx(IconSend, { size: 16 }),
|
|
802
826
|
children: ctaLabel
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevasis/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.60.1",
|
|
4
4
|
"description": "UI components and platform-aware hooks for building custom frontends on the Elevasis platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -276,8 +276,8 @@
|
|
|
276
276
|
"vitest": "^3.2.4",
|
|
277
277
|
"@elevasis/sdk": "1.36.5",
|
|
278
278
|
"@repo/core": "0.52.0",
|
|
279
|
-
"@repo/elevasis-core": "1.0.0",
|
|
280
279
|
"@repo/typescript-config": "0.0.0",
|
|
280
|
+
"@repo/elevasis-core": "1.0.0",
|
|
281
281
|
"@repo/eslint-config": "0.0.0"
|
|
282
282
|
},
|
|
283
283
|
"dependencies": {
|