Trying to impolement InfoDialogSlice and related api endpoints (Code is faulty)
This commit is contained in:
parent
8c442946d3
commit
78b7a4a5f4
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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<PokemonResponseData, number | string>({
|
||||
query: IdOrName => ({ url: `pokemon/${IdOrName}` }),
|
||||
getPokemon: builder.query<PokemonResponseData, number>({
|
||||
query: Id => ({ url: `pokemon/${Id}` }),
|
||||
}),
|
||||
getPokemonSpecies: builder.query<
|
||||
PokemonSpeciesResponseData,
|
||||
number | string
|
||||
>({
|
||||
query: IdOrName => ({ url: `pokemon-species/${IdOrName}` }),
|
||||
getPokemonSpecies: builder.query<PokemonSpeciesResponseData, number>({
|
||||
query: Id => ({ url: `pokemon-species/${Id}` }),
|
||||
}),
|
||||
getEvolutionChain: builder.query<EvolutionChainResponseData, number>({
|
||||
query: Id => ({ url: `evolution-chain/${Id}` }),
|
||||
}),
|
||||
getPokemonInfo: builder.query<string, number>({
|
||||
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' };
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
|
@ -1 +1,2 @@
|
||||
export { default } from './EvolutionSpecies';
|
||||
export * from './EvolutionSpecies';
|
||||
|
@ -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',
|
||||
},
|
||||
],
|
||||
|
@ -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 = ({
|
||||
>
|
||||
<EvolutionSpecies
|
||||
types={evo.types}
|
||||
image_url={evo.image}
|
||||
image_url={evo.image_url}
|
||||
name={evo.name}
|
||||
/>
|
||||
{evolutionChain.indexOf(evo) + 1 &&
|
||||
|
@ -1 +1,2 @@
|
||||
export { default } from './InfoDialogComponent';
|
||||
export type { InfoDialogComponentProps } from './InfoDialogComponent';
|
||||
|
@ -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 (
|
||||
<div>
|
||||
<Dialog
|
||||
aria-labelledby="customized-dialog-title"
|
||||
open={props.open}
|
||||
fullWidth
|
||||
maxWidth="md"
|
||||
className="dialog__bg noselect"
|
||||
>
|
||||
<DialogContent
|
||||
style={{
|
||||
background: `linear-gradient(${finalColor[0]}, ${finalColor[1]})`,
|
||||
}}
|
||||
className="dialog__content"
|
||||
>
|
||||
<div className="info__container">
|
||||
<div className="info__container__img">
|
||||
<div className="pokemon__id">
|
||||
#{String(props.id).padStart(3, '0')}
|
||||
</div>
|
||||
<div className="pokemon__name">{props.name}</div>
|
||||
<div
|
||||
className="pokemon__genera"
|
||||
style={{ background: finalColor[0] }}
|
||||
>
|
||||
{props.genere}
|
||||
</div>
|
||||
<div>
|
||||
<img src={props.image} alt="poke-img" />
|
||||
</div>
|
||||
<div className="info__container__data__type">
|
||||
{props.types.map(type => (
|
||||
<Tooltip
|
||||
title={type}
|
||||
key={type}
|
||||
TransitionComponent={Zoom}
|
||||
arrow
|
||||
>
|
||||
<div className={`poke__type__bg ${type}`}>
|
||||
<img src={findPokeTypeAsset(type)} alt="poke-type" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
<div className="dimensions">
|
||||
<p>
|
||||
<span
|
||||
className="info__container__headings"
|
||||
style={{ fontSize: '20px' }}
|
||||
>
|
||||
Height
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span
|
||||
className="info__container__headings"
|
||||
style={{ fontSize: '20px' }}
|
||||
>
|
||||
Weight
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="gender__container">
|
||||
{props.genderRatio === -1 ? (
|
||||
'Genderless'
|
||||
) : (
|
||||
<GenderRate genderRatio={props.genderRatio} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="info__container__data">
|
||||
<div className={'right__box'}>
|
||||
<div>
|
||||
<div className={'info__container__headings'}>About</div>
|
||||
<div className={'desc'}>{props.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<>
|
||||
<InfoDialogComponent
|
||||
openDialog={isOpen}
|
||||
id={selectedPokemonId}
|
||||
name={}
|
||||
types={}
|
||||
genera={}
|
||||
image={}
|
||||
height={}
|
||||
weight={}
|
||||
genderRatio={}
|
||||
description={}
|
||||
abilities={}
|
||||
stats={}
|
||||
evolutionChain={}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
67
src/features/InfoDialog/infoDialogSlice.ts
Normal file
67
src/features/InfoDialog/infoDialogSlice.ts
Normal file
@ -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<InfoDialogStateProps> = createSlice({
|
||||
name: 'infoDialog',
|
||||
initialState,
|
||||
reducers: {
|
||||
setIsOpen: (state, action: PayloadAction<boolean>) => {
|
||||
state.isOpen = action.payload;
|
||||
},
|
||||
setSkipGetPokemonSpeciesQuery: (state, action: PayloadAction<boolean>) => {
|
||||
state.skipGetPokemonSpeciesQuery = action.payload;
|
||||
},
|
||||
setSkipGetEvolutionChainQuery: (state, action: PayloadAction<boolean>) => {
|
||||
state.skipGetEvolutionChainQuery = action.payload;
|
||||
},
|
||||
setSelectedPokemonId: (state, action: PayloadAction<number>) => {
|
||||
state.selectedPokemonId = action.payload;
|
||||
},
|
||||
setPokemonSpeciesIdToFetch: (state, action: PayloadAction<number>) => {
|
||||
state.pokemonSpeciesIdToFetch = action.payload;
|
||||
},
|
||||
setEvolutionChainIdToFetch: (state, action: PayloadAction<number>) => {
|
||||
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);
|
||||
};
|
@ -68,7 +68,7 @@ export type PokemonSpeciesResponseData = {
|
||||
};
|
||||
};
|
||||
|
||||
type EvolutionChain = {
|
||||
export type EvolutionChain = {
|
||||
evolves_to: EvolutionChain[];
|
||||
species: {
|
||||
name: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user