Skip to content

Commit

Permalink
chore: FRON-6 include server 422 error info on page (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lombardoc4 authored Feb 27, 2024
1 parent a11a4e5 commit 64920b2
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 61 deletions.
9 changes: 8 additions & 1 deletion src/app/[season]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
'use client';

import { useAtom } from 'jotai';
import Error from 'next/error';

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

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

// Default Next Layout
Expand All @@ -8,12 +13,14 @@ export default function ResultsLayout({
}: {
children: React.ReactNode;
}) {
const [serverError] = useAtom(serverErrorAtom);

return (
<>
<div className='container mx-auto mb-4 rounded-box bg-base-300 p-4 px-2 md:my-4'>
<MainFilters />
</div>
{children}
{serverError ? <Error statusCode={422} title={serverError} /> : children}
</>
);
}
3 changes: 0 additions & 3 deletions src/app/[season]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { useAtom } from 'jotai';

import { fetchStandings } from '@/atoms/fetchCalls';
import { seasonAtom } from '@/atoms/seasons';
import {
constructorStandingsAtom,
driverStandingsAtom,
Expand All @@ -20,12 +19,10 @@ import { Timeline, TimelineElement } from '../ui/Timeline';
export default function ResultsPage() {
const [constructorStandings] = useAtom(constructorStandingsAtom);
const [driverStandings] = useAtom(driverStandingsAtom);
const [season] = useAtom(seasonAtom);
useAtom(fetchStandings);

return (
<main>
<h1>{season}</h1>
<Tabs
headers={['Schedule', 'Drivers', 'Constructors']}
containers={[
Expand Down
3 changes: 3 additions & 0 deletions src/app/ui/MainFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export const MainFilters = () => {
// Handles hydration on page load
useParamToSetAtoms();

//! Handle Server Error to stop spinning
// useAtom(serverErrorAtom)

return (
<div className='flex flex-col gap-2'>
<div className='flex gap-2 lg:gap-4'>
Expand Down
93 changes: 64 additions & 29 deletions src/atoms/fetchCalls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
nextEventTimeAtom,
} from './nextEvent';
import { raceAtom, seasonRacesAtom } from './races';
import { serverErrorAtom } from './results';
import { allSeasonsAtom, seasonAtom } from './seasons';
import { allSessionsAtom, sessionAtom } from './sessions';
import { constructorStandingsAtom, driverStandingsAtom } from './standings';
Expand Down Expand Up @@ -50,12 +51,22 @@ export const fetchSchedule = atomEffect(
set(seasonRacesAtom, null);
const params = get(seasonAtom) && `?year=${get(seasonAtom)}`;

fetchAPI('schedule' + params).then((data) => {
set(seasonRacesAtom, data.EventSchedule);
fetchAPI('schedule' + params).then(
(res: DataConfigSchema['schedule'] | ServerErrorResponse) => {
const schedule = res as DataConfigSchema['schedule'];

// Sync default year with server
set(seasonAtom, data.year);
});
const error = res as ServerErrorResponse;
if (error.detail) {
set(serverErrorAtom, error.detail[0].msg);
return;
}

set(seasonRacesAtom, schedule.EventSchedule);

// Sync default year with server
set(seasonAtom, schedule.year);
},
);
},
// Dependencies:
// seasonAtom
Expand Down Expand Up @@ -87,7 +98,14 @@ export const fetchSessionResults = atomEffect((get, set) => {
url += `?session=${sessionRound}`;
}

fetchAPI(url).then((drivers: DriverResult[]) => {
fetchAPI(url).then((res: DriverResult[] | ServerErrorResponse) => {
const drivers = res as DriverResult[];

const error = res as ServerErrorResponse;
if (error.detail) {
set(serverErrorAtom, error.detail[0].msg);
return;
}
// Formulate Constructors
const constructors = formatConstructorResults(drivers);

Expand Down Expand Up @@ -115,12 +133,21 @@ export const fetchStandings = atomEffect((get, set) => {
const round = race === 'All Races' ? '' : `&round=${race.RoundNumber}`;

// Fetch
fetchAPI('standings' + year + round).then(
({
DriverStandings,
ConstructorStandings,
}: DataConfigSchema['standings']) => {
fetchAPI('standings' + year + round)
.then((res: DataConfigSchema['standings'] | ServerErrorResponse) => {
const { DriverStandings, ConstructorStandings } =
res as DataConfigSchema['standings'];

const error = res as ServerErrorResponse;
if (error.detail) {
set(serverErrorAtom, error.detail[0].msg);

// setDefault('standings')
return;
}

// Include Drivers in Constructors Info

const constructors = ConstructorStandings.map((cs) => {
const { name } = cs.Constructor;
return {
Expand All @@ -134,8 +161,8 @@ export const fetchStandings = atomEffect((get, set) => {
// Update standings
set(constructorStandingsAtom, constructors);
set(driverStandingsAtom, DriverStandings);
},
);
})
.catch((err) => err);

// dependencies
// seasonAtom
Expand All @@ -147,22 +174,30 @@ export const fetchNextEvent = atomEffect(
(get, set) => {
// Next event do not change, only fetch if null
if (!get(nextEventAtom)) {
fetchAPI('next-event').then((data: ScheduleSchema) => {
// Get session times
const now = Date.now();
const nextEvent = formatNextEvent(data);

if (nextEvent === 'No session') return;

set(nextEventAtom, nextEvent);

if (nextEvent.time < now) {
set(nextEventLiveAtom, true);
set(nextEventTimeAtom, now - nextEvent.endTime);
} else {
set(nextEventTimeAtom, nextEvent.time - now);
}
});
fetchAPI('next-event').then(
(res: ScheduleSchema | ServerErrorResponse) => {
const data = res as ScheduleSchema;
const error = res as ServerErrorResponse;
if (error.detail) {
set(serverErrorAtom, error.detail[0].msg);
return;
}
// Get session times
const now = Date.now();
const nextEvent = formatNextEvent(data);

if (nextEvent === 'No session') return;

set(nextEventAtom, nextEvent);

if (nextEvent.time < now) {
set(nextEventLiveAtom, true);
set(nextEventTimeAtom, now - nextEvent.endTime);
} else {
set(nextEventTimeAtom, nextEvent.time - now);
}
},
);
}
},
// Dependencies: nextEventAtom
Expand Down
3 changes: 3 additions & 0 deletions src/atoms/results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import { raceAtom, seasonRacesAtom } from './races';
import { seasonAtom } from './seasons';
import { allSessionsAtom, sessionAtom } from './sessions';

// Server Error Atom
export const serverErrorAtom = atom('');

// Telemetry Active
export const telemetryDisableAtom = atom(true);
// Telemetry is disabled if no race and driver are selected
Expand Down
15 changes: 14 additions & 1 deletion src/results.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ interface ConstructorResult {
// UI format
interface DataConfigSchema {
seasons: string[];
schedule: ScheduleSchema[];
schedule: {
year: string;
EventSchedule: ScheduleSchema[];
};
drivers: string[];
sessions: string[];
standings: {
Expand All @@ -109,6 +112,16 @@ interface DataConfigSchema {
};
}

interface ServerErrorResponse {
detail: [
{
loc: string[];
msg: string;
input: string;
},
];
}

// UI Format Next Event
interface NextEventProps {
name: string;
Expand Down
53 changes: 28 additions & 25 deletions src/utils/fakerData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,34 @@ const driverResults: DriverResult[] = Array.from(Array(10).keys()).map(() => ({

export const dataConfig: DataConfigSchema = {
seasons: f1Seasons(),
schedule: Array.from(Array(3).keys()).map(() => ({
RoundNumber: 0,
Country: faker.location.country(),
Location: faker.location.city(),
OfficialEventName: faker.word.words(5),
EventDate: faker.date.future({ years: 1 }).toString(),
EventName: faker.word.words(3),
EventFormat: 'string',
Session1: 'string',
Session1Date: faker.date.future({ years: 1 }).toString(),
Session1DateUtc: faker.date.future({ years: 1 }).toString(),
Session2: 'string',
Session2Date: faker.date.future({ years: 1 }).toString(),
Session2DateUtc: faker.date.future({ years: 1 }).toString(),
Session3: 'string',
Session3Date: faker.date.future({ years: 1 }).toString(),
Session3DateUtc: faker.date.future({ years: 1 }).toString(),
Session4: 'string',
Session4Date: faker.date.future({ years: 1 }).toString(),
Session4DateUtc: faker.date.future({ years: 1 }).toString(),
Session5: 'string',
Session5Date: faker.date.future({ years: 1 }).toString(),
Session5DateUtc: faker.date.future({ years: 1 }).toString(),
F1ApiSupport: true,
})),
schedule: {
year: faker.number.int({ min: 1950, max: 2024 }).toString(),
EventSchedule: Array.from(Array(3).keys()).map(() => ({
RoundNumber: 0,
Country: faker.location.country(),
Location: faker.location.city(),
OfficialEventName: faker.word.words(5),
EventDate: faker.date.future({ years: 1 }).toString(),
EventName: faker.word.words(3),
EventFormat: 'string',
Session1: 'string',
Session1Date: faker.date.future({ years: 1 }).toString(),
Session1DateUtc: faker.date.future({ years: 1 }).toString(),
Session2: 'string',
Session2Date: faker.date.future({ years: 1 }).toString(),
Session2DateUtc: faker.date.future({ years: 1 }).toString(),
Session3: 'string',
Session3Date: faker.date.future({ years: 1 }).toString(),
Session3DateUtc: faker.date.future({ years: 1 }).toString(),
Session4: 'string',
Session4Date: faker.date.future({ years: 1 }).toString(),
Session4DateUtc: faker.date.future({ years: 1 }).toString(),
Session5: 'string',
Session5Date: faker.date.future({ years: 1 }).toString(),
Session5DateUtc: faker.date.future({ years: 1 }).toString(),
F1ApiSupport: true,
})),
},
drivers: [
'All Drivers',
'Drive 1',
Expand Down
9 changes: 7 additions & 2 deletions src/utils/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const fetchAPI = async (
const options = statusCheck ? { headers: { cache: 'no-store' } } : {};

// Get dummy data or return false
const dummy: string[] | ScheduleSchema[] | false =
const dummy: string[] | DataConfigSchema['schedule'] | false =
dataConfig[
endpoint.split('?')[0] as 'seasons' | 'schedule' | 'drivers' | 'sessions'
] || false;
Expand Down Expand Up @@ -154,8 +154,13 @@ export const fetchAPI = async (
.then((data) => data)
// Catch errors from above
.catch((err) => {
// Handle server not connecting error
if (err === 'Server not connecting') return dummy;
if (err.status === 404) return dummy;

// Handle api errors
if (err.cause.status === 422) {
return err.cause.json();
}

return dummy;
});
Expand Down

0 comments on commit 64920b2

Please sign in to comment.