Skip to content

Commit

Permalink
chore: consume standings data from server
Browse files Browse the repository at this point in the history
Initialize the use of standings data from the server
Refactor the drivers and constructors standings ui
Include results type declarations at results.d.ts
Update faker data to match standings schema
  • Loading branch information
Lombardoc4 committed Jan 22, 2024
1 parent 7a30bb2 commit ecc5b77
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 164 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"typecheck": "tsc --pretty --noEmit --incremental false"
},
"dependencies": {
"axios": "^1.6.5",
"axios": "latest",
"clsx": "latest",
"jotai": "latest",
"jotai-effect": "latest",
Expand Down
98 changes: 34 additions & 64 deletions src/app/lib/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,64 +40,7 @@ export const f1Seasons = (): string[] => {
);
};

export interface ISchedule {
RoundNumber: number;
Country: string;
Location: string;
OfficialEventName: string;
EventDate: string;
EventName: string;
EventFormat: string;
Session1: string;
Session1Date: string;
Session1DateUtc: string;
Session2: string;
Session2Date: string;
Session2DateUtc: string;
Session3: string;
Session3Date: string;
Session3DateUtc: string;
Session4: string;
Session4Date: string;
Session4DateUtc: string;
Session5: string;
Session5Date: string;
Session5DateUtc: string;
F1ApiSupport: boolean;
}

// Raw Fetch Format
export type IConstructorStandingsFetch = {
[key in 'position' | 'points' | 'wins']: string;
} & {
Constructor: {
name: string;
};
};
// UI format
export type IConstructorStandings = {
[key in 'pos' | 'points' | 'wins' | 'name']: string;
};

interface IDataConfigs {
seasons: string[];
schedule: ISchedule[];
drivers: string[];
sessions: string[];
standings: {
// drivers: {
// position: string,
// points: string,
// wins: string,
// Constructor?: {
// name: string,
// }
// }[],
constructors: IConstructorStandingsFetch[];
};
}

