@sevenfold/setto-client 0.2.0 → 0.2.2
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/admin/App.d.ts +4 -5
- package/dist/lib/urls.d.ts +6 -0
- package/dist/setto-client.js +95 -16
- package/dist/setto-client.js.map +1 -1
- package/package.json +1 -1
package/dist/admin/App.d.ts
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* Drop-in admin SPA. Mount under a route like `<Route path="/admin/*" .../>`.
|
|
3
3
|
*
|
|
4
4
|
* Behaviour after login:
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
5
|
+
* - Redirects to `/?setto=edit` on the site home (edit mode active).
|
|
6
|
+
* - Shows the dashboard only when the user lacks access to this site, or on
|
|
7
|
+
* `/admin?deployment=…` for publish progress / history.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* Editing happens on the public site at `/?setto=edit` via "Begynn å redigere".
|
|
9
|
+
* Editing happens on the public site at `/?setto=edit`.
|
|
11
10
|
*/
|
|
12
11
|
export declare function SettoAdminApp(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Site home with inline edit mode active. */
|
|
2
|
+
export declare function editModeUrl(pathname?: string): string;
|
|
3
|
+
export declare function isAdminRoute(): boolean;
|
|
4
|
+
/** Admin deployment progress panel (`/admin?deployment=…`). */
|
|
5
|
+
export declare function isAdminDeploymentView(): boolean;
|
|
6
|
+
export declare function adminRedirectUrl(): string;
|
package/dist/setto-client.js
CHANGED
|
@@ -22643,19 +22643,41 @@ const SettoBlock = forwardRef(
|
|
|
22643
22643
|
);
|
|
22644
22644
|
}
|
|
22645
22645
|
);
|
|
22646
|
+
function editModeUrl(pathname = "/") {
|
|
22647
|
+
const u = new URL(window.location.href);
|
|
22648
|
+
u.pathname = pathname;
|
|
22649
|
+
u.search = "";
|
|
22650
|
+
u.searchParams.set("setto", "edit");
|
|
22651
|
+
return u.toString();
|
|
22652
|
+
}
|
|
22653
|
+
function isAdminRoute() {
|
|
22654
|
+
return window.location.pathname.startsWith("/admin");
|
|
22655
|
+
}
|
|
22656
|
+
function isAdminDeploymentView() {
|
|
22657
|
+
return isAdminRoute() && new URLSearchParams(window.location.search).has("deployment");
|
|
22658
|
+
}
|
|
22646
22659
|
function adminRedirectUrl() {
|
|
22647
22660
|
return `${window.location.origin}/admin`;
|
|
22648
22661
|
}
|
|
22649
22662
|
function authCallbackType() {
|
|
22650
22663
|
const hash = window.location.hash.replace(/^#/, "");
|
|
22651
|
-
if (
|
|
22652
|
-
|
|
22653
|
-
|
|
22664
|
+
if (hash) {
|
|
22665
|
+
const type = new URLSearchParams(hash).get("type");
|
|
22666
|
+
if (type === "invite" || type === "recovery") return type;
|
|
22667
|
+
}
|
|
22668
|
+
const queryType = new URLSearchParams(window.location.search).get("type");
|
|
22669
|
+
if (queryType === "invite" || queryType === "recovery") return queryType;
|
|
22654
22670
|
return null;
|
|
22655
22671
|
}
|
|
22656
|
-
function
|
|
22657
|
-
|
|
22658
|
-
|
|
22672
|
+
function inviteTokenHashFromUrl() {
|
|
22673
|
+
return new URLSearchParams(window.location.search).get("token_hash");
|
|
22674
|
+
}
|
|
22675
|
+
function clearAuthParamsFromUrl() {
|
|
22676
|
+
const url = new URL(window.location.href);
|
|
22677
|
+
url.hash = "";
|
|
22678
|
+
url.searchParams.delete("token_hash");
|
|
22679
|
+
url.searchParams.delete("type");
|
|
22680
|
+
window.history.replaceState(null, "", `${url.pathname}${url.search}`);
|
|
22659
22681
|
}
|
|
22660
22682
|
function AuthGate({ children }) {
|
|
22661
22683
|
const { supabase, session, authLoading } = useSetto();
|
|
@@ -22666,16 +22688,38 @@ function AuthGate({ children }) {
|
|
|
22666
22688
|
const [error, setError] = useState(null);
|
|
22667
22689
|
const [info, setInfo] = useState(null);
|
|
22668
22690
|
const [busy, setBusy] = useState(false);
|
|
22691
|
+
const [activatingInvite, setActivatingInvite] = useState(false);
|
|
22669
22692
|
useEffect(() => {
|
|
22670
|
-
const
|
|
22671
|
-
|
|
22672
|
-
|
|
22693
|
+
const tokenHash = inviteTokenHashFromUrl();
|
|
22694
|
+
const callbackType = authCallbackType();
|
|
22695
|
+
if (!tokenHash || !callbackType) {
|
|
22696
|
+
if (callbackType) setMode("set_password");
|
|
22697
|
+
return;
|
|
22698
|
+
}
|
|
22699
|
+
let cancelled = false;
|
|
22700
|
+
setActivatingInvite(true);
|
|
22701
|
+
void supabase.auth.verifyOtp({ token_hash: tokenHash, type: callbackType }).then(({ error: verifyError }) => {
|
|
22702
|
+
if (cancelled) return;
|
|
22703
|
+
clearAuthParamsFromUrl();
|
|
22704
|
+
if (verifyError) {
|
|
22705
|
+
setError(verifyError.message);
|
|
22706
|
+
setMode("signin");
|
|
22707
|
+
return;
|
|
22708
|
+
}
|
|
22709
|
+
setMode("set_password");
|
|
22710
|
+
}).finally(() => {
|
|
22711
|
+
if (!cancelled) setActivatingInvite(false);
|
|
22712
|
+
});
|
|
22713
|
+
return () => {
|
|
22714
|
+
cancelled = true;
|
|
22715
|
+
};
|
|
22716
|
+
}, [supabase]);
|
|
22673
22717
|
if (authLoading) {
|
|
22674
22718
|
return /* @__PURE__ */ jsx("div", { style: loadingStyle, children: "Laster …" });
|
|
22675
22719
|
}
|
|
22676
22720
|
if (session && mode !== "set_password") return /* @__PURE__ */ jsx(Fragment, { children });
|
|
22677
|
-
if (mode === "set_password" && !session) {
|
|
22678
|
-
return /* @__PURE__ */ jsx("div", { style: loadingStyle, children: authCallbackType() ? "Aktiverer invitasjon …" : "Åpne lenken fra e-posten for å sette passord." });
|
|
22721
|
+
if (mode === "set_password" && !session || activatingInvite) {
|
|
22722
|
+
return /* @__PURE__ */ jsx("div", { style: loadingStyle, children: activatingInvite || authCallbackType() ? "Aktiverer invitasjon …" : "Åpne lenken fra e-posten for å sette passord." });
|
|
22679
22723
|
}
|
|
22680
22724
|
const submitSignIn = async (e) => {
|
|
22681
22725
|
e.preventDefault();
|
|
@@ -22730,7 +22774,12 @@ function AuthGate({ children }) {
|
|
|
22730
22774
|
try {
|
|
22731
22775
|
const { error: updateError } = await supabase.auth.updateUser({ password });
|
|
22732
22776
|
if (updateError) throw updateError;
|
|
22733
|
-
|
|
22777
|
+
clearAuthParamsFromUrl();
|
|
22778
|
+
const { data: sessionData } = await supabase.auth.getSession();
|
|
22779
|
+
if (sessionData.session) {
|
|
22780
|
+
window.location.replace(editModeUrl());
|
|
22781
|
+
return;
|
|
22782
|
+
}
|
|
22734
22783
|
setMode("signin");
|
|
22735
22784
|
setPassword("");
|
|
22736
22785
|
setConfirmPassword("");
|
|
@@ -22921,6 +22970,15 @@ function SiteList() {
|
|
|
22921
22970
|
const { supabase, session, config } = useSetto();
|
|
22922
22971
|
const [sites, setSites] = useState(null);
|
|
22923
22972
|
const [error, setError] = useState(null);
|
|
22973
|
+
const redirectAfterSignIn = useRef(false);
|
|
22974
|
+
useEffect(() => {
|
|
22975
|
+
const { data: sub } = supabase.auth.onAuthStateChange((event) => {
|
|
22976
|
+
if (event === "SIGNED_IN" && !isAdminDeploymentView()) {
|
|
22977
|
+
redirectAfterSignIn.current = true;
|
|
22978
|
+
}
|
|
22979
|
+
});
|
|
22980
|
+
return () => sub.subscription.unsubscribe();
|
|
22981
|
+
}, [supabase]);
|
|
22924
22982
|
useEffect(() => {
|
|
22925
22983
|
if (!session) return;
|
|
22926
22984
|
let cancelled = false;
|
|
@@ -22941,6 +22999,20 @@ function SiteList() {
|
|
|
22941
22999
|
() => sites?.find((s) => s.id === config.siteId) ?? null,
|
|
22942
23000
|
[sites, config.siteId]
|
|
22943
23001
|
);
|
|
23002
|
+
useEffect(() => {
|
|
23003
|
+
if (!redirectAfterSignIn.current || !session || sites === null || isAdminDeploymentView()) {
|
|
23004
|
+
return;
|
|
23005
|
+
}
|
|
23006
|
+
if (currentSite) {
|
|
23007
|
+
redirectAfterSignIn.current = false;
|
|
23008
|
+
window.location.replace(editModeUrl());
|
|
23009
|
+
return;
|
|
23010
|
+
}
|
|
23011
|
+
redirectAfterSignIn.current = false;
|
|
23012
|
+
}, [session, sites, currentSite]);
|
|
23013
|
+
if (redirectAfterSignIn.current && session && (sites === null || currentSite)) {
|
|
23014
|
+
return /* @__PURE__ */ jsx("div", { style: loadingRedirectStyle, children: "Åpner redigering …" });
|
|
23015
|
+
}
|
|
22944
23016
|
return /* @__PURE__ */ jsxs("div", { style: shellStyle, children: [
|
|
22945
23017
|
/* @__PURE__ */ jsxs("header", { style: headerStyle, children: [
|
|
22946
23018
|
/* @__PURE__ */ jsx("h1", { style: { margin: 0, fontSize: 22 }, children: "Setto" }),
|
|
@@ -23115,11 +23187,18 @@ function SignOutButton() {
|
|
|
23115
23187
|
return /* @__PURE__ */ jsx("button", { onClick: () => supabase.auth.signOut(), style: signOutBtnStyle, children: "Logg ut" });
|
|
23116
23188
|
}
|
|
23117
23189
|
function editUrl() {
|
|
23118
|
-
|
|
23119
|
-
u.pathname = "/";
|
|
23120
|
-
u.searchParams.set("setto", "edit");
|
|
23121
|
-
return u.toString();
|
|
23190
|
+
return editModeUrl("/");
|
|
23122
23191
|
}
|
|
23192
|
+
const loadingRedirectStyle = {
|
|
23193
|
+
minHeight: "100dvh",
|
|
23194
|
+
display: "flex",
|
|
23195
|
+
alignItems: "center",
|
|
23196
|
+
justifyContent: "center",
|
|
23197
|
+
background: "#0a0a0d",
|
|
23198
|
+
color: "#888",
|
|
23199
|
+
fontSize: 14,
|
|
23200
|
+
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif'
|
|
23201
|
+
};
|
|
23123
23202
|
const shellStyle = {
|
|
23124
23203
|
minHeight: "100dvh",
|
|
23125
23204
|
background: "#0a0a0d",
|