Skip to content

Commit 6e3ec9c

Browse files
committed
refactored state reducers, added menu nav
1 parent 66a9d4c commit 6e3ec9c

File tree

9 files changed

+253
-152
lines changed

9 files changed

+253
-152
lines changed

src/components/Editor.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ const initialSize = () => ({
2020

2121
export default ({
2222
dispatch,
23-
division,
24-
fileType,
25-
proportion,
26-
selectedColours,
23+
flag: { division, proportion, selectedColours },
24+
ui: { fileType },
2725
}: OwnProps): JSX.Element => {
2826
const [size, setSize] = useState(initialSize());
2927
const flag = useRef(null);
@@ -100,10 +98,14 @@ export default ({
10098
};
10199

102100
type OwnProps = {
103-
division: number;
104-
fileType: FileTypes;
105-
proportion: number;
106-
selectedColours: string[];
101+
flag: {
102+
division: number;
103+
proportion: number;
104+
selectedColours: string[];
105+
};
106+
ui: {
107+
fileType: FileTypes;
108+
};
107109
dispatch: (action: ReducerAction) => void;
108110
};
109111

src/components/EditorModal.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { View } from 'react-native';
33

44
import { ColourSelector, FileSaver, Modal } from '@components';
55
import Actions from '@lib/actions';
6-
import { ModalActions, ReducerAction } from '@lib/state';
6+
import { ModalActions } from '@lib/reducers';
7+
import { ReducerAction } from '@lib/state';
78

89
export default ({
910
dispatch,
10-
modalAction,
11-
selectedColours,
11+
flag: { selectedColours },
12+
ui: { modalAction },
1213
}: OwnProps): JSX.Element => {
1314
const renderModalBody = () => {
1415
switch (modalAction) {
@@ -47,7 +48,11 @@ export default ({
4748
};
4849

4950
type OwnProps = {
50-
selectedColours: string[];
51-
modalAction: ModalActions;
51+
flag: {
52+
selectedColours: string[];
53+
};
54+
ui: {
55+
modalAction: ModalActions;
56+
};
5257
dispatch: (action: ReducerAction) => void;
5358
};

src/components/Footer.tsx

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { Text, Row } from '@components';
55
import { DivisionList } from '@lib/divisions';
66
import { ProportionsList } from '@lib/proportions';
77
import Actions from '@lib/actions';
8-
import { ModalActions, ReducerAction } from '@lib/state';
8+
import { ModalActions } from '@lib/reducers';
9+
import { ReducerAction } from '@lib/state';
910
import colours from '@res/colours';
1011

1112
export const FooterButton = ({
@@ -27,59 +28,62 @@ export const FooterButton = ({
2728
type FooterButtonProps = {
2829
title: string;
2930
value: string;
30-
short: boolean;
31+
short?: boolean;
3132
onPress?: () => void;
3233
};
3334

3435
export default ({
35-
division,
36-
proportion,
37-
selectedColours,
36+
flag: { division, proportion, selectedColours },
3837
dispatch,
39-
}: OwnProps): JSX.Element => (
40-
<View style={styles.footer}>
41-
<Row>
42-
<FooterButton
43-
title="Division"
44-
value={DivisionList[division]}
45-
short={false}
46-
onPress={() => dispatch({ type: Actions.INCREMENT_DIVISION })}
47-
/>
48-
<FooterButton
49-
title="Proportion"
50-
value={ProportionsList[proportion].name}
51-
onPress={() => dispatch({ type: Actions.INCREMENT_PROPORTION })}
52-
/>
53-
<FooterButton
54-
title="Colours"
55-
value={String(selectedColours.length)}
56-
onPress={() =>
57-
dispatch({
58-
type: Actions.SET_MODAL_ACTION,
59-
payload: ModalActions.EditColours,
60-
})
61-
}
62-
/>
63-
<FooterButton
64-
title="Charges"
65-
value="5"
66-
onPress={() => dispatch({ type: Actions.INCREMENT_PROPORTION })}
67-
/>
68-
</Row>
69-
</View>
70-
);
38+
}: OwnProps): JSX.Element => {
39+
const openModal = (payload: ModalActions) =>
40+
dispatch({
41+
type: Actions.SET_MODAL_ACTION,
42+
payload,
43+
});
44+
45+
return (
46+
<View style={styles.footer}>
47+
<Row>
48+
<FooterButton
49+
title="Division"
50+
value={DivisionList[division]}
51+
short={false}
52+
onPress={() => dispatch({ type: Actions.INCREMENT_DIVISION })}
53+
/>
54+
<FooterButton
55+
title="Proportion"
56+
value={ProportionsList[proportion].name}
57+
onPress={() => dispatch({ type: Actions.INCREMENT_PROPORTION })}
58+
/>
59+
<FooterButton
60+
title="Colours"
61+
value={String(selectedColours.length)}
62+
onPress={() => openModal(ModalActions.EditColours)}
63+
/>
64+
<FooterButton
65+
title="Charges"
66+
value="0"
67+
onPress={() => openModal(ModalActions.EditCharges)}
68+
/>
69+
</Row>
70+
</View>
71+
);
72+
};
7173

7274
type OwnProps = {
73-
division: number;
74-
proportion: number;
75-
selectedColours: string[];
75+
flag: {
76+
division: number;
77+
proportion: number;
78+
selectedColours: string[];
79+
};
7680
dispatch: (action: ReducerAction) => void;
7781
};
7882

7983
const styles = StyleSheet.create({
8084
footer: {
8185
alignSelf: 'stretch',
82-
height: Platform.OS === 'android' ? 50 : 80,
86+
height: Platform.OS === 'android' ? 60 : 80,
8387
backgroundColor: colours.primaryBlue,
8488
},
8589
footerButton: {

src/components/Header.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99

1010
import { Text } from '@components';
1111
import Actions from '@lib/actions';
12-
import { ModalActions, ReducerAction } from '@lib/state';
12+
import { ModalActions } from '@lib/reducers';
13+
import { ReducerAction } from '@lib/state';
1314
import colours from '@res/colours';
1415
import { Download, Menu } from '@res/icons';
1516

src/components/Menu.tsx

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
1-
import React from 'react';
1+
import React, { useEffect, useRef } from 'react';
22
import {
3+
Animated,
4+
Dimensions,
35
Image,
46
Modal,
57
SafeAreaView,
68
StyleSheet,
79
TouchableOpacity,
810
View,
11+
StyleProp,
912
} from 'react-native';
1013

1114
import Actions from '@lib/actions';
1215
import { ReducerAction } from '@lib/state';
1316
import colours from '@res/colours';
1417

15-
export default ({ menuOpen, dispatch }: OwnProps): JSX.Element => (
18+
const width = Math.floor(Dimensions.get('screen').width / 1.2);
19+
const SlideInMenu = ({ style = {}, children }: SlideInMenuProps) => {
20+
const translateX = useRef(new Animated.Value(-width)).current;
21+
useEffect(() => {
22+
Animated.timing(translateX, {
23+
toValue: 0,
24+
duration: 250,
25+
useNativeDriver: true,
26+
}).start();
27+
});
28+
29+
return (
30+
<Animated.View style={{ ...style, transform: [{ translateX }] }}>
31+
{children}
32+
</Animated.View>
33+
);
34+
};
35+
36+
type SlideInMenuProps = {
37+
style?: StyleProp;
38+
children?: JSX.Element | JSX.Element[];
39+
};
40+
41+
export default ({ ui: { menuOpen }, dispatch }: OwnProps): JSX.Element => (
1642
<Modal
1743
transparent={true}
1844
visible={menuOpen}
@@ -22,45 +48,51 @@ export default ({ menuOpen, dispatch }: OwnProps): JSX.Element => (
2248
})
2349
}>
2450
<View style={styles.container}>
25-
<View style={styles.modalBody}>
26-
<SafeAreaView>
27-
<Image style={styles.logo} source={require('res/app_icon.png')} />
28-
</SafeAreaView>
29-
</View>
3051
<TouchableOpacity
31-
style={styles.modalEmpty}
52+
style={styles.background}
3253
onPress={() =>
3354
dispatch({
3455
type: Actions.TOGGLE_MENU,
3556
})
36-
}
37-
/>
57+
}>
58+
<SlideInMenu style={styles.modalBody}>
59+
<SafeAreaView>
60+
<View style={styles.logoContainer}>
61+
<Image style={styles.logo} source={require('res/app_icon.png')} />
62+
</View>
63+
</SafeAreaView>
64+
</SlideInMenu>
65+
</TouchableOpacity>
3866
</View>
3967
</Modal>
4068
);
4169

4270
type OwnProps = {
43-
menuOpen: boolean;
71+
ui: { menuOpen: boolean };
4472
dispatch: (action: ReducerAction) => void;
4573
};
4674

4775
const styles = StyleSheet.create({
4876
container: {
4977
flex: 1,
5078
flexDirection: 'row',
79+
backgroundColor: 'rgba(0,0,0,0.4)',
80+
},
81+
background: {
82+
flex: 1,
5183
},
5284
modalBody: {
53-
flex: 2,
85+
flex: 1,
86+
width: width,
5487
backgroundColor: colours.white,
5588
alignItems: 'center',
56-
},
57-
modalEmpty: {
58-
flex: 1,
59-
backgroundColor: 'rgba(0,0,0,0.4)',
89+
transform: [{ translateX: -width }],
6090
},
6191
logo: {
62-
width: 100,
63-
height: 100,
64-
padding: 20,
92+
width: 200,
93+
height: 200,
94+
},
95+
logoContainer: {
96+
margin: 20,
6597
},
6698
});

src/lib/reducers/flag.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Actions from '@lib/actions';
2+
import { DivisionList } from '@lib/divisions';
3+
import { ProportionsList } from '@lib/proportions';
4+
import { initialColours } from '@res/colours';
5+
6+
export type FlagStateType = {
7+
division: number;
8+
proportion: number;
9+
selectedColours: string[];
10+
};
11+
12+
const initialState: FlagStateType = {
13+
division: 2,
14+
proportion: 2,
15+
selectedColours: initialColours,
16+
};
17+
18+
const nextIndex = (currentIndex: number, list: { length: number }): number =>
19+
currentIndex + 1 === list.length ? 0 : currentIndex + 1;
20+
21+
const minimumColours = 2;
22+
23+
export type FlagReducerAction = {
24+
type: Actions;
25+
payload?: string | number;
26+
};
27+
28+
export default (
29+
state = initialState,
30+
action?: FlagReducerAction,
31+
): FlagStateType => {
32+
switch (action?.type) {
33+
case Actions.INCREMENT_DIVISION:
34+
return {
35+
...state,
36+
division: nextIndex(state.division, DivisionList),
37+
};
38+
39+
case Actions.INCREMENT_PROPORTION:
40+
return {
41+
...state,
42+
proportion: nextIndex(state.proportion, ProportionsList),
43+
};
44+
45+
case Actions.ADD_COLOUR:
46+
return {
47+
...state,
48+
selectedColours: [...state.selectedColours, String(action.payload)],
49+
};
50+
51+
case Actions.REMOVE_COLOUR:
52+
if (state.selectedColours.length === minimumColours) {
53+
return state;
54+
}
55+
56+
return {
57+
...state,
58+
selectedColours: state.selectedColours.filter(
59+
(_, index) => index !== Number(action.payload),
60+
),
61+
};
62+
63+
default:
64+
return state;
65+
}
66+
};

src/lib/reducers/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export { default as flag } from './flag';
2+
export type { FlagReducerAction } from './flag';
3+
export type { FlagStateType } from './flag';
4+
5+
export { default as ui, ModalActions } from './ui';
6+
export type { UIReducerAction } from './ui';
7+
export type { UIStateType } from './ui';

0 commit comments

Comments
 (0)