... and 📝 add sketches to Readme Co-authored-by: Alexis DRAI <alexis.drai@etu.uca.fr> Reviewed-on: alexis.drai/AD_ReactNative#3pull/11/head
parent
110d930b50
commit
bf1ecb518d
@ -1,6 +1,6 @@
|
|||||||
module.exports = function(api) {
|
module.exports = function (api) {
|
||||||
api.cache(true);
|
api.cache(true);
|
||||||
return {
|
return {
|
||||||
presets: ['babel-preset-expo'],
|
presets: ['babel-preset-expo'],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import {render} from '@testing-library/react-native';
|
|
||||||
import Greeting from './Greeting';
|
|
||||||
|
|
||||||
describe('Greeting component', () => {
|
|
||||||
it('renders Hello, World! text', () => {
|
|
||||||
const {getByText} = render(<Greeting/>);
|
|
||||||
expect(getByText('Hello, World!')).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import {Text} from 'react-native';
|
|
||||||
|
|
||||||
export default function Greeting() {
|
|
||||||
return (<Text>Hello, World!</Text>);
|
|
||||||
}
|
|
@ -0,0 +1,25 @@
|
|||||||
|
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(<TypeTacticsInfoList isWeakness={true} types={types}/>);
|
||||||
|
|
||||||
|
types.forEach(type => {
|
||||||
|
expect(getByText(type)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders "Nothing" when types array is empty', () => {
|
||||||
|
const {getByText} = render(<TypeTacticsInfoList isWeakness={false} types={[]}/>);
|
||||||
|
expect(getByText('Nothing')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders "Nothing" when types is undefined', () => {
|
||||||
|
// @ts-ignore
|
||||||
|
const {getByText} = render(<TypeTacticsInfoList isWeakness={true} types={undefined}/>);
|
||||||
|
expect(getByText('Nothing')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,40 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {StyleSheet, View, Text, ScrollView} from "react-native";
|
||||||
|
|
||||||
|
type TypeListProps = {
|
||||||
|
isWeakness: boolean;
|
||||||
|
types: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const TypeTacticsInfoList = ({isWeakness, types}: TypeListProps) => {
|
||||||
|
if (!types || types.length === 0) {
|
||||||
|
types = ['Nothing'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView style={isWeakness ? styles.weakAgainst : styles.effectiveAgainst}>
|
||||||
|
<View style={styles.list}>
|
||||||
|
<Text>{isWeakness ? 'weak against' : 'effective against'}:</Text>
|
||||||
|
{types.map((type, index) => (
|
||||||
|
<Text key={index}>{type}</Text>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
list: {
|
||||||
|
borderRadius: 5,
|
||||||
|
padding: 10,
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
weakAgainst: {
|
||||||
|
backgroundColor: '#FF6961',
|
||||||
|
},
|
||||||
|
effectiveAgainst: {
|
||||||
|
backgroundColor: '#77DD77',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TypeTacticsInfoList;
|
After Width: | Height: | Size: 836 KiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 1.1 MiB |
@ -0,0 +1,9 @@
|
|||||||
|
import {Type} from "./Type";
|
||||||
|
|
||||||
|
export interface Move {
|
||||||
|
name: string;
|
||||||
|
category: string;
|
||||||
|
power: number;
|
||||||
|
accuracy: number;
|
||||||
|
type: Type;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface Type {
|
||||||
|
name: string;
|
||||||
|
weakAgainst: string[];
|
||||||
|
effectiveAgainst: string[];
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
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";
|
||||||
|
|
||||||
|
const Stack = createStackNavigator<RootStackParamList>();
|
||||||
|
|
||||||
|
const Navigation = () => {
|
||||||
|
// TODO replace 'Move Detail' by the move name itself
|
||||||
|
return (
|
||||||
|
<NavigationContainer>
|
||||||
|
<Stack.Navigator initialRouteName="MoveList">
|
||||||
|
<Stack.Screen name="MoveList" component={MoveListScreen} options={{title: 'Moves'}}/>
|
||||||
|
<Stack.Screen name="MoveDetail" component={MoveDetailScreen} options={{title: 'Move Detail'}}/>
|
||||||
|
</Stack.Navigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Navigation;
|
@ -0,0 +1,6 @@
|
|||||||
|
import {Move} from "../entities/Move";
|
||||||
|
|
||||||
|
export type RootStackParamList = {
|
||||||
|
MoveList: undefined;
|
||||||
|
MoveDetail: { move: Move };
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
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<RootStackParamList, 'MoveDetail'>;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
route: MoveDetailScreenRouteProp;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MoveDetailScreen = ({route}: Props) => {
|
||||||
|
const {move} = route.params;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView style={styles.container}>
|
||||||
|
<Text style={styles.title}>{move.name}</Text>
|
||||||
|
<Text>Name: {move.name}</Text>
|
||||||
|
<Text>Category: {move.category}</Text>
|
||||||
|
<Text>Power: {move.power}</Text>
|
||||||
|
<Text>Accuracy: {move.accuracy}</Text>
|
||||||
|
<Text>Type: {move.type.name}</Text>
|
||||||
|
<View style={styles.typeListsContainer}>
|
||||||
|
<TypeTacticsInfoList isWeakness={true} types={move.type.weakAgainst}/>
|
||||||
|
<TypeTacticsInfoList isWeakness={false} types={move.type.effectiveAgainst}/>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
@ -0,0 +1,41 @@
|
|||||||
|
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<RootStackParamList, 'MoveList'>;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: MoveListScreenNavigationProp;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MoveListScreen = ({navigation}: Props) => {
|
||||||
|
const [moves, setMoves] = useState<Move[]>([]);
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
<ScrollView>
|
||||||
|
<View>
|
||||||
|
<FlatList
|
||||||
|
data={moves}
|
||||||
|
renderItem={({item}) => (
|
||||||
|
<TouchableOpacity onPress={() => navigation.navigate('MoveDetail', {move: item})}>
|
||||||
|
<Text>{item.name}, {item.type.name}: {item.power}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
keyExtractor={(item) => item.name}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MoveListScreen;
|
Loading…
Reference in new issue