김성연

add code

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