@sevenfold/setto-client 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/preview-bar.d.ts +29 -0
- package/dist/setto-client.js +175 -1
- package/dist/setto-client.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { SettoProvider, useSetto } from './provider';
|
|
2
2
|
export { GuestEditProvider, useGuestEdit } from './guest-edit';
|
|
3
|
+
export { SettoPreviewBar, isPreviewHost } from './preview-bar';
|
|
3
4
|
export { T } from './T';
|
|
4
5
|
export { SettoSection } from './SettoSection';
|
|
5
6
|
export { SettoBlock } from './SettoBlock';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** True when this page is served from a Setto preview address. */
|
|
2
|
+
export declare function isPreviewHost(hostname: string): boolean;
|
|
3
|
+
export type PreviewBarState = 'hidden' | 'owner' | 'visitor';
|
|
4
|
+
/**
|
|
5
|
+
* Whether the bar shows at all, and as whom.
|
|
6
|
+
*
|
|
7
|
+
* Pulled out of the component because the interesting failures are all in this
|
|
8
|
+
* decision and none of them are visual: showing «Publiser» to somebody who has
|
|
9
|
+
* already paid, showing «Forhåndsvisning» on a site that has been bought, or
|
|
10
|
+
* flashing either one during the round trip that would have said otherwise.
|
|
11
|
+
*
|
|
12
|
+
* Unknown is a state, not a default. Both `sitesLoaded` and `soldPublic` start
|
|
13
|
+
* out unresolved, and every unresolved input means `hidden` — the bar arrives
|
|
14
|
+
* a moment late rather than asserting something it has to take back.
|
|
15
|
+
*/
|
|
16
|
+
export declare function previewBarState(input: {
|
|
17
|
+
onPreview: boolean;
|
|
18
|
+
authLoading: boolean;
|
|
19
|
+
hasSession: boolean;
|
|
20
|
+
/** `sites !== null` — whether this account's site list has come back. */
|
|
21
|
+
sitesLoaded: boolean;
|
|
22
|
+
hasCurrentSite: boolean;
|
|
23
|
+
currentSiteIsLive: boolean;
|
|
24
|
+
/** The public answer, null until it arrives or if it never does. */
|
|
25
|
+
soldPublic: boolean | null;
|
|
26
|
+
/** Stripe's own `?betaling=ok`, which lands before the webhook does. */
|
|
27
|
+
paidMarker: boolean;
|
|
28
|
+
}): PreviewBarState;
|
|
29
|
+
export declare function SettoPreviewBar(): import("react").ReactPortal | null;
|
package/dist/setto-client.js
CHANGED
|
@@ -21358,6 +21358,175 @@ function useSiteAccess(supabase, session, siteId) {
|
|
|
21358
21358
|
}, [supabase, session, siteId]);
|
|
21359
21359
|
return state;
|
|
21360
21360
|
}
|
|
21361
|
+
const PREVIEW_HOST = /(^|\.)site\.setto\.no$/i;
|
|
21362
|
+
function isPreviewHost(hostname) {
|
|
21363
|
+
return PREVIEW_HOST.test(hostname);
|
|
21364
|
+
}
|
|
21365
|
+
function previewBarState(input) {
|
|
21366
|
+
if (!input.onPreview || input.authLoading) return "hidden";
|
|
21367
|
+
if (input.hasSession && !input.sitesLoaded) return "hidden";
|
|
21368
|
+
if (!input.hasSession && input.soldPublic === null) return "hidden";
|
|
21369
|
+
const bought = input.paidMarker || input.currentSiteIsLive || input.soldPublic === true;
|
|
21370
|
+
if (bought) return "hidden";
|
|
21371
|
+
return input.hasSession && input.hasCurrentSite ? "owner" : "visitor";
|
|
21372
|
+
}
|
|
21373
|
+
function SettoPreviewBar() {
|
|
21374
|
+
const { supabase, api, config, session, authLoading, currentSite, sites, editMode } = useSetto();
|
|
21375
|
+
const [onPreview, setOnPreview] = useState(false);
|
|
21376
|
+
const [busy, setBusy] = useState(false);
|
|
21377
|
+
const [error, setError] = useState(null);
|
|
21378
|
+
const [paid, setPaid] = useState(false);
|
|
21379
|
+
const [soldPublic, setSoldPublic] = useState(null);
|
|
21380
|
+
useEffect(() => {
|
|
21381
|
+
setOnPreview(isPreviewHost(window.location.hostname));
|
|
21382
|
+
setPaid(new URLSearchParams(window.location.search).get("betaling") === "ok");
|
|
21383
|
+
}, []);
|
|
21384
|
+
useEffect(() => {
|
|
21385
|
+
if (!onPreview || session) return;
|
|
21386
|
+
let cancelled = false;
|
|
21387
|
+
api.request(`/onboarding/sites/${config.siteId}/sold`, {}, "siteSold").then((d) => {
|
|
21388
|
+
if (!cancelled) setSoldPublic(d.sold === true);
|
|
21389
|
+
}).catch(() => {
|
|
21390
|
+
if (!cancelled) setSoldPublic(null);
|
|
21391
|
+
});
|
|
21392
|
+
return () => {
|
|
21393
|
+
cancelled = true;
|
|
21394
|
+
};
|
|
21395
|
+
}, [onPreview, session, api, config.siteId]);
|
|
21396
|
+
const state = previewBarState({
|
|
21397
|
+
onPreview,
|
|
21398
|
+
authLoading,
|
|
21399
|
+
hasSession: !!session,
|
|
21400
|
+
sitesLoaded: sites !== null,
|
|
21401
|
+
hasCurrentSite: !!currentSite,
|
|
21402
|
+
currentSiteIsLive: currentSite?.status === "live",
|
|
21403
|
+
soldPublic,
|
|
21404
|
+
paidMarker: paid
|
|
21405
|
+
});
|
|
21406
|
+
if (state === "hidden") return null;
|
|
21407
|
+
const owner = state === "owner";
|
|
21408
|
+
const name = currentSite?.display_name?.trim() || config.displayName?.trim() || config.siteId;
|
|
21409
|
+
const signIn = () => {
|
|
21410
|
+
window.location.href = "/setto";
|
|
21411
|
+
};
|
|
21412
|
+
const publish = async () => {
|
|
21413
|
+
setBusy(true);
|
|
21414
|
+
setError(null);
|
|
21415
|
+
try {
|
|
21416
|
+
const token = (await supabase.auth.getSession()).data.session?.access_token;
|
|
21417
|
+
if (!token) {
|
|
21418
|
+
signIn();
|
|
21419
|
+
return;
|
|
21420
|
+
}
|
|
21421
|
+
const data = await api.request(
|
|
21422
|
+
`/onboarding/sites/${config.siteId}/checkout`,
|
|
21423
|
+
{
|
|
21424
|
+
method: "POST",
|
|
21425
|
+
// Back to the page they were looking at, not to a chat window.
|
|
21426
|
+
body: { returnTo: window.location.origin + window.location.pathname }
|
|
21427
|
+
},
|
|
21428
|
+
"checkout"
|
|
21429
|
+
);
|
|
21430
|
+
if (!data.url) throw new Error("checkout_failed");
|
|
21431
|
+
window.location.href = data.url;
|
|
21432
|
+
} catch (err) {
|
|
21433
|
+
const detail = err instanceof Error ? err.message : "";
|
|
21434
|
+
setError(
|
|
21435
|
+
detail.includes("already_paid") ? "Denne siden er allerede betalt." : detail.includes("not_found") ? "Fant ingen bestilling for denne siden på kontoen din." : detail.includes("stripe_not_configured") ? "Betaling er ikke satt opp ennå." : "Klarte ikke starte betalingen. Prøv igjen."
|
|
21436
|
+
);
|
|
21437
|
+
setBusy(false);
|
|
21438
|
+
}
|
|
21439
|
+
};
|
|
21440
|
+
return createPortal(
|
|
21441
|
+
/*
|
|
21442
|
+
* Lifted above the editor's floating button when edit mode is on, which
|
|
21443
|
+
* sits in the same corner band. Sideways would collide again the moment
|
|
21444
|
+
* its toolbar opens, since that expands rightward.
|
|
21445
|
+
*/
|
|
21446
|
+
/* @__PURE__ */ jsx(
|
|
21447
|
+
"div",
|
|
21448
|
+
{
|
|
21449
|
+
style: editMode ? { ...barStyle, bottom: "calc(max(16px, env(safe-area-inset-bottom, 0px)) + 68px)" } : barStyle,
|
|
21450
|
+
"data-setto-preview-bar": "",
|
|
21451
|
+
children: owner ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21452
|
+
/* @__PURE__ */ jsx("span", { style: dotStyle, "aria-hidden": true }),
|
|
21453
|
+
/* @__PURE__ */ jsxs("span", { style: labelStyle, children: [
|
|
21454
|
+
"Du forhåndsviser nå ",
|
|
21455
|
+
/* @__PURE__ */ jsx("strong", { style: { fontWeight: 600 }, children: name })
|
|
21456
|
+
] }),
|
|
21457
|
+
error && /* @__PURE__ */ jsx("span", { style: errorStyle$1, children: error }),
|
|
21458
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: primaryStyle, onClick: publish, disabled: busy, children: busy ? "Åpner betaling …" : "Publiser" })
|
|
21459
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21460
|
+
/* @__PURE__ */ jsx("span", { style: dotStyle, "aria-hidden": true }),
|
|
21461
|
+
/* @__PURE__ */ jsxs("span", { style: labelStyle, children: [
|
|
21462
|
+
"Forhåndsvisning av ",
|
|
21463
|
+
name
|
|
21464
|
+
] }),
|
|
21465
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: primaryStyle, onClick: signIn, children: "Rediger" })
|
|
21466
|
+
] })
|
|
21467
|
+
}
|
|
21468
|
+
),
|
|
21469
|
+
document.body
|
|
21470
|
+
);
|
|
21471
|
+
}
|
|
21472
|
+
const barStyle = {
|
|
21473
|
+
position: "fixed",
|
|
21474
|
+
left: "50%",
|
|
21475
|
+
bottom: "max(16px, env(safe-area-inset-bottom, 0px))",
|
|
21476
|
+
transform: "translateX(-50%)",
|
|
21477
|
+
zIndex: 2147483e3,
|
|
21478
|
+
display: "flex",
|
|
21479
|
+
alignItems: "center",
|
|
21480
|
+
gap: 14,
|
|
21481
|
+
maxWidth: "calc(100vw - 24px)",
|
|
21482
|
+
padding: "10px 10px 10px 18px",
|
|
21483
|
+
borderRadius: 999,
|
|
21484
|
+
background: "#211711",
|
|
21485
|
+
color: "#fffdf8",
|
|
21486
|
+
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
21487
|
+
fontSize: 14,
|
|
21488
|
+
lineHeight: 1.3,
|
|
21489
|
+
boxShadow: "0 18px 40px -18px rgba(0, 0, 0, 0.65)"
|
|
21490
|
+
};
|
|
21491
|
+
const dotStyle = {
|
|
21492
|
+
width: 7,
|
|
21493
|
+
height: 7,
|
|
21494
|
+
borderRadius: "50%",
|
|
21495
|
+
background: "#c4502a",
|
|
21496
|
+
flex: "none"
|
|
21497
|
+
};
|
|
21498
|
+
const labelStyle = {
|
|
21499
|
+
whiteSpace: "nowrap",
|
|
21500
|
+
overflow: "hidden",
|
|
21501
|
+
textOverflow: "ellipsis"
|
|
21502
|
+
};
|
|
21503
|
+
const primaryStyle = {
|
|
21504
|
+
flex: "none",
|
|
21505
|
+
padding: "9px 18px",
|
|
21506
|
+
border: 0,
|
|
21507
|
+
borderRadius: 999,
|
|
21508
|
+
background: "#c4502a",
|
|
21509
|
+
color: "#fffdf8",
|
|
21510
|
+
font: "inherit",
|
|
21511
|
+
fontWeight: 600,
|
|
21512
|
+
cursor: "pointer"
|
|
21513
|
+
};
|
|
21514
|
+
const errorStyle$1 = {
|
|
21515
|
+
color: "#ffb4a2",
|
|
21516
|
+
fontSize: 13,
|
|
21517
|
+
/*
|
|
21518
|
+
* Shrinkable, unlike the label beside it.
|
|
21519
|
+
*
|
|
21520
|
+
* `nowrap` on a flex child whose `min-width` is `auto` cannot shrink below
|
|
21521
|
+
* its own text, so on a 320px phone the error shouldered «Publiser» 19px
|
|
21522
|
+
* past the right edge of the screen and the bar clipped it — the button
|
|
21523
|
+
* that takes the money, unreachable, exactly when something had gone wrong.
|
|
21524
|
+
*/
|
|
21525
|
+
minWidth: 0,
|
|
21526
|
+
overflow: "hidden",
|
|
21527
|
+
textOverflow: "ellipsis",
|
|
21528
|
+
whiteSpace: "nowrap"
|
|
21529
|
+
};
|
|
21361
21530
|
const SETTO_BASE = "/setto";
|
|
21362
21531
|
function siteHomeUrl(pathname = "/") {
|
|
21363
21532
|
const u = new URL(window.location.href);
|
|
@@ -24872,7 +25041,10 @@ function SettoProvider({ config, children }) {
|
|
|
24872
25041
|
assetStore: storeReady ? assetStoreRef.current : null
|
|
24873
25042
|
};
|
|
24874
25043
|
const editShellActive = editMode && !!value.store;
|
|
24875
|
-
return /* @__PURE__ */ jsx(SettoContext.Provider, { value, children: /* @__PURE__ */
|
|
25044
|
+
return /* @__PURE__ */ jsx(SettoContext.Provider, { value, children: /* @__PURE__ */ jsxs(SectionEditProvider, { children: [
|
|
25045
|
+
/* @__PURE__ */ jsx(EditModeShell, { active: editShellActive, themeStore: value.themeStore, children }),
|
|
25046
|
+
!onAdminRoute && /* @__PURE__ */ jsx(SettoPreviewBar, {})
|
|
25047
|
+
] }) });
|
|
24876
25048
|
}
|
|
24877
25049
|
function useSetto() {
|
|
24878
25050
|
const ctx = useContext(SettoContext);
|
|
@@ -26643,6 +26815,7 @@ export {
|
|
|
26643
26815
|
SettoForm,
|
|
26644
26816
|
SettoIcon,
|
|
26645
26817
|
SettoImage,
|
|
26818
|
+
SettoPreviewBar,
|
|
26646
26819
|
SettoProvider,
|
|
26647
26820
|
SettoRepeater,
|
|
26648
26821
|
SettoSection,
|
|
@@ -26652,6 +26825,7 @@ export {
|
|
|
26652
26825
|
extractContentKeys,
|
|
26653
26826
|
formFieldsPrefix,
|
|
26654
26827
|
isFormFieldType,
|
|
26828
|
+
isPreviewHost,
|
|
26655
26829
|
nodeChildren,
|
|
26656
26830
|
parseBlockTree,
|
|
26657
26831
|
readLocaleFields,
|