Files
gridpilot.gg/apps/website/app/profile/ProfilePageClient.tsx
2026-01-14 02:02:24 +01:00

135 lines
3.9 KiB
TypeScript

'use client';
import { useState } from 'react';
import Link from 'next/link';
import Button from '@/components/ui/Button';
import Card from '@/components/ui/Card';
import Container from '@/components/ui/Container';
import Heading from '@/components/ui/Heading';
import Input from '@/components/ui/Input';
import TabNavigation from '@/components/ui/TabNavigation';
import { routes } from '@/lib/routing/RouteConfig';
import type { Result } from '@/lib/contracts/Result';
import type { ProfileViewData } from '@/lib/view-data/ProfileViewData';
type ProfileTab = 'overview' | 'history' | 'stats';
type SaveError = string | null;
interface ProfilePageClientProps {
viewData: ProfileViewData;
mode: 'profile-exists' | 'needs-profile';
onSaveSettings: (updates: { bio?: string; country?: string }) => Promise<Result<void, string>>;
}
export function ProfilePageClient({ viewData, mode, onSaveSettings }: ProfilePageClientProps) {
const [activeTab, setActiveTab] = useState<ProfileTab>('overview');
const [editMode, setEditMode] = useState(false);
const [bio, setBio] = useState(viewData.driver.bio ?? '');
const [countryCode, setCountryCode] = useState(viewData.driver.countryCode ?? '');
const [saveError, setSaveError] = useState<SaveError>(null);
if (mode === 'needs-profile') {
return (
<Container size="md">
<Heading level={1}>Create your driver profile</Heading>
<Card>
<p>Driver profile not found for this account.</p>
<Link href={routes.protected.onboarding}>
<Button variant="primary">Start onboarding</Button>
</Link>
</Card>
</Container>
);
}
if (editMode) {
return (
<Container size="md">
<Heading level={1}>Edit profile</Heading>
<Card>
<Heading level={3}>Profile</Heading>
<Input
value={bio}
onChange={(e) => setBio(e.target.value)}
placeholder="Bio"
/>
<Input
value={countryCode}
onChange={(e) => setCountryCode(e.target.value)}
placeholder="Country code (e.g. DE)"
/>
{saveError ? <p>{saveError}</p> : null}
<Button
variant="primary"
onClick={async () => {
setSaveError(null);
const result = await onSaveSettings({ bio, country: countryCode });
if (result.isErr()) {
setSaveError(result.getError());
return;
}
setEditMode(false);
}}
>
Save
</Button>
<Button variant="secondary" onClick={() => setEditMode(false)}>
Cancel
</Button>
</Card>
</Container>
);
}
return (
<Container size="lg">
<Heading level={1}>{viewData.driver.name || 'Profile'}</Heading>
<Button variant="primary" onClick={() => setEditMode(true)}>
Edit profile
</Button>
<TabNavigation
tabs={[
{ id: 'overview', label: 'Overview' },
{ id: 'history', label: 'Race History' },
{ id: 'stats', label: 'Detailed Stats' },
]}
activeTab={activeTab}
onTabChange={(tabId) => setActiveTab(tabId as ProfileTab)}
/>
{activeTab === 'overview' ? (
<Card>
<Heading level={3}>Driver</Heading>
<p>{viewData.driver.countryCode}</p>
<p>{viewData.driver.joinedAtLabel}</p>
<p>{viewData.driver.bio ?? ''}</p>
</Card>
) : null}
{activeTab === 'history' ? (
<Card>
<Heading level={3}>Race history</Heading>
<p>Race history is currently unavailable in this view.</p>
</Card>
) : null}
{activeTab === 'stats' ? (
<Card>
<Heading level={3}>Stats</Heading>
<p>{viewData.stats?.ratingLabel ?? ''}</p>
<p>{viewData.stats?.globalRankLabel ?? ''}</p>
</Card>
) : null}
</Container>
);
}