Files
dashboards/components/AuthGuards.tsx
T

146 lines
3.6 KiB
TypeScript

"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useAuth, userCanAccessApp } from "@/components/AuthProvider";
import { getAccessToken, getRefreshToken } from "@/lib/meshkee-api";
import {
getCustomerDashboardOrigin,
hostAppFor,
type HostApp,
} from "@/lib/host";
function LoadingScreen({ message = "Loading" }: { message?: string }) {
return (
<div
style={{
minHeight: "100vh",
display: "grid",
placeItems: "center",
background: "#f6f6f6",
fontSize: 12,
letterSpacing: "0.2em",
textTransform: "uppercase",
color: "#8e8e8e",
padding: 24,
textAlign: "center",
}}
>
{message}
</div>
);
}
const websiteUrl =
process.env.NEXT_PUBLIC_WEBSITE_URL?.replace(/\/$/, "") ||
"http://localhost:3000";
function handoffToWebsite(next: string) {
try {
const target = new URL(next);
if (target.origin !== new URL(websiteUrl).origin) return false;
const access = getAccessToken();
const refresh = getRefreshToken();
if (!access || !refresh) return false;
const hash = new URLSearchParams({
access,
refresh,
next: `${target.pathname}${target.search}${target.hash}` || "/register",
}).toString();
window.location.replace(`${target.origin}/auth/handoff#${hash}`);
return true;
} catch {
return false;
}
}
export function ProtectedRoute({
children,
requiredApp,
}: {
children: React.ReactNode;
requiredApp?: HostApp;
}) {
const { user, isLoading } = useAuth();
const router = useRouter();
const app =
requiredApp ??
hostAppFor(typeof window !== "undefined" ? window.location.host : "");
useEffect(() => {
if (isLoading) return;
if (!user) {
if (app === "business") {
// Do not auto-bounce to admin (that was the manage-business loop).
// Owners can sign in on the customer host.
const params = new URLSearchParams(window.location.search);
if (params.has("businessId")) {
return;
}
window.location.replace(`${getCustomerDashboardOrigin()}/login`);
return;
}
router.replace("/login");
return;
}
if (!userCanAccessApp(user, app)) {
if (app === "admin") {
window.location.replace(`${getCustomerDashboardOrigin()}/`);
return;
}
router.replace("/login");
}
}, [isLoading, user, router, app]);
if (isLoading) {
return <LoadingScreen />;
}
if (!user) {
if (
app === "business" &&
typeof window !== "undefined" &&
new URLSearchParams(window.location.search).has("businessId")
) {
return (
<LoadingScreen message="Could not open this business. Go back and use Manage business again." />
);
}
return <LoadingScreen message="Opening…" />;
}
if (!userCanAccessApp(user, app)) {
return <LoadingScreen />;
}
return children;
}
export function GuestRoute({ children }: { children: React.ReactNode }) {
const { user, isLoading } = useAuth();
const router = useRouter();
useEffect(() => {
if (isLoading || !user) return;
const nextParam = new URLSearchParams(window.location.search).get("next");
if (nextParam && handoffToWebsite(nextParam)) return;
const app = hostAppFor(window.location.host);
if (app === "admin") {
router.replace("/");
return;
}
if (app === "business") {
router.replace("/profile");
return;
}
router.replace("/");
}, [isLoading, user, router]);
if (isLoading) return <LoadingScreen />;
if (user) return null;
return children;
}