Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Jason Zhu | 8844c3b7ae |
|
@ -9,6 +9,7 @@
|
||||||
"@mui/material": "^5.13.1",
|
"@mui/material": "^5.13.1",
|
||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
"framer-motion": "^10.12.12",
|
"framer-motion": "^10.12.12",
|
||||||
|
"graphql-request": "^6.1.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-lazy-load-image-component": "^1.5.6",
|
"react-lazy-load-image-component": "^1.5.6",
|
||||||
|
|
10
src/App.tsx
10
src/App.tsx
|
@ -8,12 +8,20 @@ import { useAppSelector } from 'app/hooks';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const selectedRegion = useAppSelector(state => state.filter.selectedRegion);
|
const selectedRegion = useAppSelector(state => state.filter.selectedRegion);
|
||||||
|
const selectedType = useAppSelector(state => state.filter.selectedType);
|
||||||
|
const selectedSort = useAppSelector(state => state.filter.selectedSort);
|
||||||
|
const selectedSearchInput = useAppSelector(state => state.filter.searchInput);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App app_container">
|
<div className="App app_container">
|
||||||
<Header />
|
<Header />
|
||||||
<Filters />
|
<Filters />
|
||||||
<Pokedex selectedRegion={selectedRegion} />
|
<Pokedex
|
||||||
|
selectedRegion={selectedRegion}
|
||||||
|
selectedType={selectedType}
|
||||||
|
selectedSort={selectedSort}
|
||||||
|
searchInput={selectedSearchInput}
|
||||||
|
/>
|
||||||
<InfoDialog />
|
<InfoDialog />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
import { AppStore } from 'app/store';
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { createApi } from '@reduxjs/toolkit/query';
|
||||||
|
import { request, gql, ClientError } from 'graphql-request';
|
||||||
|
|
||||||
|
const graphqlBaseQuery =
|
||||||
|
({ baseUrl }: { baseUrl: string }) =>
|
||||||
|
async ({ body }: { body: string }) => {
|
||||||
|
try {
|
||||||
|
const result = await request(baseUrl, body);
|
||||||
|
return { data: result };
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof ClientError) {
|
||||||
|
return { error: { status: error.response.status, data: error } };
|
||||||
|
}
|
||||||
|
return { error: { status: 500, data: error } };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const pokeGraphqlApi = createApi({
|
||||||
|
baseQuery: graphqlBaseQuery({
|
||||||
|
baseUrl: 'https://beta.pokeapi.co/graphql/v1beta',
|
||||||
|
}),
|
||||||
|
endpoints: builder => ({
|
||||||
|
getRegionList: builder.query({
|
||||||
|
query: () => ({
|
||||||
|
body: gql`
|
||||||
|
query {
|
||||||
|
pokemon_v2_region {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
transformResponse: response => response.pokemon_v2_region.data,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
|
@ -4,12 +4,12 @@ import {
|
||||||
PayloadAction,
|
PayloadAction,
|
||||||
Slice,
|
Slice,
|
||||||
} from '@reduxjs/toolkit';
|
} from '@reduxjs/toolkit';
|
||||||
import { FilterStateProps } from './types/slice';
|
import { FilterState } from './types/slice';
|
||||||
import { RegionPokemonRange } from './types/slice';
|
import { RegionPokemonRange } from './types/slice';
|
||||||
import { pokeRestApi } from 'app/services/pokeRestApi';
|
import { pokeRestApi } from 'app/services/pokeRestApi';
|
||||||
import { fetchPokemonsInTheRegion } from 'features/Pokedex/pokedexSlice';
|
import { fetchPokemonsInTheRegion } from 'features/Pokedex/pokedexSlice';
|
||||||
|
|
||||||
export const initialState: FilterStateProps = {
|
const initialState: FilterState = {
|
||||||
regionOptions: [],
|
regionOptions: [],
|
||||||
typeOptions: [],
|
typeOptions: [],
|
||||||
sortOptions: [],
|
sortOptions: [],
|
||||||
|
@ -46,7 +46,7 @@ export const initializeFilterSlice = createAsyncThunk(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const filterSlice: Slice<FilterStateProps> = createSlice({
|
export const filterSlice: Slice<FilterState> = createSlice({
|
||||||
name: 'filter',
|
name: 'filter',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export type FilterStateProps = {
|
export type FilterState = {
|
||||||
regionOptions: RegionPokemonRange[];
|
regionOptions: RegionPokemonRange[];
|
||||||
typeOptions: string[];
|
typeOptions: string[];
|
||||||
sortOptions: { name: string; value: string }[];
|
sortOptions: { name: string; value: string }[];
|
||||||
|
|
|
@ -3,10 +3,8 @@ import { configureStore, createSlice } from '@reduxjs/toolkit';
|
||||||
import type { Meta } from '@storybook/react';
|
import type { Meta } from '@storybook/react';
|
||||||
|
|
||||||
import Pokedex from './Pokedex';
|
import Pokedex from './Pokedex';
|
||||||
import { initialState as initialPokedexState } from './pokedexSlice';
|
import { initialState } from './pokedexSlice';
|
||||||
import { initialState as initialFilterState } from '../Filters/filterSlice';
|
|
||||||
import { PokedexStateProps } from './types/slice';
|
import { PokedexStateProps } from './types/slice';
|
||||||
import { FilterStateProps } from 'features/Filters/types/slice';
|
|
||||||
|
|
||||||
const MockedState = {
|
const MockedState = {
|
||||||
// Copied from Redux DevTools from browser
|
// Copied from Redux DevTools from browser
|
||||||
|
@ -64,55 +62,30 @@ const MockedState = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
filter: {
|
|
||||||
regionOptions: [],
|
|
||||||
typeOptions: [],
|
|
||||||
sortOptions: [],
|
|
||||||
selectedRegion: 'kanto',
|
|
||||||
selectedType: 'All Types',
|
|
||||||
selectedSort: 'id',
|
|
||||||
searchInput: '',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface MockStoreProps {
|
interface MockStoreProps {
|
||||||
pokedexState: PokedexStateProps;
|
pokedexState: PokedexStateProps;
|
||||||
filterState: FilterStateProps;
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a mock store
|
// Create a mock store
|
||||||
const mockPokedexSlice = (pokedexState: PokedexStateProps) => {
|
const mockSlice = (pokedexState: PokedexStateProps) => {
|
||||||
return createSlice({
|
return createSlice({
|
||||||
name: 'pokedex',
|
name: 'pokedex',
|
||||||
initialState: pokedexState,
|
initialState: pokedexState,
|
||||||
reducers: {},
|
reducers: {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const mockFilterSlice = (filterState: FilterStateProps) => {
|
const mockStore = (pokedexState: PokedexStateProps) => {
|
||||||
return createSlice({
|
|
||||||
name: 'filter',
|
|
||||||
initialState: filterState,
|
|
||||||
reducers: {},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const mockStore = (
|
|
||||||
pokedexState: PokedexStateProps,
|
|
||||||
filterState: FilterStateProps,
|
|
||||||
) => {
|
|
||||||
return configureStore({
|
return configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
filter: mockFilterSlice(filterState).reducer,
|
pokedex: mockSlice(pokedexState).reducer,
|
||||||
pokedex: mockPokedexSlice(pokedexState).reducer,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const Mockstore: React.FC<MockStoreProps> = ({
|
const Mockstore: React.FC<MockStoreProps> = ({ pokedexState, children }) => (
|
||||||
pokedexState,
|
<Provider store={mockStore(pokedexState)}>{children}</Provider>
|
||||||
filterState,
|
|
||||||
children,
|
|
||||||
}) => (
|
|
||||||
<Provider store={mockStore(pokedexState, filterState)}>{children}</Provider>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const meta: Meta<typeof Pokedex> = {
|
const meta: Meta<typeof Pokedex> = {
|
||||||
|
@ -132,53 +105,21 @@ export default meta;
|
||||||
export const Loding = {
|
export const Loding = {
|
||||||
decorators: [
|
decorators: [
|
||||||
(story: () => React.ReactNode) => (
|
(story: () => React.ReactNode) => (
|
||||||
<Mockstore
|
<Mockstore pokedexState={initialState}>{story()}</Mockstore>
|
||||||
pokedexState={initialPokedexState}
|
|
||||||
filterState={initialFilterState}
|
|
||||||
>
|
|
||||||
{story()}
|
|
||||||
</Mockstore>
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const All = {
|
export const Primary = {
|
||||||
decorators: [
|
decorators: [
|
||||||
(story: () => React.ReactNode) => (
|
(story: () => React.ReactNode) => (
|
||||||
<Mockstore
|
<Mockstore pokedexState={MockedState.pokedex}>{story()}</Mockstore>
|
||||||
pokedexState={MockedState.pokedex}
|
|
||||||
filterState={MockedState.filter}
|
|
||||||
>
|
|
||||||
{story()}
|
|
||||||
</Mockstore>
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
args: {
|
args: {
|
||||||
selectedRegion: 'kanto',
|
selectedRegion: 'kanto',
|
||||||
},
|
selectedType: 'All Types',
|
||||||
};
|
|
||||||
|
|
||||||
const filterStateOnlyFire = {
|
|
||||||
regionOptions: [],
|
|
||||||
typeOptions: [],
|
|
||||||
sortOptions: [],
|
|
||||||
selectedRegion: 'kanto',
|
|
||||||
selectedType: 'fire',
|
|
||||||
selectedSort: 'id',
|
selectedSort: 'id',
|
||||||
searchInput: '',
|
searchInput: '',
|
||||||
};
|
|
||||||
export const typeFireSelected = {
|
|
||||||
decorators: [
|
|
||||||
(story: () => React.ReactNode) => (
|
|
||||||
<Mockstore
|
|
||||||
pokedexState={MockedState.pokedex}
|
|
||||||
filterState={filterStateOnlyFire}
|
|
||||||
>
|
|
||||||
{story()}
|
|
||||||
</Mockstore>
|
|
||||||
),
|
|
||||||
],
|
|
||||||
args: {
|
|
||||||
selectedRegion: 'kanto',
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,26 +1,77 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import PokemonCard from 'components/PokemonCard';
|
import PokemonCard, { PokemonCardProps } from 'components/PokemonCard';
|
||||||
import Loading from 'components/Loading';
|
import Loading from 'components/Loading';
|
||||||
|
|
||||||
import { useAppSelector, useAppDispatch } from 'app/hooks';
|
import { useAppSelector, useAppDispatch } from 'app/hooks';
|
||||||
import {
|
import { fetchPokemonsInTheRegion } from './pokedexSlice';
|
||||||
fetchPokemonsInTheRegion,
|
|
||||||
searchedSortedFilteredPokemonCardList,
|
|
||||||
} from './pokedexSlice';
|
|
||||||
import { fetchSelectedPokemonInfo } from 'features/InfoDialog/infoDialogSlice';
|
import { fetchSelectedPokemonInfo } from 'features/InfoDialog/infoDialogSlice';
|
||||||
|
|
||||||
|
export const filterPokemonCardsByType = (
|
||||||
|
pokemonList: PokemonCardProps[],
|
||||||
|
selectedType: string,
|
||||||
|
) => {
|
||||||
|
return pokemonList.filter(
|
||||||
|
pokemon =>
|
||||||
|
selectedType === 'All Types' ||
|
||||||
|
pokemon.types.some(type => type === selectedType),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortPokemonCardsByIdOrName = (
|
||||||
|
pokemonList: PokemonCardProps[],
|
||||||
|
selectedSort: string,
|
||||||
|
) => {
|
||||||
|
return pokemonList.sort((a, b) => {
|
||||||
|
if (selectedSort === 'id') {
|
||||||
|
return a.id - b.id;
|
||||||
|
} else if (selectedSort === 'name') {
|
||||||
|
return a.name.localeCompare(b.name);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const searchPokemonCardsByName = (
|
||||||
|
pokemonList: PokemonCardProps[],
|
||||||
|
searchInput: string,
|
||||||
|
) => {
|
||||||
|
return pokemonList.filter(pokemon =>
|
||||||
|
pokemon.name.toLowerCase().includes(searchInput.toLowerCase()),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export interface PokedexProps {
|
export interface PokedexProps {
|
||||||
selectedRegion: string;
|
selectedRegion: string;
|
||||||
|
selectedType: string;
|
||||||
|
selectedSort: string;
|
||||||
|
searchInput: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Pokedex = ({ selectedRegion }: PokedexProps) => {
|
const Pokedex = ({
|
||||||
|
selectedRegion,
|
||||||
|
selectedType,
|
||||||
|
selectedSort,
|
||||||
|
searchInput,
|
||||||
|
}: PokedexProps) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const isLoadingPokemons = useAppSelector(
|
const isLoadingPokemons = useAppSelector(
|
||||||
state => state.pokedex.isLoadingPokemons,
|
state => state.pokedex.isLoadingPokemons,
|
||||||
);
|
);
|
||||||
const pokemonCardListForRendering = searchedSortedFilteredPokemonCardList(
|
const pokemonList = useAppSelector(state => state.pokedex.pokemonCardList);
|
||||||
useAppSelector(state => state),
|
|
||||||
|
const filteredPokemonList = filterPokemonCardsByType(
|
||||||
|
pokemonList,
|
||||||
|
selectedType,
|
||||||
|
);
|
||||||
|
const sortedFilteredPokemonCardList = sortPokemonCardsByIdOrName(
|
||||||
|
filteredPokemonList,
|
||||||
|
selectedSort,
|
||||||
|
);
|
||||||
|
const searchedPokemonCardList = searchPokemonCardsByName(
|
||||||
|
sortedFilteredPokemonCardList,
|
||||||
|
searchInput,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -33,7 +84,7 @@ const Pokedex = ({ selectedRegion }: PokedexProps) => {
|
||||||
<Loading />
|
<Loading />
|
||||||
) : (
|
) : (
|
||||||
<div className="all__pokemons">
|
<div className="all__pokemons">
|
||||||
{pokemonCardListForRendering.map(pokemonCard => (
|
{searchedPokemonCardList.map(pokemonCard => (
|
||||||
<PokemonCard
|
<PokemonCard
|
||||||
key={pokemonCard.id}
|
key={pokemonCard.id}
|
||||||
id={pokemonCard.id}
|
id={pokemonCard.id}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
filterPokemonCardsByType,
|
filterPokemonCardsByType,
|
||||||
sortPokemonCardsByIdOrName,
|
sortPokemonCardsByIdOrName,
|
||||||
searchPokemonCardsByName,
|
searchPokemonCardsByName,
|
||||||
} from 'features/Pokedex/pokedexSlice';
|
} from 'features/Pokedex/Pokedex';
|
||||||
import { PokemonCardProps } from 'components/PokemonCard';
|
import { PokemonCardProps } from 'components/PokemonCard';
|
||||||
import pokemon3_venusaur_card from 'features/Pokedex/__test__/pokemon3_venusaur_Card.json';
|
import pokemon3_venusaur_card from 'features/Pokedex/__test__/pokemon3_venusaur_Card.json';
|
||||||
import pokemon4_charmander_card from 'features/Pokedex/__test__/pokemon4_charmandar_Card.json';
|
import pokemon4_charmander_card from 'features/Pokedex/__test__/pokemon4_charmandar_Card.json';
|
|
@ -7,7 +7,6 @@ import { getStartAndEndIdsForRegion } from './utils';
|
||||||
import { PokemonResponseData } from 'types/api';
|
import { PokemonResponseData } from 'types/api';
|
||||||
import { pokeRestApi } from 'app/services/pokeRestApi';
|
import { pokeRestApi } from 'app/services/pokeRestApi';
|
||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
import { PokemonCardProps } from 'components/PokemonCard';
|
|
||||||
|
|
||||||
export const fetchPokemonsInTheRegion = createAsyncThunk<
|
export const fetchPokemonsInTheRegion = createAsyncThunk<
|
||||||
PokemonResponseData[],
|
PokemonResponseData[],
|
||||||
|
@ -67,57 +66,3 @@ export const pokedexSlice: Slice<PokedexStateProps> = createSlice({
|
||||||
export const { setIsLoadingPokemons } = pokedexSlice.actions;
|
export const { setIsLoadingPokemons } = pokedexSlice.actions;
|
||||||
|
|
||||||
export default pokedexSlice.reducer;
|
export default pokedexSlice.reducer;
|
||||||
|
|
||||||
/// selectors
|
|
||||||
export const filterPokemonCardsByType = (
|
|
||||||
pokemonList: PokemonCardProps[],
|
|
||||||
selectedType: string,
|
|
||||||
) => {
|
|
||||||
return pokemonList.filter(
|
|
||||||
pokemon =>
|
|
||||||
selectedType === 'All Types' ||
|
|
||||||
pokemon.types.some(type => type === selectedType),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortPokemonCardsByIdOrName = (
|
|
||||||
pokemonList: PokemonCardProps[],
|
|
||||||
selectedSort: string,
|
|
||||||
) => {
|
|
||||||
return pokemonList.sort((a, b) => {
|
|
||||||
if (selectedSort === 'id') {
|
|
||||||
return a.id - b.id;
|
|
||||||
} else if (selectedSort === 'name') {
|
|
||||||
return a.name.localeCompare(b.name);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const searchPokemonCardsByName = (
|
|
||||||
pokemonList: PokemonCardProps[],
|
|
||||||
searchInput: string,
|
|
||||||
) => {
|
|
||||||
return pokemonList.filter(pokemon =>
|
|
||||||
pokemon.name.toLowerCase().includes(searchInput.toLowerCase()),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const filteredPokemonListByType = (state: RootState) =>
|
|
||||||
filterPokemonCardsByType(
|
|
||||||
state.pokedex.pokemonCardList,
|
|
||||||
state.filter.selectedType,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const sortedFilteredPokemonCardList = (state: RootState) =>
|
|
||||||
sortPokemonCardsByIdOrName(
|
|
||||||
filteredPokemonListByType(state),
|
|
||||||
state.filter.selectedSort,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const searchedSortedFilteredPokemonCardList = (state: RootState) =>
|
|
||||||
searchPokemonCardsByName(
|
|
||||||
sortedFilteredPokemonCardList(state),
|
|
||||||
state.filter.searchInput,
|
|
||||||
);
|
|
||||||
|
|
22
yarn.lock
22
yarn.lock
|
@ -1833,6 +1833,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz#c05ed35ad82df8e6ac616c68b92c2282bd083ba4"
|
resolved "https://registry.yarnpkg.com/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz#c05ed35ad82df8e6ac616c68b92c2282bd083ba4"
|
||||||
integrity sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==
|
integrity sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==
|
||||||
|
|
||||||
|
"@graphql-typed-document-node/core@^3.2.0":
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
|
||||||
|
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.8":
|
"@humanwhocodes/config-array@^0.11.8":
|
||||||
version "0.11.8"
|
version "0.11.8"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
|
||||||
|
@ -5997,6 +6002,13 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
yaml "^1.10.0"
|
yaml "^1.10.0"
|
||||||
|
|
||||||
|
cross-fetch@^3.1.5:
|
||||||
|
version "3.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c"
|
||||||
|
integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==
|
||||||
|
dependencies:
|
||||||
|
node-fetch "^2.6.11"
|
||||||
|
|
||||||
cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||||
|
@ -7999,6 +8011,14 @@ graphemer@^1.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
|
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
|
||||||
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
||||||
|
|
||||||
|
graphql-request@^6.1.0:
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f"
|
||||||
|
integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==
|
||||||
|
dependencies:
|
||||||
|
"@graphql-typed-document-node/core" "^3.2.0"
|
||||||
|
cross-fetch "^3.1.5"
|
||||||
|
|
||||||
"graphql@^15.0.0 || ^16.0.0":
|
"graphql@^15.0.0 || ^16.0.0":
|
||||||
version "16.6.0"
|
version "16.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb"
|
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb"
|
||||||
|
@ -10260,7 +10280,7 @@ node-fetch-native@^1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.1.1.tgz#b8977dd7fe6c5599e417301ed3987bca787d3d6f"
|
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.1.1.tgz#b8977dd7fe6c5599e417301ed3987bca787d3d6f"
|
||||||
integrity sha512-9VvspTSUp2Sxbl+9vbZTlFGq9lHwE8GDVVekxx6YsNd1YH59sb3Ba8v3Y3cD8PkLNcileGGcA21PFjVl0jzDaw==
|
integrity sha512-9VvspTSUp2Sxbl+9vbZTlFGq9lHwE8GDVVekxx6YsNd1YH59sb3Ba8v3Y3cD8PkLNcileGGcA21PFjVl0jzDaw==
|
||||||
|
|
||||||
node-fetch@^2.6.1:
|
node-fetch@^2.6.1, node-fetch@^2.6.11:
|
||||||
version "2.6.11"
|
version "2.6.11"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
|
||||||
integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==
|
integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==
|
||||||
|
|
Loading…
Reference in New Issue