Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

race results prototype #17

Merged
merged 7 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,58 @@ import { useAtom } from 'jotai';
import Image from 'next/image';
import { useMemo } from 'react';

import { seasonRacesAtom } from '@/atoms/results';
import { seasonRacesAtom } from '@/atoms/races';

export const RaceSchedule = () => {
const [races] = useAtom(seasonRacesAtom);

const winterTesting = useMemo(
() => races.find((race) => race.EventFormat === 'testing'),
[races],
);
const mainEvents = useMemo(
() => races.filter((race) => race.EventFormat !== 'testing'),
[races],
);

if (races.length === 0)
return (
<div className='px-4 lg:px-0'>
<div className='mt-8 grid gap-8 md:grid-cols-2 xl:grid-cols-3 xl:gap-x-4'>
{/* 3 Placeholder Cards */}
{Array.from(Array(4).keys()).map((_, i) => (
<SkeletonResultCard key={'skeleton result card - ' + i} />
))}
</div>
</div>
);

return (
<div className='px-4 lg:px-0'>
{/* If seasonAom === current/upcomming season, then add button to bring user to next event */}
{winterTesting && <WinterTesting data={winterTesting} />}
<div className='mt-8 grid gap-8 md:grid-cols-2 xl:grid-cols-3 xl:gap-x-4'>
{/* 10 Placeholder Cards */}
{mainEvents.map((race) => (
<ResultCard key={race.EventName} data={race} />
))}
</div>
</div>
);
};

const SkeletonResultCard = () => (
<div className='card overflow-hidden p-4 shadow-xl'>
<div className='skeleton h-32 w-full'></div>

<div className='card-body p-0 pt-2'>
<div className='skeleton h-4 w-full'></div>
<div className='skeleton h-4 w-full'></div>

<div className='skeleton mx-auto h-[32px] w-[222px]'></div>
</div>
</div>
);

const ResultCard = ({ data }: { data: ScheduleSchema }) => {
const eventDate = new Date(data.EventDate);
Expand Down Expand Up @@ -82,29 +133,3 @@ const WinterTesting = ({ data }: { data: ScheduleSchema }) => {
</div>
);
};

export const RaceSchedule = () => {
const [races] = useAtom(seasonRacesAtom);

const winterTesting = useMemo(
() => races.find((race) => race.EventFormat === 'testing'),
[races],
);
const mainEvents = useMemo(
() => races.filter((race) => race.EventFormat !== 'testing'),
[races],
);

return (
<div className='px-4 lg:px-0'>
{/* If seasonAom === current/upcomming season, then add button to bring user to next event */}
{winterTesting && <WinterTesting data={winterTesting} />}
<div className='mt-8 grid gap-8 md:grid-cols-2 xl:grid-cols-3 xl:gap-x-4'>
{/* 10 Placeholder Cards */}
{mainEvents.map((race) => (
<ResultCard key={race.EventName} data={race} />
))}
</div>
</div>
);
};
70 changes: 70 additions & 0 deletions src/app/(features)/RaceTimeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import clsx from 'clsx';
import { BsFillStarFill } from 'react-icons/bs';

import { fastestLap, formatDuration, positionEnding } from '../../lib/utils';

export const DriverResultsInfo = ({
driver,
subEl = false,
}: {
driver: DriverResult;
subEl?: boolean;
}) => {
const durationPlus = driver.Position !== 1 ? '+' : '';
return (
<>
{/* Driver Standings */}
<p className='font-mono text-2xl italic'>
{positionEnding(driver.Position)} - {driver.Points} points
{fastestLap(driver.Position, driver.Points) && <BsFillStarFill />}
</p>
<div>
<div>
<h3
className={clsx('font-bold', {
'text-2xl': subEl,
'text-4xl': !subEl,
})}
>
{driver.FullName}
</h3>
<h4
className={clsx({
'text-1xl': subEl,
'text-3xl': !subEl,
})}
>
{driver.TeamName}
</h4>
</div>
</div>
{!subEl && (
<h3 className='text-2xl font-bold'>
{driver.Time
? durationPlus + formatDuration(driver.Time)
: driver.Status}
</h3>
)}
</>
);
};

export const ConstructorResultsInfo = ({ con }: { con: ConstructorResult }) => {
return (
<>
<p className='font-mono text-2xl italic'>
{positionEnding(con.position)} - {con.points} points
</p>
<h3 className='text-4xl font-bold'>{con.name}</h3>
<hr className='my-2' />
<div className='flex flex-col gap-4 md:flex-row'>
{con.drivers &&
con.drivers.map((driver: DriverResult) => (
<div key={driver.FullName}>
<DriverResultsInfo driver={driver} subEl={true} />
</div>
))}
</div>
</>
);
};
68 changes: 68 additions & 0 deletions src/app/(features)/StandingsTimeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import clsx from 'clsx';

import { positionEnding } from '../../lib/utils';

export const DriverStandingInfo = ({
driver,
subEl = false,
}: {
driver: DriverStandingSchema;
subEl?: boolean;
}) => {
return (
<>
<p className='font-mono text-2xl italic'>
{positionEnding(driver.position)}
</p>

{/* Driver Standings */}
{driver.Driver && (
<h3
className={clsx('font-bold', {
'text-2xl': subEl,
'text-4xl': !subEl,
})}
>
{driver.Driver.givenName} {driver.Driver.familyName}
</h3>
)}
{!subEl && (
<h3 className='text-2xl font-bold'>
{driver.Constructors.map(({ name }) => (
<span key={name}>{name}</span>
))}
</h3>
)}
<p>Points: {driver.points}</p>
<p>Wins: {driver.wins}</p>
</>
);
};

