Add LynkedUp roofing portal: full login + registration auth UI
- Split-screen dark/orange auth shell with animated scan showcase - Login state machine: social/email, passkey, password, OTP (email/SMS/WhatsApp), TOTP, push, try-another-way, forgot-password, terms gate, success - 4-step registration wizard: Account, Property, Verify, Address - US-default phone + address with /api/geo lookup (PIN auto-fill / search) - Roofing-themed content, Inter font, logo from public/image Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
// Keyless geo BFF for the registration address step.
|
||||
// - GET /api/geo?pin=201310 → { ok, city, state, localities[] }
|
||||
// - GET /api/geo?addr=foo&country=us → { ok, suggestions[] }
|
||||
// All data is mocked so the demo works without any external key.
|
||||
|
||||
const PINS: Record<string, { city: string; state: string; localities: string[] }> = {
|
||||
"201310": { city: "Greater Noida", state: "Uttar Pradesh", localities: ["Sector 18", "Pari Chowk", "Knowledge Park", "Alpha 1"] },
|
||||
"201301": { city: "Noida", state: "Uttar Pradesh", localities: ["Sector 1", "Sector 15", "Sector 18", "Sector 62"] },
|
||||
"110001": { city: "New Delhi", state: "Delhi", localities: ["Connaught Place", "Barakhamba", "Janpath"] },
|
||||
"400001": { city: "Mumbai", state: "Maharashtra", localities: ["Fort", "Colaba", "Churchgate"] },
|
||||
"560001": { city: "Bengaluru", state: "Karnataka", localities: ["MG Road", "Cubbon Park", "Shivajinagar"] },
|
||||
};
|
||||
|
||||
function pinFallback(pin: string) {
|
||||
// derive a plausible state from the first digit for unknown PINs
|
||||
const map: Record<string, { city: string; state: string }> = {
|
||||
"1": { city: "Delhi NCR", state: "Delhi" },
|
||||
"2": { city: "Lucknow", state: "Uttar Pradesh" },
|
||||
"3": { city: "Jaipur", state: "Rajasthan" },
|
||||
"4": { city: "Mumbai", state: "Maharashtra" },
|
||||
"5": { city: "Hyderabad", state: "Telangana" },
|
||||
"6": { city: "Chennai", state: "Tamil Nadu" },
|
||||
"7": { city: "Kolkata", state: "West Bengal" },
|
||||
};
|
||||
const hit = map[pin[0]] ?? { city: "City", state: "State" };
|
||||
return { ...hit, localities: ["Central", "North", "South", "East", "West"] };
|
||||
}
|
||||
|
||||
export function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const pin = searchParams.get("pin");
|
||||
const addr = searchParams.get("addr");
|
||||
const country = searchParams.get("country") ?? "";
|
||||
|
||||
if (pin) {
|
||||
if (!/^\d{6}$/.test(pin)) return NextResponse.json({ ok: false, error: "invalid_pin" });
|
||||
const data = PINS[pin] ?? pinFallback(pin);
|
||||
return NextResponse.json({ ok: true, ...data });
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
const q = addr.trim();
|
||||
if (q.length < 3) return NextResponse.json({ ok: true, suggestions: [] });
|
||||
const cities: Record<string, { city: string; state: string }[]> = {
|
||||
us: [{ city: "New York", state: "New York" }, { city: "Newark", state: "New Jersey" }, { city: "San Francisco", state: "California" }],
|
||||
gb: [{ city: "London", state: "" }, { city: "Manchester", state: "" }, { city: "Birmingham", state: "" }],
|
||||
ae: [{ city: "Dubai", state: "Dubai" }, { city: "Abu Dhabi", state: "Abu Dhabi" }],
|
||||
};
|
||||
const pool = cities[country.toLowerCase()] ?? cities.us;
|
||||
const suggestions = pool.map((c, i) => ({
|
||||
line1: `${q} ${10 + i * 7}, ${c.city}`,
|
||||
line2: i === 0 ? "Downtown" : "Suburb",
|
||||
city: c.city,
|
||||
state: c.state,
|
||||
postal: country.toLowerCase() === "us" ? `${10001 + i}` : `${q.slice(0, 2).toUpperCase()}${i}A 1BB`,
|
||||
}));
|
||||
return NextResponse.json({ ok: true, suggestions });
|
||||
}
|
||||
|
||||
return NextResponse.json({ ok: false, error: "missing_query" });
|
||||
}
|
||||
Reference in New Issue
Block a user