신승미

goal app

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 +});
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 +}
1 +module.exports = function(api) {
2 + api.cache(true);
3 + return {
4 + presets: ['babel-preset-expo'],
5 + };
6 +};
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 +});
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 +});
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 +}
This diff could not be displayed because it is too large.