From a823d18b058241b0a1c2bd33126e555e669e1279 Mon Sep 17 00:00:00 2001 From: Eddie Thuo Date: Wed, 10 Jan 2024 18:08:58 +0000 Subject: [PATCH] Update footy-report extension - Merge pull request #29 from thuoe/next - Merge pull request #28 from thuoe/feature/thu-34-error-handling-faulty-api-tokens - fix: handle errors across views - refactor: hooks response types - fix: handle hook data responses if invalid token is found - fix: provide error from promise hook - feat: create error toast hook - Merge pull request #27 from thuoe/main --- .../src/components/PlayerDetails.tsx | 7 +++++-- .../footy-report/src/components/TeamDetails.tsx | 6 ++++-- extensions/footy-report/src/hooks/index.ts | 1 + .../footy-report/src/hooks/useErrorToast.ts | 13 +++++++++++++ .../footy-report/src/hooks/useFetchFixtures.ts | 15 +++++++++++++-- .../src/hooks/useFetchPlayerStats.ts | 17 ++++++++++++++--- .../footy-report/src/hooks/useFetchTeams.ts | 13 +++++++++++-- .../src/hooks/useSportMonksClient.ts | 4 ++-- extensions/footy-report/src/searchTeam.tsx | 17 ++++++++++------- extensions/footy-report/src/types.ts | 7 +++++++ 10 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 extensions/footy-report/src/hooks/useErrorToast.ts diff --git a/extensions/footy-report/src/components/PlayerDetails.tsx b/extensions/footy-report/src/components/PlayerDetails.tsx index cc0b90cf88e9a..60fbadfb61bec 100644 --- a/extensions/footy-report/src/components/PlayerDetails.tsx +++ b/extensions/footy-report/src/components/PlayerDetails.tsx @@ -1,5 +1,5 @@ import { Detail } from "@raycast/api"; -import { useFetchPlayerStats } from "@src/hooks"; +import { useErrorToast, useFetchPlayerStats } from "@src/hooks"; import { Player } from "@src/types"; import { createMarkdownTable } from "@src/utils"; import { differenceInCalendarYears, parse } from "date-fns"; @@ -11,10 +11,13 @@ const PlayerDetails = ({ player: Player; team: { id: string; name: string; image_path: string }; }) => { - const { data, isLoading } = useFetchPlayerStats({ + const { data, isLoading, error } = useFetchPlayerStats({ id: player.id, teamId: team.id, }); + + useErrorToast(error); + const markdown = ` ![](${player.image_path}?raycast-width=150&raycast-height=150) diff --git a/extensions/footy-report/src/components/TeamDetails.tsx b/extensions/footy-report/src/components/TeamDetails.tsx index bad3bdc13e066..0cbb8e26474ed 100644 --- a/extensions/footy-report/src/components/TeamDetails.tsx +++ b/extensions/footy-report/src/components/TeamDetails.tsx @@ -3,14 +3,14 @@ import Squad from "@src/components/Squad"; import { Grid, List } from "@raycast/api"; import { Category, Team } from "@src/types"; import { useState, ComponentProps } from "react"; -import { useFetchFixtures } from "@src/hooks"; +import { useErrorToast, useFetchFixtures } from "@src/hooks"; const MAX_LIST_SIZE = 6; const MAX_GRID_SIZE = 50; const TeamDetails = ({ team }: { team: Team }) => { const [category, setCategory] = useState(Category.All); - const { data, isLoading } = useFetchFixtures(team.id, { + const { data, isLoading, error } = useFetchFixtures(team.id, { result_info: true, starting_at: true, }); @@ -27,6 +27,8 @@ const TeamDetails = ({ team }: { team: Team }) => { fixtures: prevFixtures, }; + useErrorToast(error); + if ( category === Category.All || category === Category.UpcomingMatches || diff --git a/extensions/footy-report/src/hooks/index.ts b/extensions/footy-report/src/hooks/index.ts index 6e79f7cece634..7a6afff129d56 100644 --- a/extensions/footy-report/src/hooks/index.ts +++ b/extensions/footy-report/src/hooks/index.ts @@ -3,3 +3,4 @@ export { default as useSportMonksClient } from "@src/hooks/useSportMonksClient"; export { default as useFetchTeams } from "@src/hooks/useFetchTeams"; export { default as useFetchFixtures } from "@src/hooks/useFetchFixtures"; export { default as useFetchPlayerStats } from "@src/hooks/useFetchPlayerStats"; +export { default as useErrorToast } from "@src/hooks/useErrorToast"; diff --git a/extensions/footy-report/src/hooks/useErrorToast.ts b/extensions/footy-report/src/hooks/useErrorToast.ts new file mode 100644 index 0000000000000..d269061787742 --- /dev/null +++ b/extensions/footy-report/src/hooks/useErrorToast.ts @@ -0,0 +1,13 @@ +import { Toast, showToast } from "@raycast/api"; + +const useErrorToast = (error: string | null) => { + if (error) { + showToast({ + style: Toast.Style.Failure, + title: "Something went wrong", + message: error, + }); + } +}; + +export default useErrorToast; diff --git a/extensions/footy-report/src/hooks/useFetchFixtures.ts b/extensions/footy-report/src/hooks/useFetchFixtures.ts index 3b263acc2d233..4514bdd8a2caa 100644 --- a/extensions/footy-report/src/hooks/useFetchFixtures.ts +++ b/extensions/footy-report/src/hooks/useFetchFixtures.ts @@ -1,7 +1,7 @@ import { formatSelectFields } from "@src/utils"; import useSportMonksClient from "./useSportMonksClient"; import { subDays, format, addDays } from "date-fns"; -import { Fixture, Result, Location } from "@src/types"; +import { Fixture, Result, Location, HookResponse } from "@src/types"; type SelectFields = { result_info: boolean; @@ -71,6 +71,17 @@ const useFetchFixtures = (teamId: string, selectFields: SelectFields) => { method: "get", path: `/fixtures/between/${startDate}/${endDate}/${teamId}?include=league;venue;participants;tvStations.tvStation;scores&select=name,${selectedFields}`, }); + const hookResponse: HookResponse = { + data: [], + isLoading, + error: null, + revalidate, + }; + + if (data?.status === 401) { + return { ...hookResponse, error: "Invalid API Token" }; + } + const response: SportMonksFixturesByRange[] = data?.data; const fixtures: Fixture[] = response ?.map(({ league, participants, scores, tvstations, ...fixtureData }) => { @@ -116,7 +127,7 @@ const useFetchFixtures = (teamId: string, selectFields: SelectFields) => { }; }) .reverse(); - return { data: fixtures, isLoading, revalidate }; + return { ...hookResponse, data: fixtures }; }; export default useFetchFixtures; diff --git a/extensions/footy-report/src/hooks/useFetchPlayerStats.ts b/extensions/footy-report/src/hooks/useFetchPlayerStats.ts index 74c7220cbcdf4..d3efdf3e4ac80 100644 --- a/extensions/footy-report/src/hooks/useFetchPlayerStats.ts +++ b/extensions/footy-report/src/hooks/useFetchPlayerStats.ts @@ -1,4 +1,5 @@ -import useSportMonksClient from "./useSportMonksClient"; +import { HookResponse } from "@src/types"; +import useSportMonksClient from "@src/hooks/useSportMonksClient"; enum EventType { GOALS = 52, @@ -61,8 +62,18 @@ const useFetchPlayerStats = ({ path: `/players/${id}?include=statistics.season.league;statistics.details&filters=playerStatisticDetailTypes:${formatEvents()};team=${teamId}`, }); - const response: SportMonksPlayerStatsDetail[] = data?.data?.statistics; + const hookResponse: HookResponse<(string | number)[], typeof revalidate> = { + data: [], + error: null, + isLoading, + revalidate, + }; + if (data?.status === 401) { + return { ...hookResponse, error: "Invalid API Token" }; + } + + const response: SportMonksPlayerStatsDetail[] = data?.data?.statistics; const stats = response ?.filter( ({ team_id, details, season: { league } }) => @@ -84,7 +95,7 @@ const useFetchPlayerStats = ({ return [name, goals, assists, appearances, yellowCards, redCards]; }); - return { data: stats, isLoading, revalidate }; + return { ...hookResponse, data: stats }; }; export default useFetchPlayerStats; diff --git a/extensions/footy-report/src/hooks/useFetchTeams.ts b/extensions/footy-report/src/hooks/useFetchTeams.ts index b5667136c6b3f..e382c9794f996 100644 --- a/extensions/footy-report/src/hooks/useFetchTeams.ts +++ b/extensions/footy-report/src/hooks/useFetchTeams.ts @@ -1,5 +1,5 @@ import { useSportMonksClient } from "@src/hooks"; -import { Team } from "@src/types"; +import { HookResponse, Team } from "@src/types"; import { formatSelectFields } from "@src/utils"; const MAX_RESULTS_PER_PAGE = 10; @@ -39,6 +39,15 @@ const useFetchTeams = (name: string, selectFields: SelectFields) => { path: `/teams/search/${name}?per_page=${MAX_RESULTS_PER_PAGE}&select=name,${selectedFields}&include=players.player.position;players.player.country`, execute: name.length !== 0, }); + const hookResponse: HookResponse = { + error: null, + data: [], + isLoading, + revalidate, + }; + if (data?.status === 401) { + return { ...hookResponse, error: "Invalid API Token" }; + } const response: SportMonksTeamResponse[] = data?.data; const teams: Team[] = response?.map((team) => { @@ -62,7 +71,7 @@ const useFetchTeams = (name: string, selectFields: SelectFields) => { }), }; }) ?? []; - return { data: teams, isLoading, revalidate }; + return { ...hookResponse, data: teams }; }; export default useFetchTeams; diff --git a/extensions/footy-report/src/hooks/useSportMonksClient.ts b/extensions/footy-report/src/hooks/useSportMonksClient.ts index fcc9cb0764d3b..42c7f9bb10e8f 100644 --- a/extensions/footy-report/src/hooks/useSportMonksClient.ts +++ b/extensions/footy-report/src/hooks/useSportMonksClient.ts @@ -12,7 +12,7 @@ type Params = { const useSportMonksClient = ({ path, method, params, execute }: Params) => { const apiKey = useAPIKey(); - const { data, revalidate, isLoading } = usePromise( + const { data, isLoading, error, revalidate } = usePromise( async (path: string) => { try { const { @@ -42,7 +42,7 @@ const useSportMonksClient = ({ path, method, params, execute }: Params) => { execute, }, ); - return { data, revalidate, isLoading }; + return { data, revalidate, isLoading, error }; }; export default useSportMonksClient; diff --git a/extensions/footy-report/src/searchTeam.tsx b/extensions/footy-report/src/searchTeam.tsx index 80e3c2c8d53fe..348acb09b054c 100644 --- a/extensions/footy-report/src/searchTeam.tsx +++ b/extensions/footy-report/src/searchTeam.tsx @@ -11,7 +11,7 @@ import { } from "@raycast/api"; import { useCachedPromise } from "@raycast/utils"; import TeamDetails from "@src/components/TeamDetails"; -import { useFetchTeams } from "@src/hooks"; +import { useErrorToast, useFetchTeams } from "@src/hooks"; import { Team } from "@src/types"; import { useState } from "react"; @@ -25,12 +25,15 @@ export default (props: LaunchProps<{ arguments: Arguments.SearchTeam }>) => { } = useCachedPromise(async () => { return LocalStorage.getItem("favorite-teams"); }); - const { data: teamsFound, isLoading: teamsLoading } = useFetchTeams( - searchText, - { - image_path: true, - }, - ); + const { + data: teamsFound, + isLoading: teamsLoading, + error, + } = useFetchTeams(searchText, { + image_path: true, + }); + + useErrorToast(error); const favoriteTeams: Team[] = favoritesCached ? JSON.parse(favoritesCached) diff --git a/extensions/footy-report/src/types.ts b/extensions/footy-report/src/types.ts index b7f212595ac89..71e76aecb6ece 100644 --- a/extensions/footy-report/src/types.ts +++ b/extensions/footy-report/src/types.ts @@ -69,3 +69,10 @@ export type Fixture = { url: string; }[]; }; + +export type HookResponse = { + data: T[]; + error: string | null; + isLoading: boolean; + revalidate: K; +};