From 1b4149522211ced35fd24edad7485412355b152b Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Fri, 16 Jun 2023 11:47:33 +0200 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=A4=96=20Connect=20this=20app=20to=20?= =?UTF-8?q?the=20API=20while=20running=20on=20Android?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 +++++++++++++------ config.ts | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 43d6acd..ccd6ef1 100644 --- a/README.md +++ b/README.md @@ -60,31 +60,31 @@ This app will contain a home page, and a "master/detail" tab for `Moves` with ba The home screen provides a logo, and tab navigation options to other parts of the application. - + ### Collection The collection screen displays a list of `Moves` fetched from the API. - +> ### Detail The detail screen displays detailed information about a selected `Move`. - +> ### Creating The creating screen provides a form for creating a new `Move`. - +> ### Updating The updating screen provides a form for updating an existing `Move`. - +> ## Using the app @@ -94,9 +94,16 @@ In order to use this app, you will need to run the dedicated backend. A `README` with [instructions](https://github.com/draialexis/pokemong_api#user-content-prep-steps) is provided for that purpose. +### Connecting to the backend locally + +First, please find the `config.ts` file at the root of this project, and replace ~~`192.168.0.15`~~ +with the IPv4 address associated with your own Wi-Fi adapter. + +To find that address out, you can run `ipconfig` on Windows or `ifconfig` on macOS/Linux in your terminal. + ### Running this app -With the [Expo CLI](https://docs.expo.dev/more/expo-cli/) installed, at the root of the project, simply run +Then, with the [Expo CLI](https://docs.expo.dev/more/expo-cli/) installed, at the root of the project, simply run ```bash npx expo start diff --git a/config.ts b/config.ts index 3b99d72..b7ae1ac 100644 --- a/config.ts +++ b/config.ts @@ -1,2 +1,2 @@ // config.ts -export const API_BASE_URL = 'http://localhost:8080'; +export const API_BASE_URL = 'http://192.168.0.15:8080'; -- 2.36.3 From 866b3406bd7631480ee10b7855585fcfeebf5fc9 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Fri, 16 Jun 2023 13:33:34 +0200 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=90=9B=20Fix=20Android=20display=20bu?= =?UTF-8?q?g=20by=20not=20inserting=20MultiSelect=20(which=20uses=20a=20Vi?= =?UTF-8?q?rtualizedList)=20into=20a=20ScrollView=20anymore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 ++- screens/moves/MoveFormScreen.tsx | 284 ++++++++++++++++++++----------- 2 files changed, 198 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index ccd6ef1..7827381 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,22 @@ The updating screen provides a form for updating an existing `Move`. > +## Some business logic + +While the back end doesn't forbid a `Move` from being both weak against and effective against the same one type, +it should. That's one of the flaws of that API. + +In this app, we did implement the business logic described above in our callbacks for our `MultiSelect` elements, like +so: + +```typescript +const handleSelectType = (selectedTypes: string[], setTypes: React.Dispatch>, otherSelectedTypes: string[]) => { + const uniqueSelectedTypes = Array.from(new Set(selectedTypes)); + const withoutDuplicatesFromOtherColumn = uniqueSelectedTypes.filter(type => !otherSelectedTypes.includes(type)); + setTypes(withoutDuplicatesFromOtherColumn); +}; +``` + ## Using the app ### Running the backend @@ -94,10 +110,10 @@ In order to use this app, you will need to run the dedicated backend. A `README` with [instructions](https://github.com/draialexis/pokemong_api#user-content-prep-steps) is provided for that purpose. -### Connecting to the backend locally +### Connecting to the backend locally First, please find the `config.ts` file at the root of this project, and replace ~~`192.168.0.15`~~ -with the IPv4 address associated with your own Wi-Fi adapter. +with the IPv4 address associated with your own Wi-Fi adapter. To find that address out, you can run `ipconfig` on Windows or `ifconfig` on macOS/Linux in your terminal. diff --git a/screens/moves/MoveFormScreen.tsx b/screens/moves/MoveFormScreen.tsx index 576ffe6..d581a3f 100644 --- a/screens/moves/MoveFormScreen.tsx +++ b/screens/moves/MoveFormScreen.tsx @@ -1,23 +1,32 @@ // screens/moves/MoveFormScreen.tsx -import React, { useEffect, useState } from 'react'; -import { Button, StyleSheet, Text, TextInput } from 'react-native'; -import { StackNavigationProp } from '@react-navigation/stack'; -import { RootStackParamList } from "../../navigation/navigationTypes"; -import { useDispatch, useSelector } from 'react-redux'; -import { createMove, updateMove } from '../../redux/actions/moveActions'; -import { AppDispatch, RootState } from "../../redux/store"; -import { Move } from "../../entities/Move"; -import { RouteProp } from "@react-navigation/native"; -import { MOVE_FORM } from "../../navigation/constants"; -import { Picker } from "@react-native-community/picker"; -import { ItemValue } from "@react-native-community/picker/typings/Picker"; -import { MoveCategoryName } from "../../entities/MoveCategoryName"; -import { TypeName } from "../../entities/TypeName"; -import MultiSelect from "react-native-multiple-select"; -import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view"; -import AlertModal from "../../components/AlertModal"; -import { MOVE_ERROR } from "../../redux/constants"; +import React, { useEffect, useState } from 'react'; +import { + Button, + KeyboardAvoidingView, + Modal, + Platform, + ScrollView, + StyleSheet, + Text, + TextInput, + View +} from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { RootStackParamList } from "../../navigation/navigationTypes"; +import { useDispatch, useSelector } from 'react-redux'; +import { createMove, updateMove } from '../../redux/actions/moveActions'; +import { AppDispatch, RootState } from "../../redux/store"; +import { Move } from "../../entities/Move"; +import { RouteProp } from "@react-navigation/native"; +import { MOVE_FORM } from "../../navigation/constants"; +import { Picker } from "@react-native-community/picker"; +import { ItemValue } from "@react-native-community/picker/typings/Picker"; +import { MoveCategoryName } from "../../entities/MoveCategoryName"; +import { TypeName } from "../../entities/TypeName"; +import MultiSelect from "react-native-multiple-select"; +import AlertModal from "../../components/AlertModal"; +import { MOVE_ERROR } from "../../redux/constants"; type MoveFormScreenNavigationProp = StackNavigationProp; type MoveFormScreenRouteProp = RouteProp; @@ -50,6 +59,14 @@ const MoveFormScreen = ({ navigation, route }: Props) => { }); }, [navigation, route.params?.move]); + const [isModalVisible, setModalVisible] = useState(false); + const [currentMultiSelect, setCurrentMultiSelect] = useState<'weakAgainst' | 'effectiveAgainst'>('weakAgainst'); + + const handleOpenModal = (multiSelect: 'weakAgainst' | 'effectiveAgainst') => { + setCurrentMultiSelect(multiSelect); + setModalVisible(true); + }; + const [selectedWeakAgainst, setSelectedWeakAgainst] = useState(move.type.weakAgainst); const [selectedEffectiveAgainst, setSelectedEffectiveAgainst] = useState(move.type.effectiveAgainst); @@ -76,89 +93,113 @@ const MoveFormScreen = ({ navigation, route }: Props) => { }; return ( - - dispatch({ type: MOVE_ERROR, payload: null })} - /> - Name: - setMove({ ...move, name: text })} - style={styles.input} - /> - Category: - - setMove({ ...move, category: itemValue as MoveCategoryName }) - }> - {Object.values(MoveCategoryName).map((value) => - - )} - - Power: - { - if (!isNaN(Number(text))) { - setMove({ ...move, power: Number(text) }); - } - }} - style={styles.input} - keyboardType="numeric" - /> - Accuracy: - { - if (!isNaN(Number(text))) { - setMove({ ...move, accuracy: Number(text) }); - } - }} - style={styles.input} - keyboardType="numeric" - /> - Type: - - setMove({ ...move, type: { ...move.type, name: itemValue as TypeName } }) - }> - {Object.values(TypeName).map((value) => - - )} - - Weak Against: - ({ id: value, name: value })) - } - uniqueKey="id" - onSelectedItemsChange={ - (selectedItems) => handleSelectType(selectedItems, setSelectedWeakAgainst, selectedEffectiveAgainst) - } - selectedItems={selectedWeakAgainst} - displayKey="name" - /> - Effective Against: - ({ id: value, name: value })) - } - uniqueKey="id" - onSelectedItemsChange={ - (selectedItems) => handleSelectType(selectedItems, setSelectedEffectiveAgainst, selectedWeakAgainst) - } - selectedItems={selectedEffectiveAgainst} - displayKey="name" - /> -