From 78b7a4a5f44d357ce074f3e4ca3319f4e5bcfc3c Mon Sep 17 00:00:00 2001 From: Jason Zhu Date: Wed, 17 May 2023 21:50:34 +1000 Subject: [PATCH] Trying to impolement InfoDialogSlice and related api endpoints (Code is faulty) --- src/app/services/pokeApi.test.ts | 16 ++ src/app/services/pokeApi.ts | 61 ++++++- src/app/store.ts | 2 + src/components/EvolutionSpecies/index.ts | 1 + .../InfoDialogComponent.stories.tsx | 4 +- .../InfoDialogComponent.tsx | 8 +- src/components/InfoDialogComponent/index.ts | 1 + src/features/InfoDialog/InfoDialog.tsx | 159 +++++------------- src/features/InfoDialog/infoDialogSlice.ts | 67 ++++++++ src/types/api.ts | 2 +- 10 files changed, 189 insertions(+), 132 deletions(-) create mode 100644 src/features/InfoDialog/infoDialogSlice.ts diff --git a/src/app/services/pokeApi.test.ts b/src/app/services/pokeApi.test.ts index 2d71819..a24bd88 100644 --- a/src/app/services/pokeApi.test.ts +++ b/src/app/services/pokeApi.test.ts @@ -1,6 +1,8 @@ import { pokedexSlice } from 'features/Pokedex/pokedexSlice'; import { pokeApi } from 'app/services/pokeApi'; import { filterSlice } from 'features/Filters/filterSlice'; +import { getIdFromUrl } from 'app/services/pokeApi'; + import { configureStore } from '@reduxjs/toolkit'; import { AppStore } from 'app/store'; @@ -87,4 +89,18 @@ describe('pokeApi', () => { }); }); }); + + describe('test helper functions', () => { + test('getIdFromUrl works correctly for PokemonSpecies', () => { + const url = 'https://pokeapi.co/api/v2/pokemon-species/6/'; + const id = getIdFromUrl(url); + expect(id).toBe(6); + }); + + test('getIdFromUrl works correctly for evolution-chain', () => { + const url = 'https://pokeapi.co/api/v2/evolution-chain/2/'; + const id = getIdFromUrl(url); + expect(id).toBe(2); + }); + }); }); diff --git a/src/app/services/pokeApi.ts b/src/app/services/pokeApi.ts index 04663be..1000c1e 100644 --- a/src/app/services/pokeApi.ts +++ b/src/app/services/pokeApi.ts @@ -9,7 +9,10 @@ import { PokemonResponseData, EvolutionChainResponseData, PokemonSpeciesResponseData, + EvolutionChain, } from 'types/api'; +import { InfoDialogComponentProps } from 'components/InfoDialogComponent'; +import { EvolutionSpeciesProps } from 'components/EvolutionSpecies'; export interface pokeApiFullListFetchArgs extends FetchArgs { fetchAllPages?: boolean; @@ -27,6 +30,11 @@ interface PokeAPIFullListResponse { results: any[]; } +export const getIdFromUrl = (url: string) => { + const urlParts = url.split('/'); + return parseInt(urlParts[urlParts.length - 2]); +}; + async function fetchAllPages(url: string | null) { const allResults: any[] = []; @@ -40,6 +48,23 @@ async function fetchAllPages(url: string | null) { return allResults; } +export const convertEvolutionChainResponseDataToEvolutionSpeciesProps = ( + evo: EvolutionChainResponseData, +): EvolutionSpeciesProps[] => { + const result: EvolutionSpeciesProps[] = []; + // const addEvolutionSpeciesProps = (evo: EvolutionChain, level: number) => { + // result.push({ + // name: evo.species.name, + // }); + // evo.evolves_to.forEach(evo => { + // addEvolutionSpeciesProps(evo, level + 1); + // }); + // }; + // + // addEvolutionSpeciesProps(evo.chain, 0); + return result; +}; + export const paginationBaseQuery = (baseUrl: string) => fetchBaseQuery({ baseUrl }); @@ -94,18 +119,40 @@ export const pokeApi = createApi({ }; }, }), - getPokemon: builder.query({ - query: IdOrName => ({ url: `pokemon/${IdOrName}` }), + getPokemon: builder.query({ + query: Id => ({ url: `pokemon/${Id}` }), }), - getPokemonSpecies: builder.query< - PokemonSpeciesResponseData, - number | string - >({ - query: IdOrName => ({ url: `pokemon-species/${IdOrName}` }), + getPokemonSpecies: builder.query({ + query: Id => ({ url: `pokemon-species/${Id}` }), }), getEvolutionChain: builder.query({ query: Id => ({ url: `evolution-chain/${Id}` }), }), + getPokemonInfo: builder.query({ + async queryFn(pokemonId, queryApi) { + const pokemon: PokemonResponseData = await queryApi + .dispatch(pokeApi.endpoints.getPokemon.initiate(pokemonId)) + .unwrap(); + + const pokemonSpecies: PokemonSpeciesResponseData = await queryApi + .dispatch( + pokeApi.endpoints.getPokemonSpecies.initiate( + getIdFromUrl(pokemon.species.url), + ), + ) + .unwrap(); + + const evolutionChain: EvolutionChainResponseData = await queryApi + .dispatch( + pokeApi.endpoints.getEvolutionChain.initiate( + getIdFromUrl(pokemonSpecies.evolution_chain.url), + ), + ) + .unwrap(); + + return { data: 'test' }; + }, + }), }), }); diff --git a/src/app/store.ts b/src/app/store.ts index d664fde..f25d38b 100644 --- a/src/app/store.ts +++ b/src/app/store.ts @@ -1,6 +1,7 @@ import { configureStore } from '@reduxjs/toolkit'; import { pokedexSlice } from 'features/Pokedex/pokedexSlice'; import { filterSlice } from 'features/Filters/filterSlice'; +import { infoDialogSlice } from 'features/InfoDialog/infoDialogSlice'; import { pokeApi } from './services/pokeApi'; export const store = configureStore({ @@ -8,6 +9,7 @@ export const store = configureStore({ // component slices pokedex: pokedexSlice.reducer, filter: filterSlice.reducer, + infoDialog: infoDialogSlice.reducer, // api slices [pokeApi.reducerPath]: pokeApi.reducer, diff --git a/src/components/EvolutionSpecies/index.ts b/src/components/EvolutionSpecies/index.ts index f413555..a45e03a 100644 --- a/src/components/EvolutionSpecies/index.ts +++ b/src/components/EvolutionSpecies/index.ts @@ -1 +1,2 @@ export { default } from './EvolutionSpecies'; +export * from './EvolutionSpecies'; diff --git a/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx b/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx index 2df6200..d13e4a5 100644 --- a/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx +++ b/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx @@ -36,14 +36,14 @@ export const Duduo: Story = { evolutionChain: [ { types: ['normal', 'flying'], - image: + image_url: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/84.svg', name: 'Doduo', }, { name: 'Dodrio', types: ['normal', 'flying'], - image: + image_url: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/85.svg', }, ], diff --git a/src/components/InfoDialogComponent/InfoDialogComponent.tsx b/src/components/InfoDialogComponent/InfoDialogComponent.tsx index 8f02ed0..1b2ef17 100644 --- a/src/components/InfoDialogComponent/InfoDialogComponent.tsx +++ b/src/components/InfoDialogComponent/InfoDialogComponent.tsx @@ -7,7 +7,9 @@ import { findPokeTypeAsset } from 'components/PokemonTypes'; import { colorTypeGradients } from 'components/utils'; import GenderRate from 'components/GenderRate'; import Delayed from 'components/Delayed'; -import EvolutionSpecies from 'components/EvolutionSpecies'; +import EvolutionSpecies, { + EvolutionSpeciesProps, +} from 'components/EvolutionSpecies'; interface Stat { stat__name: string; @@ -27,7 +29,7 @@ export interface InfoDialogComponentProps { description: string; abilities: string[]; stats: Stat[]; - evolutionChain: { types: string[]; image: string; name: string }[]; + evolutionChain: EvolutionSpeciesProps[]; } const InfoDialog = ({ @@ -171,7 +173,7 @@ const InfoDialog = ({ > {evolutionChain.indexOf(evo) + 1 && diff --git a/src/components/InfoDialogComponent/index.ts b/src/components/InfoDialogComponent/index.ts index e81c84b..26b8473 100644 --- a/src/components/InfoDialogComponent/index.ts +++ b/src/components/InfoDialogComponent/index.ts @@ -1 +1,2 @@ export { default } from './InfoDialogComponent'; +export type { InfoDialogComponentProps } from './InfoDialogComponent'; diff --git a/src/features/InfoDialog/InfoDialog.tsx b/src/features/InfoDialog/InfoDialog.tsx index 006f82a..f04dae0 100644 --- a/src/features/InfoDialog/InfoDialog.tsx +++ b/src/features/InfoDialog/InfoDialog.tsx @@ -1,131 +1,52 @@ -import { Dialog, DialogContent, Tooltip, Zoom } from '@mui/material'; +import { useEffect } from 'react'; -import { findPokeTypeAsset } from 'components/PokemonTypes'; -import { colorTypeGradients } from 'components/utils'; -import GenderRate from 'components/GenderRate'; +import { useAppDispatch, useAppSelector } from 'app/hooks'; + +import InfoDialogComponent from 'components/InfoDialogComponent'; +import { + useGetPokemonQuery, + useGetPokemonSpeciesQuery, + useGetEvolutionChainQuery, +} from 'app/services/pokeApi'; +import { setPokemonSpeciesIdToFetch } from './infoDialogSlice'; export interface InfoDialogProps { open: boolean; - cancel: boolean; - id: number; - name: string; - genere: string; - types: string[]; - height: number; - weight: number; - genderRatio: number; - description: string; - abilities: string[]; - stats: { - hp: number; - attack: number; - defense: number; - spAttack: number; - spDefense: number; - speed: number; - }; - image: string; + pokemonId: string | number; } -const InfoDialog = (props: InfoDialogProps) => { - let finalColor; +const InfoDialog = ({ pokemonId }: InfoDialogProps) => { + const dispatch = useAppDispatch(); - if (props.types.length === 2) { - finalColor = colorTypeGradients( - props.types[0], - props.types[1], - props.types.length, - ); - } else { - finalColor = colorTypeGradients( - props.types[0], - props.types[0], - props.types.length, - ); - } + const isOpen = useAppSelector(state => state.infoDialog.isOpen); + const skipGetPokemonSpeciesQuery = useAppSelector( + state => state.infoDialog.skipGetPokemonSpeciesQuery, + ); + const skipGetEvolutionChainQuery = useAppSelector( + state => state.infoDialog.skipGetEvolutionChainQuery, + ); + const selectedPokemonId = useAppSelector( + state => state.infoDialog.selectedPokemonId, + ); return ( -
- - -
-
-
- #{String(props.id).padStart(3, '0')} -
-
{props.name}
-
- {props.genere} -
-
- poke-img -
-
- {props.types.map(type => ( - -
- poke-type -
-
- ))} -
-
-

- - Height - -

-

- - Weight - -

-
-
- {props.genderRatio === -1 ? ( - 'Genderless' - ) : ( - - )} -
-
-
-
-
-
About
-
{props.description}
-
-
-
-
-
-
-
+ <> + + ); }; diff --git a/src/features/InfoDialog/infoDialogSlice.ts b/src/features/InfoDialog/infoDialogSlice.ts new file mode 100644 index 0000000..da2347b --- /dev/null +++ b/src/features/InfoDialog/infoDialogSlice.ts @@ -0,0 +1,67 @@ +import { createSlice } from '@reduxjs/toolkit'; +import type { Slice, PayloadAction } from '@reduxjs/toolkit'; +import { buildDevCheckHandler } from '@reduxjs/toolkit/dist/query/core/buildMiddleware/devMiddleware'; +import { useAppSelector } from '../../app/hooks'; +import { pokeApi } from '../../app/services/pokeApi'; +import { PokemonResponseData } from '../../types/api'; + +export type InfoDialogStateProps = { + isOpen: boolean; + skipGetPokemonSpeciesQuery: boolean; + skipGetEvolutionChainQuery: boolean; + selectedPokemonId: number; + pokemonSpeciesIdToFetch: number; + evolutionChainIdToFetch: number; +}; + +export const initialState: InfoDialogStateProps = { + isOpen: false, + skipGetPokemonSpeciesQuery: false, + skipGetEvolutionChainQuery: false, + selectedPokemonId: 0, + pokemonSpeciesIdToFetch: 0, + evolutionChainIdToFetch: 0, +}; + +export const infoDialogSlice: Slice = createSlice({ + name: 'infoDialog', + initialState, + reducers: { + setIsOpen: (state, action: PayloadAction) => { + state.isOpen = action.payload; + }, + setSkipGetPokemonSpeciesQuery: (state, action: PayloadAction) => { + state.skipGetPokemonSpeciesQuery = action.payload; + }, + setSkipGetEvolutionChainQuery: (state, action: PayloadAction) => { + state.skipGetEvolutionChainQuery = action.payload; + }, + setSelectedPokemonId: (state, action: PayloadAction) => { + state.selectedPokemonId = action.payload; + }, + setPokemonSpeciesIdToFetch: (state, action: PayloadAction) => { + state.pokemonSpeciesIdToFetch = action.payload; + }, + setEvolutionChainIdToFetch: (state, action: PayloadAction) => { + state.evolutionChainIdToFetch = action.payload; + }, + }, +}); + +export const { + setIsOpen, + setSkipGetPokemonSpeciesQuery, + setSkipGetEvolutionChainQuery, + setSelectedPokemonId, + setPokemonSpeciesIdToFetch, + setEvolutionChainIdToFetch, +} = infoDialogSlice.actions; + +export default infoDialogSlice.reducer; + +const fetchSelectedPokemonInfo = () => async (dispatch: any, getState: any) => { + dispatch(setIsOpen(true)); + const selectedPokemonId = getState().InfoDialog.selectedPokemonId; + const { data: selectedPokemon } = + pokeApi.useGetPokemonQuery(selectedPokemonId); +}; diff --git a/src/types/api.ts b/src/types/api.ts index 13a3f42..5a5e3e7 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -68,7 +68,7 @@ export type PokemonSpeciesResponseData = { }; }; -type EvolutionChain = { +export type EvolutionChain = { evolves_to: EvolutionChain[]; species: { name: string;