Showing
12 changed files
with
254 additions
and
0 deletions
App.js
0 → 100644
1 | +import { useState } from "react"; | ||
2 | +import { StyleSheet, View, FlatList, Button } from "react-native"; | ||
3 | +import { StatusBar } from "expo-status-bar"; | ||
4 | + | ||
5 | +import GoalItem from "./components/GoalItem"; | ||
6 | +import GoalInput from "./components/GoalInput"; | ||
7 | + | ||
8 | +export default function App() { | ||
9 | + const [modalIsVisible, setModalIsVisible] = useState(false); | ||
10 | + const [goals, setGoals] = useState([]); | ||
11 | + | ||
12 | + function startAddGoalHandler() { | ||
13 | + setModalIsVisible(true); | ||
14 | + } | ||
15 | + | ||
16 | + function endAddGoalHandler() { | ||
17 | + setModalIsVisible(false); | ||
18 | + } | ||
19 | + | ||
20 | + function addGoalHandler(enteredGoalText) { | ||
21 | + setGoals((currentGoals) => [ | ||
22 | + ...currentGoals, | ||
23 | + { text: enteredGoalText, id: Math.random().toString() }, | ||
24 | + ]); | ||
25 | + endAddGoalHandler(); | ||
26 | + } | ||
27 | + | ||
28 | + function deleteGoalHandler(id) { | ||
29 | + setGoals((currentGoals) => { | ||
30 | + return currentGoals.filter((goal) => goal.id !== id); | ||
31 | + }); | ||
32 | + } | ||
33 | + | ||
34 | + return ( | ||
35 | + <> | ||
36 | + <StatusBar style="light" /> | ||
37 | + <View style={styles.appContainer}> | ||
38 | + <Button | ||
39 | + title="Add New Goal" | ||
40 | + color="#a065ec" | ||
41 | + onPress={startAddGoalHandler} | ||
42 | + /> | ||
43 | + <GoalInput | ||
44 | + visible={modalIsVisible} | ||
45 | + onAddGoal={addGoalHandler} | ||
46 | + onCancel={endAddGoalHandler} | ||
47 | + /> | ||
48 | + <View style={styles.goalsContainer}> | ||
49 | + <FlatList | ||
50 | + data={goals} | ||
51 | + renderItem={(itemData) => { | ||
52 | + return ( | ||
53 | + <GoalItem | ||
54 | + text={itemData.item.text} | ||
55 | + id={itemData.item.id} | ||
56 | + onDeleteItem={deleteGoalHandler} | ||
57 | + /> | ||
58 | + ); | ||
59 | + }} | ||
60 | + keyExtractor={(item, index) => { | ||
61 | + return item.id; | ||
62 | + }} | ||
63 | + alwaysBounceVertical={false} | ||
64 | + /> | ||
65 | + </View> | ||
66 | + </View> | ||
67 | + </> | ||
68 | + ); | ||
69 | +} | ||
70 | + | ||
71 | +const styles = StyleSheet.create({ | ||
72 | + appContainer: { | ||
73 | + flex: 1, | ||
74 | + paddingTop: 50, | ||
75 | + paddingHorizontal: 16, | ||
76 | + }, | ||
77 | + goalsContainer: { | ||
78 | + flex: 6, | ||
79 | + }, | ||
80 | +}); |
app.json
0 → 100644
1 | +{ | ||
2 | + "expo": { | ||
3 | + "name": "RNC", | ||
4 | + "slug": "RNC", | ||
5 | + "version": "1.0.0", | ||
6 | + "orientation": "portrait", | ||
7 | + "icon": "./assets/icon.png", | ||
8 | + "backgroundColor": "#1e085a", | ||
9 | + "splash": { | ||
10 | + "image": "./assets/splash.png", | ||
11 | + "resizeMode": "contain", | ||
12 | + "backgroundColor": "#ffffff" | ||
13 | + }, | ||
14 | + "updates": { | ||
15 | + "fallbackToCacheTimeout": 0 | ||
16 | + }, | ||
17 | + "assetBundlePatterns": ["**/*"], | ||
18 | + "ios": { | ||
19 | + "supportsTablet": true | ||
20 | + }, | ||
21 | + "android": { | ||
22 | + "adaptiveIcon": { | ||
23 | + "foregroundImage": "./assets/adaptive-icon.png", | ||
24 | + "backgroundColor": "#FFFFFF" | ||
25 | + } | ||
26 | + }, | ||
27 | + "web": { | ||
28 | + "favicon": "./assets/favicon.png" | ||
29 | + } | ||
30 | + } | ||
31 | +} |
assets/adaptive-icon.png
0 → 100644
17.1 KB
assets/favicon.png
0 → 100644
1.43 KB
assets/icon.png
0 → 100644
21.9 KB
assets/images/goal.png
0 → 100644
18.7 KB
assets/splash.png
0 → 100644
46.2 KB
babel.config.js
0 → 100644
components/GoalInput.js
0 → 100644
1 | +import { useState } from "react"; | ||
2 | +import { | ||
3 | + View, | ||
4 | + TextInput, | ||
5 | + Button, | ||
6 | + StyleSheet, | ||
7 | + Modal, | ||
8 | + Image, | ||
9 | +} from "react-native"; | ||
10 | + | ||
11 | +function GoalInput(props) { | ||
12 | + const [enteredGoalText, setEnteredGoalText] = useState(""); | ||
13 | + | ||
14 | + function goalInputHandler(enteredText) { | ||
15 | + setEnteredGoalText(enteredText); | ||
16 | + } | ||
17 | + | ||
18 | + function addGoalHandler() { | ||
19 | + props.onAddGoal(enteredGoalText); | ||
20 | + setEnteredGoalText(""); | ||
21 | + } | ||
22 | + | ||
23 | + return ( | ||
24 | + <Modal visible={props.visible} animationType="slide"> | ||
25 | + <View style={styles.inputContainer}> | ||
26 | + <Image | ||
27 | + style={styles.image} | ||
28 | + source={require("../assets/images/goal.png")} | ||
29 | + /> | ||
30 | + <TextInput | ||
31 | + style={styles.textInput} | ||
32 | + placeholder="Your goal" | ||
33 | + onChangeText={goalInputHandler} | ||
34 | + value={enteredGoalText} | ||
35 | + /> | ||
36 | + <View style={styles.buttonContainer}> | ||
37 | + <View style={styles.button}> | ||
38 | + <Button title="Cancel" onPress={props.onCancel} color="#f31282" /> | ||
39 | + </View> | ||
40 | + <View style={styles.button}> | ||
41 | + <Button title="Add Goal" onPress={addGoalHandler} color="#b180f0" /> | ||
42 | + </View> | ||
43 | + </View> | ||
44 | + </View> | ||
45 | + </Modal> | ||
46 | + ); | ||
47 | +} | ||
48 | + | ||
49 | +export default GoalInput; | ||
50 | + | ||
51 | +const styles = StyleSheet.create({ | ||
52 | + inputContainer: { | ||
53 | + flex: 1, | ||
54 | + justifyContent: "center", | ||
55 | + alignItems: "center", | ||
56 | + padding: 16, | ||
57 | + backgroundColor: "#311b6b", | ||
58 | + }, | ||
59 | + image: { | ||
60 | + width: 100, | ||
61 | + height: 100, | ||
62 | + margin: 20, | ||
63 | + }, | ||
64 | + textInput: { | ||
65 | + borderWidth: 1, | ||
66 | + borderColor: "#e4d0ff", | ||
67 | + backgroundColor: "#e4d0ff", | ||
68 | + color: "#120438", | ||
69 | + borderRadius: 6, | ||
70 | + width: "100%", | ||
71 | + padding: 8, | ||
72 | + }, | ||
73 | + buttonContainer: { | ||
74 | + marginTop: 16, | ||
75 | + flexDirection: "row", | ||
76 | + }, | ||
77 | + button: { | ||
78 | + width: 100, | ||
79 | + marginHorizontal: 8, | ||
80 | + }, | ||
81 | +}); |
components/GoalItem.js
0 → 100644
1 | +import { StyleSheet, View, Text, Pressable } from "react-native"; | ||
2 | + | ||
3 | +function GoalItem(props) { | ||
4 | + return ( | ||
5 | + <View style={styles.goalItem}> | ||
6 | + <Pressable | ||
7 | + android_ripple={{ color: "#ddddd" }} | ||
8 | + onPress={props.onDeleteItem.bind(this, props.id)} | ||
9 | + style={({ pressed }) => pressed && styles.pressedItem} | ||
10 | + > | ||
11 | + <Text style={styles.goalText}>{props.text}</Text> | ||
12 | + </Pressable> | ||
13 | + </View> | ||
14 | + ); | ||
15 | +} | ||
16 | + | ||
17 | +export default GoalItem; | ||
18 | + | ||
19 | +const styles = StyleSheet.create({ | ||
20 | + goalItem: { | ||
21 | + margin: 8, | ||
22 | + borderRadius: 6, | ||
23 | + backgroundColor: "#5e0acc", | ||
24 | + }, | ||
25 | + pressedItem: { | ||
26 | + opacity: 0.5, | ||
27 | + }, | ||
28 | + goalText: { | ||
29 | + color: "white", | ||
30 | + padding: 8, | ||
31 | + }, | ||
32 | +}); |
package.json
0 → 100644
1 | +{ | ||
2 | + "name": "rnc", | ||
3 | + "version": "1.0.0", | ||
4 | + "main": "node_modules/expo/AppEntry.js", | ||
5 | + "scripts": { | ||
6 | + "start": "expo start", | ||
7 | + "android": "expo start --android", | ||
8 | + "ios": "expo start --ios", | ||
9 | + "web": "expo start --web", | ||
10 | + "eject": "expo eject" | ||
11 | + }, | ||
12 | + "dependencies": { | ||
13 | + "expo": "~45.0.0", | ||
14 | + "expo-status-bar": "~1.3.0", | ||
15 | + "react": "17.0.2", | ||
16 | + "react-dom": "17.0.2", | ||
17 | + "react-native": "0.68.2", | ||
18 | + "react-native-web": "0.17.7" | ||
19 | + }, | ||
20 | + "devDependencies": { | ||
21 | + "@babel/core": "^7.12.9" | ||
22 | + }, | ||
23 | + "private": true | ||
24 | +} |
yarn.lock
0 → 100644
This diff could not be displayed because it is too large.
-
Please register or login to post a comment