MotorSignal-App/website/app/account/page.tsx

33 lines
3.2 KiB
TypeScript

import Link from 'next/link';
import { cookies } from 'next/headers';
type CurrentUser = { id: string; email: string; email_verified: boolean };
type Vehicle = { id: string; nickname: string; make: string; model: string; year?: number | null };
type Ride = { id: string; started_at: string; distance_miles?: number | null; top_speed_mph?: number | null; status: string };
type Subscription = { plan: string; status: string };
async function loadAccount(): Promise<{ user: CurrentUser; vehicles: Vehicle[]; rides: Ride[]; subscription: Subscription } | null> {
const token = (await cookies()).get('motorsignal_access_token')?.value;
if (!token) return null;
const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app';
try {
const response = await fetch(`${baseUrl}/api/v1/me`, { headers: { authorization: `Bearer ${token}` }, cache: 'no-store' });
if (!response.ok) return null;
const user = await response.json() as CurrentUser;
const [vehiclesResponse, ridesResponse, subscriptionResponse] = await Promise.all([
fetch(`${baseUrl}/api/v1/vehicles`, { headers: { authorization: `Bearer ${token}` }, cache: 'no-store' }),
fetch(`${baseUrl}/api/v1/rides?page=1&page_size=5`, { headers: { authorization: `Bearer ${token}` }, cache: 'no-store' }),
fetch(`${baseUrl}/api/v1/me/subscription`, { headers: { authorization: `Bearer ${token}` }, cache: 'no-store' }),
]);
return { user, vehicles: vehiclesResponse.ok ? await vehiclesResponse.json() as Vehicle[] : [], rides: ridesResponse.ok ? (await ridesResponse.json()).items as Ride[] : [], subscription: subscriptionResponse.ok ? await subscriptionResponse.json() as Subscription : { plan: 'free', status: 'unknown' } };
} catch {
return null;
}
}
export default async function AccountPage() {
const account = await loadAccount();
if (!account) return <section className="content-page"><span className="eyebrow">Account portal</span><h1>Sign in to your rider space.</h1><p>Manage your MotorSignal account, security, vehicles, and ride history from one place.</p><div className="hero-actions"><Link className="button" href="/login">Sign in</Link><Link className="button button-secondary" href="/register">Create account</Link></div></section>;
return <section className="content-page"><span className="eyebrow">Account portal</span><h1>Welcome back.</h1><p>{account.user.email}</p><div className="account-grid"><article className="panel"><h2>Profile</h2><p>Account status: <strong>Active</strong></p><p>Email verification: <strong>{account.user.email_verified ? 'Verified' : 'Pending'}</strong></p></article><article className="panel"><h2>Plan</h2><p><strong>{account.subscription.plan}</strong> · {account.subscription.status}</p></article><article className="panel"><h2>Vehicles</h2>{account.vehicles.length ? account.vehicles.map((vehicle) => <p key={vehicle.id}><strong>{vehicle.nickname}</strong> · {vehicle.year ?? ''} {vehicle.make} {vehicle.model}</p>) : <p>No vehicles yet.</p>}</article><article className="panel"><h2>Recent rides</h2>{account.rides.length ? account.rides.map((ride) => <p key={ride.id}>{new Date(ride.started_at).toLocaleDateString()} · {ride.distance_miles ?? 0} mi · {ride.status}</p>) : <p>No rides yet.</p>}</article></div></section>;
}