Skip to content

Commit

Permalink
JSAB2-67 Connect troops frontend to backend (green-fox-academy#22)
Browse files Browse the repository at this point in the history
*  JSAB2-67, add action creator and reducer

* JSAB2-67, fetch troop in component

* JASB2-67, add loader and error handler

* JASB2-67, fix lint problem

* JSAB2-67, remove env file

* JSAB2-67, rename action

* JSAB2-67, apply dotenv

* JSAB2-67, fix lint problem

* JSAB2-67, rename const url to uppercase

* JSAB2-67, move url definition

* JSAB2-67, fix lint problem

* JSAB2-67, fix troop info not updating

* JSAB2-67, add more troops in endpoint

* JSAB2-67, improve string style

* JSAB2-67, fix spelling

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, fix spelling

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, fix spelling

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, fix spelling

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, change initial state of isLoading

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, use destructuring  for state

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, remove unnecessary state

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, use destructuring for state

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>

* JSAB2-67, fix spelling

* JSAB2-67, adjust fetch error

* JSAB2-67, change naming

* JSAB2-67, improve error message to user

* JSAB2-67, fix mocked troops id

* JSAB2-67, adjust reducer flow and use common color

* JSAB2-67, change naming

* JSAB2-67, fix naming

* JSAB2-67, change naming

* JSAB2-67, change error text

Co-Authored-By: evasimonyi <30794349+evasimonyi@users.noreply.github.com>
  • Loading branch information
GuJialu and evasimonyi committed Dec 13, 2019
1 parent 5b69089 commit b591f24
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 13 deletions.
30 changes: 29 additions & 1 deletion backend/routers/troops.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const myTroops = {
defence: 1,
started_at: 12345789,
finished_at: 12399999,
}, {
},
{
id: 2,
level: 1,
hp: 1,
Expand All @@ -21,6 +22,33 @@ const myTroops = {
started_at: 12345789,
finished_at: 12399999,
},
{
id: 3,
level: 2,
hp: 1,
attack: 1,
defence: 1,
started_at: 12345789,
finished_at: 12399999,
},
{
id: 4,
level: 3,
hp: 1,
attack: 1,
defence: 1,
started_at: 12345789,
finished_at: 12399999,
},
{
id: 5,
level: 3,
hp: 1,
attack: 1,
defence: 1,
started_at: 12345789,
finished_at: 12399999,
},
],
};

Expand Down
21 changes: 17 additions & 4 deletions frontend/src/Troop/TroopInformation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
View, Image, Text,
StyleSheet,
} from 'react-native';
import PropTypes from 'prop-types';
import { CardView } from '../common/components';
import troopAvatar from '../../assets/troop/troop-avatar.jpg';
import attackIcon from '../../assets/troop/attack.png';
Expand All @@ -29,26 +30,38 @@ const styles = StyleSheet.create({
},
});

function TroopInformation() {
function TroopInformation({ attack, defence, sustenance }) {
return (
<CardView style={{ flexDirection: 'row', alignItems: 'center' }}>
<Image style={styles.troopAvatar} source={troopAvatar} />
<View>
<View style={styles.fieldStyle}>
<Text style={styles.textStyle}>Attack: 35</Text>
<Text style={styles.textStyle}>
{`Attack: ${attack}`}
</Text>
<Image resizeMode="contain" source={attackIcon} style={styles.iconStyle} />
</View>
<View style={styles.fieldStyle}>
<Text style={styles.textStyle}>Defence: 35</Text>
<Text style={styles.textStyle}>
{`Defence: ${defence}`}
</Text>
<Image resizeMode="contain" source={defenceIcon} style={styles.iconStyle} />
</View>
<View style={styles.fieldStyle}>
<Text style={styles.textStyle}>Sustenance: 23</Text>
<Text style={styles.textStyle}>
{`Sustenance: ${sustenance}`}
</Text>
<Image resizeMode="contain" source={cookieIcon} style={styles.iconStyle} />
</View>
</View>
</CardView>
);
}

TroopInformation.propTypes = {
attack: PropTypes.number.isRequired,
defence: PropTypes.number.isRequired,
sustenance: PropTypes.number.isRequired,
};

export default TroopInformation;
22 changes: 22 additions & 0 deletions frontend/src/Troop/actionCreator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { SERVER_URL } from 'react-native-dotenv';

export const FETCH_TROOPS_SUCCESS = 'fetchTroopsSuccess';
export const FETCH_TROOPS_REQUEST = 'fetchTroopsRequest';
export const FETCH_TROOPS_FAILURE = 'fetchTroopsFailure';

const URL = `http://${SERVER_URL}/kingdom/troops`;

export function fetchTroops() {
return (dispatch) => {
dispatch({ type: FETCH_TROOPS_REQUEST });
fetch(URL)
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw new Error(response.status);
})
.then((response) => dispatch({ type: FETCH_TROOPS_SUCCESS, payload: response.troops }))
.catch((error) => dispatch({ type: FETCH_TROOPS_FAILURE, payload: error }));
};
}
65 changes: 57 additions & 8 deletions frontend/src/Troop/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import {
View, ActivityIndicator,
Text, StyleSheet,
} from 'react-native';
import Colors from '../common/colors';

