Change Redux code style by move all slice initialization process into pokedexSlice, Component are majorly for presentation
parent
fa4fb04efb
commit
83ae2f34d7
|
@ -4,33 +4,10 @@ import {
|
|||
setSelectedRegion,
|
||||
setSelectedType,
|
||||
setSelectedSort,
|
||||
setRegionPokemonIdsList,
|
||||
} from 'features/Pokedex/pokedexSlice';
|
||||
import { RegionPokemonRange } from 'features/Pokedex/types/slice';
|
||||
import { useAppDispatch, useAppSelector } from 'app/hooks';
|
||||
|
||||
const useGetSortOptions = () => {
|
||||
const sortOptions = [
|
||||
{ name: 'ID', value: 'id' },
|
||||
{ name: 'Name', value: 'name' },
|
||||
];
|
||||
return { data: sortOptions };
|
||||
};
|
||||
|
||||
export const useGetRegionPokemons = () => {
|
||||
const data: RegionPokemonRange[] = [
|
||||
{ region: 'kanto', startId: 1, endId: 151 },
|
||||
{ region: 'johto', startId: 152, endId: 251 },
|
||||
{ region: 'hoenn', startId: 252, endId: 386 },
|
||||
{ region: 'sinnoh', startId: 387, endId: 493 },
|
||||
{ region: 'unova', startId: 494, endId: 649 },
|
||||
{ region: 'kalos', startId: 650, endId: 721 },
|
||||
{ region: 'alola', startId: 722, endId: 809 },
|
||||
{ region: 'galar', startId: 810, endId: 898 },
|
||||
];
|
||||
return { data: data };
|
||||
};
|
||||
|
||||
export const createRegionPokemonListOptionElements = (
|
||||
data: RegionPokemonRange[],
|
||||
) => {
|
||||
|
@ -49,54 +26,20 @@ export const createRegionPokemonListOptionElements = (
|
|||
|
||||
const Filters = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selectedRegion = useAppSelector(state => state.pokedex.selectedRegion);
|
||||
const selectedType = useAppSelector(state => state.pokedex.selectedType);
|
||||
const selectedSort = useAppSelector(state => state.pokedex.selectedSort);
|
||||
|
||||
const handleRegionChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
dispatch(setSelectedRegion(event.target.value));
|
||||
};
|
||||
const handleTypeChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
dispatch(setSelectedType(event.target.value));
|
||||
};
|
||||
const handleSortChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
dispatch(setSelectedSort(event.target.value));
|
||||
};
|
||||
const regionPokemonList = useAppSelector(
|
||||
state => state.pokedex.regionPokemonIdsList,
|
||||
);
|
||||
const sortOptions = useAppSelector(state => state.pokedex.sortList);
|
||||
|
||||
const { data: typesData, isLoading: typesLoading } = useGetTypeListQuery();
|
||||
const { data: sortOptions } = useGetSortOptions();
|
||||
const { data: regionPokemonListData } = useGetRegionPokemons();
|
||||
|
||||
// Action when loading the component
|
||||
useEffect(() => {
|
||||
dispatch(setRegionPokemonIdsList(regionPokemonListData));
|
||||
const optionElements =
|
||||
createRegionPokemonListOptionElements(regionPokemonList);
|
||||
|
||||
const initailRegion = Object.keys(regionPokemonListData)[0];
|
||||
if (initailRegion) {
|
||||
const initialEvent = {
|
||||
target: { value: initailRegion },
|
||||
} as React.ChangeEvent<HTMLSelectElement>;
|
||||
handleRegionChange(initialEvent);
|
||||
}
|
||||
|
||||
if (sortOptions && sortOptions.length > 0) {
|
||||
const initialSortEvent = {
|
||||
target: { value: sortOptions[0].value },
|
||||
} as React.ChangeEvent<HTMLSelectElement>;
|
||||
handleSortChange(initialSortEvent);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Send the first type as the default selected type
|
||||
useEffect(() => {
|
||||
if (typesData && typesData.results.length > 0) {
|
||||
const initialTypeEvent = {
|
||||
target: { value: typesData.results[0].name },
|
||||
} as React.ChangeEvent<HTMLSelectElement>;
|
||||
handleTypeChange(initialTypeEvent);
|
||||
}
|
||||
}, [typesData]);
|
||||
|
||||
const optionElements = createRegionPokemonListOptionElements(
|
||||
regionPokemonListData,
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<div className="filter__container">
|
||||
|
@ -105,8 +48,8 @@ const Filters = () => {
|
|||
<div>REGION</div>
|
||||
<select
|
||||
name="regionSelect"
|
||||
onChange={handleRegionChange}
|
||||
value={Object.keys(regionPokemonListData)[0]}
|
||||
onChange={e => dispatch(setSelectedRegion(e.target.value))}
|
||||
value={selectedRegion}
|
||||
>
|
||||
{optionElements}
|
||||
</select>
|
||||
|
@ -115,7 +58,11 @@ const Filters = () => {
|
|||
<div className="filter__items">
|
||||
<div>
|
||||
<div>TYPE</div>
|
||||
<select name="regionSelect" onChange={handleTypeChange}>
|
||||
<select
|
||||
name="regionSelect"
|
||||
onChange={e => dispatch(setSelectedType(e.target.value))}
|
||||
value={selectedType}
|
||||
>
|
||||
{typesLoading ? (
|
||||
<option>Loading...</option>
|
||||
) : (
|
||||
|
@ -134,7 +81,8 @@ const Filters = () => {
|
|||
<select
|
||||
name="sortSelect"
|
||||
disabled={typesLoading}
|
||||
onChange={handleSortChange}
|
||||
onChange={e => dispatch(setSelectedSort(e.target.value))}
|
||||
value={selectedSort}
|
||||
>
|
||||
{sortOptions.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
|
|
|
@ -3,25 +3,29 @@ import Pokemon from './Pokemon';
|
|||
import Filters from './Filters';
|
||||
import Loading from 'components/Loading';
|
||||
|
||||
import charizard from 'features/Pokedex/Pokemon/assets/stories/charizard.svg';
|
||||
import { useAppSelector } from 'app/hooks';
|
||||
|
||||
const Pokedex = () => {
|
||||
const isFetchingRegionPokemonList = useAppSelector(
|
||||
state => state.pokedex.fetchingRegionPokemonList,
|
||||
const isLoadingPokemons = useAppSelector(
|
||||
state => state.pokedex.isLoadingPokemons,
|
||||
);
|
||||
const pokemonList = useAppSelector(state => state.pokedex.pokemonList);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Filters />
|
||||
{isFetchingRegionPokemonList ? (
|
||||
{isLoadingPokemons ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<Pokemon
|
||||
name={'Charizard'}
|
||||
number={6}
|
||||
image={charizard}
|
||||
types={['fire', 'flying']}
|
||||
/>
|
||||
pokemonList.map(pokemon => (
|
||||
<Pokemon
|
||||
key={pokemon.id}
|
||||
name={pokemon.name}
|
||||
number={pokemon.id}
|
||||
image={pokemon.sprites.other.dream_world.front_default}
|
||||
types={pokemon.types.map(type => type.type.name)}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -6,12 +6,31 @@ import { PokedexState, RegionPokemonRange } from 'features/Pokedex/types/slice';
|
|||
|
||||
import { getStartAndEndIdsForRegion } from './utils';
|
||||
import { PokemonResponseData } from './types/api';
|
||||
import { pokedexApi } from './pokedexApi';
|
||||
|
||||
const data: RegionPokemonRange[] = [
|
||||
{ region: 'kanto', startId: 1, endId: 151 },
|
||||
{ region: 'johto', startId: 152, endId: 251 },
|
||||
{ region: 'hoenn', startId: 252, endId: 386 },
|
||||
{ region: 'sinnoh', startId: 387, endId: 493 },
|
||||
{ region: 'unova', startId: 494, endId: 649 },
|
||||
{ region: 'kalos', startId: 650, endId: 721 },
|
||||
{ region: 'alola', startId: 722, endId: 809 },
|
||||
{ region: 'galar', startId: 810, endId: 898 },
|
||||
];
|
||||
const sortOptions = [
|
||||
{ name: 'ID', value: 'id' },
|
||||
{ name: 'Name', value: 'name' },
|
||||
];
|
||||
pokedexApi.endpoints.getTypeList.initiate();
|
||||
|
||||
const initialState: PokedexState = {
|
||||
selectedRegion: '',
|
||||
regionPokemonIdsList: [],
|
||||
regionPokemonIdsList: data,
|
||||
selectedType: '',
|
||||
typeList: [],
|
||||
selectedSort: '',
|
||||
sortList: sortOptions,
|
||||
isLoadingPokemons: true,
|
||||
pokemonList: [],
|
||||
};
|
||||
|
@ -41,6 +60,22 @@ export const pokedexSlice: Slice<PokedexState> = createSlice({
|
|||
setPokemonList: (state, action: PayloadAction<PokemonResponseData[]>) => {
|
||||
state.pokemonList = action.payload;
|
||||
},
|
||||
setTypeList: (state, action: PayloadAction<string[]>) => {
|
||||
state.typeList = action.payload;
|
||||
},
|
||||
},
|
||||
extraReducers: builder => {
|
||||
builder.addMatcher(
|
||||
pokedexApi.endpoints.getTypeList.matchFulfilled,
|
||||
(state, action) => {
|
||||
if (action.payload && action.payload.results.length > 0) {
|
||||
const regionListResults = action.payload.results;
|
||||
state.typeList = regionListResults.map(region => region.name);
|
||||
|
||||
state.selectedType = action.payload.results[0].name;
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -48,7 +83,6 @@ export const {
|
|||
setSelectedRegion,
|
||||
setSelectedType,
|
||||
setSelectedSort,
|
||||
setRegionPokemonIdsList,
|
||||
setIsLoadingPokemons,
|
||||
setPokemonList,
|
||||
} = pokedexSlice.actions;
|
||||
|
|
|
@ -4,7 +4,9 @@ export type PokedexState = {
|
|||
selectedRegion: string;
|
||||
regionPokemonIdsList: RegionPokemonRange[];
|
||||
selectedType: string;
|
||||
typeList: string[];
|
||||
selectedSort: string;
|
||||
sortList: { name: string; value: string }[];
|
||||
isLoadingPokemons: boolean;
|
||||
pokemonList: PokemonResponseData[];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue