Files
website/components/RequireAuth.tsx
T

82 lines
1.8 KiB
TypeScript

"use client";
import { useEffect, useState, type ReactNode } from "react";
import {
clearTokens,
getAccessToken,
getCustomerLoginUrl,
} from "@/lib/session";
const MESHKEE_API_URL =
process.env.NEXT_PUBLIC_MESHKEE_API_URL?.replace(/\/$/, "") ||
"https://api.meshkee.com/api/v1";
async function verifySession(accessToken: string, signal: AbortSignal) {
const response = await fetch(`${MESHKEE_API_URL}/auth/me`, {
headers: { Authorization: `Bearer ${accessToken}` },
signal,
cache: "no-store",
});
return response.ok;
}
export default function RequireAuth({
children,
returnPath = "/register",
}: {
children: ReactNode;
returnPath?: string;
}) {
const [ready, setReady] = useState(false);
useEffect(() => {
const controller = new AbortController();
async function ensureAuth() {
const token = getAccessToken();
if (!token) {
window.location.replace(getCustomerLoginUrl(returnPath));
return;
}
try {
const ok = await verifySession(token, controller.signal);
if (controller.signal.aborted) return;
if (!ok) {
clearTokens();
window.location.replace(getCustomerLoginUrl(returnPath));
return;
}
setReady(true);
} catch {
if (controller.signal.aborted) return;
clearTokens();
window.location.replace(getCustomerLoginUrl(returnPath));
}
}
void ensureAuth();
return () => controller.abort();
}, [returnPath]);
if (!ready) {
return (
<div
style={{
minHeight: "50vh",
display: "grid",
placeItems: "center",
fontSize: 12,
letterSpacing: "0.2em",
textTransform: "uppercase",
color: "#8e8e8e",
}}
>
Checking account…
</div>
);
}
return children;
}