김성연

add code

Showing 118 changed files with 3455 additions and 0 deletions
1 +# Default ignored files
2 +/shelf/
3 +/workspace.xml
4 +# Editor-based HTTP Client requests
5 +/httpRequests/
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<module type="WEB_MODULE" version="4">
3 + <component name="NewModuleRootManager">
4 + <content url="file://$MODULE_DIR$" />
5 + <orderEntry type="inheritedJdk" />
6 + <orderEntry type="sourceFolder" forTests="false" />
7 + </component>
8 +</module>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="JavaScriptSettings">
4 + <option name="languageLevel" value="JSX" />
5 + </component>
6 + <component name="ProjectPlainTextFileTypeManager">
7 + <file url="file://$PROJECT_DIR$/render_server_react_native/components/CardComponent.js" />
8 + </component>
9 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="ProjectModuleManager">
4 + <modules>
5 + <module fileurl="file://$PROJECT_DIR$/.idea/code.iml" filepath="$PROJECT_DIR$/.idea/code.iml" />
6 + </modules>
7 + </component>
8 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="VcsDirectoryMappings">
4 + <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
5 + <mapping directory="$PROJECT_DIR$/locationTest/expo-location-example" vcs="Git" />
6 + <mapping directory="$PROJECT_DIR$/my-project" vcs="Git" />
7 + <mapping directory="$PROJECT_DIR$/render_server_react_native" vcs="Git" />
8 + <mapping directory="$PROJECT_DIR$/render_server_react_native/@expo/vector-icons" vcs="Git" />
9 + </component>
10 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="WebServers">
4 + <option name="servers">
5 + <webServer id="1b403629-1b05-48f5-aa8c-1b92f496c1d2" name="2019-BigData" url="http://133.186.211.42">
6 + <fileTransfer host="133.186.211.42" port="22" accessType="SFTP">
7 + <advancedOptions>
8 + <advancedOptions dataProtectionLevel="Private" passiveMode="true" shareSSLContext="true" />
9 + </advancedOptions>
10 + <option name="port" value="22" />
11 + </fileTransfer>
12 + </webServer>
13 + </option>
14 + </component>
15 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 + "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 +}
1 +node_modules/**/*
2 +.expo/*
3 +npm-debug.*
4 +*.jks
5 +*.p8
6 +*.p12
7 +*.key
8 +*.mobileprovision
9 +*.orig.*
10 +web-build/
11 +web-report/
12 +
13 +# macOS
14 +.DS_Store
15 +env.js
16 +.env
1 +import React, {useState} from 'react';
2 +import {StyleSheet, Text, View, Image, StatusBar, AsyncStorage} from 'react-native';
3 +import {AppLoading} from "expo";
4 +import {Asset} from 'expo-asset';
5 +import {Provider} from 'react-redux';
6 +import * as Font from 'expo-font'
7 +import {Ionicons} from "@expo/vector-icons";
8 +import {NavigationContainer} from "@react-navigation/native";
9 +import store from './store';
10 +import StackNavigation from "./navigations/StackNavigation";
11 +import {AuthProvider} from "./AuthContext";
12 +import {host} from './env';
13 +import axios from "axios";
14 +
15 +const cacheImages = (images) => {
16 + return images.map((image) => {
17 + if (typeof image === 'string') {
18 + return Image.prefetch(image);
19 + } else {
20 + return Asset.fromModule(image).downloadAsync();
21 + }
22 + })
23 +};
24 +
25 +const cacheFonts = (fonts) => {
26 + return fonts.map((font) => {
27 + return Font.loadAsync(font);
28 + })
29 +};
30 +
31 +const App = () => {
32 + const [isReady, setIsReady] = useState(false);
33 + const [user, setUser] = useState('');
34 +
35 + const loadAssets = async () => {
36 + const images = cacheImages(
37 + ['https://images.unsplash.com/photo-1532278951723-545f655c97f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60']
38 + );
39 + const fonts = cacheFonts([Ionicons.font]);
40 +
41 + // await AsyncStorage.removeItem('cookie');
42 + const cookie = await AsyncStorage.getItem('cookie');
43 + console.log('cookie', cookie);
44 + if (cookie) {
45 + try {
46 + axios.defaults.headers.Cookie = cookie;
47 + console.log('user/loadMe 요청보냄', `http://${host}:4001/user/loadMe`);
48 + const res = await axios.get(`http://${host}:4001/user/loadMe`);
49 + const {user} = res.data;
50 + console.log(user);
51 + setUser(user);
52 + } catch (e) {
53 + console.error(e);
54 + }
55 + }
56 +
57 + return Promise.all([images, fonts]);
58 + };
59 +
60 + const onFinish = () => {
61 + setIsReady(true);
62 + };
63 + const onError = (err) => {
64 + console.error(err)
65 + };
66 + return (
67 + <>
68 + {isReady
69 + ?
70 + <Provider store={store}>
71 + <AuthProvider user={user}>
72 + <NavigationContainer>
73 + <StatusBar barstyle={'light-content'}/>
74 + <StackNavigation/>
75 + </NavigationContainer>
76 + </AuthProvider>
77 + </Provider>
78 + :
79 + <AppLoading
80 + startAsync={loadAssets}
81 + onFinish={onFinish}
82 + onError={onError}
83 + />
84 + }
85 + </>
86 + );
87 +};
88 +
89 +
90 +export default App;
91 +
92 +const styles = StyleSheet.create({
93 + container: {
94 + flex: 1,
95 + backgroundColor: '#fff',
96 + alignItems: 'center',
97 + justifyContent: 'center',
98 + },
99 +});
1 +import { Platform, StyleSheet, Dimensions } from "react-native";
2 +
3 +const { width, height } = Dimensions.get("window");
4 +const SCREEN_WIDTH = width < height ? width : height;
5 +const numColumns = 2;
6 +
7 +export const AppStyles = {
8 + color: {
9 + main: "#5ea23a",
10 + text: "#696969",
11 + title: "#464646",
12 + subtitle: "#545454",
13 + categoryTitle: "#161616",
14 + tint: "#ff5a66",
15 + description: "#bbbbbb",
16 + filterTitle: "#8a8a8a",
17 + starRating: "#2bdf85",
18 + location: "#a9a9a9",
19 + white: "white",
20 + facebook: "#4267b2",
21 + grey: "grey",
22 + greenBlue: "#00aea8",
23 + placeholder: "#a0a0a0",
24 + background: "#f2f2f2",
25 + blue: "#3293fe"
26 + },
27 + fontSize: {
28 + title: 30,
29 + content: 20,
30 + normal: 16
31 + },
32 + buttonWidth: {
33 + main: "70%"
34 + },
35 + textInputWidth: {
36 + main: "80%"
37 + },
38 + fontName: {
39 + main: "Noto Sans",
40 + bold: "Noto Sans"
41 + },
42 + borderRadius: {
43 + main: 25,
44 + small: 5
45 + }
46 +};
47 +
48 +export const AppIcon = {
49 + container: {
50 + backgroundColor: "white",
51 + borderRadius: 20,
52 + padding: 8,
53 + marginRight: 10
54 + },
55 + style: {
56 + tintColor: AppStyles.color.tint,
57 + width: 25,
58 + height: 25
59 + },
60 + images: {
61 + home: require("./assets/icons/home.png"),
62 + defaultUser: require("./assets/icons/default_user.jpg"),
63 + logout: require("./assets/icons/shutdown.png")
64 + }
65 +};
66 +
67 +export const HeaderButtonStyle = StyleSheet.create({
68 + multi: {
69 + flexDirection: "row"
70 + },
71 + container: {
72 + padding: 10
73 + },
74 + image: {
75 + justifyContent: "center",
76 + width: 35,
77 + height: 35,
78 + margin: 6
79 + },
80 + rightButton: {
81 + color: AppStyles.color.tint,
82 + marginRight: 10,
83 + fontWeight: "normal",
84 + fontFamily: AppStyles.fontName.main
85 + }
86 +});
87 +
88 +export const ListStyle = StyleSheet.create({
89 + title: {
90 + fontSize: 16,
91 + color: AppStyles.color.subtitle,
92 + fontFamily: AppStyles.fontName.bold,
93 + fontWeight: "bold"
94 + },
95 + subtitleView: {
96 + minHeight: 55,
97 + flexDirection: "row",
98 + paddingTop: 5,
99 + marginLeft: 10
100 + },
101 + leftSubtitle: {
102 + flex: 2
103 + },
104 + avatarStyle: {
105 + height: 80,
106 + width: 80
107 + }
108 +});
1 +import React, {createContext, useContext, useEffect, useState} from 'react';
2 +import {useDispatch, useSelector} from 'react-redux';
3 +import {LOAD_ME_SUCCESS} from "./reducers/user";
4 +
5 +export const AuthContext = createContext({});
6 +export const AuthProvider = (props) => {
7 + const {children, user} = props;
8 +
9 + const dispatch = useDispatch();
10 +
11 + const onLoadMe = async () => {
12 + try {
13 + await dispatch({
14 + type: LOAD_ME_SUCCESS,
15 + data: {
16 + user
17 + }
18 + });
19 + } catch (e) {
20 + console.log(e);
21 + }
22 + };
23 +
24 + useEffect(() => {
25 + onLoadMe();
26 + console.log('AuthContext user', user);
27 + }, [user]);
28 +
29 + return (
30 + <AuthContext.Provider>
31 + {children}
32 + </AuthContext.Provider>
33 + )
34 +};
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "expo": {
3 + "name": "render_server_react_native",
4 + "slug": "render_server_react_native",
5 + "platforms": [
6 + "ios",
7 + "android",
8 + "web"
9 + ],
10 + "version": "1.0.0",
11 + "orientation": "portrait",
12 + "icon": "./assets/icon.png",
13 + "splash": {
14 + "image": "./assets/splash.png",
15 + "resizeMode": "contain",
16 + "backgroundColor": "#ffffff"
17 + },
18 + "updates": {
19 + "fallbackToCacheTimeout": 0
20 + },
21 + "assetBundlePatterns": [
22 + "**/*"
23 + ],
24 + "ios": {
25 + "supportsTablet": true
26 + }
27 + }
28 +}
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
1 +[{"index":1,"avgSpeed": 53},{"index":2,"avgSpeed":60}]
...\ No newline at end of file ...\ No newline at end of file
1 +module.exports = function(api) {
2 + api.cache(true);
3 + return {
4 + presets: ['babel-preset-expo'],
5 + };
6 +};
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {Text, View, StyleSheet, TouchableOpacity, ScrollView} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {useNavigation} from '@react-navigation/native';
5 +import styled from "styled-components";
6 +import {AntDesign, MaterialCommunityIcons} from "@expo/vector-icons";
7 +
8 +
9 +const Banner = styled.View`
10 + flex: 1;
11 + margin-left: 15px;
12 + margin-bottom: 5px;
13 + width: 3px;
14 + height: 3px;
15 + border-radius: 20px;
16 + border: 3px solid #88c600;
17 +
18 +`;
19 +
20 +const BusPathComponent = (props) => {
21 + const navigation = useNavigation();
22 + const [busPath, setBusPath] = useState(null);
23 + const [seeStaList, setSeeStaList] = useState(false);
24 + const {pathDetail} = props;
25 +
26 + const changeSeeStaList = () => {
27 + setSeeStaList(!seeStaList);
28 + console.log(seeStaList)
29 + };
30 +
31 + useEffect(() => {
32 + console.log(props.pathDetail);
33 + setBusPath(props.pathDetail);
34 + }, []);
35 +
36 + return (
37 + <ScrollView>
38 + <View style={{flexDirection: 'row', flex: 5}}>
39 + <View style={styles.pathType}>
40 + <MaterialCommunityIcons style={{flex: 1}} color={'#88c600'} name={'bus'} size={20}/>
41 + <Text style={{flex: 1, fontSize: 13}}>{pathDetail.time}</Text>
42 + </View>
43 + <View style={{flex: 1}}>
44 + <Banner/>
45 + <Banner/>
46 + <Banner/>
47 + <Banner/>
48 + <Banner/>
49 + <Banner/>
50 + <Banner/>
51 + </View>
52 + <View style={styles.inputTile}>
53 + <Text style={styles.stationStyle}>{pathDetail.startName}</Text>
54 + <Text style={styles.idStyle}>{pathDetail.startID}</Text>
55 + {pathDetail.arrivalInfo.map((bus, index) => {
56 + return (
57 + <View>
58 + <Text style={styles.busStyle}>{bus.busNo}</Text>
59 + {bus.msg.msg1.indexOf('undefined') !== -1 ?
60 + null
61 + :
62 + <>
63 + <Text style={styles.busSubStyle}>{bus.msg.msg1}</Text>
64 + </>
65 + }
66 + {bus.msg.msg2.indexOf('undefined') !== -1 ?
67 + null
68 + :
69 + <>
70 + <Text style={styles.busSubStyle}>{bus.msg.msg2}</Text>
71 + </>
72 + }
73 + </View>
74 + )
75 + })}
76 + <View style={styles.stationListStyle}>
77 + <Text style={styles.cntStyle}>{pathDetail.stationCnt} 정류소 이동</Text>
78 + <TouchableOpacity style={{flex: 1, marginTop: 17}} onPress={changeSeeStaList}>
79 + <AntDesign color={'darkgrey'} name={'caretdown'} size={15}/>
80 + </TouchableOpacity>
81 + </View>
82 + <View>
83 + {seeStaList === true ?
84 + <View>
85 + {pathDetail.stationList.map((bus, index) => {
86 + return (
87 + <>
88 + <Text>{bus.stationName}</Text>
89 + </>
90 + )
91 + })}
92 + </View>
93 + :
94 + null
95 + }
96 + </View>
97 + <Text style={styles.stationStyle}>{pathDetail.endName}</Text>
98 + </View>
99 + </View>
100 + </ScrollView>
101 + );
102 +}
103 +export default BusPathComponent;
104 +
105 +const styles = StyleSheet.create({
106 + inputTile: {
107 + marginLeft: 6,
108 + flex: 4,
109 + color: 'grey',
110 + },
111 + inputText: {
112 + fontWeight: 'normal',
113 + fontSize: 15,
114 + },
115 + pathType: {
116 + flexDirection: 'column',
117 + flex: 0.4,
118 + alignItems: 'center',
119 + justifyContent: 'center',
120 + marginLeft: 5,
121 + marginTop: 10,
122 + },
123 + stationStyle: {
124 + fontWeight: 'bold',
125 + fontSize: 15,
126 + },
127 + idStyle: {
128 + marginTop: 3,
129 + marginBottom: 20,
130 + color: 'grey',
131 + fontSize: 14
132 + },
133 + busStyle: {
134 + fontWeight: 'bold',
135 + fontSize: 14,
136 + color: '#88c600'
137 + },
138 + cntStyle: {
139 + flex: 1,
140 + marginTop: 20,
141 + marginBottom: 3,
142 + color: 'grey',
143 + fontSize: 14
144 + },
145 + stationListStyle: {
146 + flexDirection: 'row',
147 + flex: 1,
148 + },
149 + busSubStyle: {
150 + marginTop: 2,
151 + fontSize: 12,
152 + color: 'red',
153 + }
154 +})
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {View, Text, Button, Image, TouchableOpacity, StyleSheet, Platform} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {LOG_IN_REQUEST, LOG_OUT_REQUEST} from "../reducers/user";
5 +import {MaterialCommunityIcons} from "@expo/vector-icons";
6 +import {useNavigation} from '@react-navigation/native';
7 +import DateTimePicker from '@react-native-community/datetimepicker';
8 +import {SET_TIME_SUCCESS} from "../reducers/location";
9 +import moment from "moment";
10 +
11 +const DateTimePickerComponent = (props) => {
12 + const [date, setDate] = useState(new Date());
13 + const [mode, setMode] = useState('time');
14 + const {goToMapsClick} = props;
15 +
16 + const onChange = (event, selectedDate) => {
17 + const currentDate = selectedDate || date;
18 + console.log(currentDate);
19 + setDate(currentDate);
20 + };
21 +
22 + // SET FINISH TIME
23 + const dispatch = useDispatch();
24 + const onSubmit = async () => {
25 + if (!date) {
26 + return
27 + }
28 + console.log('SET_TIME_SUCCESS GO!!', date);
29 + await dispatch({
30 + type: SET_TIME_SUCCESS,
31 + data: {
32 + date
33 + }
34 + });
35 + };
36 +
37 + useEffect(() => {
38 + if (goToMapsClick === true) {
39 + console.log(goToMapsClick);
40 + console.log('goToMapsClick!');
41 + onSubmit();
42 + }
43 + setDate(date);
44 + }, [goToMapsClick, date]);
45 +
46 + return (
47 + <View>
48 + <DateTimePicker
49 + testID="dateTimePicker"
50 + value={date}
51 + mode={mode}
52 + is24Hour={true}
53 + display="default"
54 + onChange={onChange}
55 + style={styles.TextStyle}
56 + />
57 +
58 + </View>
59 + );
60 +};
61 +
62 +const styles = StyleSheet.create({
63 + containerStyle: {
64 + marginTop: 10,
65 + alignItems: 'center',
66 + justifyContent: 'center',
67 + },
68 + TextStyle: {
69 + flex: 1,
70 + marginBottom: 240,
71 + }
72 +});
73 +
74 +export default DateTimePickerComponent;
75 +
1 +import React, {useState, useEffect} from 'react';
2 +import {Text, View, StyleSheet, TouchableOpacity, ScrollView} from 'react-native';
3 +import styled from 'styled-components';
4 +import {MaterialCommunityIcons, AntDesign} from '@expo/vector-icons';
5 +import {useNavigation} from '@react-navigation/native';
6 +
7 +
8 +const ShowDetail = styled.TouchableOpacity`
9 + flex: 2;
10 + position: absolute;
11 + right: 6px;
12 + bottom: 2px;
13 + width: 30px;
14 + height: 30px;
15 + border-radius: 50px;
16 +`;
17 +
18 +const Banner = styled.View`
19 + flex: 1;
20 + margin-left: 15px;
21 + margin-bottom: 5px;
22 + width: 3px;
23 + height: 3px;
24 + border-radius: 20px;
25 + border: 3px solid #273b96;
26 +`;
27 +
28 +
29 +const GoPathSummary = (props) => {
30 + const navigation = useNavigation();
31 + const [pathSummary, setPathSummary] = useState(null);
32 + const goPathDetail = () => {
33 + navigation.navigate('GoPathDetail', {'detail': props.detail});
34 + };
35 +
36 + useEffect
37 + (() => {
38 + console.log(props.summary);
39 + setPathSummary(props.summary);
40 + }, []);
41 +
42 +
43 + return (
44 + <View>
45 + {pathSummary ?
46 + <>
47 + <View style={styles.container}>
48 +
49 + <View style={styles.titleParagraph}>
50 + <Text style={styles.hourStyle}>{pathSummary.hour1} {pathSummary.min1} 출발
51 + <Text style={styles.conditionStyle}>정확</Text>
52 + </Text>
53 + <Text style={styles.hourStyle}>{pathSummary.hour2} {pathSummary.min2} 출발
54 + <Text style={styles.conditionStyle}>여유</Text>
55 + </Text>
56 + </View>
57 + <View style={{flexDirection: 'row', flex: 2, marginLeft: 70}}>
58 + <Text style={{flex: 1, fontSize: 13, fontWeight: 'bold'}}>총소요시간: {pathSummary.totalTime}</Text>
59 + <Text style={{flex: 1, fontSize: 13, fontWeight: 'bold'}}>비용: {pathSummary.payment}</Text>
60 + </View>
61 + <View style={{flexDirection: 'row', flex: 5, marginLeft: 70, marginTop: 20}}>
62 + <View style={styles.pathType}>
63 + <MaterialCommunityIcons style={{flex: 1}} color={'#273b96'} name={'train'} size={20}/>
64 + </View>
65 + <View style={styles.inputTile}>
66 + <Text style={styles.stationStyle}>{pathSummary.firstStartStation}</Text>
67 + <Text style={styles.stationStyle}>{pathSummary.lastEndStation}</Text>
68 + </View>
69 + </View>
70 + <View style={{position: 'absolute', right: 10}}>
71 + <ShowDetail onPress={goPathDetail}>
72 + <AntDesign color={'darkgrey'} name={'caretright'} size={32}/>
73 + </ShowDetail>
74 + </View>
75 +
76 + </View>
77 + </>
78 + :
79 + null
80 + }
81 + </View>
82 + );
83 +}
84 +
85 +const styles = StyleSheet.create({
86 + container: {
87 + flex: 1,
88 + flexDirection: 'column',
89 + paddingTop: 40,
90 + paddingBottom: 30,
91 + backgroundColor: '#ecf0f1',
92 + alignItems: 'center',
93 + justifyContent: 'center',
94 + borderWidth: 1,
95 + borderColor: 'darkgrey',
96 + },
97 + paragraph: {
98 + flex: 1,
99 + fontSize: 14,
100 + fontWeight: 'bold',
101 + textAlign: 'center',
102 + color: '#34495e',
103 + },
104 + titleParagraph: {
105 + flexDirection: 'column',
106 + flex: 1,
107 + },
108 + inputTile: {
109 + marginLeft: 6,
110 + flex: 4,
111 + color: 'grey',
112 + },
113 + inputText: {
114 + fontWeight: 'normal',
115 + fontSize: 15,
116 + },
117 + pathType: {
118 + flexDirection: 'column',
119 + flex: 0.4,
120 + alignItems: 'center',
121 + justifyContent: 'center',
122 + marginLeft: 5,
123 + marginTop: 10,
124 + },
125 + stationStyle: {
126 + fontWeight: 'bold',
127 + fontSize: 15,
128 + },
129 + idStyle: {
130 + marginTop: 3,
131 + marginBottom: 20,
132 + color: 'grey',
133 + fontSize: 14
134 + },
135 + laneStyle: {
136 + fontWeight: 'bold',
137 + fontSize: 15,
138 + color: '#EBA900'
139 + },
140 + cntStyle: {
141 + flex: 1,
142 + marginTop: 20,
143 + marginBottom: 3,
144 + color: 'grey',
145 + fontSize: 14
146 + },
147 + stationListStyle: {
148 + flexDirection: 'row',
149 + flex: 1,
150 + },
151 + hourStyle: {
152 + flexDirection: 'row',
153 + flex: 1,
154 + fontSize: 18,
155 + fontWeight: 'bold',
156 + marginBottom: 20,
157 + },
158 + conditionStyle: {
159 + paddingLeft: 10,
160 + fontSize: 15,
161 + color: 'red',
162 + }
163 +});
164 +
165 +export default GoPathSummary;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {Text, View, StyleSheet, TouchableOpacity, ScrollView} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {useNavigation} from '@react-navigation/native';
5 +import styled from "styled-components";
6 +import {AntDesign, MaterialCommunityIcons} from "@expo/vector-icons";
7 +
8 +const Banner = styled.View`
9 + flex: 1;
10 + margin-left: 15px;
11 + margin-bottom: 5px;
12 + width: 3px;
13 + height: 3px;
14 + border-radius: 20px;
15 + border: 3px solid #EBA900;
16 +`;
17 +
18 +const LanePathComponent = (props) => {
19 + const navigation = useNavigation();
20 + const [lanePath, setLanePath] = useState(null);
21 + const [seeLaneList, setSeeLaneList] = useState(false);
22 + const {pathDetail} = props;
23 +
24 +
25 + const changeSeeLaneList = () => {
26 + setSeeLaneList(!seeLaneList);
27 + console.log(seeLaneList)
28 + };
29 +
30 + useEffect(() => {
31 + console.log(props.pathDetail);
32 + setLanePath(props.pathDetail);
33 + }, []);
34 +
35 + return (
36 + <ScrollView>
37 + <View style={{flexDirection: 'row', flex: 5}}>
38 + <View style={styles.pathType}>
39 + <MaterialCommunityIcons style={{flex: 1}} color={'#EBA900'} name={'train'} size={20}/>
40 + <Text style={{flex: 1, fontSize: 13}}>{pathDetail.time}</Text>
41 + </View>
42 + <View style={{flex: 1}}>
43 + <Banner/>
44 + <Banner/>
45 + <Banner/>
46 + <Banner/>
47 + <Banner/>
48 + <Banner/>
49 + <Banner/>
50 + </View>
51 + <View style={styles.inputTile}>
52 + <Text style={styles.stationStyle}>{pathDetail.startName}</Text>
53 + <Text style={styles.idStyle}>{pathDetail.startID}</Text>
54 + {pathDetail.laneList.map((lane, index) => {
55 + return (
56 + <Text style={styles.laneStyle}>{lane.name}</Text>
57 + )
58 + })}
59 + <View style={styles.stationListStyle}>
60 + <Text style={styles.cntStyle}>{pathDetail.stationCnt} 정류소 이동</Text>
61 + <TouchableOpacity style={{flex: 1, marginTop: 17}} onPress={changeSeeLaneList}>
62 + <AntDesign color={'darkgrey'} name={'caretdown'} size={15}/>
63 + </TouchableOpacity>
64 + </View>
65 + {seeLaneList === true ?
66 + <View>
67 + {pathDetail.stationList.map((lane, index) => {
68 + return (
69 + <Text>{lane}</Text>
70 + )
71 + })}
72 + </View>
73 + :
74 + null
75 + }
76 + <Text style={styles.stationStyle}>{pathDetail.endName}</Text>
77 + </View>
78 + </View>
79 + </ScrollView>
80 + );
81 +}
82 +export default LanePathComponent;
83 +
84 +const styles = StyleSheet.create({
85 + inputTile: {
86 + marginLeft: 6,
87 + flex: 4,
88 + color: 'grey',
89 + },
90 + inputText: {
91 + fontWeight: 'normal',
92 + fontSize: 15,
93 + },
94 + pathType: {
95 + flexDirection: 'column',
96 + flex: 0.4,
97 + alignItems: 'center',
98 + justifyContent: 'center',
99 + marginLeft: 5,
100 + marginTop: 10,
101 + },
102 + stationStyle: {
103 + fontWeight: 'bold',
104 + fontSize: 15,
105 + },
106 + idStyle: {
107 + marginTop: 3,
108 + marginBottom: 20,
109 + color: 'grey',
110 + fontSize: 14
111 + },
112 + laneStyle: {
113 + fontWeight: 'bold',
114 + fontSize: 15,
115 + color: '#EBA900'
116 + },
117 + cntStyle: {
118 + flex: 1,
119 + marginTop: 20,
120 + marginBottom: 3,
121 + color: 'grey',
122 + fontSize: 14
123 + },
124 + stationListStyle: {
125 + flexDirection: 'row',
126 + flex: 1,
127 + }
128 +})
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import {ActivityIndicator, View} from 'react-native';
3 +
4 +const LoadingComponent = () => {
5 + return (
6 + <View style={{
7 + flex: 1,
8 + justifyContent: 'center',
9 + alignItems: 'center'
10 + }}>
11 + <ActivityIndicator color={'grey'}/>
12 + </View>
13 + )
14 +};
15 +
16 +
17 +
18 +export default LoadingComponent;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {View, Text, Button, StyleSheet, TextInput, TouchableOpacity} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {LOG_IN_REQUEST, LOG_OUT_REQUEST} from "../reducers/user";
5 +import styled from "styled-components";
6 +import {useNavigation} from '@react-navigation/native';
7 +import Profile from "../screens/Profile";
8 +
9 +
10 +const LoginButton = styled.TouchableOpacity`
11 + align-items: center;
12 + justify-content: center;
13 + width: 60px;
14 + height: 40px;
15 + background-color: #e6e6fa;
16 + border: 1px;
17 + marginBottom: 10px;
18 + border-radius: 50px;
19 +
20 +`;
21 +
22 +const SignUpButton = styled.TouchableOpacity`
23 + align-items: center;
24 + justify-content: center;
25 + width: 60px;
26 + height: 40px;
27 + background-color: #e6e6fa;
28 + border: 1px;
29 + border-radius: 50px;
30 +
31 +`;
32 +
33 +
34 +const LoginComponent = () => {
35 + const navigation = useNavigation();
36 + const [loading, setLoading] = useState(true);
37 + const [email, setEmail] = useState('');
38 + const [password, setPassword] = useState('');
39 +
40 +
41 + const {me} = useSelector(state => state.user);
42 + const {isLoggingIn} = useSelector(state => state.user);
43 +
44 + const onChangeEmail = (email) => {
45 + setEmail(email)
46 + };
47 +
48 + const onChangePassword = (password) => {
49 + setPassword(password);
50 + };
51 +
52 + const dispatch = useDispatch();
53 + const onSubmit = async () => {
54 + if (!email || !password) {
55 + return
56 + }
57 + await dispatch({
58 + type: LOG_IN_REQUEST,
59 + data: {
60 + email,
61 + password
62 + }
63 + });
64 +
65 + };
66 + const goSignUp = () => {
67 + navigation.navigate('SignUp');
68 + }
69 +
70 + useEffect(() => {
71 + if (me) {
72 + navigation.navigate('Profile');
73 + }
74 + }, [me]);
75 +
76 + useEffect(() => {
77 + setLoading(false);
78 + setEmail('');
79 + setPassword('');
80 + }, []);
81 +
82 + return (
83 + <View style={styles.containerStyle}>
84 + <TextInput
85 + style={styles.input}
86 + placeholder="Type here to Email!"
87 + onChangeText={onChangeEmail}
88 + defaultValue={email}
89 + />
90 + <TextInput
91 + style={styles.input}
92 + placeholder="Type here to password!"
93 + type="password"
94 + onChangeText={onChangePassword}
95 + />
96 + <LoginButton
97 + title={'Login'}
98 + onPress={onSubmit}>
99 + <Text style={{color: '#696969'}}>Login</Text>
100 + </LoginButton>
101 + <SignUpButton
102 + title={'Login'}
103 + onPress={goSignUp}>
104 + <Text style={{color: '#696969'}}>SignUp</Text>
105 + </SignUpButton>
106 + </View>
107 + )
108 +};
109 +
110 +const styles = StyleSheet.create({
111 + containerStyle: {
112 + // flex: 1,
113 + alignItems: 'center',
114 + // justifyContent: 'center',
115 + // backgroundColor: '#ecf0f1',
116 + // marginTop: 100,
117 + },
118 + input: {
119 + width: 200,
120 + height: 44,
121 + padding: 10,
122 + borderWidth: 1,
123 + borderColor: '#778899',
124 + marginBottom: 10,
125 + }
126 +});
127 +
128 +export default LoginComponent;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {View, Text, Button, Image, TouchableOpacity, StyleSheet, Alert} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {LOG_IN_REQUEST, LOG_OUT_REQUEST} from "../reducers/user";
5 +import {MaterialCommunityIcons} from "@expo/vector-icons";
6 +import {useNavigation} from '@react-navigation/native';
7 +import {SET_PERVELOCITY_SUCCESS} from "../reducers/location";
8 +import Login from "../screens/Login";
9 +import Papa from 'papaparse';
10 +
11 +
12 +const MyProfileComponent = () => {
13 + const navigation = useNavigation();
14 + const [loading, setLoading] = useState(true);
15 + const [numRecord, setNumRecord] = useState(0);
16 +
17 + const {me} = useSelector(state => state.user);
18 + const {isLoggingIn} = useSelector(state => state.user);
19 +
20 + const downloadFile = async () => {
21 + const uri = "https://www.mapmyfitness.com/workout/export/csv";
22 + let fileUri = FileSystem.documentDirectory + "userVelocity.txt";
23 + FileSystem.downloadAsync(uri, fileUri)
24 + .then(({uri}) => {
25 + saveFile(uri);
26 + })
27 + .catch(error => {
28 + console.error(error);
29 + })
30 + }
31 +
32 + const saveFile = async (fileUri) => {
33 + const {status} = await Permissions.askAsync(Permissions.CAMERA_ROLL);
34 + if (status === "granted") {
35 + const asset = await MediaLibrary.createAssetAsync(fileUri)
36 + await MediaLibrary.createAlbumAsync("Download", asset, false)
37 + }
38 + }
39 +
40 + const dispatch = useDispatch();
41 + const loadPersonalVelocity = async () => {
42 + try {
43 +
44 + const userVelocity = require('../assets/userFile/userVelocity');
45 + var allAvgSpeed = 0;
46 + setNumRecord(userVelocity.length);
47 + userVelocity.map((i, index) => {
48 + allAvgSpeed = allAvgSpeed + i.avgSpeed;
49 + });
50 +
51 + var personalVelocity = parseInt(allAvgSpeed / userVelocity.length);
52 + await dispatch({
53 + type: SET_PERVELOCITY_SUCCESS,
54 + data: {
55 + personalVelocity: personalVelocity
56 + }
57 + });
58 +
59 + Alert.alert(
60 + 'MAP 사용자 평균 속도 설정',
61 + ` 사용자 평균 속도를 설정하였습니다. `,
62 + [
63 + {
64 + text: 'Cancel',
65 + onPress: () => console.log('Cancel Pressed'),
66 + style: 'cancel',
67 + },
68 + {text: 'OK', onPress: () => console.log('OK Pressed')},
69 + ],
70 + {cancelable: false}
71 + );
72 +
73 + } catch (e) {
74 + console.log(e);
75 + }
76 +
77 + };
78 +
79 + useEffect(() => {
80 + setNumRecord(0);
81 + }, []);
82 +
83 + useEffect(() => {
84 + console.log(numRecord)
85 + }, [numRecord]);
86 +
87 + const onLogout = async () => {
88 + await dispatch({
89 + type: LOG_OUT_REQUEST
90 + });
91 + console.log('onLogout');
92 + };
93 + return (
94 + <View>
95 + {me ?
96 + <View>
97 + <View style={{flexDirection: 'row', paddingTop: 15}}>
98 + <View style={{flex: 1, alignItems: 'center'}}>
99 + <Image source={{url: 'https://steemitimages.com/u/anpigon/avatar'}}
100 + style={{width: 75, height: 75, borderRadius: 37.5}}/>
101 + </View>
102 + <View style={{flex: 3}}>
103 + <View style={{flexDirection: 'row', justifyContent: 'space-around', marginTop: 12}}>
104 + <View style={{alignItems: 'center'}}>
105 + <Text style={{fontSize: 15, fontWeight: 'bold'}}>{me.email}</Text>
106 + <Text style={{fontSize: 10, color: 'gray'}}>email</Text>
107 + </View>
108 + <View style={{alignItems: 'center'}}>
109 + <Text style={{fontSize: 15, fontWeight: 'bold'}}>{me.nickName}</Text>
110 + <Text style={{fontSize: 10, color: 'gray'}}>nickName</Text>
111 + </View>
112 + <View style={{alignItems: 'center'}}>
113 + <Text style={{fontSize: 15, fontWeight: 'bold'}}>{numRecord}</Text>
114 + <Text style={{fontSize: 10, color: 'gray'}}>numRecord</Text>
115 + </View>
116 + </View>
117 + <View style={{flexDirection: 'row'}}>
118 + <TouchableOpacity
119 + onPress={loadPersonalVelocity}
120 + style={{
121 + flex: 4,
122 + marginLeft: 10,
123 + justifyContent: 'center',
124 + alignItems: 'center',
125 + borderWidth: 1,
126 + borderColor: 'black',
127 + height: 30,
128 + marginTop: 17
129 + }}>
130 + <Text style={{fontSize: 13}}>load personal velocity</Text>
131 + </TouchableOpacity>
132 + <TouchableOpacity
133 + onPress={onLogout}
134 + style={{
135 + borderColor: 'black',
136 + borderWidth: 1,
137 + flex: 1,
138 + marginRight: 10,
139 + marginLeft: 5,
140 + justifyContent: 'center',
141 + alignItems: 'center',
142 + height: 30,
143 + marginTop: 17
144 + }}>
145 + <MaterialCommunityIcons color={'black'} name={'logout'} size={20}/>
146 + </TouchableOpacity>
147 + </View>
148 + </View>
149 + </View>
150 + < View style={{paddingHorizontal: 20, paddingVertical: 10}}>
151 + </View>
152 + </View>
153 + :
154 + <View style={{alignItems: 'center', justifyContent: 'center', marginTop: 200}}>
155 + <Text style={{fontSize: 30, textAlign: 'center', fontWeight: 'bold'}}>유저 정보가 없습니다.</Text>
156 + </View>
157 + }
158 + </View>
159 + )
160 +};
161 +
162 +const styles = StyleSheet.create({
163 + containerStyle: {
164 + marginTop: 10,
165 + alignItems: 'center',
166 + justifyContent: 'center',
167 + },
168 + TextStyle: {
169 + width: 200,
170 + height: 44,
171 + padding: 10,
172 + borderWidth: 1,
173 + borderColor: '#778899',
174 + marginBottom: 10,
175 + }
176 +});
177 +
178 +export default MyProfileComponent;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {View, Text, Button, TextInput, TouchableOpacity, StyleSheet} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {SIGN_UP_REQUEST} from "../reducers/user";
5 +import styled from "styled-components";
6 +import {useNavigation} from '@react-navigation/native';
7 +import Profile from "../screens/Profile";
8 +
9 +
10 +const SignUpButton = styled.TouchableOpacity`
11 + align-items: center;
12 + justify-content: center;
13 + width: 60px;
14 + height: 40px;
15 + background-color: #e6e6fa;
16 + border: 1px;
17 + marginBottom: 10px;
18 + border-radius: 50px;
19 +`;
20 +
21 +const GoLoginButton = styled.TouchableOpacity`
22 + align-items: center;
23 + justify-content: center;
24 + width: 60px;
25 + height: 40px;
26 + background-color: #e6e6fa;
27 + border: 1px;
28 + border-radius: 50px;
29 +`;
30 +
31 +
32 +const SignUpComponent = () => {
33 + const navigation = useNavigation();
34 + const [email, setEmail] = useState('');
35 + const [nickName, setNickName] = useState('');
36 + const [password, setPassword] = useState('');
37 +
38 +
39 + const {me} = useSelector(state => state.user);
40 + const {isSigningUp} = useSelector(state => state.user);
41 +
42 + const onChangeEmail = (email) => {
43 + setEmail(email)
44 + };
45 +
46 + const onChangePassword = (password) => {
47 + setPassword(password);
48 + };
49 +
50 + const onChangeNickName = (nickName) => {
51 + setNickName(nickName)
52 + };
53 +
54 + const dispatch = useDispatch();
55 + const onSubmit = async () => {
56 + await dispatch({
57 + type: SIGN_UP_REQUEST,
58 + data: {
59 + email,
60 + nickName,
61 + password
62 + }
63 + });
64 + if (me !== null) {
65 + navigation.navigate('Profile');
66 + }
67 + };
68 +
69 + return (
70 + <View styles={styles.containerStyle}>
71 + <TextInput
72 + style={styles.input}
73 + placeholder="Type here to Email!"
74 + onChangeText={onChangeEmail}
75 + />
76 + <TextInput
77 + style={styles.input}
78 + placeholder="Type here to nickname!"
79 + onChangeText={onChangeNickName}
80 + />
81 + <TextInput
82 + style={styles.input}
83 + placeholder="Type here to password!"
84 + type="password"
85 + onChangeText={onChangePassword}
86 + />
87 + <SignUpButton
88 + title={'signUp'}
89 + onPress={onSubmit}>
90 + <Text style={{color: '#696969'}}>signUp</Text>
91 + </SignUpButton>
92 + <GoLoginButton
93 + title={'signUp'}
94 + onPress={onSubmit}>
95 + <Text style={{color: '#696969'}}>Login</Text>
96 + </GoLoginButton>
97 + </View>
98 + )
99 +};
100 +
101 +export default SignUpComponent;
102 +
103 +const styles = StyleSheet.create({
104 + containerStyle: {
105 + // flex: 1,
106 + alignItems: 'center',
107 + // justifyContent: 'center',
108 + // backgroundColor: '#ecf0f1',
109 + // marginTop: 100,
110 + },
111 + input: {
112 + width: 200,
113 + height: 44,
114 + padding: 10,
115 + borderWidth: 1,
116 + borderColor: '#778899',
117 + marginBottom: 10,
118 + }
119 +});
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useEffect} from 'react';
2 +import MapView, {Marker} from 'react-native-maps';
3 +import {StyleSheet, Text, TextInput, View, TouchableOpacity, Alert} from 'react-native';
4 +import screen from '../constants/layout';
5 +import {useSelector, useDispatch} from "react-redux";
6 +import * as Location from 'expo-location';
7 +import {set} from "react-native-reanimated";
8 +import {MaterialCommunityIcons} from "@expo/vector-icons";
9 +import {SET_ELOC_REQUEST, SET_LOC_REQUEST, SET_SLOC_REQUEST, SET_USER_LOC} from "../reducers/location";
10 +import axios from 'axios';
11 +
12 +const StartAndFinishLocationComponent = () => {
13 + const [hasPermission, setHasPermission] = useState(false);
14 + const [startTextLocation, setStartTextLocation] = useState('');
15 + const [endTextLocation, setEndTextLocation] = useState('');
16 + const [userLocation, setUserLocation] = useState(null);
17 + const [errorMsg, setErrorMsg] = useState(null);
18 +
19 + const onChangeStartLocation = (startTextLocation) => {
20 + setStartTextLocation(startTextLocation);
21 + };
22 +
23 + const onChangeFinishLocation = (endTextLocation) => {
24 + setEndTextLocation(endTextLocation);
25 + };
26 +
27 + const dispatch = useDispatch();
28 + const onSetUserLocation = async () => {
29 + const {status} = await Location.requestPermissionsAsync();
30 + if (status !== 'granted') {
31 + setErrorMsg('Permission to access location was denied')
32 + }
33 + const location = await Location.getCurrentPositionAsync({});
34 + setStartTextLocation('현위치');
35 + setUserLocation(location);
36 + console.log(location);
37 + await dispatch({
38 + type: SET_USER_LOC,
39 + data: {
40 + userLocation
41 + }
42 + });
43 + };
44 +
45 + const setLocation = async () => {
46 + if (startTextLocation && startTextLocation !== '현위치') {
47 + console.log(startTextLocation);
48 + await dispatch({
49 + type: SET_SLOC_REQUEST,
50 + data: {
51 + startTextLocation
52 + }
53 + })
54 + }
55 +
56 + if (endTextLocation) {
57 + console.log(endTextLocation);
58 + await dispatch({
59 + type: SET_ELOC_REQUEST,
60 + data: {
61 + endTextLocation
62 + }
63 + }
64 + )
65 + }
66 +
67 + Alert.alert(
68 + 'MAP ROUTE 설정',
69 + ` 출발지 ${startTextLocation}, 목적지 ${endTextLocation} 맞습니까? `,
70 + [
71 + {
72 + text: 'Cancel',
73 + onPress: () => console.log('Cancel Pressed'),
74 + style: 'cancel',
75 + },
76 + {text: 'OK', onPress: () => console.log('OK Pressed')},
77 + ],
78 + {cancelable: false}
79 + );
80 + };
81 +
82 +
83 + return (
84 + <View style={styles.container}>
85 + <View style={styles.input}>
86 + <MaterialCommunityIcons color={'red'} name={'map-marker'} size={26}/>
87 + <TextInput
88 + style={styles.inputText}
89 + onChangeText={onChangeStartLocation}
90 + value={startTextLocation}
91 + />
92 + <TouchableOpacity onPress={onSetUserLocation}>
93 + <MaterialCommunityIcons color={'grey'} name={'crosshairs-gps'} size={30}/>
94 + </TouchableOpacity>
95 +
96 + </View>
97 + <View style={styles.input}>
98 + <MaterialCommunityIcons color={'blue'} name={'map-marker'} size={26}/>
99 + <TextInput
100 + style={styles.inputText}
101 + onChangeText={onChangeFinishLocation}
102 + value={endTextLocation}
103 + />
104 + </View>
105 + <View style={{flexDirection: 'row', alignItems: 'center'}}>
106 + <TouchableOpacity style={styles.buttonStyle} onPress={setLocation}>
107 + <Text>Map설정</Text>
108 + </TouchableOpacity>
109 + </View>
110 + </View>
111 + )
112 +};
113 +
114 +export default StartAndFinishLocationComponent;
115 +
116 +const styles = StyleSheet.create({
117 + container: {
118 + alignItems: 'center',
119 + marginTop: 50,
120 + marginLeft: 20,
121 + marginRight: 20,
122 + opacity: 0.5,
123 + },
124 + input: {
125 + borderRadius: 10,
126 + backgroundColor: '#f0f8ff',
127 + paddingLeft: 10,
128 + paddingRight: 10,
129 + width: 300,
130 + height: 50,
131 + alignItems: 'center',
132 + flexDirection: 'row',
133 + justifyContent: 'space-between',
134 + borderBottomColor: '#f0f8ff',
135 + marginBottom: 10
136 + // borderBottomWidth: StyleSheet.hairlineWidth,
137 + },
138 + inputText: {
139 + flex: 1,
140 + },
141 + textStyle: {
142 + fontWeight: 'bold',
143 + fontSize: 17,
144 + marginRight: 15,
145 + },
146 + buttonStyle: {
147 + flex: 0.5,
148 + backgroundColor: '#f0f8ff',
149 + alignItems: 'center',
150 + justifyContent: 'center',
151 + width: 10,
152 + height: 30,
153 + borderWidth: 1,
154 + borderColor: 'grey',
155 + marginBottom: 20,
156 + borderRadius: 30
157 + }
158 +});
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {Text, View, StyleSheet, TouchableOpacity, ScrollView, TextInput} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {useNavigation} from '@react-navigation/native';
5 +import styled from "styled-components";
6 +import {MaterialCommunityIcons, AntDesign} from '@expo/vector-icons';
7 +
8 +
9 +const Banner = styled.View`
10 + flex: 1;
11 + margin-left: 15px;
12 + margin-bottom: 5px;
13 + width: 3px;
14 + height: 3px;
15 + border-radius: 20px;
16 + border: 3px solid grey;
17 +
18 +`;
19 +
20 +
21 +const WalkPathComponent = (props) => {
22 + const navigation = useNavigation();
23 + const [walkPath, setWalkPath] = useState(null);
24 + const {pathDetail} = props;
25 +
26 + useEffect(() => {
27 + console.log(props.pathDetail.distance);
28 + setWalkPath(props.pathDetail);
29 + }, []);
30 +
31 + return (
32 + <ScrollView>
33 + <View style={{flexDirection: 'row', flex: 5}}>
34 + <View style={styles.pathType}>
35 + <MaterialCommunityIcons style={{flex: 1}} color={'darkgrey'} name={'walk'} size={20}/>
36 + <Text style={{flex: 1, fontSize: 13}}>{pathDetail.time}</Text>
37 + </View>
38 + <View style={{flex: 1}}>
39 + <Banner/>
40 + <Banner/>
41 + <Banner/>
42 + <Banner/>
43 + <Banner/>
44 + <Banner/>
45 + <Banner/>
46 + </View>
47 + <View style={styles.inputTile}>
48 + <Text style={styles.inputText}> 도보 {pathDetail.distance}m 이동</Text>
49 + </View>
50 + </View>
51 + </ScrollView>
52 + );
53 +}
54 +export default WalkPathComponent;
55 +
56 +const styles = StyleSheet.create({
57 + inputTile: {
58 + flex: 4,
59 + justifyContent: 'center',
60 + color: 'grey',
61 + },
62 + inputText: {
63 + fontWeight: 'normal',
64 + fontSize: 15,
65 + },
66 + pathType: {
67 + flexDirection: 'column',
68 + flex: 0.4,
69 + alignItems: 'center',
70 + justifyContent: 'center',
71 + marginLeft: 5,
72 + marginTop: 10,
73 + }
74 +})
...\ No newline at end of file ...\ No newline at end of file
1 +import {Dimensions} from 'react-native';
2 +
3 +const {width, height} = Dimensions.get('screen');
4 +
5 +export default{
6 + width,
7 + height
8 +}
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {userLayoutEffect} from 'react';
2 +import {createStackNavigator} from "@react-navigation/stack";
3 +import SelectOrTakePhotoTabNavigation from "./SelectOrTakePhotoTabNavigation";
4 +import UploadPhoto from "../screens/UploadPhoto";
5 +
6 +const Stack = createStackNavigator();
7 +
8 +const SelectOrTakePhotoStackNavigation = () => {
9 + return (
10 + <Stack.Navigator
11 + mode='card'
12 + screenOptions={{
13 + headerShown: false
14 + }}
15 + >
16 + <Stack.Screen
17 + name='SelectOrTakePhotoTabNavigation'
18 + component={SelectOrTakePhotoTabNavigation}
19 + />
20 + <Stack.Screen
21 + name='UploadPhoto'
22 + component={UploadPhoto}
23 + />
24 + </Stack.Navigator>
25 + )
26 +};
27 +
28 +export default SelectOrTakePhotoStackNavigation;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useLayoutEffect} from 'react';
2 +import {Ionicons} from "@expo/vector-icons";
3 +import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
4 +import TakePhoto from "../screens/TakePhoto";
5 +import SelectPhoto from "../screens/SelectPhoto";
6 +
7 +const Tab = createBottomTabNavigator();
8 +
9 +const SelectOrTakePhotoTabNavigation = (props) => {
10 + const {navigation, route} = props;
11 + // useLayoutEffect(() => {}, [route]);
12 +
13 + return (
14 + <Tab.Navigator
15 + tabBarOptions = {{}}
16 + >
17 + <Tab.Screen
18 + name='SelectPhoto'
19 + component={SelectPhoto}
20 + />
21 +
22 + <Tab.Screen
23 + name='TakePhoto'
24 + component={TakePhoto}
25 + />
26 +
27 + </Tab.Navigator>
28 + )
29 +};
30 +
31 +export default SelectOrTakePhotoTabNavigation;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {userLayoutEffect} from 'react';
2 +import {createStackNavigator} from "@react-navigation/stack";
3 +import SetLocationTabNavigation from "./SetLocationTabNavigation";
4 +import GoPathDetail from "../screens/GoPathDetail";
5 +import OptRoutePath from "../screens/OptRoutePath";
6 +
7 +const Stack = createStackNavigator();
8 +
9 +const SetLocationStackNavigation = () => {
10 + return (
11 + <Stack.Navigator
12 + mode='card'
13 + screenOptions={{
14 + headerShown: false
15 + }}
16 + >
17 + <Stack.Screen
18 + name='SetLocationTabNavigation'
19 + component={SetLocationTabNavigation}
20 + />
21 +
22 + <Stack.Screen
23 + name='GoPathDetail'
24 + component={GoPathDetail}
25 + />
26 +
27 + </Stack.Navigator>
28 +
29 + )
30 +};
31 +
32 +export default SetLocationStackNavigation;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useLayoutEffect} from 'react';
2 +import {Ionicons} from "@expo/vector-icons";
3 +import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
4 +import Maps from "../screens/Maps";
5 +import OptRoutePath from "../screens/OptRoutePath";
6 +
7 +const Tab = createBottomTabNavigator();
8 +
9 +const SetLocationTabNavigation = (props) => {
10 + const {navigation, route} = props;
11 + // useLayoutEffect(() => {}, [route]);
12 +
13 + return (
14 + <Tab.Navigator
15 + tabBarOptions={{}}
16 + >
17 + <Tab.Screen
18 + name='Maps'
19 + component={Maps}
20 + />
21 +
22 + <Tab.Screen
23 + name='OptRoutePath'
24 + component={OptRoutePath}
25 + />
26 +
27 + </Tab.Navigator>
28 + )
29 +};
30 +
31 +export default SetLocationTabNavigation;
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import {createStackNavigator} from "@react-navigation/stack";
3 +import Gallery from "../screens/Gallery";
4 +import Maps from "../screens/Maps";
5 +import Main from "../screens/Main";
6 +import TabNavigation from "./TabNavigation";
7 +import {TouchableOpacity} from "react-native";
8 +import {MaterialCommunityIcons} from "@expo/vector-icons";
9 +import SelectOrTakePhotoStackNavigation from "./SelectOrTakePhotoStackNavigation";
10 +import SetLocationStackNavigation from "./SetLocationStackNavigation";
11 +import Profile from "../screens/Profile";
12 +import Login from "../screens/Login";
13 +import SignUp from "../screens/SignUp";
14 +
15 +const Stack = createStackNavigator();
16 +//
17 +// const openBrowser = (url) => async () => {
18 +// await WebBrowser.openBrowserAsync(url);
19 +// };
20 +
21 +const StackNavigation = () => {
22 + return (
23 + <Stack.Navigator
24 + mode='card'
25 + screenOptions={{
26 + headerTitle: 'SGGO',
27 + headerRight: () => {
28 + return (
29 + <TouchableOpacity style={{marginRight: 5}}>
30 + <MaterialCommunityIcons color={'grey'} name={'send'} size={24}/>
31 + </TouchableOpacity>
32 + )
33 + }
34 + }}
35 + >
36 + <Stack.Screen
37 + name='TabNavigation'
38 + component={TabNavigation}
39 + />
40 + <Stack.Screen
41 + name='SelectOrTakePhotoStackNavigation'
42 + component={SelectOrTakePhotoStackNavigation}
43 + />
44 + <Stack.Screen
45 + name='SetLocationStackNavigation'
46 + component={SetLocationStackNavigation}
47 + />
48 + <Stack.Screen
49 + name='Maps'
50 + component={Maps}
51 + />
52 + <Stack.Screen
53 + name='Gallery'
54 + component={Gallery}
55 + />
56 +
57 + <Stack.Screen
58 + name='Login'
59 + component={Login}
60 + />
61 +
62 + <Stack.Screen
63 + name='SignUp'
64 + component={SignUp}
65 + />
66 + </Stack.Navigator>
67 + )
68 +};
69 +
70 +export default StackNavigation;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useLayoutEffect} from 'react';
2 +import {Ionicons} from "@expo/vector-icons";
3 +import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
4 +import Main from "../screens/Main";
5 +import Login from "../screens/Login";
6 +import Profile from "../screens/Profile";
7 +import LocationTimeSet from "../screens/LocationTimeSet";
8 +import Maps from "../screens/Maps";
9 +
10 +const Tab = createBottomTabNavigator();
11 +
12 +const TabNavigation = (props) => {
13 + const {navigation, route} = props;
14 + // useLayoutEffect(() => {}, [route]);
15 +
16 + return (
17 + <Tab.Navigator
18 + // screenOptions = {({route})=>{}}
19 + tabBarOptions={{}}
20 + >
21 +
22 + <Tab.Screen
23 + name='login'
24 + component={Login}
25 + />
26 +
27 + <Tab.Screen
28 + name='LocationTimeSet'
29 + component={LocationTimeSet}
30 + />
31 +
32 + <Tab.Screen
33 + name='Profile'
34 + component={Profile}
35 + />
36 +
37 + </Tab.Navigator>
38 + )
39 +};
40 +
41 +export default TabNavigation;
...\ No newline at end of file ...\ No newline at end of file
This diff could not be displayed because it is too large.
1 +{
2 + "main": "node_modules/expo/AppEntry.js",
3 + "scripts": {
4 + "start": "expo start",
5 + "android": "expo start --android",
6 + "ios": "expo start --ios",
7 + "web": "expo start --web",
8 + "eject": "expo eject"
9 + },
10 + "dependencies": {
11 + "@react-native-community/datetimepicker": "2.2.2",
12 + "@react-native-community/masked-view": "0.1.6",
13 + "@react-navigation/bottom-tabs": "^5.4.1",
14 + "@react-navigation/native": "^5.3.0",
15 + "@react-navigation/stack": "^5.2.11",
16 + "axios": "^0.19.2",
17 + "expo": "~37.0.3",
18 + "expo-asset": "^8.1.4",
19 + "expo-camera": "~8.2.0",
20 + "expo-file-system": "~8.1.0",
21 + "expo-font": "^8.1.1",
22 + "expo-location": "~8.1.0",
23 + "expo-media-library": "~8.1.0",
24 + "expo-permissions": "~8.1.0",
25 + "expo-web-browser": "^8.2.1",
26 + "moment": "^2.26.0",
27 + "native-base": "^2.13.12",
28 + "node-nikerunclub": "^1.0.0",
29 + "papaparse": "^5.2.0",
30 + "react": "~16.9.0",
31 + "react-dom": "~16.9.0",
32 + "react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
33 + "react-native-bottom-action-sheet": "^2.0.1",
34 + "react-native-fast-image": "^8.1.5",
35 + "react-native-gesture-handler": "~1.6.0",
36 + "react-native-maps": "0.26.1",
37 + "react-native-reanimated": "~1.7.0",
38 + "react-native-safe-area-context": "0.7.3",
39 + "react-native-screens": "~2.2.0",
40 + "react-native-web": "~0.11.7",
41 + "react-redux": "^7.2.0",
42 + "redux": "^4.0.5",
43 + "redux-saga": "^1.1.3",
44 + "styled-components": "^5.1.0"
45 + },
46 + "devDependencies": {
47 + "@babel/core": "^7.8.6",
48 + "@expo/vector-icons": "^10.0.6",
49 + "babel-preset-expo": "~8.1.0"
50 + },
51 + "private": true
52 +}
1 +import {combineReducers} from "redux";
2 +import user from './user';
3 +import location from './location';
4 +
5 +const rootReducer = combineReducers({
6 + user,
7 + location
8 +});
9 +
10 +export default rootReducer;
...\ No newline at end of file ...\ No newline at end of file
1 +export const initialState = {
2 + startLocation: null,
3 + endLocation: null,
4 + endTime: '',
5 +
6 + optRoute: null,
7 +
8 + settingLocation: false,
9 + settingTime: false,
10 + settingOptRoute: false,
11 + settingVelocity: false,
12 +
13 +
14 + personalVelocity: 60,
15 + info: '',
16 +};
17 +
18 +export const SET_SLOC_REQUEST = 'SET_SLOC_REQUEST';
19 +export const SET_SLOC_SUCCESS = 'SET_SLOC_SUCCESS';
20 +export const SET_SLOC_FAILURE = 'SET_SLOC_FAILURE';
21 +export const SET_ELOC_REQUEST = 'SET_ELOC_REQUEST';
22 +export const SET_ELOC_SUCCESS = 'SET_ELOC_SUCCESS';
23 +export const SET_ELOC_FAILURE = 'SET_ELOC_FAILURE';
24 +export const SET_USER_LOC = 'SET_USER_LOC';
25 +
26 +export const SET_TIME_REQUEST = 'SET_TIME_REQUEST';
27 +export const SET_TIME_SUCCESS = 'SET_TIME_SUCCESS';
28 +export const SET_TIME_FAILURE = 'SET_TIME_FAILURE';
29 +
30 +export const SET_OPTROUTE_REQUEST = 'SET_OPTROUTE_REQUEST';
31 +export const SET_OPTROUTE_SUCCESS = 'SET_OPTROUTE_SUCCESS';
32 +export const SET_OPTROUTE_FAILURE = 'SET_OPTROUTE_FAILURE';
33 +
34 +export const SET_PERVELOCITY_REQUEST = 'SET_PERVELOCITY_REQUEST';
35 +export const SET_PERVELOCITY_SUCCESS = 'SET_PERVELOCITY_SUCCESS';
36 +export const SET_PERVELOCITY_FAILURE = 'SET_PERVELOCITY_FAILURE';
37 +
38 +
39 +export default (state = initialState, action) => {
40 + switch (action.type) {
41 +
42 + case SET_SLOC_REQUEST: {
43 + return {
44 + ...state,
45 + settingLocation: true,
46 + }
47 + }
48 +
49 + case SET_SLOC_SUCCESS: {
50 + const {startLocation} = action.data;
51 + return {
52 + ...state,
53 + startLocation,
54 + isLoggingIn: false,
55 + };
56 + }
57 +
58 + case SET_SLOC_FAILURE: {
59 + const {info} = action.data;
60 + return {
61 + ...state,
62 + settingLocation: false,
63 + info,
64 + }
65 + }
66 +
67 +
68 + case SET_ELOC_REQUEST: {
69 + return {
70 + ...state,
71 + settingLocation: true,
72 + }
73 + }
74 +
75 + case SET_ELOC_SUCCESS: {
76 + const {endLocation} = action.data;
77 + return {
78 + ...state,
79 + endLocation,
80 + isLoggingIn: false,
81 + };
82 + }
83 +
84 + case SET_ELOC_FAILURE: {
85 + const {info} = action.data;
86 + return {
87 + ...state,
88 + settingLocation: false,
89 + info,
90 + }
91 + }
92 +
93 + case SET_USER_LOC: {
94 + var {userLocation} = action.data;
95 + userLocation = {
96 + title: '현위치',
97 + latitude: userLocation.coords.latitude,
98 + longitude: userLocation.coords.longitude,
99 + latitudeDelta: 0.0039,
100 + longitudeDelta: 0.0039,
101 + description: 'start point',
102 +
103 + };
104 + console.log(userLocation.coords);
105 + return {
106 + ...state,
107 + startLocation: userLocation,
108 + settingLocation: false
109 + }
110 + }
111 +
112 + case SET_TIME_REQUEST: {
113 + return {
114 + ...state,
115 + settingTime: true,
116 + }
117 + }
118 + case SET_TIME_SUCCESS: {
119 + const {date} = action.data;
120 + console.log('reducer SET_TIME_SUCCESS', date);
121 + return {
122 + ...state,
123 + endTime: date,
124 + settingTime: false,
125 + }
126 + }
127 + case SET_TIME_FAILURE: {
128 + const {info} = action.data;
129 + return {
130 + ...state,
131 + settingTime: false,
132 + }
133 + }
134 +
135 + case SET_OPTROUTE_REQUEST: {
136 + return {
137 + ...state,
138 + settingOptRoute: true,
139 + }
140 + }
141 +
142 + case SET_OPTROUTE_SUCCESS: {
143 + var {optRoute} = action.data;
144 + console.log('SET_OPTROUTE_SUCCESST', optRoute);
145 + return {
146 + ...state,
147 + optRoute: optRoute,
148 + settingOptRoute: false,
149 + }
150 + }
151 +
152 + case SET_OPTROUTE_FAILURE: {
153 + const {info} = action.data;
154 + return {
155 + ...state,
156 + settingOptRoute: false,
157 + }
158 + }
159 +
160 +
161 + case SET_PERVELOCITY_REQUEST: {
162 + return {
163 + ...state,
164 + settingVelocity: true,
165 + }
166 + }
167 +
168 + case SET_PERVELOCITY_SUCCESS: {
169 + var {personalVelocity} = action.data;
170 + console.log('SET_PERVELOCITY_SUCCESS', personalVelocity);
171 + return {
172 + ...state,
173 + personalVelocity,
174 + settingVelocity: true,
175 + }
176 + }
177 +
178 + case SET_PERVELOCITY_FAILURE: {
179 + const {info} = action.data;
180 + return {
181 + ...state,
182 + settingVelocity: false,
183 + }
184 + }
185 +
186 + default: {
187 + return {
188 + ...state,
189 + };
190 + }
191 + }
192 +};
...\ No newline at end of file ...\ No newline at end of file
1 +export const initialState = {
2 + me: null,
3 + nikeRecord: null,
4 +
5 + isLoggingIn: false,
6 + isSigningUp: false,
7 + isLoadingMe: false,
8 + isLoggingOut: false,
9 +
10 + info: '',
11 +};
12 +
13 +export const LOG_IN_REQUEST = 'LOG_IN_REQUEST';
14 +export const LOG_IN_SUCCESS = 'LOG_IN_SUCCESS';
15 +export const LOG_IN_FAILURE = 'LOG_IN_FAILURE';
16 +
17 +export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST';
18 +export const SIGN_UP_SUCCESS = 'SIGN_UP_SUCCESS';
19 +export const SIGN_UP_FAILURE = 'SIGN_UP_FAILURE';
20 +
21 +export const LOAD_ME_REQUEST = 'LOAD_USER_REQUEST';
22 +export const LOAD_ME_SUCCESS = 'LOAD_USER_SUCCESS';
23 +export const LOAD_ME_FAILURE = 'LOAD_USER_FAILURE';
24 +
25 +export const LOG_OUT_REQUEST = 'LOG_OUT_REQUEST';
26 +export const LOG_OUT_SUCCESS = 'LOG_OUT_SUCCESS';
27 +export const LOG_OUT_FAILURE = 'LOG_OUT_FAILURE';
28 +
29 +export default (state = initialState, action) => {
30 + switch (action.type) {
31 +
32 + case LOG_IN_REQUEST: {
33 + return {
34 + ...state,
35 + isLoggingIn: true,
36 + }
37 + }
38 +
39 + case LOG_IN_SUCCESS: {
40 + const {me} = action.data;
41 + return {
42 + ...state,
43 + me,
44 + isLoggingIn: false,
45 + };
46 + }
47 +
48 + case LOG_IN_FAILURE: {
49 + const {info} = action.data;
50 + return {
51 + ...state,
52 + isLoggingIn: false,
53 + info,
54 + }
55 + }
56 +
57 + case SIGN_UP_REQUEST: {
58 + return {
59 + ...state,
60 + isSigningUp: true
61 + }
62 + }
63 + case SIGN_UP_SUCCESS: {
64 + const {me} = action.data;
65 + return {
66 + ...state,
67 + me,
68 + isSigningUp: false,
69 + };
70 + }
71 + case SIGN_UP_FAILURE: {
72 + const {info} = action.data;
73 + return {
74 + ...state,
75 + isSigningUp: false,
76 + info
77 + };
78 + }
79 +
80 + case LOAD_ME_REQUEST: {
81 + return {
82 + ...state,
83 + isLoadingMe: true
84 + }
85 + }
86 + case LOAD_ME_SUCCESS: {
87 + const {user} = action.data;
88 + console.log(user);
89 + return {
90 + ...state,
91 + me: user,
92 + isLoadingMe: false
93 + }
94 + }
95 + case LOAD_ME_FAILURE: {
96 + const {info} = action.data;
97 + return {
98 + ...state,
99 + isLoadingMe: false,
100 + info
101 + }
102 + }
103 +
104 +
105 + case LOG_OUT_REQUEST: {
106 + return {
107 + ...state,
108 + isLoggingOut: true
109 + }
110 + }
111 +
112 + case LOG_OUT_SUCCESS: {
113 + console.log('LOG_OUT_SUCCESS 완료');
114 + return {
115 + ...state,
116 + me: null,
117 + isLoggingOut: false
118 + }
119 + }
120 +
121 + case LOG_OUT_FAILURE: {
122 + const {info} = action.data;
123 + return {
124 + ...state,
125 + isLoggingOut: false,
126 + info
127 + }
128 + }
129 +
130 + default: {
131 + return {
132 + ...state,
133 + };
134 + }
135 + }
136 +};
...\ No newline at end of file ...\ No newline at end of file
1 +import {all, fork} from 'redux-saga/effects';
2 +
3 +import user from './user';
4 +import location from './location';
5 +
6 +export default function* rootSaga() {
7 + yield all([
8 + fork(user),
9 + fork(location),
10 + ])
11 +}
...\ No newline at end of file ...\ No newline at end of file
1 +import {all, call, fork, delay, put, takeEvery, takeLatest} from 'redux-saga/effects';
2 +import axios from 'axios';
3 +import {coordAPIKEY, host} from '../env';
4 +
5 +
6 +import {
7 + SET_ELOC_REQUEST,
8 + SET_SLOC_REQUEST,
9 + SET_SLOC_SUCCESS,
10 + SET_ELOC_SUCCESS,
11 + SET_SLOC_FAILURE,
12 + SET_ELOC_FAILURE,
13 + SET_OPTROUTE_REQUEST,
14 + SET_OPTROUTE_SUCCESS,
15 + SET_OPTROUTE_FAILURE,
16 +} from "../reducers/location";
17 +
18 +function setStartLocationAPI(data) {
19 + const {startTextLocation} = data;
20 + console.log(startTextLocation);
21 + return axios.get(`http://api.vworld.kr/req/address?service=address&request=getcoord&version=1.0&crs=epsg:4326&address=${startTextLocation}&refine=true&simple=false&format=json&type=road&key=${coordAPIKEY}`);
22 +}
23 +
24 +function setEndLocationAPI(data) {
25 + const {endTextLocation} = data;
26 + console.log(endTextLocation);
27 + return axios.get(`http://api.vworld.kr/req/address?service=address&request=getcoord&version=1.0&crs=epsg:4326&address=${endTextLocation}&refine=true&simple=false&format=json&type=road&key=${coordAPIKEY}`);
28 +}
29 +
30 +function setOptRouteAPI(data) {
31 + const {startLocation, endLocation, endTime, personalVelocity} = data;
32 + console.log('제발 좀 되라', startLocation, endLocation, endTime, personalVelocity);
33 + return axios.post(`http://${host}:4001/api/setOptRoute`, {
34 + startLocation,
35 + endLocation,
36 + endTime,
37 + personalVelocity
38 + }, {withCredentials: true});
39 +}
40 +
41 +function* setStartLocation(action) {
42 + try {
43 + console.log('saga의 setLocation', action.data);
44 + let res = yield call(setStartLocationAPI, action.data);
45 + let longitude, latitude = null;
46 +
47 + if (res.data.response.status === "OK") {
48 + longitude = parseFloat(res.data.response.result.point.x);
49 + latitude = parseFloat(res.data.response.result.point.y);
50 + }
51 + //
52 + // if (res.data.status === "OK") {
53 + // latitude = res.data.results[0].geometry.location.lat;
54 + // longitude = res.data.results[0].geometry.location.lng;
55 + // console.log(latitude, longitude)
56 + // }
57 +
58 + console.log('startRes: ', longitude, latitude);
59 +
60 + yield put({
61 + type: SET_SLOC_SUCCESS,
62 + data: {
63 + startLocation: {
64 + title: action.data.startTextLocation,
65 + description: 'start point',
66 + longitude: longitude,
67 + latitude: latitude,
68 + latitudeDelta: 1.2,
69 + longitudeDelta: 1.2
70 +
71 + }
72 + }
73 + })
74 + } catch (e) {
75 + console.error(e);
76 + yield put({
77 + type: SET_SLOC_FAILURE,
78 + data: {
79 + info: e.response.data.info
80 + }
81 + });
82 + }
83 +}
84 +
85 +function* setEndLocation(action) {
86 + try {
87 + let res = yield call(setEndLocationAPI, action.data);
88 + let longitude, latitude = null;
89 +
90 + //
91 + // if (res.data.status === "OK") {
92 + // latitude = res.data.results[0].geometry.location.lat;
93 + // longitude = res.data.results[0].geometry.location.lng;
94 + // console.log(latitude, longitude)
95 + // }
96 +
97 + if (res.data.response.status === "OK") {
98 + longitude = parseFloat(res.data.response.result.point.x);
99 + latitude = parseFloat(res.data.response.result.point.y);
100 + }
101 +
102 + console.log('finishRes: ', longitude, latitude);
103 +
104 + yield put({
105 + type: SET_ELOC_SUCCESS,
106 + data: {
107 + endLocation: {
108 + title: action.data.endTextLocation,
109 + description: 'end point',
110 + longitude: longitude,
111 + latitude: latitude,
112 + latitudeDelta: 1.2,
113 + longitudeDelta: 1.2
114 + }
115 + }
116 + });
117 + } catch (e) {
118 + console.error(e);
119 + yield put({
120 + type: SET_ELOC_FAILURE,
121 + data: {
122 + info: e.response.data.info
123 + }
124 + })
125 +
126 + }
127 +}
128 +
129 +function* setOptRoute(action) {
130 + try {
131 + let res = yield call(setOptRouteAPI, action.data);
132 + const {optRoute} = res.data;
133 + yield put({
134 + type: SET_OPTROUTE_SUCCESS,
135 + data: {
136 + optRoute: optRoute
137 + }
138 + });
139 +
140 + } catch (e) {
141 + console.error(e);
142 + yield put({
143 + type: SET_OPTROUTE_FAILURE,
144 + data: {
145 + info: e.response.data.info
146 + }
147 + })
148 + }
149 +}
150 +
151 +
152 +function* watchSetStartLocation() {
153 + console.log('watchSetStartLocation');
154 + yield takeLatest(SET_SLOC_REQUEST, setStartLocation);
155 +}
156 +
157 +function* watchSetEndLocation() {
158 + console.log('watchSetEndLocation');
159 + yield takeLatest(SET_ELOC_REQUEST, setEndLocation)
160 +}
161 +
162 +function* watchSetOptRoute() {
163 + console.log('watchSetOptimalRoute');
164 + yield takeLatest(SET_OPTROUTE_REQUEST, setOptRoute)
165 +}
166 +
167 +export default function* locationSaga() {
168 + yield all([
169 + fork(watchSetStartLocation),
170 + fork(watchSetEndLocation),
171 + fork(watchSetOptRoute),
172 + ]);
173 +};
...\ No newline at end of file ...\ No newline at end of file
1 +import {all, call, fork, delay, put, takeEvery, takeLatest} from 'redux-saga/effects';
2 +import axios from 'axios';
3 +import {host} from '../env';
4 +import {
5 + LOG_IN_FAILURE,
6 + LOG_IN_REQUEST,
7 + LOG_IN_SUCCESS,
8 +
9 + SIGN_UP_FAILURE,
10 + SIGN_UP_REQUEST,
11 + SIGN_UP_SUCCESS,
12 +
13 + LOAD_ME_REQUEST,
14 + LOAD_ME_SUCCESS,
15 + LOAD_ME_FAILURE,
16 +
17 + LOG_OUT_REQUEST,
18 + LOG_OUT_SUCCESS,
19 + LOG_OUT_FAILURE,
20 +} from '../reducers/user';
21 +import {AsyncStorage} from 'react-native';
22 +
23 +const parseCookies = (cookies = '') =>
24 + cookies
25 + .split(';')
26 + .map(v =>
27 + v.split('=')
28 + )
29 + .reduce((acc, [key, value]) => {
30 + acc[key.trim()] = decodeURIComponent(value);
31 + console.log(acc);
32 + return acc;
33 + }, {});
34 +
35 +//로그인
36 +function loginAPI(data) {
37 + const {email, password} = data;
38 + console.log(email, password);
39 + console.log(`http://${host}:4001/user/login`);
40 +
41 + return axios.post(`http://${host}:4001/user/login`, {
42 + email, password
43 + }, {
44 + withCredentials: true
45 + });
46 +}
47 +
48 +// # 함수의 동기적인 호출을 할 때 사용
49 +// 응답이 다 받아진 후에 실행할 때 사용
50 +function* login(action) {
51 + try {
52 + console.log('login하러 왔어요');
53 + const res = yield call(loginAPI, action.data);
54 + console.log('서버 login에서 온 응답', res);
55 + const {user} = res.data;
56 + const cookieArray = res.headers['set-cookie'];
57 + console.log(cookieArray);
58 + yield call(AsyncStorage.setItem, 'cookie', `userChecker=s%3A${cookieArray.map(cookie => parseCookies(cookie)['userChecker'].substring(2))}`);
59 + yield put({
60 + type: LOG_IN_SUCCESS,
61 + data: {
62 + me: user
63 + }
64 + })
65 + } catch (e) {
66 + console.error(e);
67 + yield put({
68 + type: LOG_IN_FAILURE,
69 + data: {
70 + info: e.response.data.info
71 + }
72 + })
73 + }
74 +};
75 +
76 +function* watchLogin() {
77 + yield takeLatest(LOG_IN_REQUEST, login);
78 +}
79 +
80 +// 회원가입
81 +function signUpAPI(data) {
82 + const {email, nickName, password} = data;
83 + return axios.post(`http://${host}:4001/user/signUp`, {
84 + email, nickName, password
85 + }, {
86 + withCredentials: true
87 + });
88 +}
89 +
90 +function* signUp(action) {
91 + try {
92 + console.log('signUp 실행원할');
93 + const res = yield call(signUpAPI, action.data);
94 + const {me} = res.data;
95 + yield put({
96 + type: SIGN_UP_SUCCESS,
97 + data: {
98 + me
99 + }
100 + });
101 + } catch (e) {
102 + console.error(e);
103 + yield put({
104 + type: SIGN_UP_FAILURE,
105 + data: {
106 + info: e.response.data.info
107 + }
108 + });
109 + }
110 +}
111 +
112 +// # generator 함수에서 마지막 액션 하나만 유효하다고 인정
113 +// 실수로 회원가입 버튼을 연달아 누를 경우 서버의 요청이 2번 가지 않게함
114 +function* watchSignUp() {
115 + yield takeLatest(SIGN_UP_REQUEST, signUp);
116 +}
117 +
118 +
119 +function loadMeAPI() {
120 + return axios.get(`http://${host}:4001/user/loadMe`, {withCredentials: true})
121 +};
122 +
123 +function* loadMe(action) {
124 + try {
125 + console.log('loadMe 실행원할');
126 + const res = yield call(loadMeAPI, action.data);
127 + const {user} = res.data;
128 + yield put({
129 + type: LOAD_ME_SUCCESS,
130 + data: {
131 + user
132 + }
133 + })
134 + } catch (e) {
135 + console.error(e);
136 + yield put({
137 + type: LOAD_ME_FAILURE,
138 + data: {
139 + info: e.response.data.info
140 + }
141 + })
142 + }
143 +};
144 +
145 +function* watchLoadMe() {
146 + yield takeLatest(LOAD_ME_REQUEST, loadMe);
147 +}
148 +
149 +function logoutAPI() {
150 + return axios.get(`http://${host}:4001/user/logout`, {withCredentials: true});
151 +}
152 +
153 +function* logout() {
154 + try {
155 + const res = yield call(logoutAPI);
156 + console.log('logout 완료');
157 + yield call(AsyncStorage.removeItem, 'cookie');
158 + yield put({
159 + type: LOG_OUT_SUCCESS
160 + });
161 + } catch (e) {
162 + console.error(e);
163 + yield put({
164 + type: LOG_OUT_FAILURE,
165 + data: {
166 + info: e.response.data.info
167 + }
168 + })
169 + }
170 +}
171 +
172 +function* watchLogoutMe() {
173 + yield takeLatest(LOG_OUT_REQUEST, logout);
174 +}
175 +
176 +// # 모든 액션을 유효하게 인정한다.
177 +// while(true)로 감싸는 효과
178 +// takeEvery
179 +
180 +// # 함수의 비동기적인 호출을 사용할 때
181 +// call과 다르게 fork는 순서 상관없이 실행할 때 사용
182 +export default function* userSaga() {
183 + yield all([
184 + fork(watchLogin),
185 + fork(watchSignUp),
186 + fork(watchLoadMe),
187 + fork(watchLogoutMe),
188 + ]);
189 +}
190 +
1 +import React from 'react';
2 +import {View, Text, Button} from 'react-native';
3 +import {useNavigation} from "@react-navigation/native";
4 +
5 +const Gallery = () => {
6 + const navigation = useNavigation();
7 +
8 + return (
9 + <View>
10 + <Text>
11 + 하이하이
12 + </Text>
13 + </View>
14 + )
15 +};
16 +
17 +export default Gallery;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {Text, View, StyleSheet, TouchableOpacity, ScrollView, TextInput} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {useNavigation} from '@react-navigation/native';
5 +import WalkPathComponent from "../components/WalkPathComponent";
6 +import BusPathComponent from "../components/BusPathComponent";
7 +import LanePathComponent from "../components/LanePathComponent";
8 +import {MaterialCommunityIcons} from "@expo/vector-icons";
9 +
10 +const GoPathDetail = (props) => {
11 + const navigation = useNavigation();
12 + const {route} = props;
13 + const {detail} = route.params;
14 + const [pathDetails, setPathDetails] = useState(null);
15 + const {startLocation, endLocation, optRoute} = useSelector(state => state.location);
16 +
17 +
18 + useEffect(() => {
19 + setPathDetails(detail);
20 + console.log(detail)
21 + }, []);
22 +
23 +
24 + return (
25 + <ScrollView>
26 + <View style={styles.input}>
27 + <MaterialCommunityIcons color={'red'} name={'map-marker'} size={26}/>
28 + <TextInput
29 + style={styles.inputText}
30 + value={startLocation.title}
31 + />
32 + </View>
33 + {pathDetails ?
34 + pathDetails.map((detail, index) => {
35 + if (detail.trafficType === '도보') {
36 + return (
37 + <WalkPathComponent pathDetail={detail}/>
38 + )
39 + } else if (detail.trafficType === '버스') {
40 + return (
41 + <BusPathComponent pathDetail={detail}/>
42 + )
43 + } else (detail.trafficType === '지하철')
44 + {
45 + return (
46 + <LanePathComponent pathDetail={detail}/>
47 + )
48 + }
49 + })
50 + :
51 + null
52 + }
53 + <View style={styles.input}>
54 + <MaterialCommunityIcons color={'blue'} name={'map-marker'} size={26}/>
55 + <TextInput
56 + style={styles.inputText}
57 + value={endLocation.title}
58 + />
59 + </View>
60 + </ScrollView>
61 + );
62 +}
63 +export default GoPathDetail;
64 +
65 +const styles = StyleSheet.create({
66 + input: {
67 + borderRadius: 20,
68 + paddingLeft: 10,
69 + paddingTop: 5,
70 + paddingRight: 10,
71 + width: 350,
72 + height: 30,
73 + alignItems: 'center',
74 + flexDirection: 'row',
75 + justifyContent: 'space-between',
76 + borderBottomColor: '#f0f8ff',
77 + marginBottom: 10,
78 + // borderBottomWidth: StyleSheet.hairlineWidth,
79 + },
80 + inputText: {
81 + flex: 1,
82 + fontWeight: 'bold',
83 + }
84 +})
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useEffect} from 'react';
2 +import {View, Text, Button, StyleSheet} from 'react-native';
3 +import StartAndFinishLocationComponent from "../components/StartAndFinishLocationComponent";
4 +import DateTimePickerComponent from "../components/DateTimePickerComponent";
5 +import styled from "styled-components";
6 +import {useNavigation} from "@react-navigation/native";
7 +import {useDispatch, useSelector} from "react-redux";
8 +import {SET_OPTROUTE_REQUEST} from "../reducers/location";
9 +
10 +const GoToMaps = styled.TouchableOpacity`
11 + flex: 0.5;
12 + backgroundColor: #f0f8ff;
13 + align-items: center;
14 + justify-content: center;
15 + width: 180px;
16 + height: 30px;
17 + border-radius: 30px;
18 + border-width: 1px;
19 + border-color: #a9a9a9;
20 + position: absolute;
21 + left: 55;
22 +`;
23 +
24 +const LocationTimeSet = () => {
25 + const navigation = useNavigation();
26 + const [goToMapsClick, setGoToMapsClick] = useState(false);
27 +
28 + const {startLocation} = useSelector(state => state.location);
29 + const {endLocation} = useSelector(state => state.location);
30 +
31 + const dispatch = useDispatch();
32 + const goToMaps = async () => {
33 + setGoToMapsClick(true);
34 + navigation.navigate('SetLocationStackNavigation');
35 + setTimeout(() => {
36 + setGoToMapsClick(false)
37 + }, 2000)
38 + };
39 +
40 + useEffect(() => {
41 + }, []);
42 +
43 + return (
44 + <View>
45 + <StartAndFinishLocationComponent/>
46 + <DateTimePickerComponent goToMapsClick={goToMapsClick}/>
47 +
48 + <View style={{flexDirection: 'row', marginLeft: 50}}>
49 + <GoToMaps onPress={goToMaps}>
50 + <Text>도착 시간 설정</Text>
51 + </GoToMaps>
52 + </View>
53 + </View>
54 + )
55 +};
56 +
57 +
58 +const styles = StyleSheet.create({
59 + containerStyle: {
60 + flex: 1,
61 + alignItems: 'center',
62 + justifyContent: 'center',
63 + backgroundColor: '#ecf0f1',
64 + marginTop: 100,
65 + },
66 + input: {
67 + width: 200,
68 + height: 44,
69 + padding: 10,
70 + borderWidth: 1,
71 + borderColor: '#778899',
72 + marginBottom: 10,
73 + }
74 +});
75 +
76 +export default LocationTimeSet;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {View, Text, Image, TextInput, TouchableOpacity, StyleSheet} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {useNavigation} from '@react-navigation/native';
5 +import LoginComponent from "../components/LoginComponent";
6 +import styled from "styled-components";
7 +
8 +
9 +const Login = (props) => {
10 + const navigation = useNavigation();
11 + const [loading, setLoading] = useState(true);
12 + const [isLogin, setIsLogin] = useState(true);
13 +
14 + const {me} = useSelector(state => state.user);
15 + const {isLoggingIn} = useSelector(state => state.user);
16 +
17 + const changeIsLogin = () => {
18 + return setIsLogin(!isLogin);
19 + }
20 +
21 + useEffect(() => {
22 + setLoading(false);
23 + }, [me]);
24 +
25 +
26 + return (
27 + <View style={styles.changeStyle}>
28 + {me ?
29 + <View style={{flex: 2}}>
30 + <Image
31 + style={{width: 500, height: 600, flex: 1}}
32 + source={require('../assets/nike.png')}
33 + />
34 + <TouchableOpacity
35 + title={'SGGO'}
36 + style={{flex: 1, fontSize: 100}}
37 + >
38 + </TouchableOpacity>
39 + </View>
40 + :
41 + <View style={styles.loginStyle}>
42 + <Text style={styles.inputText}>로그인</Text>
43 + <LoginComponent/>
44 + </View>
45 + }
46 + </View>
47 + )
48 +};
49 +
50 +export default Login;
51 +
52 +const styles = StyleSheet.create({
53 + changeStyle: {
54 + flex: 2,
55 + alignItems: 'center',
56 + justifyContent: 'center',
57 + borderColor: 'darkgrey',
58 + },
59 + loginStyle: {
60 + flex: 1,
61 + marginTop: 30,
62 + },
63 + inputText: {
64 + borderColor: 'darkgrey',
65 + fontWeight: 'bold',
66 + fontSize: 20,
67 + marginBottom: 10
68 + }
69 +
70 +});
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import {View, Text, TouchableOpacity} from 'react-native';
3 +import styled from "styled-components";
4 +import {useNavigation} from "@react-navigation/native";
5 +import {useSelector} from "react-redux";
6 +
7 +
8 +const GoToGalleryButton = styled.TouchableOpacity`
9 + width: 60px;
10 + border: 1px;
11 +
12 + align-items: center;
13 + justify-content: center;
14 +
15 + flex: 2
16 +`;
17 +
18 +const GoToSelectOrTakePhotoButton = styled.TouchableOpacity`
19 + position: absolute;
20 + right: 20px;
21 + bottom: 20px;
22 + width: 30px;
23 + height: 30px;
24 + border-radius: 50px;
25 + border: 15px solid green;
26 +`;
27 +
28 +const Main = () => {
29 + const navigation = useNavigation();
30 +
31 + const goToGallery = () => {
32 + navigation.navigate('Gallery');
33 + };
34 +
35 + const goToSelectOrTakePhoto = () => {
36 + navigation.navigate('SelectOrTakePhotoStackNavigation');
37 + };
38 +
39 +
40 + const {me} = useSelector(state => state.user);
41 +
42 +
43 + return (
44 + <>
45 + <View style={{
46 + flex: 1,
47 + alignItems: 'center',
48 + justifyContent: 'center'
49 + }}>
50 + <GoToGalleryButton title={'갤러리로 가보자'} onPress={goToGallery}>
51 + <Text>갤러리로 가보자</Text>
52 + </GoToGalleryButton>
53 + <View style={{
54 + flex: 8,
55 + flexDirection: 'row'
56 + }}>
57 + <Text style={{
58 + width: '100%',
59 + flex: 1,
60 + backgroundColor: 'red'
61 + }}>메인페이지</Text>
62 + <Text style={{
63 + width: '100%',
64 + flex: 1,
65 + backgroundColor: 'grey',
66 + }}>메인페이지2</Text>
67 + <GoToSelectOrTakePhotoButton onPress={goToSelectOrTakePhoto}/>
68 + </View>
69 + </View>
70 + </>
71 + )
72 +};
73 +
74 +export default Main;
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import {View, Text, TouchableOpacity, Image, StyleSheet} from 'react-native';
3 +import styled from "styled-components";
4 +import {useNavigation} from "@react-navigation/native";
5 +import {useSelector} from "react-redux";
6 +
7 +const MainImage = (props) => {
8 + const navigation = useNavigation();
9 +
10 + const {me} = useSelector(state => state.user);
11 +
12 +
13 + return (
14 + <>
15 + <View style={styles.containerStyle}>
16 + <Text>로그인에 성공하였습니다</Text>
17 + </View>
18 + </>
19 + )
20 +};
21 +export default MainImage;
22 +
23 +const styles = StyleSheet.create({
24 + containerStyle: {
25 + flex: 1,
26 + },
27 +});
1 +import React, {useState, useEffect} from 'react';
2 +import MapView, {Marker, Polygon, AnimatedRegion} from 'react-native-maps';
3 +import {StyleSheet, Text, TextInput, TouchableOpacity, View} from 'react-native';
4 +import screen from '../constants/layout';
5 +import {useDispatch, useSelector} from "react-redux";
6 +import {useNavigation} from "@react-navigation/native";
7 +import {AntDesign, MaterialCommunityIcons} from "@expo/vector-icons";
8 +import {SET_OPTROUTE_REQUEST} from "../reducers/location";
9 +import styled from "styled-components";
10 +import OptRoutePath from "./OptRoutePath";
11 +
12 +const GoToOptRoutePath = styled.TouchableOpacity`
13 + flex: 2;
14 + position: absolute;
15 + right: 8px;
16 + bottom: 20px;
17 + width: 30px;
18 + height: 30px;
19 + border-radius: 50px;
20 +`;
21 +
22 +const Maps = (props) => {
23 + const navigation = useNavigation();
24 + const [region, setRegion] = useState(null);
25 + const [markers, setMarkers] = useState([]);
26 + const [pathList, setPathList] = useState([]);
27 + const {startLocation, endLocation, optRoute, endTime, personalVelocity} = useSelector(state => state.location);
28 + const onRegionChange = (region) => {
29 + setRegion(region);
30 + };
31 +
32 + useEffect(() => {
33 + setRegion({
34 + latitude: 37.56647,
35 + longitude: 126.977963,
36 + latitudeDelta: 1.5,
37 + longitudeDelta: 1.5
38 + });
39 + if (startLocation || endLocation) {
40 + setMarkers([startLocation, endLocation]);
41 + }
42 +
43 + }, []);
44 +
45 + const dispatch = useDispatch();
46 + const goToOptRoutePath = async () => {
47 + try {
48 + console.log('set optroute request');
49 + await dispatch({
50 + type: SET_OPTROUTE_REQUEST,
51 + data: {
52 + startLocation,
53 + endLocation,
54 + endTime,
55 + personalVelocity
56 + }
57 + });
58 + setTimeout(() => {
59 + if (optRoute !== null) {
60 + navigation.navigate('OptRoutePath', {optRoute: optRoute})
61 + }
62 + }, 3000);
63 + } catch (e) {
64 + console.error(e);
65 + }
66 + };
67 +
68 + useEffect(() => {
69 + setMarkers([startLocation, endLocation]);
70 + }, [startLocation, endLocation]);
71 +
72 +
73 + return (
74 + <View style={styles.container}>
75 + <View style={styles.input}>
76 + <MaterialCommunityIcons color={'red'} name={'map-marker'} size={26}/>
77 + <TextInput
78 + style={styles.inputText}
79 + value={startLocation.title}
80 + />
81 + </View>
82 + <View style={styles.input}>
83 + <MaterialCommunityIcons color={'blue'} name={'map-marker'} size={26}/>
84 + <TextInput
85 + style={styles.inputText}
86 + value={endLocation.title}
87 + />
88 + </View>
89 + <MapView
90 + style={styles.mapStyle}
91 + initialRegion={region}
92 + onRegionChange={onRegionChange}
93 + textStyle={{color: '#bc8b00'}}
94 + showsUserLocation={true}
95 + >
96 + {markers ?
97 + markers.map((marker, index) => {
98 + return (
99 + <MapView.Marker draggable
100 + key={index}
101 + coordinate={marker}
102 + title={marker.title}
103 + />
104 + )
105 + })
106 + :
107 + null
108 + }
109 + </MapView>
110 + <GoToOptRoutePath onPress={goToOptRoutePath}>
111 + <AntDesign color={'darkgrey'} name={'caretright'} size={32}/>
112 + </GoToOptRoutePath>
113 + </View>
114 + )
115 +};
116 +
117 +const styles = StyleSheet.create({
118 + container: {
119 + flex: 1,
120 + backgroundColor: '#fff',
121 + alignItems: 'center',
122 + },
123 + mapStyle: {
124 + width: screen.width,
125 + height: screen.height,
126 + },
127 + textStyle: {
128 + flex: 1,
129 + fontWeight: 'bold',
130 + fontSize: 20,
131 + color: 'grey',
132 + marginBottom: 20,
133 + },
134 + input: {
135 + borderRadius: 10,
136 + backgroundColor: '#f0f8ff',
137 + paddingLeft: 10,
138 + paddingTop: 5,
139 + paddingRight: 10,
140 + width: 350,
141 + height: 30,
142 + alignItems: 'center',
143 + flexDirection: 'row',
144 + justifyContent: 'space-between',
145 + borderBottomColor: '#f0f8ff',
146 + marginBottom: 10
147 + // borderBottomWidth: StyleSheet.hairlineWidth,
148 + },
149 + inputText: {
150 + flex: 1,
151 + },
152 +});
153 +
154 +export default Maps;
155 +
1 +import React, {useState, useEffect} from 'react';
2 +import {View, Text, Button, ScrollView} from 'react-native';
3 +import {useNavigation} from '@react-navigation/native';
4 +import {useDispatch, useSelector} from "react-redux";
5 +import GoPathSummary from '../components/GoPathSummary';
6 +
7 +const OptRoutePath = (props) => {
8 + const navigation = useNavigation();
9 + const {route} = props;
10 + const {optRoute} = route.params;
11 +
12 + const [pathList, setPathList] = useState([]);
13 + const {startLocation} = useSelector(state => state.location);
14 + const {endLocation} = useSelector(state => state.location);
15 +
16 + const dispatch = useDispatch();
17 + const setOptRouteRequest = async () => {
18 + try {
19 + console.log('set optroute request');
20 + setTimeout(() => {
21 + if (optRoute.pathList) {
22 + for (var i = 0; i < optRoute.pathList.length; i++) {
23 + setPathList(oldPath => [...oldPath, optRoute.pathList[i]]);
24 + }
25 + }
26 + }, 3000);
27 +
28 + } catch (e) {
29 + console.error(e);
30 + }
31 + };
32 +
33 +
34 + useEffect(() => {
35 + setOptRouteRequest();
36 + }, []);
37 +
38 + return (
39 + <ScrollView>
40 + {pathList ?
41 + pathList.map((path, index) => {
42 + return (
43 + <>
44 + <GoPathSummary summary={path.info} detail={path.subPathList}/>
45 + </>
46 + )
47 + })
48 + :
49 + null
50 + }
51 + </ScrollView>
52 + )
53 +};
54 +
55 +export default OptRoutePath;
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import {View, Text, Button} from 'react-native';
3 +import MyProfileComponent from "../components/MyProfileComponent";
4 +
5 +const Profile = () => {
6 + const {me} = (state => state.user);
7 + return (
8 + <View>
9 + {!me ?
10 + <MyProfileComponent/>
11 + :
12 + null
13 + }
14 + </View>
15 + )
16 +};
17 +
18 +export default Profile;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useEffect, useState} from 'react';
2 +import * as MediaLibrary from 'expo-media-library';
3 +import * as Permission from 'expo-permissions';
4 +import {Image, ImageBackground, ScrollView, View, Text, TouchableOpacity} from "react-native";
5 +import {useNavigation} from '@react-navigation/native';
6 +import LoadingComponent from "../components/LoadingComponent";
7 +import screen from '../constants/layout';
8 +import {UploadPhoto} from './UploadPhoto';
9 +
10 +const SelectPhoto = (props) => {
11 + const navigation = useNavigation();
12 + const [loading, setLoading] = useState(false);
13 + const [hasPermission, setHasPermission] = useState(true);
14 + const [selectedPhoto, setSelectedPhoto] = useState([]);
15 + const [allPhotos, setAllPhotos] = useState([]);
16 +
17 + const getPhotos = async () => {
18 + try {
19 + const {assets} = await MediaLibrary.getAssetsAsync();
20 + const [firstPhoto] = assets;
21 + setSelectedPhoto([firstPhoto]);
22 + setAllPhotos(assets);
23 + } catch (e) {
24 + console.error(e)
25 + } finally {
26 + setLoading(false);
27 + }
28 + };
29 +
30 + const askPermission = async () => {
31 + try {
32 + setLoading(true);
33 + const {status} = await Permission.askAsync(Permission.CAMERA_ROLL);
34 + console.log(status);
35 + if (status === 'granted') {
36 + setHasPermission(true);
37 + await getPhotos();
38 + }
39 + } catch (e) {
40 + console.error(e);
41 + setHasPermission(false);
42 + }
43 + };
44 +
45 + const changeSelectedPhoto = (photo) => {
46 + setSelectedPhoto([photo]);
47 + };
48 +
49 + const uploadPhoto = () => {
50 + navigation.navigate('UploadPhoto', {photos: selectedPhoto})
51 + };
52 +
53 + useEffect(() => {
54 + askPermission();
55 + return () => {
56 + setLoading(true);
57 + setHasPermission(false);
58 + setSelectedPhoto([]);
59 + setAllPhotos([]);
60 + }
61 + }, []);
62 +
63 + return (
64 + <View>
65 + {loading
66 + ?
67 + <LoadingComponent/>
68 + :
69 + hasPermission
70 + ?
71 + selectedPhoto[0]
72 + ?
73 + <>
74 + <ImageBackground
75 + style={{width: screen.width, height: screen.height / 2}}
76 + source={{uri: selectedPhoto[0].uri}}
77 + >
78 + <TouchableOpacity
79 + style={{
80 + justifyContent: 'center',
81 + alignItems: 'center',
82 + }}
83 + key={selectedPhoto.id}
84 + onPress={uploadPhoto}
85 + >
86 + <Text>선택</Text>
87 + </TouchableOpacity>
88 + </ImageBackground>
89 +
90 + <ScrollView>
91 +
92 + <>
93 + <ScrollView horizontal contentContainerStyle={{flexDirection: 'row'}}>
94 + {allPhotos.map(photo => {
95 + return (
96 + <TouchableOpacity
97 + key={photo.id}
98 + onPress={() => changeSelectedPhoto(photo)}>
99 + <Image
100 + source={{uri: photo.uri}}
101 + style={{
102 + width: screen.width / 3,
103 + height: screen.height / 4,
104 + opacity: photo.id === selectedPhoto[0].id ? 0.6 : 1
105 + }}/>
106 + </TouchableOpacity>
107 + )
108 + }
109 + )}
110 + </ScrollView>
111 + </>
112 +
113 + </ScrollView>
114 + </>
115 + :
116 + null
117 + :
118 + <Text>사용자 권한이 없습니다</Text>
119 + }
120 + </View>
121 + )
122 +};
123 +
124 +export default SelectPhoto;
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useState, useContext, useEffect, useCallback} from 'react';
2 +import {View, Text, Button, TextInput, TouchableOpacity, StyleSheet} from 'react-native';
3 +import {useDispatch, useSelector} from "react-redux";
4 +import {useNavigation} from '@react-navigation/native';
5 +import SignUpComponent from "../components/SignUpComponent";
6 +
7 +
8 +const SignUp = (props) => {
9 + const navigation = useNavigation();
10 + const [loading, setLoading] = useState(true);
11 + const [isLogin, setIsLogin] = useState(true);
12 +
13 + const {me} = useSelector(state => state.user);
14 + const {isLoggingIn} = useSelector(state => state.user);
15 +
16 + const changeIsLogin = () => {
17 + return setIsLogin(!isLogin);
18 + }
19 +
20 + useEffect(() => {
21 + setLoading(false);
22 + }, [me]);
23 +
24 + return (
25 + <View style={styles.changeStyle}>
26 + <View style={styles.loginStyle}>
27 + <Text style={styles.inputText}>회원가입</Text>
28 + <SignUpComponent/>
29 + </View>
30 + </View>
31 + )
32 +};
33 +
34 +export default SignUp;
35 +
36 +const styles = StyleSheet.create({
37 + changeStyle: {
38 + flex: 2,
39 + alignItems: 'center',
40 + justifyContent: 'center',
41 + borderColor: 'darkgrey',
42 + },
43 + loginStyle: {
44 + flex: 1,
45 + marginTop: 30,
46 + },
47 + inputText: {
48 + borderColor: 'darkgrey',
49 + fontWeight: 'bold',
50 + fontSize: 20,
51 + marginBottom: 10
52 + }
53 +
54 +});
...\ No newline at end of file ...\ No newline at end of file
1 +import React, {useEffect, useState, useRef} from 'react';
2 +import * as MediaLibrary from 'expo-media-library';
3 +import * as Permission from 'expo-permissions';
4 +import {Image, ImageBackground, ScrollView, View, Text, TouchableOpacity} from "react-native";
5 +import {useNavigation} from '@react-navigation/native';
6 +import LoadingComponent from "../components/LoadingComponent";
7 +import screen from '../constants/layout';
8 +import { Camera } from 'expo-camera';
9 +import styled from "styled-components";
10 +import {MaterialCommunityIcons} from "@expo/vector-icons";
11 +
12 +const TakePhotoButton = styled.TouchableOpacity`
13 + width: 70px;
14 + height: 70px;
15 + border-radius: 50px;
16 + border: 15px solid green;
17 +`;
18 +
19 +
20 +const TakePhoto = (props) => {
21 + const navigation = useNavigation();
22 + const [loading, setLoading] = useState(false);
23 + const [hasPermission, setHasPermission] = useState(false);
24 + const [cameraType, setCameraType] = useState(Camera.Constants.Type.back);
25 + const [canTakePhoto, setCanTakePhoto] = useState(true);
26 + const cameraRef = useRef(null);
27 +
28 +
29 + const askPermission = async () => {
30 + try {
31 + setLoading(true);
32 + const {status} = await Permission.askAsync(Permission.CAMERA);
33 + console.log(status);
34 + if (status === 'granted') {
35 + setHasPermission(true);
36 + }
37 + } catch (e) {
38 + console.error(e);
39 + setHasPermission(false);
40 + } finally {
41 + setLoading(false)
42 + }
43 + };
44 +
45 + const changeCameraType = () => {
46 + if (cameraType === Camera.Constants.Type.front) {
47 + setCameraType(Camera.Constants.Type.back);
48 + } else {
49 + setCameraType(Camera.Constants.Type.front);
50 + }
51 + };
52 +
53 + const takePhoto = async () => {
54 + if (!canTakePhoto) {
55 + return
56 + }
57 + try {
58 + setCanTakePhoto(false);
59 + const {uri} = await cameraRef.current.takePictureAsync({quality: 1});
60 + const asset = await MediaLibrary.createAssetAsync(uri);
61 + navigation.navigate('UploadPhoto', {photo: asset});
62 + } catch (e) {
63 + console.error(e);
64 + setCanTakePhoto(true);
65 + }
66 + };
67 +
68 + const goUpload = () => {
69 + navigation.navigate('UploadPhoto');
70 + };
71 +
72 + useEffect(() => {
73 + askPermission();
74 + }, []);
75 +
76 + return (
77 + <View style={{alignItems: 'center'}}>
78 + {loading
79 + ? <LoadingComponent/>
80 + : hasPermission ?
81 + <View>
82 + <Camera
83 + ref={cameraRef}
84 + type={cameraType}
85 + style={{
86 + justifyContent: 'flex-end',
87 + padding: 10,
88 + width: screen.width,
89 + height: screen.height / 2
90 + }}>
91 + <TouchableOpacity onPress={changeCameraType}>
92 + <MaterialCommunityIcons color={'green'} name={'camera'} size={24}/>
93 + </TouchableOpacity>
94 + </Camera>
95 + <TakePhotoButton
96 + onPress={takePhoto}
97 + disabled={!canTakePhoto}
98 + />
99 + <TakePhotoButton
100 + onPress={goUpload}
101 + />
102 + </View>
103 + :
104 + null
105 + }
106 + </View>
107 + )
108 +};
109 +
110 +export default TakePhoto;
...\ No newline at end of file ...\ No newline at end of file
1 +import React from 'react';
2 +import {View, Text, Image, Button, StyleSheet} from 'react-native';
3 +import styled from "styled-components";
4 +
5 +const UploadPhoto = (props) => {
6 + const {route} = props;
7 + const {photos} = route.params;
8 +
9 +
10 + return (
11 + <View>
12 + <Text>
13 + 하이하이
14 + </Text>
15 + <View>{photos.map((photo, index) => {
16 + return (
17 + <Image style={{width: 200, height: 200}} source={{uri: photo.uri}} key={photo.id}/>)
18 + })}</View>
19 +
20 + </View>
21 + )
22 +}
23 +export default UploadPhoto;
...\ No newline at end of file ...\ No newline at end of file
1 +import createSagaMiddleware from "redux-saga";
2 +import {applyMiddleware, compose, createStore} from "redux";
3 +import rootReducer from "./reducers";
4 +import rootSaga from "./sagas";
5 +
6 +const sagaMiddleware = createSagaMiddleware();
7 +const middlewares = [sagaMiddleware];
8 +const enhancer = compose(
9 + applyMiddleware(...middlewares),
10 + // !options.isServer && typeof window.REDUX_DEVTOOLS_EXTENSION !== 'undefined' ? window.REDUX_DEVTOOLS_EXTENSION() : (f) => f,
11 +);
12 +const store = createStore(rootReducer, enhancer);
13 +sagaMiddleware.run(rootSaga);
14 +
15 +export default store;
...\ No newline at end of file ...\ No newline at end of file
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.