website refactor
This commit is contained in:
@@ -1,20 +1,10 @@
|
||||
'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 { useEffect, useState } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { ProfileTemplate, type ProfileTab } from '@/templates/ProfileTemplate';
|
||||
import type { ProfileViewData } from '@/lib/view-data/ProfileViewData';
|
||||
|
||||
type ProfileTab = 'overview' | 'history' | 'stats';
|
||||
|
||||
type SaveError = string | null;
|
||||
import type { Result } from '@/lib/contracts/Result';
|
||||
|
||||
interface ProfilePageClientProps {
|
||||
viewData: ProfileViewData;
|
||||
@@ -23,112 +13,55 @@ interface ProfilePageClientProps {
|
||||
}
|
||||
|
||||
export function ProfilePageClient({ viewData, mode, onSaveSettings }: ProfilePageClientProps) {
|
||||
const [activeTab, setActiveTab] = useState<ProfileTab>('overview');
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const tabParam = searchParams.get('tab') as ProfileTab | null;
|
||||
|
||||
const [activeTab, setActiveTab] = useState<ProfileTab>(tabParam || '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);
|
||||
const [friendRequestSent, setFriendRequestSent] = useState(false);
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (activeTab === 'overview') {
|
||||
params.delete('tab');
|
||||
} else {
|
||||
params.set('tab', activeTab);
|
||||
}
|
||||
const query = params.toString();
|
||||
const currentQuery = searchParams.toString();
|
||||
|
||||
if (query !== currentQuery) {
|
||||
router.replace(`/profile${query ? `?${query}` : ''}`, { scroll: false });
|
||||
}
|
||||
}, [activeTab, searchParams, router]);
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
useEffect(() => {
|
||||
const tab = searchParams.get('tab') as ProfileTab | null;
|
||||
if (tab && tab !== activeTab) {
|
||||
setActiveTab(tab);
|
||||
}
|
||||
}, [searchParams, activeTab]);
|
||||
|
||||
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>
|
||||
<ProfileTemplate
|
||||
viewData={viewData}
|
||||
mode={mode}
|
||||
activeTab={activeTab}
|
||||
onTabChange={setActiveTab}
|
||||
editMode={editMode}
|
||||
onEditModeChange={setEditMode}
|
||||
friendRequestSent={friendRequestSent}
|
||||
onFriendRequestSend={() => setFriendRequestSent(true)}
|
||||
onSaveSettings={async (updates) => {
|
||||
const result = await onSaveSettings(updates);
|
||||
if (result.isErr()) {
|
||||
// In a real app, we'd show a toast or error message.
|
||||
// For now, we just throw to let the UI handle it if needed,
|
||||
// or we could add an error state to this client component.
|
||||
throw new Error(result.getError());
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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 Button from '@/ui/Button';
|
||||
import Card from '@/ui/Card';
|
||||
import Container from '@/ui/Container';
|
||||
import Heading from '@/ui/Heading';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
|
||||
export default async function ProfileLiveriesPage() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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 Button from '@/ui/Button';
|
||||
import Card from '@/ui/Card';
|
||||
import Container from '@/ui/Container';
|
||||
import Heading from '@/ui/Heading';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
|
||||
export default async function ProfileLiveryUploadPage() {
|
||||
|
||||
@@ -4,7 +4,8 @@ import { updateProfileAction } from './actions';
|
||||
import { ProfilePageClient } from './ProfilePageClient';
|
||||
|
||||
export default async function ProfilePage() {
|
||||
const result = await ProfilePageQuery.execute();
|
||||
const query = new ProfilePageQuery();
|
||||
const result = await query.execute();
|
||||
|
||||
if (result.isErr()) {
|
||||
notFound();
|
||||
@@ -13,5 +14,11 @@ export default async function ProfilePage() {
|
||||
const viewData = result.unwrap();
|
||||
const mode = viewData.driver.id ? 'profile-exists' : 'needs-profile';
|
||||
|
||||
return <ProfilePageClient viewData={viewData} mode={mode} onSaveSettings={updateProfileAction} />;
|
||||
return (
|
||||
<ProfilePageClient
|
||||
viewData={viewData}
|
||||
mode={mode}
|
||||
onSaveSettings={updateProfileAction}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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 Button from '@/ui/Button';
|
||||
import Card from '@/ui/Card';
|
||||
import Container from '@/ui/Container';
|
||||
import Heading from '@/ui/Heading';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
|
||||
export default async function ProfileSettingsPage() {
|
||||
|
||||
Reference in New Issue
Block a user