@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
291 lines (290 loc) • 11 kB
JavaScript
'use client';
import { jsx as t, jsxs as u } from "react/jsx-runtime";
import c from "react";
import { motion as L } from "framer-motion";
import { useOAuth as b } from "../../../hooks/use-oauth.js";
import { useMagicLink as E } from "../../../hooks/use-magic-link.js";
import { useOrganization as P } from "../../../hooks/use-organization.js";
import { LoadingSpinner as p } from "./loading-spinner.js";
import { ErrorBoundary as R } from "./error-boundary.js";
function S() {
return typeof window > "u" ? new URLSearchParams() : new URLSearchParams(window.location.search);
}
function A() {
if (typeof window > "u") return new URLSearchParams();
const e = window.location.hash;
return new URLSearchParams(e.startsWith("#") ? e.slice(1) : e);
}
function v() {
const e = S();
return A().forEach((a, n) => {
e.has(n) || e.set(n, a);
}), e;
}
function y() {
const e = v();
if (e.has("code") && e.has("state"))
return "oauth";
if (e.has("token") && e.has("type")) {
const o = e.get("type");
if (o === "magic_link" || o === "email_verification")
return "magic-link";
}
return e.has("invitation_token") || e.has("invite") ? "invitation" : e.has("verification_token") || e.has("verify") ? "verification" : e.has("error") || e.has("error_description") ? "error" : null;
}
function T({
onSuccess: e,
onError: o,
successUrl: a,
errorUrl: n
}) {
const { handleCallback: s } = b(), [f, h] = c.useState(!0), [d, l] = c.useState(null);
return c.useEffect(() => {
(async () => {
try {
const r = v(), i = r.get("code"), x = r.get("state"), k = r.get("provider") || "google", w = r.get("error");
if (w) {
const N = r.get("error_description") || "OAuth authentication failed";
throw new Error(`OAuth Error: ${w} - ${N}`);
}
if (!i)
throw new Error("No authorization code received from OAuth provider");
const m = await s(k, i, x);
if (m.success)
e?.(m), a ? window.location.href = a : (window.history.replaceState({}, document.title, window.location.pathname), window.location.href = "/dashboard");
else
throw new Error(m.error || "OAuth authentication failed");
} catch (r) {
const i = r instanceof Error ? r : new Error("OAuth processing failed");
l(i), o?.(i), n && setTimeout(() => {
window.location.href = n;
}, 3e3);
} finally {
h(!1);
}
})();
}, [s, e, o, a, n]), d ? /* @__PURE__ */ u("div", { className: "text-center", children: [
/* @__PURE__ */ u("div", { className: "text-danger-600 mb-4", children: [
/* @__PURE__ */ t("svg", { className: "w-12 h-12 mx-auto mb-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ t("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.732 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
/* @__PURE__ */ t("h3", { className: "text-lg font-semibold", children: "Authentication Failed" }),
/* @__PURE__ */ t("p", { className: "text-sm text-default-500 mt-2", children: d.message })
] }),
n && /* @__PURE__ */ t("p", { className: "text-xs text-default-400", children: "Redirecting to sign in page..." })
] }) : /* @__PURE__ */ t(
p,
{
variant: "spinner",
size: "lg",
showText: !0,
text: "Completing sign in...",
centered: !0
}
);
}
function _({
onSuccess: e,
onError: o,
successUrl: a,
errorUrl: n
}) {
const { verifyFromUrl: s } = E(), [f, h] = c.useState(!0), [d, l] = c.useState(null);
return c.useEffect(() => {
(async () => {
try {
const r = await s();
if (r.success) {
if (e?.(r), r.requiresAdditionalVerification) {
const i = new URLSearchParams();
i.set("mfa_token", r.mfaToken || ""), window.location.href = `/auth/mfa?${i.toString()}`;
return;
}
a ? window.location.href = a : (window.history.replaceState({}, document.title, window.location.pathname), window.location.href = "/dashboard");
} else
throw new Error(r.error || "Magic link verification failed");
} catch (r) {
const i = r instanceof Error ? r : new Error("Magic link processing failed");
l(i), o?.(i), n && setTimeout(() => {
window.location.href = n;
}, 3e3);
} finally {
h(!1);
}
})();
}, [s, e, o, a, n]), d ? /* @__PURE__ */ u("div", { className: "text-center", children: [
/* @__PURE__ */ u("div", { className: "text-danger-600 mb-4", children: [
/* @__PURE__ */ t("svg", { className: "w-12 h-12 mx-auto mb-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ t("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.732 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
/* @__PURE__ */ t("h3", { className: "text-lg font-semibold", children: "Verification Failed" }),
/* @__PURE__ */ t("p", { className: "text-sm text-default-500 mt-2", children: d.message })
] }),
n && /* @__PURE__ */ t("p", { className: "text-xs text-default-400", children: "Redirecting to sign in page..." })
] }) : /* @__PURE__ */ t(
p,
{
variant: "pulse",
size: "lg",
showText: !0,
text: "Verifying magic link...",
centered: !0
}
);
}
function M({
onSuccess: e,
onError: o,
successUrl: a,
errorUrl: n
}) {
const { acceptInvitation: s } = P(), [f, h] = c.useState(!0), [d, l] = c.useState(null);
return c.useEffect(() => {
(async () => {
try {
const r = v(), i = r.get("invitation_token") || r.get("invite");
if (!i)
throw new Error("No invitation token found");
await s(i), e?.({ invitationToken: i }), a ? window.location.href = a : (window.history.replaceState({}, document.title, window.location.pathname), window.location.href = "/dashboard");
} catch (r) {
const i = r instanceof Error ? r : new Error("Invitation processing failed");
l(i), o?.(i), n && setTimeout(() => {
window.location.href = n;
}, 3e3);
} finally {
h(!1);
}
})();
}, [s, e, o, a, n]), d ? /* @__PURE__ */ u("div", { className: "text-center", children: [
/* @__PURE__ */ u("div", { className: "text-danger-600 mb-4", children: [
/* @__PURE__ */ t("svg", { className: "w-12 h-12 mx-auto mb-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ t("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.732 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
/* @__PURE__ */ t("h3", { className: "text-lg font-semibold", children: "Invitation Failed" }),
/* @__PURE__ */ t("p", { className: "text-sm text-default-500 mt-2", children: d.message })
] }),
n && /* @__PURE__ */ t("p", { className: "text-xs text-default-400", children: "Redirecting to sign in page..." })
] }) : /* @__PURE__ */ t(
p,
{
variant: "dots",
size: "lg",
showText: !0,
text: "Processing invitation...",
centered: !0
}
);
}
function O({
type: e = "auto",
successUrl: o,
errorUrl: a,
onSuccess: n,
onError: s,
loadingComponent: f,
errorComponent: h,
showLoading: d = !0,
loadingText: l = "Processing...",
className: g = "",
children: r
}) {
const i = e === "auto" ? y() : e;
if (!i && !r)
return null;
if (r)
return /* @__PURE__ */ t("div", { className: g, children: r });
const x = d ? f || /* @__PURE__ */ t("div", { className: "flex items-center justify-center min-h-64", children: /* @__PURE__ */ t(
p,
{
variant: "spinner",
size: "lg",
showText: !0,
text: l,
centered: !0
}
) }) : null, k = () => {
switch (i) {
case "oauth":
return /* @__PURE__ */ t(
T,
{
onSuccess: n,
onError: s,
successUrl: o,
errorUrl: a
}
);
case "magic-link":
return /* @__PURE__ */ t(
_,
{
onSuccess: n,
onError: s,
successUrl: o,
errorUrl: a
}
);
case "invitation":
return /* @__PURE__ */ t(
M,
{
onSuccess: n,
onError: s,
successUrl: o,
errorUrl: a
}
);
case "error":
const w = v(), m = w.get("error_description") || w.get("error") || "An error occurred", N = new Error(m);
return h ? /* @__PURE__ */ t(h, { error: N, retry: () => window.location.reload() }) : /* @__PURE__ */ u("div", { className: "text-center", children: [
/* @__PURE__ */ u("div", { className: "text-danger-600 mb-4", children: [
/* @__PURE__ */ t("svg", { className: "w-12 h-12 mx-auto mb-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ t("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.732 16.5c-.77.833.192 2.5 1.732 2.5z" }) }),
/* @__PURE__ */ t("h3", { className: "text-lg font-semibold", children: "Authentication Error" }),
/* @__PURE__ */ t("p", { className: "text-sm text-default-500 mt-2", children: m })
] }),
a && /* @__PURE__ */ t("p", { className: "text-xs text-default-400", children: "Redirecting to sign in page..." })
] });
default:
return x;
}
};
return /* @__PURE__ */ t(
L.div,
{
initial: { opacity: 0 },
animate: { opacity: 1 },
className: `${g}`,
children: /* @__PURE__ */ t(
R,
{
title: "Redirect Processing Error",
subtitle: "There was a problem processing the authentication redirect.",
onError: s,
showDetails: process.env.NODE_ENV === "development",
children: k()
}
)
}
);
}
function V() {
const [e, o] = c.useState(null), [a, n] = c.useState(!1), [s, f] = c.useState(null);
c.useEffect(() => {
const l = y();
o(l), n(!!l);
}, []);
const h = c.useCallback((l) => {
n(!1), f(null);
}, []), d = c.useCallback((l) => {
n(!1), f(l);
}, []);
return {
redirectType: e,
isProcessing: a,
error: s,
handleSuccess: h,
handleError: d,
hasRedirect: !!e
};
}
var $ = O;
export {
O as RedirectHandler,
$ as default,
V as useRedirectHandler
};
//# sourceMappingURL=redirect-handler.js.map