Compare commits

...

4 Commits

7 changed files with 115 additions and 55 deletions

View File

@ -1,16 +1,38 @@
import { Provider } from 'react-redux';
import type { Meta, StoryObj } from '@storybook/react';
import EvolutionSpecies from './EvolutionSpecies';
import {
MockedState,
MockStoreProps,
mockStore,
} from 'features/InfoDialog/infoDialogSlice.storybook';
const Mockstore: React.FC<MockStoreProps> = ({ InfoDialogState, children }) => (
<Provider store={mockStore({ InfoDialogState })}>{children}</Provider>
);
const meta: Meta<typeof EvolutionSpecies> = {
title: 'Component/EvolutionSpecies',
component: EvolutionSpecies,
decorators: [
(story: () => React.ReactNode) => (
<div style={{ padding: '3rem' }}>{story()}</div>
),
],
tags: ['autodocs'],
excludeStories: /.*MockedState$/,
};
export default meta;
type Story = StoryObj<typeof EvolutionSpecies>;
export const Bulbasaur: Story = {
decorators: [
(story: () => React.ReactNode) => (
<Mockstore InfoDialogState={MockedState.infoDialog}>{story()}</Mockstore>
),
],
args: {
types: ['grass', 'poison'],
image_url:
@ -20,6 +42,11 @@ export const Bulbasaur: Story = {
};
export const Magneton: Story = {
decorators: [
(story: () => React.ReactNode) => (
<Mockstore InfoDialogState={MockedState.infoDialog}>{story()}</Mockstore>
),
],
args: {
types: ['electric', 'steel'],
image_url:

View File

@ -3,18 +3,22 @@ import { motion } from 'framer-motion';
import './EvolutionSpecies.css';
import { LazyLoadImage } from 'react-lazy-load-image-component';
import { colorTypeGradients } from 'components/utils';
import { useAppDispatch } from '../../app/hooks';
import { fetchSelectedPokemonInfo } from '../../features/InfoDialog/infoDialogSlice';
export interface EvolutionSpeciesProps {
export type EvolutionSpeciesProps = {
types: string[];
name: string;
image_url: string;
}
};
const EvolutionSpecies = ({
types,
name,
image_url,
}: EvolutionSpeciesProps) => {
const dispatch = useAppDispatch();
const finalColor = colorTypeGradients(types);
return (
@ -47,6 +51,7 @@ const EvolutionSpecies = ({
delayMethod={'debounce'}
effect={'blur'}
className={'evo_img'}
onClick={() => dispatch(fetchSelectedPokemonInfo(name))}
/>
</div>
</div>

View File

@ -1,16 +1,38 @@
import { Provider } from 'react-redux';
import type { Meta, StoryObj } from '@storybook/react';
import InfoDialogComponent from './InfoDialogComponent';
import {
MockedState,
MockStoreProps,
mockStore,
} from 'features/InfoDialog/infoDialogSlice.storybook';
const Mockstore: React.FC<MockStoreProps> = ({ InfoDialogState, children }) => (
<Provider store={mockStore({ InfoDialogState })}>{children}</Provider>
);
const meta: Meta<typeof InfoDialogComponent> = {
title: 'Component/InfoDialogComponent',
component: InfoDialogComponent,
decorators: [
(story: () => React.ReactNode) => (
<div style={{ padding: '3rem' }}>{story()}</div>
),
],
tags: ['autodocs'],
excludeStories: /.*MockedState$/,
};
export default meta;
type Story = StoryObj<typeof InfoDialogComponent>;
export const Duduo: Story = {
decorators: [
(story: () => React.ReactNode) => (
<Mockstore InfoDialogState={MockedState.infoDialog}>{story()}</Mockstore>
),
],
args: {
openDialog: true,
id: 84,

View File

@ -7,31 +7,18 @@ import { findPokeTypeAsset } from 'components/PokemonTypes';
import { colorTypeGradients } from 'components/utils';
import GenderRate from 'components/GenderRate';
import Delayed from 'components/Delayed';
import EvolutionSpecies, {
EvolutionSpeciesProps,
} from 'components/EvolutionSpecies';
import EvolutionSpecies from 'components/EvolutionSpecies';
import { InfoDialogDetails } from 'features/InfoDialog/infoDialogSlice';
export interface Stat {
stat__name: string;
stat__value: number;
}
export interface InfoDialogComponentProps {
export type InfoDialogComponentProps = InfoDialogDetails & {
openDialog: boolean;
closeDialog: () => void;
id: number;
name: string;
types: string[];
genera: string;
image: string;
height: number;
weight: number;
genderRatio: number;
description: string;
abilities: string[];
stats: Stat[];
evolutionChain: EvolutionSpeciesProps[];
}
};
const InfoDialog = ({
openDialog,

View File

@ -0,0 +1,48 @@
import { InfoDialogStateProps } from './infoDialogSlice';
import { configureStore, createSlice } from '@reduxjs/toolkit';
export const MockedState = {
// Copied from Redux DevTools from browser
infoDialog: {
isOpen: false,
InfoDialogDetails: {
id: 0,
name: '',
genera: '',
image: '',
types: [],
height: 0,
weight: 0,
genderRatio: 0,
description: '',
abilities: [],
stats: [],
evolutionChain: [],
},
},
};
export interface MockStoreProps {
InfoDialogState: InfoDialogStateProps;
children: React.ReactNode;
}
export const mockSlice = (infoDialogState: {
InfoDialogState: InfoDialogStateProps;
}) => {
return createSlice({
name: 'infoDialog',
initialState: infoDialogState,
reducers: {},
});
};
export const mockStore = (infoDialogState: {
InfoDialogState: InfoDialogStateProps;
}) => {
return configureStore({
reducer: {
infoDialog: mockSlice(infoDialogState).reducer,
},
});
};

View File

@ -13,7 +13,7 @@ import {
PokemonSpeciesResponseData,
} from 'types/api';
type InfoDiaglogDetails = {
export type InfoDialogDetails = {
id: number;
name: string;
genera: string;
@ -28,7 +28,7 @@ type InfoDiaglogDetails = {
evolutionChain: EvolutionSpeciesProps[];
};
const initialInfoDialogDetails: InfoDiaglogDetails = {
const initialInfoDialogDetails: InfoDialogDetails = {
id: 0,
name: '',
genera: '',
@ -45,7 +45,7 @@ const initialInfoDialogDetails: InfoDiaglogDetails = {
export type InfoDialogStateProps = {
isOpen: boolean;
InfoDialogDetails: InfoDiaglogDetails;
InfoDialogDetails: InfoDialogDetails;
};
export const initialState: InfoDialogStateProps = {
@ -90,7 +90,7 @@ export const constructPokemonInfoFromResponses = (
fetchedPokemon: PokemonResponseData,
fetchedPokemonSpecies: PokemonSpeciesResponseData,
evolutionChain: EvolutionSpeciesProps[],
): InfoDiaglogDetails => {
): InfoDialogDetails => {
return {
id: fetchedPokemon.id,
name: fetchedPokemon.name,
@ -114,12 +114,12 @@ export const constructPokemonInfoFromResponses = (
export const fetchSelectedPokemonInfo = createAsyncThunk(
'infoDialog/fetchSelectedPokemonInfo',
async (pokemonId: number, thunkAPI) => {
async (pokemonIdOrName: number | string, thunkAPI) => {
const dispatch = thunkAPI.dispatch;
try {
const selectedPokemon = await dispatch(
pokeApi.endpoints.getPokemon.initiate(pokemonId),
pokeApi.endpoints.getPokemon.initiate(pokemonIdOrName),
);
if (selectedPokemon.data) {

View File

@ -62,31 +62,6 @@ const MockedState = {
},
],
},
filter: {
regionOptions: [],
typeOptions: [],
sortOptions: [],
selectedRegion: '',
selectedType: '',
selectedSort: '',
searchInput: '',
},
pokeApi: {
queries: {},
mutations: {},
provided: {},
subscriptions: {},
config: {
online: true,
focused: true,
middlewareRegistered: false,
refetchOnFocus: false,
refetchOnReconnect: false,
refetchOnMountOrArgChange: false,
keepUnusedDataFor: 60,
reducerPath: 'pokeApi',
},
},
};
interface MockStoreProps {
@ -99,11 +74,7 @@ const mockSlice = (pokedexState: PokedexStateProps) => {
return createSlice({
name: 'pokedex',
initialState: pokedexState,
reducers: {
setIsLoadingPokemons: (state, action) => {
state.isLoadingPokemons = action.payload;
},
},
reducers: {},
});
};
const mockStore = (pokedexState: PokedexStateProps) => {