import { fetchTroops } from './actionCreator';
import TroopInformation from './TroopInformation';
import TroopLevel from './TroopLevel';

Expand All @@ -13,21 +20,63 @@ const styles = StyleSheet.create({
},
});

function TroopLevels() {
function TroopLevels({ level1TroopNum, level2TroopNum, level3TroopNum }) {
return (
<View style={styles.levelList}>
<TroopLevel level={1} troops={13} />
<TroopLevel level={2} troops={8} />
<TroopLevel level={3} troops={2} />
{level1TroopNum !== 0 && <TroopLevel level={1} troops={level1TroopNum} />}
{level2TroopNum !== 0 && <TroopLevel level={2} troops={level2TroopNum} />}
{level3TroopNum !== 0 && <TroopLevel level={3} troops={level3TroopNum} />}
</View>
);
}

TroopLevels.propTypes = {
level1TroopNum: PropTypes.number.isRequired,
level2TroopNum: PropTypes.number.isRequired,
level3TroopNum: PropTypes.number.isRequired,
};

function Troop() {
const listOfTroops = useSelector((state) => state.troop.listOfTroops);
const isLoading = useSelector((state) => state.troop.isLoading);
const error = useSelector((state) => state.troop.error);
const dispatch = useDispatch();

useEffect(() => {
dispatch(fetchTroops());
}, []);

if (error) {
return (
<Text>{`Oops, ${error.message}`}</Text>
);
}

if (isLoading) {
return (
<ActivityIndicator size="large" color={Colors.tealColor} />
);
}

const level1TroopNum = listOfTroops.filter((troop) => troop.level === 1).length;
const level2TroopNum = listOfTroops.filter((troop) => troop.level === 2).length;
const level3TroopNum = listOfTroops.filter((troop) => troop.level === 3).length;
const attack = level1TroopNum + level2TroopNum * 2 + level3TroopNum * 3;
const defence = level1TroopNum + level2TroopNum * 2 + level3TroopNum * 3;
const sustenance = level1TroopNum + level2TroopNum + level3TroopNum;

return (
<View style={{ flexDirection: 'column' }}>
<TroopInformation />
<TroopLevels />
<TroopInformation
attack={attack}
defence={defence}
sustenance={sustenance}
/>
<TroopLevels
level1TroopNum={level1TroopNum}
level2TroopNum={level2TroopNum}
level3TroopNum={level3TroopNum}
/>
</View>
);
}
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/Troop/troopReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FETCH_TROOPS_SUCCESS, FETCH_TROOPS_REQUEST, FETCH_TROOPS_FAILURE } from './actionCreator';

const initialState = {
listOfTroops: [],
isLoading: false,
error: undefined,
};

export default function troop(state = initialState, action) {
switch (action.type) {
case FETCH_TROOPS_REQUEST:
return { ...state, isLoading: true };
case FETCH_TROOPS_SUCCESS:
return { ...state, listOfTroops: action.payload, isLoading: false };
case FETCH_TROOPS_FAILURE:
return { ...state, isLoading: false, error: action.payload };
default:
return state;
}
}
2 changes: 2 additions & 0 deletions frontend/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import menu from './Menu/menuReducer';
import buildings from './Buildings/buildingReducer';
import troop from './Troop/troopReducer';

const rootReducer = combineReducers({
menu,
buildings,
troop,
});

export default createStore(rootReducer, applyMiddleware(thunk));

0 comments on commit b591f24

Please sign in to comment.