be4bd5f41d
The invite link is token-only, so the landing page couldn't tell the invited email or whether an account existed — it dumped everyone on an empty register screen. Now it calls a public lookup (/api/invite/lookup → be-crm) and: - first-time invitee → register with the email prefilled + locked; - email already registered → sign in with the email prefilled; - signed-in + registered → accept immediately; signed-in + no profile → onboarding. Login now redeems the pending invite after sign-in (password/OTP/OAuth), so an existing user's invite is accepted on login (not only when already logged in).
29 lines
1.2 KiB
TypeScript
29 lines
1.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
|
|
// Server-side proxy to be-crm's public invitation lookup, so the invite landing page
|
|
// can learn the invited email + roles and whether an account exists — before the
|
|
// invitee has a session. Server-to-server avoids CORS. No secrets involved (the token
|
|
// is the only credential, and it was emailed to the invitee).
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
const CRM_BASE_URL = (process.env.CRM_BASE_URL ?? "https://crm.lynkedup.cloud").replace(/\/$/, "");
|
|
|
|
export async function GET(request: Request) {
|
|
const token = new URL(request.url).searchParams.get("token") ?? "";
|
|
if (token.length < 16 || token.length > 256) {
|
|
return NextResponse.json({ ok: false, status: "invalid" }, { status: 400 });
|
|
}
|
|
try {
|
|
const res = await fetch(`${CRM_BASE_URL}/public/invitations/lookup?token=${encodeURIComponent(token)}`, {
|
|
headers: { Accept: "application/json" },
|
|
cache: "no-store",
|
|
});
|
|
if (!res.ok) return NextResponse.json({ ok: false, status: "unavailable" }, { status: 502 });
|
|
const data = await res.json();
|
|
return NextResponse.json(data);
|
|
} catch {
|
|
return NextResponse.json({ ok: false, status: "unavailable" }, { status: 502 });
|
|
}
|
|
}
|