From 8f217d678afe318cad2c7caf9df6473b2e866d87 Mon Sep 17 00:00:00 2001 From: Jason Zhu Date: Sat, 20 May 2023 15:07:12 +1000 Subject: [PATCH] Implement onClick action in EvolutionSpecies.tsx, and fix all related storybook --- .../EvolutionSpecies.stories.tsx | 70 +++++++++++++++++++ .../EvolutionSpecies/EvolutionSpecies.tsx | 9 ++- .../InfoDialogComponent.stories.tsx | 65 +++++++++++++++++ src/features/InfoDialog/infoDialogSlice.ts | 4 +- 4 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/components/EvolutionSpecies/EvolutionSpecies.stories.tsx b/src/components/EvolutionSpecies/EvolutionSpecies.stories.tsx index 11112bd..6470480 100644 --- a/src/components/EvolutionSpecies/EvolutionSpecies.stories.tsx +++ b/src/components/EvolutionSpecies/EvolutionSpecies.stories.tsx @@ -1,16 +1,81 @@ +import { Provider } from 'react-redux'; +import { configureStore, createSlice } from '@reduxjs/toolkit'; import type { Meta, StoryObj } from '@storybook/react'; import EvolutionSpecies from './EvolutionSpecies'; +import { InfoDialogStateProps } from 'features/InfoDialog/infoDialogSlice'; + +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: [], + }, + }, +}; + +interface MockStoreProps { + InfoDialogState: InfoDialogStateProps; + children: React.ReactNode; +} + +const mockSlice = (infoDialogState: { + InfoDialogState: InfoDialogStateProps; +}) => { + return createSlice({ + name: 'infoDialog', + initialState: infoDialogState, + reducers: {}, + }); +}; + +const mockStore = (infoDialogState: { + InfoDialogState: InfoDialogStateProps; +}) => { + return configureStore({ + reducer: { + infoDialog: mockSlice(infoDialogState).reducer, + }, + }); +}; + +const Mockstore: React.FC = ({ InfoDialogState, children }) => ( + {children} +); const meta: Meta = { title: 'Component/EvolutionSpecies', component: EvolutionSpecies, + decorators: [ + (story: () => React.ReactNode) => ( +
{story()}
+ ), + ], + tags: ['autodocs'], + excludeStories: /.*MockedState$/, }; export default meta; type Story = StoryObj; export const Bulbasaur: Story = { + decorators: [ + (story: () => React.ReactNode) => ( + {story()} + ), + ], args: { types: ['grass', 'poison'], image_url: @@ -20,6 +85,11 @@ export const Bulbasaur: Story = { }; export const Magneton: Story = { + decorators: [ + (story: () => React.ReactNode) => ( + {story()} + ), + ], args: { types: ['electric', 'steel'], image_url: diff --git a/src/components/EvolutionSpecies/EvolutionSpecies.tsx b/src/components/EvolutionSpecies/EvolutionSpecies.tsx index 1868755..33e9ebb 100644 --- a/src/components/EvolutionSpecies/EvolutionSpecies.tsx +++ b/src/components/EvolutionSpecies/EvolutionSpecies.tsx @@ -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))} /> diff --git a/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx b/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx index d13e4a5..5bd8ae4 100644 --- a/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx +++ b/src/components/InfoDialogComponent/InfoDialogComponent.stories.tsx @@ -1,16 +1,81 @@ +import { Provider } from 'react-redux'; +import { configureStore, createSlice } from '@reduxjs/toolkit'; import type { Meta, StoryObj } from '@storybook/react'; import InfoDialogComponent from './InfoDialogComponent'; +import { InfoDialogStateProps } from 'features/InfoDialog/infoDialogSlice'; + +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: [], + }, + }, +}; + +interface MockStoreProps { + InfoDialogState: InfoDialogStateProps; + children: React.ReactNode; +} + +const mockSlice = (infoDialogState: { + InfoDialogState: InfoDialogStateProps; +}) => { + return createSlice({ + name: 'infoDialog', + initialState: infoDialogState, + reducers: {}, + }); +}; + +const mockStore = (infoDialogState: { + InfoDialogState: InfoDialogStateProps; +}) => { + return configureStore({ + reducer: { + infoDialog: mockSlice(infoDialogState).reducer, + }, + }); +}; + +const Mockstore: React.FC = ({ InfoDialogState, children }) => ( + {children} +); const meta: Meta = { title: 'Component/InfoDialogComponent', component: InfoDialogComponent, + decorators: [ + (story: () => React.ReactNode) => ( +
{story()}
+ ), + ], + tags: ['autodocs'], + excludeStories: /.*MockedState$/, }; export default meta; type Story = StoryObj; export const Duduo: Story = { + decorators: [ + (story: () => React.ReactNode) => ( + {story()} + ), + ], args: { openDialog: true, id: 84, diff --git a/src/features/InfoDialog/infoDialogSlice.ts b/src/features/InfoDialog/infoDialogSlice.ts index f4c3b13..8857df2 100644 --- a/src/features/InfoDialog/infoDialogSlice.ts +++ b/src/features/InfoDialog/infoDialogSlice.ts @@ -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) {