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==