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:
2026-06-27 18:36:08 +05:30
parent 50b120e184
commit 8c5df83d63
13 changed files with 2520 additions and 21 deletions
+104
View File
@@ -0,0 +1,104 @@
"use client";
import { GoogleMark, MicrosoftMark, AppleMark, Icon } from "./icons";
/** Left brand showcase panel for the split-screen auth layout. */
export function PortalAside() {
return (
<aside className="portal-aside">
<span className="scanline" />
<div className="aside-top">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img className="logo-img" src="/image/logo.png" alt="Lynkedup Pro Portal" />
<span className="eyebrow"><i className="pdot" /> Drone-powered</span>
</div>
<div>
<h2>
Roofing,
<br />
Revolutionized.
</h2>
<p className="lede">
AI-powered drone &amp; LiDAR roof inspections, instant estimates and
insurance-ready reports for homeowners and contractors.
</p>
<div className="stat-strip">
<div className="stat-chip"><b>5,847</b><span>Roofs scanned</span></div>
<div className="stat-chip"><b>15 min</b><span>Avg estimate</span></div>
<div className="stat-chip"><b>96%</b><span>Lead accuracy</span></div>
</div>
</div>
<div className="preview-card">
<div className="pc-row">
<span className="pc-av"></span>
<span className="pc-id">
<b>Roof scan #8842-A</b>
<span>LiDAR mapping · Verified</span>
</span>
<span className="pc-check"><Icon name="check" size={15} /></span>
</div>
<div className="pc-bar"><span style={{ width: "76%" }} /></div>
<div className="pc-meta"><span>Structure integrity</span><span>76%</span></div>
</div>
<div className="aside-trust">
<span><Icon name="lock" size={13} /> 256-bit SSL</span>
<span><Icon name="shield" size={13} /> Licensed &amp; Insured</span>
<span><Icon name="check" size={13} /> Drone-Powered</span>
</div>
</aside>
);
}
/** Compact logo shown above the form on small screens (aside is hidden). */
export function PanelBrand() {
return (
<div className="panel-brand">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/image/logo.png" alt="Lynkedup Pro Portal" />
</div>
);
}
/** The three OAuth provider buttons used on login + register. */
export function OAuthButtons({ onPick }: { onPick: (p: string) => void }) {
return (
<div className="col gap-3">
<button className="btn btn-oauth" onClick={() => onPick("Google")}>
<GoogleMark /> Continue with Google
</button>
<button className="btn btn-oauth" onClick={() => onPick("Microsoft")}>
<MicrosoftMark /> Continue with Microsoft
</button>
<button className="btn btn-oauth" onClick={() => onPick("Apple")}>
<AppleMark /> Continue with Apple
</button>
</div>
);
}
export function Divider({ label }: { label: string }) {
return <div className="divider">{label}</div>;
}
/** SSL / government / official-portal trust strip shown under the card. */
export function TrustBadges() {
return (
<div className="trust">
<span><Icon name="lock" size={14} /> 256-bit SSL</span>
<span><Icon name="shield" size={14} /> Licensed &amp; Insured</span>
<span><Icon name="check" size={14} /> Drone-Powered</span>
</div>
);
}
/** A small "← email@…" chip shown on inner steps. */
export function BackChip({ label, onBack }: { label: string; onBack: () => void }) {
return (
<button className="btn btn-sm" style={{ width: "auto", borderRadius: 999 }} onClick={onBack}>
<Icon name="chevL" size={15} /> {label}
</button>
);
}