// constructor is a keyword cannot be used
export const ConstructorStandingInfo = ({
con,
}: {
con: ConstructorStandingSchema;
}) => {
return (
<>
<p className='font-mono text-2xl italic'>
{positionEnding(con.position)}
</p>

<h3 className='text-4xl font-bold'>{con.Constructor.name}</h3>
<p>Points: {con.points}</p>
<p>Wins: {con.wins}</p>
<hr className='my-2' />
<div className='flex flex-col gap-4 md:flex-row'>
{con.Drivers &&
con.Drivers.map((driver) => (
<div key={driver.Driver.dateOfBirth}>
<DriverStandingInfo driver={driver} subEl={true} />
</div>
))}
</div>
</>
);
};
89 changes: 89 additions & 0 deletions src/app/[season]/[location]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
'use client';

import { useAtom } from 'jotai';
import { useEffect } from 'react';

import {
ConstructorResultsInfo,
DriverResultsInfo,
} from '@/app/(features)/RaceTimeline';
import { Tabs } from '@/app/ui/Tabs';
import { Timeline, TimelineElement } from '@/app/ui/Timeline';
import { allConstructorAtom } from '@/atoms/constructors';
import { allDriversAtom } from '@/atoms/drivers';
import { raceAtom, seasonRacesAtom } from '@/atoms/races';
import { fetchSessionResults } from '@/atoms/sessions';

// import { RaceSchedule } from '../../RaceResults';
// import { handleRaceChangeAtom, seasonRacesAtom } from '@/atoms/races';

export default function ResultsPage({
params,
}: {
params: { location: string };
}) {
const [races] = useAtom(seasonRacesAtom);
const [_, setRace] = useAtom(raceAtom);

useEffect(() => {
setRace(
races.find((race) => race.Location === params.location) || 'All Races',
);
}, [races, params.location, setRace]);
// useAtom(fetchStandings);
// useAtom(fetchSessionResults);
useAtom(fetchSessionResults);

// const [constructorStandings] = useAtom(constructorStandingsAtom);
// const [driverStandings] = useAtom(driverStandingsAtom);
const [drivers] = useAtom(allDriversAtom);
const [constructors] = useAtom(allConstructorAtom);

// const [driverStandings] = useAtom(driverStandingsAtom);

// const [, handleRaceChange] = useAtom(handleRaceChangeAtom);
// const [allRaces] = useAtom(seasonRacesAtom)

// if (!params) return <></>;
// Get all

// if (allRaces && allRaces.length > 0) {
// console.log('all races', allRaces[parseInt(params.round) - 1])

// handleRaceChange(allRaces[parseInt(params.round) - 1]);
// }

return (
<main>
<Tabs
headers={['Drivers', 'Constructors']}
containers={[
<Timeline key='Driver Results'>
{drivers.map((driver, index, allDrivers) => (
<TimelineElement
key={driver.FullName}
first={index === 0}
last={index === allDrivers.length - 1}
odd={index % 2 === 0}
>
<DriverResultsInfo driver={driver} />
</TimelineElement>
))}
</Timeline>,
<Timeline key='Constructor Results'>
{constructors.map((con, index, allConstructors) => (
<TimelineElement
key={con.name}
first={index === 0}
last={index === allConstructors.length - 1}
odd={index % 2 === 0}
>
<ConstructorResultsInfo con={con} />
</TimelineElement>
))}
</Timeline>,
]}
/>
</main>
);
}
4 changes: 2 additions & 2 deletions src/app/results/layout.tsx → src/app/[season]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { MainFilters } from '../MainFilters';
import { MainFilters } from '../ui/MainFilters';

// Default Next Layout
export default function ResultsLayout({
Expand All @@ -10,7 +10,7 @@ export default function ResultsLayout({
}) {
return (
<>
<div className='container mx-auto mb-4 rounded-box bg-base-300 p-4 md:my-4'>
<div className='container mx-auto mb-4 rounded-box bg-base-300 p-4 px-2 md:my-4'>
<MainFilters />
</div>
{children}
Expand Down
58 changes: 58 additions & 0 deletions src/app/[season]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client';

import { useAtom } from 'jotai';

import {
constructorStandingsAtom,
driverStandingsAtom,
fetchStandings,
} from '@/atoms/standings';

import { RaceSchedule } from '../(features)/RaceSchedule';
import {
ConstructorStandingInfo,
DriverStandingInfo,
} from '../(features)/StandingsTimeline';
import { Tabs } from '../ui/Tabs';
import { Timeline, TimelineElement } from '../ui/Timeline';

export default function ResultsPage() {
useAtom(fetchStandings);
const [constructorStandings] = useAtom(constructorStandingsAtom);
const [driverStandings] = useAtom(driverStandingsAtom);

return (
<main>
<Tabs
headers={['Races', 'Drivers', 'Constructors']}
containers={[
<RaceSchedule key='Race Schedule' />,
<Timeline key='Driver Standings'>
{driverStandings.map((driver, index, allDrivers) => (
<TimelineElement
key={driver.Driver.givenName}
first={index === 0}
last={index === allDrivers.length - 1}
odd={index % 2 === 0}
>
<DriverStandingInfo driver={driver} />
</TimelineElement>
))}
</Timeline>,
<Timeline key='Constructor Standings'>
{constructorStandings.map((constructor, index, allConstructors) => (
<TimelineElement
key={constructor.Constructor.name}
first={index === 0}
last={index === allConstructors.length - 1}
odd={index % 2 === 0}
>
<ConstructorStandingInfo con={constructor} />
</TimelineElement>
))}
</Timeline>,
]}
/>
</main>
);
}
Loading
Loading