const dataConfig: IDataConfigs = {
const dataConfig: DataConfigSchema = {
seasons: f1Seasons(),
schedule: Array.from(Array(3).keys()).map(() => ({
RoundNumber: 0,
Expand Down Expand Up @@ -134,21 +77,48 @@ const dataConfig: IDataConfigs = {
],
sessions: ['Practice 1', 'Practice 2', 'Practice 3', 'Qualifying', 'Race'],
standings: {
// drivers: {

// },
constructors: Array.from(Array(10).keys()).map(() => ({
DriverStandings: Array.from(Array(5).keys()).map(() => ({
positionText: faker.number.int(20).toString(),
position: faker.number.int(20).toString(),
points: faker.number.int(25).toString(),
wins: faker.number.int(10).toString(),
Driver: {
driverId: faker.person.middleName(),
permanentNumber: faker.number.int(99).toString(),
code: faker.word.sample(3),
url: faker.internet.domainName(),
givenName: faker.person.firstName(),
familyName: faker.person.lastName(),
dateOfBirth: faker.date.birthdate().toString(),
nationality: faker.location.country(),
},
Constructors: [
{
constructorId: faker.person.middleName(),
url: faker.internet.domainName(),
name: faker.person.middleName(),
nationality: faker.location.country(),
},
],
})),
ConstructorStandings: Array.from(Array(5).keys()).map(() => ({
positionText: faker.number.int(20).toString(),
position: faker.number.int(20).toString(),
points: faker.number.int(25).toString(),
wins: faker.number.int(10).toString(),
Constructor: {
constructorId: faker.person.middleName(),
url: faker.internet.domainName(),
name: faker.person.middleName(),
nationality: faker.location.country(),
},
})),
season: 0,
round: 0,
},
};

const serverURL = 'http://0.0.0.0:8081';
const serverURL = 'http://127.0.0.1:8081';
export const fetchAPI = async (
endpoint: string,
statusCheck: boolean = false,
Expand All @@ -158,7 +128,7 @@ export const fetchAPI = async (
const options = statusCheck ? { headers: { cache: 'no-store' } } : {};

// Get dummy data or return false
const dummy: string[] | ISchedule[] | false =
const dummy: string[] | ScheduleSchema[] | false =
dataConfig[
endpoint.split('?')[0] as 'seasons' | 'schedule' | 'drivers' | 'sessions'
] || false;
Expand Down
6 changes: 2 additions & 4 deletions src/app/results/RaceResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { useMemo } from 'react';

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

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

const ResultCard = ({ data }: { data: ISchedule }) => {
const ResultCard = ({ data }: { data: ScheduleSchema }) => {
const eventDate = new Date(data.EventDate);
const eventPassed = new Date() > eventDate;

Expand Down Expand Up @@ -49,7 +47,7 @@ const ResultCard = ({ data }: { data: ISchedule }) => {
);
};

const WinterTesting = ({ data }: { data: ISchedule }) => {
const WinterTesting = ({ data }: { data: ScheduleSchema }) => {
const eventDate = new Date(data.EventDate);
const eventPassed = new Date() > eventDate;

Expand Down
79 changes: 18 additions & 61 deletions src/app/results/SeasonResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,33 @@

import { useAtom } from 'jotai';

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

import { RaceSchedule } from './RaceResults';
import { driverData, DriverHeadings } from '../lib/placerholder-results';
import { IConstructorStandings, positionEnding } from '../lib/utils';
import { Table } from '../ui/Table';
import { StandingsTimeline } from './StandingsTimeline';
import { Tabs } from '../ui/Tabs';

const ConstuctorHeadings = ['position', 'points', 'wins', 'name'];

const ConstructorCard = ({ data }: { data: IConstructorStandings }) => (
<div className='card overflow-hidden bg-base-100 shadow-xl'>
<div className='card-body px-0 pb-4 pt-2'>
<h3 className='card-title max-w-64'>
{positionEnding(data.pos)} {data.name}
</h3>
<div className='flex'>
<p className='flex-1'>
Points:
<br />
{data.points}
</p>
<p className='flex-1'>
Wins:
<br />
{data.wins}
</p>
</div>
</div>
</div>
);

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

return (
<>
<div className='mt-8 grid gap-8 lg:hidden'>
{constructorStandings.map((constructor) => (
<ConstructorCard key={constructor.name} data={constructor} />
))}
</div>
<div className='hidden lg:block'>
<Table
key='Constructors Championship'
headings={ConstuctorHeadings}
data={constructorStandings}
/>
</div>
</>
);
};

const tabHeaders = ['Races', 'Drivers', 'Constructors'];
const tabs = [
<RaceSchedule key='Race Results' />,
<Table
key='Drivers Championship'
headings={DriverHeadings}
data={driverData}
/>,
];

export default function ResultsPage() {
return (
<main>
<Tabs
headers={tabHeaders}
containers={[...tabs, <ConstructorResults key='ConstructorResults' />]}
headers={['Races', 'Drivers', 'Constructors']}
containers={[
<RaceSchedule key='Race Results' />,
<StandingsTimeline key='Driver Standings' data={driverStandings} />,
<StandingsTimeline
key='Constructor Standings'
data={constructorStandings}
/>,
]}
/>
</main>
);
Expand Down
137 changes: 137 additions & 0 deletions src/app/results/StandingsTimeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import clsx from 'clsx';

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

export const StandingsTimeline = ({
data,
}: {
data: DriverStandingSchema[] | ConstructorStandingSchema[];
}) => {
return (
<ul className='timeline timeline-vertical timeline-snap-icon max-md:timeline-compact'>
{data.map((standing, i: number) => {
const odd = i % 2 === 1;
return (
<li
// className='item-start mb-10'
key={
(standing as DriverStandingSchema)?.Driver?.givenName ||
(standing as ConstructorStandingSchema)?.Constructor?.name
}
>
{/* ! Use Flex order ! Yay */}
<PositionMarker pos={positionEnding(standing.position)} odd={odd} />
<TimelineMarker />
<div
className={clsx('timeline-end timeline-box !mb-10', {
'md:timeline-start md:text-end': !odd,
})}
>
{Object.prototype.hasOwnProperty.call(standing, 'Driver') && (
<DriverStandingInfo driver={standing as DriverStandingSchema} />
)}
{Object.prototype.hasOwnProperty.call(
standing,
'Constructor',
) && (
<ConstructorStandingInfo
con={standing as ConstructorStandingSchema}
/>
)}
</div>
<hr />
</li>
);
})}
</ul>
);
};

const DriverStandingInfo = ({
driver,
subEl = false,
}: {
driver: DriverStandingSchema;
subEl?: boolean;
}) => {
return (
<>
{/* 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>
</>
);
};

const ConstructorStandingInfo = ({
con,
}: {
con: ConstructorStandingSchema;
}) => {
return (
<>
<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>
</>
);
};

const PositionMarker = ({
pos,
odd = false,
}: {
pos: string;
odd?: boolean;
}) => (
<div
className={clsx('timeline-start timeline-box !mb-auto', {
'md:timeline-end': !odd,
})}
>
<p className='font-mono text-2xl italic'>{pos}</p>
</div>
);

const TimelineMarker = () => (
<div className='timeline-middle mx-2'>
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 20 20'
fill='currentColor'
className='h-4 w-4'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75'
/>
</svg>
</div>
);
Loading

0 comments on commit ecc5b77

Please sign in to comment.