@businessdash/sdk 0.9.60 → 0.9.70
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 +1012 -186
- package/assets/biab-sw.js +92 -0
- package/dist/account-core/index.d.ts +126 -0
- package/dist/account-core/index.d.ts.map +1 -0
- package/dist/account-core/index.js +191 -0
- package/dist/account-core/index.js.map +1 -0
- package/dist/account.d.ts +11 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +11 -0
- package/dist/account.js.map +1 -0
- package/dist/auth-handler.d.ts +1 -1
- package/dist/auth-links.d.ts +33 -0
- package/dist/auth-links.d.ts.map +1 -0
- package/dist/auth-links.js +64 -0
- package/dist/auth-links.js.map +1 -0
- package/dist/blog-core/index.d.ts +112 -0
- package/dist/blog-core/index.d.ts.map +1 -0
- package/dist/blog-core/index.js +330 -0
- package/dist/blog-core/index.js.map +1 -0
- package/dist/blog.d.ts +11 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +11 -0
- package/dist/blog.js.map +1 -0
- package/dist/chat-core/index.d.ts +97 -0
- package/dist/chat-core/index.d.ts.map +1 -0
- package/dist/chat-core/index.js +237 -0
- package/dist/chat-core/index.js.map +1 -0
- package/dist/chat.d.ts +11 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +11 -0
- package/dist/chat.js.map +1 -0
- package/dist/checkout-core/index.d.ts +65 -0
- package/dist/checkout-core/index.d.ts.map +1 -0
- package/dist/checkout-core/index.js +159 -0
- package/dist/checkout-core/index.js.map +1 -0
- package/dist/checkout.d.ts +10 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +10 -0
- package/dist/checkout.js.map +1 -0
- package/dist/cli.js +133 -25
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +567 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +807 -1
- package/dist/client.js.map +1 -1
- package/dist/contracts.d.ts +3309 -761
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +541 -4
- package/dist/contracts.js.map +1 -1
- package/dist/data-model-schema.d.ts +1 -1
- package/dist/data-model-schema.d.ts.map +1 -1
- package/dist/element.d.ts +30 -0
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +56 -0
- package/dist/element.js.map +1 -1
- package/dist/embed-protocol.d.ts +86 -0
- package/dist/embed-protocol.d.ts.map +1 -0
- package/dist/embed-protocol.js +60 -0
- package/dist/embed-protocol.js.map +1 -0
- package/dist/framework-support.d.ts +122 -0
- package/dist/framework-support.d.ts.map +1 -0
- package/dist/framework-support.js +323 -0
- package/dist/framework-support.js.map +1 -0
- package/dist/index.cjs +1244 -5
- package/dist/legal-core/index.cjs +115 -0
- package/dist/legal-core/index.d.ts +160 -0
- package/dist/legal-core/index.d.ts.map +1 -0
- package/dist/legal-core/index.js +220 -0
- package/dist/legal-core/index.js.map +1 -0
- package/dist/marketing-core/index.d.ts +66 -0
- package/dist/marketing-core/index.d.ts.map +1 -0
- package/dist/marketing-core/index.js +154 -0
- package/dist/marketing-core/index.js.map +1 -0
- package/dist/marketing.d.ts +7 -0
- package/dist/marketing.d.ts.map +1 -0
- package/dist/marketing.js +7 -0
- package/dist/marketing.js.map +1 -0
- package/dist/mcp-adapters/index.d.ts +135 -0
- package/dist/mcp-adapters/index.d.ts.map +1 -0
- package/dist/mcp-adapters/index.js +187 -0
- package/dist/mcp-adapters/index.js.map +1 -0
- package/dist/mcp-adapters.d.ts +7 -0
- package/dist/mcp-adapters.d.ts.map +1 -0
- package/dist/mcp-adapters.js +7 -0
- package/dist/mcp-adapters.js.map +1 -0
- package/dist/model3d-core/index.cjs +95 -0
- package/dist/model3d-core/index.d.ts +167 -0
- package/dist/model3d-core/index.d.ts.map +1 -0
- package/dist/model3d-core/index.js +158 -0
- package/dist/model3d-core/index.js.map +1 -0
- package/dist/notifications-core/index.cjs +315 -0
- package/dist/notifications-core/index.d.ts +229 -0
- package/dist/notifications-core/index.d.ts.map +1 -0
- package/dist/notifications-core/index.js +445 -0
- package/dist/notifications-core/index.js.map +1 -0
- package/dist/portal-core/index.d.ts +451 -0
- package/dist/portal-core/index.d.ts.map +1 -0
- package/dist/portal-core/index.js +819 -0
- package/dist/portal-core/index.js.map +1 -0
- package/dist/portal.d.ts +7 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +7 -0
- package/dist/portal.js.map +1 -0
- package/dist/push-core/index.cjs +171 -0
- package/dist/push-core/index.d.ts +149 -0
- package/dist/push-core/index.d.ts.map +1 -0
- package/dist/push-core/index.js +231 -0
- package/dist/push-core/index.js.map +1 -0
- package/dist/react-marketing.d.ts +1 -17
- package/dist/react-marketing.d.ts.map +1 -1
- package/dist/react-marketing.js +4 -0
- package/dist/react-marketing.js.map +1 -1
- package/dist/react.d.ts +294 -101
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +302 -246
- package/dist/react.js.map +1 -1
- package/dist/seed-core/index.d.ts +354 -0
- package/dist/seed-core/index.d.ts.map +1 -0
- package/dist/seed-core/index.js +420 -0
- package/dist/seed-core/index.js.map +1 -0
- package/dist/seed.d.ts +7 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +7 -0
- package/dist/seed.js.map +1 -0
- package/dist/seo-core/blog.d.ts +94 -0
- package/dist/seo-core/blog.d.ts.map +1 -0
- package/dist/seo-core/blog.js +149 -0
- package/dist/seo-core/blog.js.map +1 -0
- package/dist/seo-core/commerce.d.ts +64 -0
- package/dist/seo-core/commerce.d.ts.map +1 -0
- package/dist/seo-core/commerce.js +87 -0
- package/dist/seo-core/commerce.js.map +1 -0
- package/dist/seo-core/index.cjs +751 -0
- package/dist/seo-core/index.d.ts +226 -0
- package/dist/seo-core/index.d.ts.map +1 -0
- package/dist/seo-core/index.js +455 -0
- package/dist/seo-core/index.js.map +1 -0
- package/dist/seo-core/local.d.ts +181 -0
- package/dist/seo-core/local.d.ts.map +1 -0
- package/dist/seo-core/local.js +193 -0
- package/dist/seo-core/local.js.map +1 -0
- package/dist/sitemap-core/index.cjs +167 -0
- package/dist/sitemap-core/index.d.ts +155 -0
- package/dist/sitemap-core/index.d.ts.map +1 -0
- package/dist/sitemap-core/index.js +195 -0
- package/dist/sitemap-core/index.js.map +1 -0
- package/dist/social-core/index.d.ts +74 -0
- package/dist/social-core/index.d.ts.map +1 -0
- package/dist/social-core/index.js +72 -0
- package/dist/social-core/index.js.map +1 -0
- package/dist/social.d.ts +7 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +7 -0
- package/dist/social.js.map +1 -0
- package/dist/solid-compat.d.ts +204 -0
- package/dist/solid-compat.d.ts.map +1 -0
- package/dist/solid-compat.js +221 -0
- package/dist/solid-compat.js.map +1 -0
- package/dist/store-core/index.d.ts +141 -0
- package/dist/store-core/index.d.ts.map +1 -0
- package/dist/store-core/index.js +277 -0
- package/dist/store-core/index.js.map +1 -0
- package/dist/store.d.ts +12 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +12 -0
- package/dist/store.js.map +1 -0
- package/dist/vanilla.d.ts +111 -0
- package/dist/vanilla.d.ts.map +1 -1
- package/dist/vanilla.js +206 -0
- package/dist/vanilla.js.map +1 -1
- package/dist/verify-core/index.d.ts +98 -0
- package/dist/verify-core/index.d.ts.map +1 -0
- package/dist/verify-core/index.js +186 -0
- package/dist/verify-core/index.js.map +1 -0
- package/dist/verify.d.ts +8 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +8 -0
- package/dist/verify.js.map +1 -0
- package/openapi.json +4316 -1313
- package/package.json +121 -9
- package/src/account-core/index.ts +309 -0
- package/src/account.ts +11 -0
- package/src/angular/headless.ts +519 -0
- package/src/angular/index.ts +3 -0
- package/src/auth-links.ts +76 -0
- package/src/blog-core/index.ts +423 -0
- package/src/blog.ts +11 -0
- package/src/chat-core/index.ts +335 -0
- package/src/chat.ts +11 -0
- package/src/checkout-core/index.ts +225 -0
- package/src/checkout.ts +10 -0
- package/src/cli.ts +184 -28
- package/src/client.ts +998 -0
- package/src/contracts.ts +730 -11
- package/src/data-model-schema.ts +1 -1
- package/src/element.ts +102 -0
- package/src/embed-protocol.ts +100 -0
- package/src/framework-support.ts +440 -0
- package/src/legal-core/index.ts +276 -0
- package/src/marketing-core/index.ts +209 -0
- package/src/marketing.ts +7 -0
- package/src/mcp-adapters/index.ts +264 -0
- package/src/mcp-adapters.ts +7 -0
- package/src/model3d-core/index.ts +248 -0
- package/src/notifications-core/index.ts +650 -0
- package/src/portal-core/index.ts +1564 -0
- package/src/portal.ts +7 -0
- package/src/push-core/index.ts +335 -0
- package/src/qwik.tsx +602 -2
- package/src/react-marketing.tsx +5 -0
- package/src/react.tsx +434 -319
- package/src/seed-core/index.ts +735 -0
- package/src/seed.ts +7 -0
- package/src/seo-core/blog.ts +216 -0
- package/src/seo-core/commerce.ts +138 -0
- package/src/seo-core/index.ts +605 -0
- package/src/seo-core/local.ts +333 -0
- package/src/sitemap-core/index.ts +296 -0
- package/src/social-core/index.ts +103 -0
- package/src/social.ts +7 -0
- package/src/solid-compat.tsx +347 -0
- package/src/solid-surfaces.tsx +1311 -0
- package/src/solid.tsx +82 -60
- package/src/store-core/index.ts +426 -0
- package/src/store.ts +12 -0
- package/src/svelte/SocialLinks.svelte +84 -0
- package/src/svelte/headless.ts +435 -0
- package/src/svelte/index.ts +9 -0
- package/src/vanilla.ts +367 -0
- package/src/verify-core/index.ts +288 -0
- package/src/verify.ts +8 -0
- package/src/vue/headless.ts +527 -0
- package/src/vue/index.ts +3 -0
package/dist/react.js
CHANGED
|
@@ -1,13 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Every export in this file is browser-only. The components hold state and
|
|
5
|
+
* subscribe to stores; the four programmatic helpers (`signIn`, `signUp`,
|
|
6
|
+
* `signOut`, `requestPasswordReset`) each bail out on
|
|
7
|
+
* `typeof window === "undefined"` because they navigate. Nothing here is meant
|
|
8
|
+
* to execute during a server render.
|
|
9
|
+
*
|
|
10
|
+
* WHY THE DIRECTIVE IS HERE
|
|
11
|
+
*
|
|
12
|
+
* Without it, a React Server Components framework treats this module as server
|
|
13
|
+
* code by default, and importing `<BiabForm>` into a page throws "you're
|
|
14
|
+
* importing a component that needs useState". The only way out is for every
|
|
15
|
+
* consumer to hand-write a `"use client"` wrapper per component — which is
|
|
16
|
+
* exactly what the Next App Router starter had to do, sixteen times, for
|
|
17
|
+
* components the SDK could have marked itself.
|
|
18
|
+
*
|
|
19
|
+
* `react-analytics.tsx` already carried this. `react.tsx` — the entry point
|
|
20
|
+
* that actually holds the components — did not.
|
|
21
|
+
*
|
|
22
|
+
* Bundlers that don't implement the directive treat it as a no-op string
|
|
23
|
+
* expression, so this is inert everywhere except RSC.
|
|
24
|
+
*/
|
|
2
25
|
import { createContext, Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore, } from "react";
|
|
26
|
+
import { createFollowersController, createUserController, } from "./account-core/index.js";
|
|
27
|
+
import { buildAuthHref, clearLocalFollow, DEFAULT_AUTH_BASE_PATH, followerStoreKey, readLocalFollow, writeLocalFollow, } from "./auth-links.js";
|
|
28
|
+
import { createBlogController } from "./blog-core/index.js";
|
|
29
|
+
import { createChatController } from "./chat-core/index.js";
|
|
30
|
+
import { createCheckoutController } from "./checkout-core/index.js";
|
|
3
31
|
import { BiabDevClient } from "./client.js";
|
|
32
|
+
import { DEFAULT_EMBED_SANDBOX, DEFAULT_REFRESH_LEAD_MS, refreshDelayMs, subscribeToEmbedMessages, } from "./embed-protocol.js";
|
|
4
33
|
import { buildAcceptAttr, concurrentRevealCount, createFormController, evalCondition, fetchIconNames, filterIconNames, flattenValueFields, formatCalcValue, iconUrl, isPendingFileValue, resolveFieldAutocomplete, shouldSearchOptions, validateFile, } from "./forms-core/index.js";
|
|
5
34
|
import { baseUnitFor, convertToBase, formatMeasurement, isMeasurementCategory, unitsForCategory, } from "./forms-core/units.js";
|
|
6
35
|
import { US_STATES } from "./forms-core/us-states.js";
|
|
36
|
+
import { createMarketingController } from "./marketing-core/index.js";
|
|
37
|
+
import { createPortalController } from "./portal-core/index.js";
|
|
7
38
|
import { createBiabClient } from "./sdk.js";
|
|
8
|
-
import {
|
|
39
|
+
import { resolveSocialLinks, SOCIAL_FALLBACK_GLYPH, SOCIAL_LIST_STYLE, } from "./social-core/index.js";
|
|
40
|
+
import { createStoreController } from "./store-core/index.js";
|
|
41
|
+
import { createVerifyController, } from "./verify-core/index.js";
|
|
9
42
|
function useEmbedSession(loader, options) {
|
|
10
|
-
const { apiKey, baseUrl, refreshLeadMs =
|
|
43
|
+
const { apiKey, baseUrl, refreshLeadMs = DEFAULT_REFRESH_LEAD_MS } = options;
|
|
11
44
|
const client = useMemo(() => new BiabDevClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
|
|
12
45
|
const [state, setState] = useState({ status: "idle" });
|
|
13
46
|
// `loader` is recreated per surface; depending on it would refetch on every
|
|
@@ -32,10 +65,12 @@ function useEmbedSession(loader, options) {
|
|
|
32
65
|
useEffect(() => {
|
|
33
66
|
if (state.status !== "ready")
|
|
34
67
|
return;
|
|
35
|
-
|
|
36
|
-
|
|
68
|
+
// The schedule itself lives in `embed-protocol.ts` so both bindings
|
|
69
|
+
// re-mint at the same moment — an embed that expires in Solid but not in
|
|
70
|
+
// React would be a bug nobody thinks to look for.
|
|
71
|
+
const delay = refreshDelayMs(state.session.expiresAt, refreshLeadMs, Date.now());
|
|
72
|
+
if (delay === null)
|
|
37
73
|
return;
|
|
38
|
-
const delay = Math.max(1_000, expiresAt - Date.now() - refreshLeadMs);
|
|
39
74
|
const timer = setTimeout(() => {
|
|
40
75
|
void refresh();
|
|
41
76
|
}, delay);
|
|
@@ -44,23 +79,9 @@ function useEmbedSession(loader, options) {
|
|
|
44
79
|
return { client, state, refresh };
|
|
45
80
|
}
|
|
46
81
|
function useEmbedMessages(iframeRef, handler) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return;
|
|
51
|
-
if (e.data.kind !== "biab")
|
|
52
|
-
return;
|
|
53
|
-
if (iframeRef.current &&
|
|
54
|
-
e.source !== null &&
|
|
55
|
-
e.source !== iframeRef.current.contentWindow)
|
|
56
|
-
return;
|
|
57
|
-
const { kind, ...rest } = e.data;
|
|
58
|
-
void kind;
|
|
59
|
-
handler(rest);
|
|
60
|
-
};
|
|
61
|
-
window.addEventListener("message", onMessage);
|
|
62
|
-
return () => window.removeEventListener("message", onMessage);
|
|
63
|
-
}, [handler, iframeRef]);
|
|
82
|
+
// The listener, and the origin check inside it, live in
|
|
83
|
+
// `embed-protocol.ts` so the Solid binding enforces exactly the same rule.
|
|
84
|
+
useEffect(() => subscribeToEmbedMessages(() => iframeRef.current, handler), [handler, iframeRef]);
|
|
64
85
|
}
|
|
65
86
|
// Asserted-compat with the underlying DashboardSessionResponse so the public
|
|
66
87
|
// `useDashboardSession` shape doesn't churn for existing callers.
|
|
@@ -102,7 +123,7 @@ export function Dashboard({ className, style, title = "Business In A Box Dashboa
|
|
|
102
123
|
if (state.status !== "ready") {
|
|
103
124
|
return (_jsx(_Fragment, { children: loadingFallback ?? (_jsx("div", { className: className, style: { padding: 16, ...style }, children: "Loading dashboard\u2026" })) }));
|
|
104
125
|
}
|
|
105
|
-
return (_jsx("iframe", { className: className, sandbox:
|
|
126
|
+
return (_jsx("iframe", { className: className, sandbox: DEFAULT_EMBED_SANDBOX, src: state.session.url, style: { ...defaultIframeStyle, ...style }, title: title }));
|
|
106
127
|
}
|
|
107
128
|
function EmbedIframe({ state, refresh, title, className, style, loadingFallback, errorFallback, onEvent, extraSandbox, }) {
|
|
108
129
|
const iframeRef = useRef(null);
|
|
@@ -121,7 +142,9 @@ function EmbedIframe({ state, refresh, title, className, style, loadingFallback,
|
|
|
121
142
|
if (state.status !== "ready") {
|
|
122
143
|
return (_jsx(_Fragment, { children: loadingFallback ?? (_jsx("div", { className: className, style: { padding: 16, ...style }, children: "Loading\u2026" })) }));
|
|
123
144
|
}
|
|
124
|
-
const sandbox =
|
|
145
|
+
const sandbox = extraSandbox
|
|
146
|
+
? `${DEFAULT_EMBED_SANDBOX} ${extraSandbox}`
|
|
147
|
+
: DEFAULT_EMBED_SANDBOX;
|
|
125
148
|
return (_jsx("iframe", { className: className, ref: iframeRef, sandbox: sandbox, src: state.session.url, style: { ...defaultIframeStyle, ...style }, title: title }));
|
|
126
149
|
}
|
|
127
150
|
export function Storefront({ apiKey, baseUrl, productId, className, style, title = "Storefront", loadingFallback, errorFallback, onEvent, onCartChange, refreshLeadMs, }) {
|
|
@@ -272,103 +295,72 @@ export function Chatbot({ apiKey, baseUrl, className, style, title = "Assistant"
|
|
|
272
295
|
*/
|
|
273
296
|
export function useChatbot(options) {
|
|
274
297
|
const { apiKey, baseUrl } = options;
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
setIsPending(true);
|
|
287
|
-
const next = [
|
|
288
|
-
...messages,
|
|
289
|
-
{ role: "user", content: trimmed },
|
|
290
|
-
];
|
|
291
|
-
setMessages(next);
|
|
292
|
-
try {
|
|
293
|
-
const input = { messages: next };
|
|
294
|
-
const reply = await client.chatbot.chat(input);
|
|
295
|
-
setMessages((prev) => [
|
|
296
|
-
...prev,
|
|
297
|
-
{ role: "assistant", content: reply.text },
|
|
298
|
-
]);
|
|
299
|
-
setLatestUiActions(reply.uiActions ?? []);
|
|
300
|
-
if (reply.availability)
|
|
301
|
-
setAvailability(reply.availability);
|
|
302
|
-
return reply;
|
|
303
|
-
}
|
|
304
|
-
catch (err) {
|
|
305
|
-
const e = err instanceof Error ? err : new Error("Chat failed");
|
|
306
|
-
setError(e);
|
|
307
|
-
return null;
|
|
308
|
-
}
|
|
309
|
-
finally {
|
|
310
|
-
setIsPending(false);
|
|
311
|
-
}
|
|
312
|
-
}, [client, messages]);
|
|
313
|
-
const reset = useCallback(() => {
|
|
314
|
-
setMessages([]);
|
|
315
|
-
setError(null);
|
|
316
|
-
setLatestUiActions([]);
|
|
317
|
-
}, []);
|
|
318
|
-
const getConfig = useCallback(async () => client.chatbot.getConfig(), [client]);
|
|
319
|
-
const refreshAvailability = useCallback(async () => {
|
|
320
|
-
try {
|
|
321
|
-
const next = await client.chatbot.getAvailability();
|
|
322
|
-
setAvailability(next);
|
|
323
|
-
return next;
|
|
324
|
-
}
|
|
325
|
-
catch {
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
}, [client]);
|
|
329
|
-
const getForm = useCallback(async (slug) => {
|
|
330
|
-
try {
|
|
331
|
-
// Chat `show_form` flow → the chatbot path (Live + chatbotAccess).
|
|
332
|
-
return await client.chatbot.getChatForm(slug);
|
|
333
|
-
}
|
|
334
|
-
catch {
|
|
335
|
-
return null;
|
|
336
|
-
}
|
|
337
|
-
}, [client]);
|
|
338
|
-
const submitForm = useCallback(async (slug, input) => {
|
|
339
|
-
try {
|
|
340
|
-
const priorChat = messages.map((m, i) => ({
|
|
341
|
-
role: m.role,
|
|
342
|
-
content: m.content,
|
|
343
|
-
createdAt: i,
|
|
344
|
-
}));
|
|
345
|
-
// Chatbot submit carries the transcript → chatbot path.
|
|
346
|
-
return await client.chatbot.submitChatForm(slug, {
|
|
347
|
-
...input,
|
|
348
|
-
priorChat: input.priorChat ?? priorChat,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
catch (err) {
|
|
352
|
-
setError(err instanceof Error ? err : new Error("Submit failed"));
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
}, [client, messages]);
|
|
356
|
-
const uploadFile = useCallback((args) => client.chatbot.uploadFile(args), [client]);
|
|
298
|
+
const controller = useMemo(() => createChatController({
|
|
299
|
+
client: new BiabDevClient({ apiKey, baseUrl }),
|
|
300
|
+
}), [apiKey, baseUrl]);
|
|
301
|
+
useEffect(() => () => controller.destroy(), [controller]);
|
|
302
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
303
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
304
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
305
|
+
const uploadFile = useCallback((args) => new BiabDevClient({ apiKey, baseUrl }).chatbot.uploadFile(args), [apiKey, baseUrl]);
|
|
306
|
+
// The returned shape is unchanged from before this hook was moved onto
|
|
307
|
+
// `chat-core`, so existing consumers keep working — only the implementation
|
|
308
|
+
// moved, and it now backs every other framework's chat binding too.
|
|
357
309
|
return {
|
|
358
|
-
messages,
|
|
359
|
-
send,
|
|
360
|
-
reset,
|
|
361
|
-
isPending,
|
|
362
|
-
error,
|
|
363
|
-
getConfig,
|
|
364
|
-
latestUiActions,
|
|
365
|
-
availability,
|
|
366
|
-
refreshAvailability,
|
|
367
|
-
getForm,
|
|
368
|
-
submitForm,
|
|
310
|
+
messages: snap.messages,
|
|
311
|
+
send: controller.send,
|
|
312
|
+
reset: controller.reset,
|
|
313
|
+
isPending: snap.isPending,
|
|
314
|
+
error: snap.error,
|
|
315
|
+
getConfig: controller.loadConfig,
|
|
316
|
+
latestUiActions: snap.uiActions,
|
|
317
|
+
availability: snap.availability,
|
|
318
|
+
refreshAvailability: controller.refreshAvailability,
|
|
319
|
+
getForm: controller.getForm,
|
|
320
|
+
submitForm: controller.submitForm,
|
|
321
|
+
requestHuman: controller.requestHuman,
|
|
369
322
|
uploadFile,
|
|
370
323
|
};
|
|
371
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Headless storefront + cart for React — the native alternative to
|
|
327
|
+
* `<Storefront>`, which is a hosted page in an iframe. Everything lives in
|
|
328
|
+
* `createStoreController`; this only bridges it into React.
|
|
329
|
+
*
|
|
330
|
+
* ```tsx
|
|
331
|
+
* const store = useStorefront({ apiKey, baseUrl });
|
|
332
|
+
* return store.products.map((p) => <MyCard key={p.id} product={p} />);
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
export function useStorefront(options) {
|
|
336
|
+
const { apiKey, baseUrl, pageSize, categoryId } = options;
|
|
337
|
+
const controller = useMemo(() => createStoreController({
|
|
338
|
+
client: new BiabDevClient({ apiKey, baseUrl }),
|
|
339
|
+
...(pageSize ? { pageSize } : {}),
|
|
340
|
+
...(categoryId ? { categoryId } : {}),
|
|
341
|
+
}), [apiKey, baseUrl, pageSize, categoryId]);
|
|
342
|
+
useEffect(() => {
|
|
343
|
+
void controller.load();
|
|
344
|
+
return () => controller.destroy();
|
|
345
|
+
}, [controller]);
|
|
346
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
347
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
348
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
349
|
+
return {
|
|
350
|
+
...snap,
|
|
351
|
+
loadMore: controller.loadMore,
|
|
352
|
+
filterByCategory: controller.filterByCategory,
|
|
353
|
+
openProduct: controller.openProduct,
|
|
354
|
+
closeProduct: controller.closeProduct,
|
|
355
|
+
addToCart: controller.addToCart,
|
|
356
|
+
updateQuantity: controller.updateQuantity,
|
|
357
|
+
removeItem: controller.removeItem,
|
|
358
|
+
applyCoupon: controller.applyCoupon,
|
|
359
|
+
removeCoupon: controller.removeCoupon,
|
|
360
|
+
clearCart: controller.clearCart,
|
|
361
|
+
refreshCart: controller.refreshCart,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
372
364
|
const STATIC_FIELD_TYPES = new Set([
|
|
373
365
|
"title",
|
|
374
366
|
"subtitle",
|
|
@@ -646,7 +638,10 @@ export function ChatbotInline({ apiKey, baseUrl, welcomeMessage, title = "Assist
|
|
|
646
638
|
let cancelled = false;
|
|
647
639
|
void getConfig()
|
|
648
640
|
.then((cfg) => {
|
|
649
|
-
|
|
641
|
+
// `null` means the config couldn't be read — the core reports that
|
|
642
|
+
// rather than throwing, because a chat that can't fetch its upload
|
|
643
|
+
// settings should still let the visitor talk. Keep the defaults.
|
|
644
|
+
if (cancelled || !cfg)
|
|
650
645
|
return;
|
|
651
646
|
setFileUploadsEnabled(cfg.fileUploadsEnabled);
|
|
652
647
|
setEmailCaptureMode(cfg.emailCaptureMode);
|
|
@@ -925,17 +920,8 @@ export function Blog({ apiKey, baseUrl, postSlug, className, style, title = "Blo
|
|
|
925
920
|
const { state, refresh } = useEmbedSession((client) => client.blog.createSession(input), { apiKey, baseUrl, refreshLeadMs });
|
|
926
921
|
return (_jsx(EmbedIframe, { className: className, errorFallback: errorFallback, loadingFallback: loadingFallback, onEvent: onEvent, refresh: refresh, state: state, style: style, title: title }));
|
|
927
922
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
const base = (props.basePath ?? DEFAULT_AUTH_BASE_PATH).replace(/\/$/, "");
|
|
931
|
-
const params = new URLSearchParams();
|
|
932
|
-
if (props.returnTo)
|
|
933
|
-
params.set("returnTo", props.returnTo);
|
|
934
|
-
if (props.loginHint)
|
|
935
|
-
params.set("loginHint", props.loginHint);
|
|
936
|
-
const qs = params.toString();
|
|
937
|
-
return `${base}/${subroute}${qs ? `?${qs}` : ""}`;
|
|
938
|
-
}
|
|
923
|
+
// `buildAuthHref` and `DEFAULT_AUTH_BASE_PATH` come from `./auth-links.js` so
|
|
924
|
+
// every binding builds the same handler URLs from the same query contract.
|
|
939
925
|
export function SignIn({ children, ...rest }) {
|
|
940
926
|
return (_jsx("a", { className: rest.className, href: buildAuthHref("sign-in", rest), style: rest.style, children: children ?? "Sign in" }));
|
|
941
927
|
}
|
|
@@ -1021,73 +1007,21 @@ export async function requestPasswordReset(input) {
|
|
|
1021
1007
|
* the cookie + handler path are the source of truth.
|
|
1022
1008
|
*/
|
|
1023
1009
|
export function useUser(options) {
|
|
1024
|
-
const basePath =
|
|
1025
|
-
const
|
|
1026
|
-
status: "loading",
|
|
1027
|
-
user: null,
|
|
1028
|
-
});
|
|
1010
|
+
const basePath = options?.basePath;
|
|
1011
|
+
const controller = useMemo(() => createUserController(basePath ? { basePath } : {}), [basePath]);
|
|
1029
1012
|
useEffect(() => {
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
}
|
|
1039
|
-
else {
|
|
1040
|
-
setState({ status: "signed-out", user: null });
|
|
1041
|
-
}
|
|
1042
|
-
})
|
|
1043
|
-
.catch(() => {
|
|
1044
|
-
if (cancelled)
|
|
1045
|
-
return;
|
|
1046
|
-
setState({ status: "signed-out", user: null });
|
|
1047
|
-
});
|
|
1048
|
-
return () => {
|
|
1049
|
-
cancelled = true;
|
|
1050
|
-
};
|
|
1051
|
-
}, [basePath]);
|
|
1052
|
-
return state;
|
|
1053
|
-
}
|
|
1054
|
-
const FOLLOWER_STORE_PREFIX = "biab.followers.";
|
|
1055
|
-
function readLocalFollow(key) {
|
|
1056
|
-
if (typeof window === "undefined")
|
|
1057
|
-
return null;
|
|
1058
|
-
try {
|
|
1059
|
-
const raw = window.localStorage.getItem(key);
|
|
1060
|
-
if (!raw)
|
|
1061
|
-
return null;
|
|
1062
|
-
const parsed = JSON.parse(raw);
|
|
1063
|
-
return typeof parsed?.email === "string"
|
|
1064
|
-
? { email: parsed.email, at: Number(parsed.at) || 0 }
|
|
1065
|
-
: null;
|
|
1066
|
-
}
|
|
1067
|
-
catch {
|
|
1068
|
-
return null;
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
function writeLocalFollow(key, value) {
|
|
1072
|
-
if (typeof window === "undefined")
|
|
1073
|
-
return;
|
|
1074
|
-
try {
|
|
1075
|
-
window.localStorage.setItem(key, JSON.stringify(value));
|
|
1076
|
-
}
|
|
1077
|
-
catch {
|
|
1078
|
-
// storage disabled / quota — the local hint is best-effort.
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
function clearLocalFollow(key) {
|
|
1082
|
-
if (typeof window === "undefined")
|
|
1083
|
-
return;
|
|
1084
|
-
try {
|
|
1085
|
-
window.localStorage.removeItem(key);
|
|
1086
|
-
}
|
|
1087
|
-
catch {
|
|
1088
|
-
// ignore
|
|
1089
|
-
}
|
|
1013
|
+
controller.start();
|
|
1014
|
+
return () => controller.destroy();
|
|
1015
|
+
}, [controller]);
|
|
1016
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
1017
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
1018
|
+
// The shape is unchanged for callers; the fetch moved to `account-core` so
|
|
1019
|
+
// every framework reads the session the same way.
|
|
1020
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1090
1021
|
}
|
|
1022
|
+
// `LocalFollow`, `followerStoreKey`, `readLocalFollow`, `writeLocalFollow` and
|
|
1023
|
+
// `clearLocalFollow` come from `./auth-links.js` — one storage format, so a
|
|
1024
|
+
// visitor who subscribed through one binding is recognised by another.
|
|
1091
1025
|
/**
|
|
1092
1026
|
* Visitor-facing followers/subscribe client, bound to a publishable token so it
|
|
1093
1027
|
* works browser-side with no backend.
|
|
@@ -1112,43 +1046,50 @@ function clearLocalFollow(key) {
|
|
|
1112
1046
|
*/
|
|
1113
1047
|
export function useFollowers(options) {
|
|
1114
1048
|
const { token, siteId, baseUrl } = options;
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1049
|
+
const controller = useMemo(() => createFollowersController({
|
|
1050
|
+
client: createBiabClient({
|
|
1051
|
+
apiKey: token,
|
|
1052
|
+
siteId,
|
|
1053
|
+
baseUrl: baseUrl ?? DEFAULT_PACKAGE_BASE_URL,
|
|
1054
|
+
}),
|
|
1117
1055
|
siteId,
|
|
1118
|
-
baseUrl: baseUrl ?? DEFAULT_PACKAGE_BASE_URL,
|
|
1119
1056
|
}), [token, siteId, baseUrl]);
|
|
1120
|
-
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1057
|
+
useEffect(() => () => controller.destroy(), [controller]);
|
|
1058
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
1059
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
1060
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1061
|
+
// Same shape as before the move onto `account-core`, including the
|
|
1062
|
+
// local-storage hint, so existing consumers are untouched.
|
|
1063
|
+
return {
|
|
1064
|
+
join: controller.join,
|
|
1065
|
+
leave: controller.leave,
|
|
1066
|
+
me: controller.me,
|
|
1067
|
+
edit: controller.edit,
|
|
1068
|
+
subscribedLocally: snap.subscribedLocally,
|
|
1069
|
+
localEmail: snap.localEmail,
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Headless checkout for React. `start()` mints a Stripe session and `redirect()`
|
|
1074
|
+
* navigates — split apart so a native app or an SSR render can use the first
|
|
1075
|
+
* without the second.
|
|
1076
|
+
*/
|
|
1077
|
+
export function useCheckout(options) {
|
|
1078
|
+
const { apiKey, baseUrl } = options;
|
|
1079
|
+
const controller = useMemo(() => createCheckoutController({
|
|
1080
|
+
client: new BiabDevClient({ apiKey, baseUrl }),
|
|
1081
|
+
}), [apiKey, baseUrl]);
|
|
1082
|
+
useEffect(() => () => controller.destroy(), [controller]);
|
|
1083
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
1084
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
1085
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1086
|
+
return {
|
|
1087
|
+
...snap,
|
|
1088
|
+
start: controller.start,
|
|
1089
|
+
redirect: controller.redirect,
|
|
1090
|
+
resolve: controller.resolve,
|
|
1091
|
+
reset: controller.reset,
|
|
1092
|
+
};
|
|
1152
1093
|
}
|
|
1153
1094
|
/**
|
|
1154
1095
|
* Lazy-fetch a single marketing page by `pageKey`. The hook reads from the
|
|
@@ -2384,16 +2325,13 @@ export function BiabForm(props) {
|
|
|
2384
2325
|
return (_jsxs("div", { className: "biab-coupon-notice", children: [_jsx("p", { className: "biab-coupon-notice__text", children: text }), a.coupon?.finePrint && (_jsx("p", { className: "biab-coupon-notice__fine", children: a.coupon.finePrint }))] }, `coupon-${i}`));
|
|
2385
2326
|
}), consecutive ? (_jsxs("div", { className: "biab-nav", children: [_jsx("button", { className: "biab-btn biab-btn--back biab-btn--ghost", disabled: snap.isFirstStep, onClick: () => controller.back(), type: "button", children: "Back" }), !snap.isLastStep ? (_jsx("button", { className: "biab-btn biab-btn--next", disabled: !snap.canAdvance, onClick: () => controller.next(), type: "button", children: "Next" })) : (_jsx("button", { className: "biab-btn biab-btn--submit", disabled: snap.submitting || snap.uploading, onClick: () => void handleSubmit(), type: "button", children: snap.submitting ? "Sending…" : submitLabel }))] })) : (_jsx("div", { className: "biab-nav", children: _jsx("button", { className: "biab-btn biab-btn--submit", disabled: snap.submitting || snap.uploading, onClick: () => void handleSubmit(), type: "button", children: snap.submitting ? "Sending…" : submitLabel }) })), snap.result && !snap.result.ok && snap.errorList.length === 0 && (_jsx("div", { className: "biab-form__error", role: "alert", children: snap.result.message }))] }) }) }));
|
|
2386
2327
|
}
|
|
2387
|
-
function SocialGlyph({
|
|
2388
|
-
if (
|
|
2389
|
-
const src = color
|
|
2390
|
-
? `https://cdn.simpleicons.org/${iconSlug}/${encodeURIComponent(color)}`
|
|
2391
|
-
: `https://cdn.simpleicons.org/${iconSlug}`;
|
|
2328
|
+
function SocialGlyph({ iconUrl, size, className, label, }) {
|
|
2329
|
+
if (iconUrl) {
|
|
2392
2330
|
return (
|
|
2393
2331
|
// biome-ignore lint: remote brand icon from the simple-icons CDN
|
|
2394
|
-
_jsx("img", { alt: label, className: className, height: size, loading: "lazy", src:
|
|
2332
|
+
_jsx("img", { alt: label, className: className, height: size, loading: "lazy", src: iconUrl, width: size }));
|
|
2395
2333
|
}
|
|
2396
|
-
return (_jsxs("svg", { "aria-hidden": true, className: className, fill: "none", height: size, stroke: "currentColor", strokeWidth:
|
|
2334
|
+
return (_jsxs("svg", { "aria-hidden": true, className: className, fill: "none", height: size, stroke: "currentColor", strokeWidth: SOCIAL_FALLBACK_GLYPH.strokeWidth, viewBox: SOCIAL_FALLBACK_GLYPH.viewBox, width: size, children: [_jsx("title", { children: label }), _jsx("circle", { ...SOCIAL_FALLBACK_GLYPH.circle }), _jsx("path", { d: SOCIAL_FALLBACK_GLYPH.path })] }));
|
|
2397
2335
|
}
|
|
2398
2336
|
/**
|
|
2399
2337
|
* Render every social profile on the company as an icon + link, in canonical
|
|
@@ -2402,17 +2340,135 @@ function SocialGlyph({ iconSlug, color, size, className, label, }) {
|
|
|
2402
2340
|
* globe. Returns `null` when no socials are set.
|
|
2403
2341
|
*/
|
|
2404
2342
|
export function SocialLinks({ socials, color, size = 20, className, linkClassName, iconClassName, }) {
|
|
2405
|
-
|
|
2343
|
+
// Rows, URLs and icon URLs come from `social-core`, shared with every other
|
|
2344
|
+
// binding — only the markup below is React's.
|
|
2345
|
+
const rows = resolveSocialLinks(socials, { color });
|
|
2406
2346
|
if (rows.length === 0)
|
|
2407
2347
|
return null;
|
|
2408
|
-
return (_jsx("ul", { className: className, style: {
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2348
|
+
return (_jsx("ul", { className: className, style: SOCIAL_LIST_STYLE, children: rows.map((row) => (_jsx("li", { children: _jsx("a", { "aria-label": row.label, className: linkClassName, href: row.url, rel: "noopener noreferrer", target: "_blank", title: row.label, children: _jsx(SocialGlyph, { className: iconClassName, iconUrl: row.iconUrl, label: row.label, size: size }) }) }, row.key))) }));
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Headless blog for React — the native alternative to `<Blog>`, which is a
|
|
2352
|
+
* hosted page in an iframe. Posts, taxonomy, a single post, comments and likes
|
|
2353
|
+
* as data; the layout and the URLs are yours.
|
|
2354
|
+
*
|
|
2355
|
+
* ```tsx
|
|
2356
|
+
* const blog = useBlog({ apiKey, baseUrl });
|
|
2357
|
+
* return blog.posts.map((p) => <MyCard key={p.slug} post={p} />);
|
|
2358
|
+
* ```
|
|
2359
|
+
*/
|
|
2360
|
+
export function useBlog(options) {
|
|
2361
|
+
const { apiKey, baseUrl, pageSize, categoryId } = options;
|
|
2362
|
+
const controller = useMemo(() => createBlogController({
|
|
2363
|
+
client: new BiabDevClient({ apiKey, baseUrl }),
|
|
2364
|
+
...(pageSize ? { pageSize } : {}),
|
|
2365
|
+
...(categoryId ? { categoryId } : {}),
|
|
2366
|
+
}), [apiKey, baseUrl, pageSize, categoryId]);
|
|
2367
|
+
useEffect(() => {
|
|
2368
|
+
void controller.load();
|
|
2369
|
+
return () => controller.destroy();
|
|
2370
|
+
}, [controller]);
|
|
2371
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
2372
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
2373
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
2374
|
+
return {
|
|
2375
|
+
...snap,
|
|
2376
|
+
loadMore: controller.loadMore,
|
|
2377
|
+
filterByCategory: controller.filterByCategory,
|
|
2378
|
+
openPost: controller.openPost,
|
|
2379
|
+
closePost: controller.closePost,
|
|
2380
|
+
loadComments: controller.loadComments,
|
|
2381
|
+
loadMoreComments: controller.loadMoreComments,
|
|
2382
|
+
postComment: controller.postComment,
|
|
2383
|
+
toggleLike: controller.toggleLike,
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* Headless email / phone verification for React.
|
|
2388
|
+
*
|
|
2389
|
+
* Read `flow` before rendering: `otp` wants a code field, `link` wants a
|
|
2390
|
+
* "check your email" message and no field at all.
|
|
2391
|
+
*/
|
|
2392
|
+
export function useVerify(options) {
|
|
2393
|
+
const { apiKey, baseUrl, kind, resendCooldownSeconds } = options;
|
|
2394
|
+
const controller = useMemo(() => createVerifyController({
|
|
2395
|
+
client: new BiabDevClient({ apiKey, baseUrl }),
|
|
2396
|
+
kind,
|
|
2397
|
+
...(resendCooldownSeconds ? { resendCooldownSeconds } : {}),
|
|
2398
|
+
}), [apiKey, baseUrl, kind, resendCooldownSeconds]);
|
|
2399
|
+
useEffect(() => () => controller.destroy(), [controller]);
|
|
2400
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
2401
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
2402
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
2403
|
+
return {
|
|
2404
|
+
...snap,
|
|
2405
|
+
start: controller.start,
|
|
2406
|
+
resend: controller.resend,
|
|
2407
|
+
confirm: controller.confirm,
|
|
2408
|
+
canResend: controller.canResend,
|
|
2409
|
+
reset: controller.reset,
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
/**
|
|
2413
|
+
* The signed-in customer's portal for React — work, quotes, contracts,
|
|
2414
|
+
* invoices, orders, downloads, shipping, reviews, referrals, profile and
|
|
2415
|
+
* notification settings. The native alternative to `<Dashboard>`, which is a
|
|
2416
|
+
* hosted page in an iframe.
|
|
2417
|
+
*
|
|
2418
|
+
* `sessionToken` is required: every portal route is scoped to the signed-in
|
|
2419
|
+
* customer, and without one the portal renders empty rather than signed-out.
|
|
2420
|
+
*
|
|
2421
|
+
* Two things the API imposes and this hook does not hide. There are no list
|
|
2422
|
+
* endpoints for invoices, quotes, contracts or shipments — `work` carries the
|
|
2423
|
+
* counts and you open each by id. And a submitted review is queued for staff
|
|
2424
|
+
* approval, so it will NOT appear in `reviews`; watch `reviewAwaitingModeration`
|
|
2425
|
+
* to tell the customer it is pending rather than live.
|
|
2426
|
+
*/
|
|
2427
|
+
export function usePortal(options) {
|
|
2428
|
+
const { apiKey, baseUrl, sessionToken } = options;
|
|
2429
|
+
const controller = useMemo(() => createPortalController({
|
|
2430
|
+
client: new BiabDevClient({ apiKey, baseUrl }),
|
|
2431
|
+
sessionToken,
|
|
2432
|
+
}), [apiKey, baseUrl, sessionToken]);
|
|
2433
|
+
useEffect(() => {
|
|
2434
|
+
void controller.load();
|
|
2435
|
+
return () => controller.destroy();
|
|
2436
|
+
}, [controller]);
|
|
2437
|
+
const subscribe = useCallback((onStoreChange) => controller.subscribe(() => onStoreChange()), [controller]);
|
|
2438
|
+
const getSnapshot = useCallback(() => controller.snapshot(), [controller]);
|
|
2439
|
+
const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
2440
|
+
return {
|
|
2441
|
+
...snap,
|
|
2442
|
+
loadOrders: controller.loadOrders,
|
|
2443
|
+
loadInvoices: controller.loadInvoices,
|
|
2444
|
+
loadQuotes: controller.loadQuotes,
|
|
2445
|
+
loadContracts: controller.loadContracts,
|
|
2446
|
+
loadShipments: controller.loadShipments,
|
|
2447
|
+
loadMessages: controller.loadMessages,
|
|
2448
|
+
postMessage: controller.postMessage,
|
|
2449
|
+
markMessagesRead: controller.markMessagesRead,
|
|
2450
|
+
loadPayments: controller.loadPayments,
|
|
2451
|
+
loadReviews: controller.loadReviews,
|
|
2452
|
+
loadReferrals: controller.loadReferrals,
|
|
2453
|
+
loadNotificationPreferences: controller.loadNotificationPreferences,
|
|
2454
|
+
loadOtherOrgs: controller.loadOtherOrgs,
|
|
2455
|
+
openJob: controller.openJob,
|
|
2456
|
+
openOrder: controller.openOrder,
|
|
2457
|
+
openInvoice: controller.openInvoice,
|
|
2458
|
+
openQuote: controller.openQuote,
|
|
2459
|
+
openContract: controller.openContract,
|
|
2460
|
+
trackShipment: controller.trackShipment,
|
|
2461
|
+
closeDetail: controller.closeDetail,
|
|
2462
|
+
postJobComment: controller.postJobComment,
|
|
2463
|
+
acceptQuote: controller.acceptQuote,
|
|
2464
|
+
rejectQuote: controller.rejectQuote,
|
|
2465
|
+
signContract: controller.signContract,
|
|
2466
|
+
payInvoice: controller.payInvoice,
|
|
2467
|
+
updateProfile: controller.updateProfile,
|
|
2468
|
+
updateNotificationPreferences: controller.updateNotificationPreferences,
|
|
2469
|
+
submitReview: controller.submitReview,
|
|
2470
|
+
submitReturnRequest: controller.submitReturnRequest,
|
|
2471
|
+
contactCompany: controller.contactCompany,
|
|
2472
|
+
};
|
|
2417
2473
|
}
|
|
2418
2474
|
//# sourceMappingURL=react.js.map
|