✨ 💄 Create Move screens #3
Merged
alexis.drai
merged 3 commits from genesis/create-move-detail
into main
2 years ago
@ -1,6 +1,6 @@
|
||||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
};
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
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