diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/App.tsx b/App.tsx index 53bd1cf..e6b6278 100644 --- a/App.tsx +++ b/App.tsx @@ -1,7 +1,13 @@ -import React from 'react'; -import Navigation from "./navigation/Navigation"; +// App.tsx + +import React from 'react'; +import Navigation from "./navigation/Navigation"; +import store from "./redux/store"; +import { Provider } from "react-redux"; export default function App() { - return ; - // TODO Send to homescreen instead, and include a bottom bar to navigate to Moves, Pokemongs, Trainers + return ( + + + ); } diff --git a/README.md b/README.md index 3c48434..409a754 100644 --- a/README.md +++ b/README.md @@ -44,5 +44,6 @@ This app will contain several "master/detail" tabs. They are as follows. ## Using the app -This app is linked to a backend that is set up to accept CORS from [`http://localhost:19006`](http://localhost:19006), so please make sure you're -not overriding that default port number when running it. +This app is linked to a backend that is set up to accept CORS from [`http://localhost:19006`](http://localhost:19006). +If you want to use the dedicated API, please make sure you're not overriding that default port number when running this +app. diff --git a/assets/favicon.png b/assets/favicon.png index e75f697..96de913 100644 Binary files a/assets/favicon.png and b/assets/favicon.png differ diff --git a/assets/home.png b/assets/home.png new file mode 100644 index 0000000..b3f6a10 Binary files /dev/null and b/assets/home.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..36d15eb Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/moves.png b/assets/moves.png new file mode 100644 index 0000000..f726cad Binary files /dev/null and b/assets/moves.png differ diff --git a/assets/pokemongs.png b/assets/pokemongs.png new file mode 100644 index 0000000..d628c77 Binary files /dev/null and b/assets/pokemongs.png differ diff --git a/assets/trainers.png b/assets/trainers.png new file mode 100644 index 0000000..c47fe83 Binary files /dev/null and b/assets/trainers.png differ diff --git a/components/MoveListItem.tsx b/components/MoveListItem.tsx new file mode 100644 index 0000000..845e3af --- /dev/null +++ b/components/MoveListItem.tsx @@ -0,0 +1,32 @@ +// components/MoveListItem.test.ts + +import { Move } from "../entities/Move"; +import React from "react"; +import { StyleSheet, Text, TouchableOpacity } from "react-native"; + +type MoveListItemProps = { + move: Move; + onPress: () => void; +}; + +const MoveListItem: React.FC = ({ move, onPress }) => ( + + {move.name}, {move.type.name}: {move.power} + +); + +const styles = StyleSheet.create({ + listItem: { + backgroundColor: '#DDD', + padding: 20, + marginVertical: 8, + marginHorizontal: 16, + borderRadius: 10, + }, + listItemText: { + color: '#333', + fontSize: 18, + }, +}); + +export default MoveListItem; diff --git a/components/TypeTacticsInfoList.test.tsx b/components/TypeTacticsInfoList.test.tsx index 4a8bee7..5ff2eae 100644 --- a/components/TypeTacticsInfoList.test.tsx +++ b/components/TypeTacticsInfoList.test.tsx @@ -1,11 +1,13 @@ -import React from 'react'; -import {render} from '@testing-library/react-native'; +// components/TypeTacticsInfoList.test.ts + +import React from 'react'; +import { render } from '@testing-library/react-native'; import TypeTacticsInfoList from './TypeTacticsInfoList'; describe('TypeTacticsInfoList component', () => { it('renders types correctly', () => { const types = ['FIRE', 'WATER', 'GRASS']; - const {getByText} = render(); + const { getByText } = render(); types.forEach(type => { expect(getByText(type)).toBeTruthy(); @@ -13,13 +15,13 @@ describe('TypeTacticsInfoList component', () => { }); it('renders "Nothing" when types array is empty', () => { - const {getByText} = render(); + const { getByText } = render(); expect(getByText('Nothing')).toBeTruthy(); }); it('renders "Nothing" when types is undefined', () => { // @ts-ignore - const {getByText} = render(); + const { getByText } = render(); expect(getByText('Nothing')).toBeTruthy(); }); }); diff --git a/components/TypeTacticsInfoList.tsx b/components/TypeTacticsInfoList.tsx index 07c0068..e9c8d3b 100644 --- a/components/TypeTacticsInfoList.tsx +++ b/components/TypeTacticsInfoList.tsx @@ -1,39 +1,56 @@ -import React from "react"; -import {StyleSheet, View, Text, ScrollView} from "react-native"; +// components/TypeTacticsInfoList.ts + +import React from "react"; +import { ScrollView, StyleSheet, Text, View } from "react-native"; type TypeListProps = { isWeakness: boolean; types: string[]; }; -const TypeTacticsInfoList = ({isWeakness, types}: TypeListProps) => { +const TypeTacticsInfoList = ({ isWeakness, types }: TypeListProps) => { if (!types || types.length === 0) { types = ['Nothing']; } return ( - - - {isWeakness ? 'weak against' : 'effective against'}: - {types.map((type, index) => ( - {type} - ))} - - + + {isWeakness ? 'Weak Against' : 'Effective Against'}: + + + {types.map((type, index) => ( + {type} + ))} + + + ); }; const styles = StyleSheet.create({ list: { - borderRadius: 5, padding: 10, - marginBottom: 10, + }, + title: { + fontSize: 18, + fontWeight: 'bold', + marginBottom: 5, + }, + type: { + fontSize: 16, + marginBottom: 5, }, weakAgainst: { backgroundColor: '#FF6961', + borderRadius: 10, + marginBottom: 10, + padding: 10, }, effectiveAgainst: { backgroundColor: '#77DD77', + borderRadius: 10, + marginBottom: 10, + padding: 10, }, }); diff --git a/config.ts b/config.ts new file mode 100644 index 0000000..3b99d72 --- /dev/null +++ b/config.ts @@ -0,0 +1,2 @@ +// config.ts +export const API_BASE_URL = 'http://localhost:8080'; diff --git a/entities/Move.ts b/entities/Move.ts index d51f06e..a824c21 100644 --- a/entities/Move.ts +++ b/entities/Move.ts @@ -1,4 +1,6 @@ -import {Type} from "./Type"; +// entities/Move.ts + +import { Type } from "./Type"; export interface Move { name: string; diff --git a/entities/Type.ts b/entities/Type.ts index 0f44ecb..2ad552c 100644 --- a/entities/Type.ts +++ b/entities/Type.ts @@ -1,3 +1,5 @@ +// entities/Type.ts + export interface Type { name: string; weakAgainst: string[]; diff --git a/navigation/.gitkeep b/navigation/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/navigation/Navigation.tsx b/navigation/Navigation.tsx index 1503034..0c62f97 100644 --- a/navigation/Navigation.tsx +++ b/navigation/Navigation.tsx @@ -1,22 +1,67 @@ -import React from 'react'; -import {NavigationContainer} from '@react-navigation/native'; -import {createStackNavigator} from '@react-navigation/stack'; -import MoveListScreen from '../screens/MoveListScreen'; -import MoveDetailScreen from '../screens/MoveDetailScreen'; -import {RootStackParamList} from "./navigationTypes"; +// navigation/Navigation.tsx + +import React from 'react'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { NavigationContainer } from '@react-navigation/native'; +import MoveListScreen from '../screens/moves/MoveListScreen'; +import MoveDetailScreen from '../screens/moves/MoveDetailScreen'; +import HomeScreen from '../screens/HomeScreen'; +import { createStackNavigator } from '@react-navigation/stack'; +import { RootStackParamList, RootTabParamList } from "./navigationTypes"; +import { Image, StyleSheet } from 'react-native'; const Stack = createStackNavigator(); +const Tab = createBottomTabNavigator(); + +const MoveStack = () => { + return ( + + + ({ title: route.params.move.name })} + /> + + ); +}; const Navigation = () => { - // TODO replace 'Move Detail' by the move name itself return ( - - - - + + + }}/> + + }}/> + + }}/> + + }}/> + ); }; +const styles = StyleSheet.create({ + icon: { + width: 24, + height: 24, + padding: 8, + }, +}); + export default Navigation; diff --git a/navigation/navigationTypes.ts b/navigation/navigationTypes.ts index b676d17..66f9358 100644 --- a/navigation/navigationTypes.ts +++ b/navigation/navigationTypes.ts @@ -1,6 +1,15 @@ -import {Move} from "../entities/Move"; +// navigation/navigationTypes.ts + +import { Move } from "../entities/Move"; export type RootStackParamList = { MoveList: undefined; MoveDetail: { move: Move }; }; + +export type RootTabParamList = { + Home: undefined; + Pokemongs: undefined; + Moves: undefined; + Trainers: undefined; +}; diff --git a/package.json b/package.json index 414c99f..856919c 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/native": "^6.1.6", "@react-navigation/stack": "^6.3.16", + "@reduxjs/toolkit": "^1.9.5", "@testing-library/react-native": "^12.1.2", "@types/react": "~18.0.27", "expo": "^48.0.0", @@ -50,6 +51,9 @@ "react-native-safe-area-context": "4.5.0", "react-native-screens": "~3.20.0", "react-native-web": "~0.18.11", + "react-redux": "^8.0.7", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", "typescript": "^4.9.4" }, "devDependencies": { diff --git a/redux/actions/.gitkeep b/redux/actions/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/redux/actions/moveActions.ts b/redux/actions/moveActions.ts new file mode 100644 index 0000000..12cf0ce --- /dev/null +++ b/redux/actions/moveActions.ts @@ -0,0 +1,26 @@ +// redux/actions/moveAction.ts + +import { FETCH_MOVES } from '../constants'; +import { Move } from "../../entities/Move"; +import { Dispatch } from "redux"; +import { API_BASE_URL } from "../../config"; + +export const setMoves = (moves: Move[]) => { + return { + type: FETCH_MOVES, + payload: moves, + }; +} + +export const getMoves = () => { + return async (dispatch: Dispatch) => { + try { + const response = await fetch(`${API_BASE_URL}/move`); + const data = await response.json(); + dispatch(setMoves(data)); + } + catch (error) { + console.error(error); + } + } +} diff --git a/redux/constants.ts b/redux/constants.ts index 8b13789..a330d8c 100644 --- a/redux/constants.ts +++ b/redux/constants.ts @@ -1 +1,3 @@ +// redux/constants.ts +export const FETCH_MOVES = 'FETCH_MOVES'; diff --git a/redux/reducers/.gitkeep b/redux/reducers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/redux/reducers/moveReducer.ts b/redux/reducers/moveReducer.ts new file mode 100644 index 0000000..b9730df --- /dev/null +++ b/redux/reducers/moveReducer.ts @@ -0,0 +1,27 @@ +// redux/reducers/moveReducer.ts +import { FETCH_MOVES } from '../constants'; +import { Move } from "../../entities/Move"; +import { AnyAction } from "redux"; + +export type MoveState = { + moves: Move[]; +}; + +type MoveAction = AnyAction & { + type: typeof FETCH_MOVES; + payload?: Move[]; +}; + +const initialState: MoveState = { + moves: [], +} + +export default function moveReducer(state = initialState, action: MoveAction): MoveState { + switch (action.type) { + case FETCH_MOVES: + return { ...state, moves: action.payload || [] }; + default: + return state; + } +} + diff --git a/redux/store.ts b/redux/store.ts index e69de29..23c33cc 100644 --- a/redux/store.ts +++ b/redux/store.ts @@ -0,0 +1,15 @@ +// redux/store.ts + +import { configureStore } from '@reduxjs/toolkit' +import moveReducer from './reducers/moveReducer'; + +export type AppDispatch = typeof store.dispatch; + +const store = configureStore({ + reducer: { + move: moveReducer + }, + middleware: (getDefaultMiddleware) => getDefaultMiddleware(), +}); + +export default store; diff --git a/screens/.gitkeep b/screens/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/screens/HomeScreen.tsx b/screens/HomeScreen.tsx new file mode 100644 index 0000000..af331b3 --- /dev/null +++ b/screens/HomeScreen.tsx @@ -0,0 +1,14 @@ +// screens/HomeScreen.tsx + +import React from 'react'; +import { Image, View } from 'react-native'; + +const HomeScreen = () => { + return ( + + + + ); +}; + +export default HomeScreen; diff --git a/screens/MoveDetailScreen.tsx b/screens/MoveDetailScreen.tsx deleted file mode 100644 index a72218c..0000000 --- a/screens/MoveDetailScreen.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import {ScrollView, StyleSheet, Text, View} from 'react-native'; -import {RouteProp} from '@react-navigation/native'; -import {RootStackParamList} from "../navigation/navigationTypes"; -import TypeTacticsInfoList from "../components/TypeTacticsInfoList" - -type MoveDetailScreenRouteProp = RouteProp; - -type Props = { - route: MoveDetailScreenRouteProp; -}; - -const MoveDetailScreen = ({route}: Props) => { - const {move} = route.params; - - return ( - - {move.name} - Name: {move.name} - Category: {move.category} - Power: {move.power} - Accuracy: {move.accuracy} - Type: {move.type.name} - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#FFFFFF', - padding: 20, - }, - title: { - fontSize: 24, - fontWeight: 'bold', - }, - list: { - backgroundColor: '#F0F0F0', - borderRadius: 5, - padding: 10, - marginBottom: 10, - }, - typeListsContainer: { - flexDirection: 'row', - justifyContent: 'space-between', - }, -}); - -export default MoveDetailScreen; diff --git a/screens/MoveListScreen.tsx b/screens/MoveListScreen.tsx deleted file mode 100644 index 2f2eb49..0000000 --- a/screens/MoveListScreen.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {FlatList, ScrollView, Text, TouchableOpacity, View} from 'react-native'; -import {StackNavigationProp} from '@react-navigation/stack'; -import {RootStackParamList} from "../navigation/navigationTypes"; -import {Move} from "../entities/Move"; - -type MoveListScreenNavigationProp = StackNavigationProp; - -type Props = { - navigation: MoveListScreenNavigationProp; -}; - -const MoveListScreen = ({navigation}: Props) => { - const [moves, setMoves] = useState([]); - - // FIXME LATER use a redux store to fetch the data - useEffect(() => { - fetch('http://localhost:8080/move') - .then(response => response.json()) - .then(data => setMoves(data)) - .catch(error => console.error(error)); - }, []); - - return ( - - - ( - navigation.navigate('MoveDetail', {move: item})}> - {item.name}, {item.type.name}: {item.power} - - )} - keyExtractor={(item) => item.name} - /> - - - ); -}; - -export default MoveListScreen; diff --git a/screens/moves/MoveDetailScreen.tsx b/screens/moves/MoveDetailScreen.tsx new file mode 100644 index 0000000..d9cfc39 --- /dev/null +++ b/screens/moves/MoveDetailScreen.tsx @@ -0,0 +1,55 @@ +// screens/moves/MoveDetailScreen.tsx + +import React from 'react'; +import { ScrollView, StyleSheet, Text, View } from 'react-native'; +import { RouteProp } from '@react-navigation/native'; +import { RootStackParamList } from "../../navigation/navigationTypes"; +import TypeTacticsInfoList from "../../components/TypeTacticsInfoList" + +type MoveDetailScreenRouteProp = RouteProp; + +type Props = { + route: MoveDetailScreenRouteProp; +}; + +const MoveDetailScreen = ({ route }: Props) => { + const { move } = route.params; + + return ( + + Name: {move.name} + Category: {move.category} + Power: {move.power} + Accuracy: {move.accuracy} + Type: {move.type.name} + + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#FFFFFF', + padding: 20, + }, + title: { + fontSize: 24, + fontWeight: 'bold', + marginBottom: 10, + }, + detail: { + fontSize: 18, + marginBottom: 5, + }, + typeListsContainer: { + flexDirection: 'row', + justifyContent: 'space-evenly', + marginTop: 10, + }, +}); + +export default MoveDetailScreen; diff --git a/screens/moves/MoveListScreen.tsx b/screens/moves/MoveListScreen.tsx new file mode 100644 index 0000000..72567ef --- /dev/null +++ b/screens/moves/MoveListScreen.tsx @@ -0,0 +1,51 @@ +// screens/moves/MoveListScreen.tsx + +import React, { useEffect } from 'react'; +import { FlatList, ScrollView, View } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { RootStackParamList } from "../../navigation/navigationTypes"; +import { useDispatch, useSelector } from 'react-redux'; +import { getMoves } from '../../redux/actions/moveActions'; +import { MoveState } from "../../redux/reducers/moveReducer"; +import { AppDispatch } from "../../redux/store"; +import MoveListItem from "../../components/MoveListItem"; + +type MoveListScreenNavigationProp = StackNavigationProp; + +type Props = { + navigation: MoveListScreenNavigationProp; +}; +type RootState = { + move: MoveState; +}; + +const MoveListScreen = ({ navigation }: Props) => { + const dispatch = useDispatch(); + const moves = useSelector((state: RootState) => state.move.moves); + + useEffect(() => { + const loadMoves = async () => { + await (dispatch as AppDispatch)(getMoves()); + }; + loadMoves(); + }, [dispatch]); + + return ( + + + ( + navigation.navigate('MoveDetail', { move: item })} + /> + )} + keyExtractor={(item) => item.name} + /> + + + ); +}; + +export default MoveListScreen; diff --git a/yarn.lock b/yarn.lock index 563e42a..3f76486 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1044,6 +1044,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb" + integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ== + dependencies: + regenerator-runtime "^0.13.11" + "@babel/template@^7.0.0", "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": version "7.20.7" resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" @@ -2141,6 +2148,16 @@ color "^4.2.3" warn-once "^0.1.0" +"@reduxjs/toolkit@^1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" + integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== + dependencies: + immer "^9.0.21" + redux "^4.2.1" + redux-thunk "^2.4.2" + reselect "^4.1.8" + "@segment/loosely-validate-event@^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz" @@ -2326,6 +2343,14 @@ resolved "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz" integrity sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA== +"@types/hoist-non-react-statics@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/html-minifier-terser@^6.0.0": version "6.1.0" resolved "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" @@ -2421,6 +2446,15 @@ dependencies: "@types/react" "^17" +"@types/react@*": + version "18.2.8" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.8.tgz#a77dcffe4e9af148ca4aa8000c51a1e8ed99e2c8" + integrity sha512-lTyWUNrd8ntVkqycEEplasWy2OxNlShj3zqS0LuB1ENUGis5HodmhM7DtCoUGbxj3VW/WsGA0DUhpG6XrM7gPA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/react@^17": version "17.0.59" resolved "https://registry.npmjs.org/@types/react/-/react-17.0.59.tgz" @@ -2489,6 +2523,11 @@ resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz" integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + "@types/ws@^8.5.1": version "8.5.4" resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz" @@ -5365,7 +5404,7 @@ hermes-profile-transformer@^0.0.6: dependencies: source-map "^0.7.3" -hoist-non-react-statics@^3.3.0: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -5552,6 +5591,11 @@ image-size@^0.6.0: resolved "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz" integrity sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA== +immer@^9.0.21: + version "9.0.21" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" + integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz" @@ -8494,6 +8538,18 @@ react-native@0.71.8: whatwg-fetch "^3.0.0" ws "^6.2.2" +react-redux@^8.0.7: + version "8.0.7" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.7.tgz#b74ef2f7ce2076e354540aa3511d3670c2b62571" + integrity sha512-1vRQuCQI5Y2uNmrMXg81RXKiBHY3jBzvCvNmZF437O/Z9/pZ+ba2uYHbemYXb3g8rjsacBGo+/wmfrQKzMhJsg== + dependencies: + "@babel/runtime" "^7.12.1" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/use-sync-external-store" "^0.0.3" + hoist-non-react-statics "^3.3.2" + react-is "^18.0.0" + use-sync-external-store "^1.0.0" + react-refresh@^0.4.0: version "0.4.3" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz" @@ -8567,6 +8623,18 @@ recast@^0.20.4: source-map "~0.6.1" tslib "^2.0.1" +redux-thunk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" + integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== + +redux@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz" @@ -8693,7 +8761,7 @@ requires-port@^1.0.0: resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^4.0.0: +reselect@^4.0.0, reselect@^4.1.8: version "4.1.8" resolved "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz" integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==