diff --git a/salamander-app/APIkit.js b/salamander-app/APIkit.js index 83fc46a0ef4df11a671f675206c488d557a047f5..28b107b28fec08f3b755df764033b3f01130e065 100644 --- a/salamander-app/APIkit.js +++ b/salamander-app/APIkit.js @@ -16,4 +16,4 @@ export const setClientToken = token => { }); }; -export default APIKit; \ No newline at end of file +export default APIKit; diff --git a/salamander-app/assets/images/ninaMiniLogo.png b/salamander-app/assets/images/ninaMiniLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..eb6b656fe81a65360ac2365df5f59e38b3d4bfbd Binary files /dev/null and b/salamander-app/assets/images/ninaMiniLogo.png differ diff --git a/salamander-app/components/MyButton.js b/salamander-app/components/CustomButton.js similarity index 85% rename from salamander-app/components/MyButton.js rename to salamander-app/components/CustomButton.js index d4c44616566c5c2573954ef18ef1431c207b267a..a7d87ccaef6293b1ea071cee2aa68dae6050d5a8 100644 --- a/salamander-app/components/MyButton.js +++ b/salamander-app/components/CustomButton.js @@ -2,13 +2,13 @@ import * as React from 'react'; import { Button } from 'react-native-paper'; import { StyleSheet } from 'react-native' -const MyButton = (props) => ( +const CustomButton = (props) => ( <Button style={{...styles.button, ...props.style}} icon={props.icon} mode={props.mode} onPress={props.onPress}> {props.title} </Button> ); -export default MyButton; +export default CustomButton; const styles = StyleSheet.create({ button: { diff --git a/salamander-app/components/MyHeader.js b/salamander-app/components/CustomHeader.js similarity index 84% rename from salamander-app/components/MyHeader.js rename to salamander-app/components/CustomHeader.js index 446ccbba4ae75e14cae3355c5998390378d8124e..a90920bd58d41624be4c19b9a24fe22190846f4d 100644 --- a/salamander-app/components/MyHeader.js +++ b/salamander-app/components/CustomHeader.js @@ -1,7 +1,7 @@ import * as React from 'react'; import { Appbar } from 'react-native-paper'; -const MyHeader = ({ navigation, previous, scene }) => { +const CustomHeader = ({ navigation, previous, scene }) => { const { options } = scene.descriptor; const title = @@ -19,4 +19,4 @@ const MyHeader = ({ navigation, previous, scene }) => { ); }; -export default MyHeader; \ No newline at end of file +export default CustomHeader; \ No newline at end of file diff --git a/salamander-app/components/CustomIconButton.js b/salamander-app/components/CustomIconButton.js deleted file mode 100644 index 048ae8806686a69c12d41700fba7c5bf67e45eed..0000000000000000000000000000000000000000 --- a/salamander-app/components/CustomIconButton.js +++ /dev/null @@ -1,13 +0,0 @@ -import * as React from 'react'; -import { IconButton, Colors } from 'react-native-paper'; - -const CustomIconButton = (props) => ( - <IconButton - icon={props.icon} - color={Colors.red500} - size={90} - onPress={props.onPress} - /> -); - -export default CustomIconButton; \ No newline at end of file diff --git a/salamander-app/components/CustomImagePicker.js b/salamander-app/components/CustomImagePicker.js index e89d8271480b3b95c8b3dbe855dce25a75bc50bc..c75fb3d3c540908fe919b088939ea3682cad8c62 100644 --- a/salamander-app/components/CustomImagePicker.js +++ b/salamander-app/components/CustomImagePicker.js @@ -2,8 +2,8 @@ import React, { useState, useEffect } from 'react'; import { Image, View, Platform } from 'react-native'; import * as ImagePicker from 'expo-image-picker'; import Constants from 'expo-constants'; -import MyButton from './MyButton'; -import CustomIconButton from './CustomIconButton'; +import CustomButton from './CustomButton'; +import { IconButton, Colors } from 'react-native-paper'; const CustomImagePicker = () => { const [image, setImage] = useState(null); @@ -36,7 +36,7 @@ const CustomImagePicker = () => { return ( <View > - <CustomIconButton icon="image" onPress={pickImage} /> + <IconButton icon="image" color={Colors.red500} size={90} onPress={pickImage} /> {image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />} </View> ); diff --git a/salamander-app/components/MyTouchableOpacity.js b/salamander-app/components/CustomTouchableOpacity.js similarity index 92% rename from salamander-app/components/MyTouchableOpacity.js rename to salamander-app/components/CustomTouchableOpacity.js index d71ae5225ca90dc0ea941355051f65c1fd5554df..48637215e3af6a3b5dbe4019bffcba266e435890 100644 --- a/salamander-app/components/MyTouchableOpacity.js +++ b/salamander-app/components/CustomTouchableOpacity.js @@ -2,7 +2,7 @@ import React from 'react' import { StyleSheet, Text, View, TouchableOpacity } from 'react-native' import { Icon } from 'react-native-elements' -const MyTouchableOpacity = (props) => { +const CustomTouchableOpacity = (props) => { return ( <TouchableOpacity style={styles.touchable} onPress={props.onPress}> <View style={styles.touchableText}> @@ -14,7 +14,7 @@ const MyTouchableOpacity = (props) => { ) } -export default MyTouchableOpacity +export default CustomTouchableOpacity const styles = StyleSheet.create({ touchable: { diff --git a/salamander-app/components/EditUserHeader.js b/salamander-app/components/EditUserHeader.js new file mode 100644 index 0000000000000000000000000000000000000000..91b789c103b6c26dee6d03cf630d2b9f8464aac5 --- /dev/null +++ b/salamander-app/components/EditUserHeader.js @@ -0,0 +1,28 @@ +import React from 'react' +import { StyleSheet, Image } from 'react-native' +import { Appbar } from 'react-native-paper'; + +const EditUserHeader = (props) => { + return ( + <Appbar.Header style={styles.header}> + <Image + style={styles.image} + source={props.source} + /> + </Appbar.Header> + ) +} + +export default EditUserHeader + +const styles = StyleSheet.create({ + header: { + justifyContent: "center", + flexDirection: "row" + }, + image: { + width: 40, + height: 40, + marginLeft: 15, + } +}) diff --git a/salamander-app/components/MyTextField.js b/salamander-app/components/MyTextField.js deleted file mode 100644 index c8f7ca958284d037c5f6c4ca2bf17c0b72822ffe..0000000000000000000000000000000000000000 --- a/salamander-app/components/MyTextField.js +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { TextInput } from 'react-native-paper'; -import { StyleSheet } from 'react-native' - -const MyTextField = (props) => { - - return ( - <TextInput - style={{...styles.textfield, ...props.style}} - label={props.label} - secureTextEntry={props.secureTextEntry} - mode={props.mode} - placeholder={props.placeholder} - value={props.text} - onChangeText={props.onChangeText} - /> - ); -}; - -const styles = StyleSheet.create({ - textfield: { - margin: 0, - }, -}) - - - -export default MyTextField; - diff --git a/salamander-app/components/PendingUser.js b/salamander-app/components/PendingUser.js new file mode 100644 index 0000000000000000000000000000000000000000..65a38e485913428c4edc04576d00c27e887b3e1b --- /dev/null +++ b/salamander-app/components/PendingUser.js @@ -0,0 +1,76 @@ +import React from 'react' +import { StyleSheet, Text, View } from 'react-native' +import { IconButton, Colors } from 'react-native-paper'; + +import APIKit from '../APIkit' + +const PendingUser = (props) => { + + const acceptUser = (email, id) => { + let bodyFormData = new FormData(); + bodyFormData.append("id", id); + bodyFormData.append("email", email); + bodyFormData.append("accepted", 1); + + APIKit.post('/pendingUsers', bodyFormData) + .then(function (response) { + console.log(response.data); + if (response.data.status === 200) { + props.getPendingUsers(); + } + }) + .catch(function (response) { + //handle error + console.log(response); + }); + } + + const denyUser = (email, id) => { + let bodyFormData = new FormData(); + bodyFormData.append("id", id); + bodyFormData.append("email", email); + bodyFormData.append("accepted", 0); + + APIKit.post('/pendingUsers', bodyFormData) + .then(function (response) { + console.log(response.data); + if (response.data.status === 200) { + props.getPendingUsers(); + } + }) + .catch(function (response) { + //handle error + console.log(response); + }); + } + + return ( + <View style={styles.item}> + <Text style={styles.title}>{props.email}</Text> + <View style={styles.buttons} > + <IconButton icon="cancel" color={Colors.orange500} size={20} onPress={() => {denyUser(props.email, props.id)}} /> + <IconButton icon="check-circle-outline" color={Colors.orange500} size={20} onPress={() => {acceptUser(props.email, props.id)}} /> + </View> + </View> + ) +} + +export default PendingUser + +const styles = StyleSheet.create({ + item: { + margin: 5, + marginVertical: 8, + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + marginHorizontal: 16, + }, + buttons: { + flexDirection: "row", + alignSelf: "flex-end", + }, + title: { + fontSize: 16 + }, +}) diff --git a/salamander-app/components/RegisterLocationModal.js b/salamander-app/components/RegisterLocationModal.js index 5e8de7f832ba98578a2794f22f5d1acba3137187..c98e517a6eacdc0088baf62599400385dc0724c2 100644 --- a/salamander-app/components/RegisterLocationModal.js +++ b/salamander-app/components/RegisterLocationModal.js @@ -1,8 +1,9 @@ import React, {useEffect} from 'react' import { StyleSheet, View, ScrollView, Text, Modal } from 'react-native' +import { TextInput } from 'react-native-paper'; + import APIKit from "../APIkit"; -import MyTextField from '../components/MyTextField'; -import MyButton from '../components/MyButton'; +import CustomButton from './CustomButton'; import { Appbar } from 'react-native-paper'; @@ -41,23 +42,45 @@ const RegisterLocationModal = (props) => { return ( <Modal visible={props.visible} animationType="slide"> - <Appbar> + <Appbar.Header style={{justifyContent: "space-between", flexDirection: "row" }}> <Appbar.Content title="Register Location" /> - </Appbar> + </Appbar.Header> <ScrollView style={styles.scrollView}> <View style={styles.container}> - <MyTextField onChangeText={name => setName(name)} style={styles.textfieldLocation} mode='flat' placeholder='Location name' label='Location name' /> + <TextInput + onChangeText={name => setName(name)} + style={styles.textfieldLocation} + mode='flat' + placeholder='Location name' + label='Location name' + /> <View style={styles.radiusContainer}> - <MyTextField onChangeText={radius => setRadius(radius)} style={styles.textfieldRadius} mode='flat' placeholder='Radius' label='Radius'/> + <TextInput + onChangeText={radius => setRadius(radius)} + style={styles.textfieldRadius} + mode='flat' + placeholder='Radius' + label='Radius' + /> <Text style={styles.radiusText}>Meter</Text> </View> <Text style={styles.radiusText}>Latitude: {props.latitude}</Text> <Text style={styles.radiusText}>Longitude: {props.longitude}</Text> <Text style={styles.radiusText}>{errormessage}</Text> <View style={styles.buttonContainer}> - <MyButton style={styles.button} title="Cancel" onPress={() => cancel()} /> - <MyButton style={styles.button} title="Confirm" onPress={() => registerLocation()} /> + <CustomButton + style={styles.button} + title="Cancel" + mode="outlined" + onPress={() => cancel()} + /> + <CustomButton + style={styles.button} + mode="contained" + title="Confirm" + onPress={() => registerLocation()} + /> </View> </View> diff --git a/salamander-app/components/SalamanderInfoModal.js b/salamander-app/components/SalamanderInfoModal.js index 9f32f24c2016e2bd67e0462c084fb94b1f937bb0..69d7a5b6fc6de2c300ced5509e8088deecedd847 100644 --- a/salamander-app/components/SalamanderInfoModal.js +++ b/salamander-app/components/SalamanderInfoModal.js @@ -1,8 +1,7 @@ import React from 'react' import { StyleSheet, View, ScrollView, Text, Modal } from 'react-native' -import MyTextField from '../components/MyTextField'; -import MyButton from '../components/MyButton'; +import CustomButton from './CustomButton'; import { Appbar } from 'react-native-paper'; import CustomDropDown from './CustomDropDown'; @@ -23,9 +22,9 @@ const SalamanderInfoModal = (props) => { return ( <Modal visible={props.visible} animationType="slide"> - <Appbar> + <Appbar.Header style={{justifyContent: "space-between", flexDirection: "row" }}> <Appbar.Content title="Salamander Information" /> - </Appbar> + </Appbar.Header> <ScrollView style={styles.scrollView}> <View style={styles.container}> <Text style={styles.text}>Species</Text> @@ -37,8 +36,18 @@ const SalamanderInfoModal = (props) => { <CustomDropDown myItems={sex} /> </View> <View style={styles.buttonContainer}> - <MyButton style={styles.button} title="Cancel" onPress={props.onCancel} /> - <MyButton style={styles.button} title="Confirm" onPress={() => console.log("Pressed")} /> + <CustomButton + style={styles.button} + title="Cancel" + mode="outlined" + onPress={props.onCancel} + /> + <CustomButton + style={styles.button} + title="Confirm" + mode="contained" + onPress={() => console.log("Pressed")} + /> </View> </View> </ScrollView> diff --git a/salamander-app/navigation/EditUserStackScreen.js b/salamander-app/navigation/EditUserStackScreen.js index a6c0d73c081d16e3eeba048b7577a902ee928dde..78189896b247828692d35ba8d91af29bdf2225e9 100644 --- a/salamander-app/navigation/EditUserStackScreen.js +++ b/salamander-app/navigation/EditUserStackScreen.js @@ -5,6 +5,8 @@ import VerifyPasswordScreen from '../screens/VerifyPasswordScreen'; import { ChangeEmailScreen } from '../screens/ChangeEmailScreen'; import ChangePasswordScreen from '../screens/ChangePasswordScreen'; import { DeleteAccountScreen } from '../screens/DeleteAccountScreen'; +import ManageUsersScreen from '../screens/ManageUsersScreen'; +import PendingUsersScreen from '../screens/PendingUsersScreen'; const EditUserStack = createStackNavigator(); @@ -22,6 +24,14 @@ const EditUserStackScreen = () => ( name="ChangePassword" component={ChangePasswordScreen} /> + <EditUserStack.Screen + name="PendingUsers" + component={PendingUsersScreen} + /> + <EditUserStack.Screen + name="ManageUsers" + component={ManageUsersScreen} + /> <EditUserStack.Screen name="DeleteAccount" component={DeleteAccountScreen} diff --git a/salamander-app/navigation/RootStackScreen.js b/salamander-app/navigation/RootStackScreen.js index f3901765db2abb5e56d89e0ab9c40ca4d84649ee..dfb9d4e1cc030f1371df529c256ee86741efe18c 100644 --- a/salamander-app/navigation/RootStackScreen.js +++ b/salamander-app/navigation/RootStackScreen.js @@ -4,7 +4,6 @@ import { createStackNavigator } from "@react-navigation/stack"; import TabsScreen from './TabsScreen'; import AuthStackScreen from './AuthStackScreen'; import EditUserStackScreen from './EditUserStackScreen'; -import VerifyPasswordScreen from '../screens/VerifyPasswordScreen'; const RootStack = createStackNavigator(); diff --git a/salamander-app/navigation/TabsScreen.js b/salamander-app/navigation/TabsScreen.js index f1ded7ea62691e419f81f4e04c45f247b933fcf6..acc624c5dfc72a607023c08d49f9e52249918b40 100644 --- a/salamander-app/navigation/TabsScreen.js +++ b/salamander-app/navigation/TabsScreen.js @@ -6,9 +6,7 @@ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityI import {HomeScreen} from '../screens/HomeScreen'; import CameraScreen from '../screens/CameraScreen'; import { ProfileScreen } from '../screens/ProfileScreen'; -import RegisterLocationScreen from '../screens/RegisterLocationScreen'; -import SalamanderInfoScreen from '../screens/SalamanderInfoScreen'; -import MyHeader from '../components/MyHeader'; +import CustomHeader from '../components/CustomHeader'; import { ChangeNameScreen } from '../screens/ChangeNameScreen'; @@ -21,7 +19,7 @@ const ProfileStackScreen = () => ( <ProfileStack.Navigator initialRouteName="Profile" screenOptions={{ - header: (props) => <MyHeader {...props} />, + header: (props) => <CustomHeader {...props} />, }} > <ProfileStack.Screen name="Profile" component={ProfileScreen} options={{ headerTitle: 'Profile' }} /> @@ -33,10 +31,9 @@ const ProfileStackScreen = () => ( <CameraStack.Navigator initialRouteName="Camera" screenOptions={{ - header: (props) => <MyHeader {...props} />, + header: (props) => <CustomHeader {...props} />, }}> <CameraStack.Screen name="Camera" component={CameraScreen} options={{ headerTitle: 'Camera' }} /> - <CameraStack.Screen name="SalamanderInformation" component={SalamanderInfoScreen} options={{ headerTitle: 'Salamander Information' }} /> </CameraStack.Navigator> ) @@ -44,12 +41,9 @@ const ProfileStackScreen = () => ( <HomeStack.Navigator initialRouteName="Home" screenOptions={{ - header: (props) => <MyHeader {...props} />, + header: (props) => <CustomHeader {...props} />, }}> <HomeStack.Screen name="Home" component={HomeScreen} options={{ headerTitle: 'Home' }} /> - <HomeStack.Screen name="RegisterLocation" component={RegisterLocationScreen} options={({ route }) => ({ - title: route.params.name - })} /> </HomeStack.Navigator> ) diff --git a/salamander-app/screens/CameraScreen.js b/salamander-app/screens/CameraScreen.js index a5f32598f1210ebb04b0da64df9ac162fa972d1e..17b881ad5e8bb4c2e988275c2e7e313aded8bf0e 100644 --- a/salamander-app/screens/CameraScreen.js +++ b/salamander-app/screens/CameraScreen.js @@ -2,10 +2,10 @@ import React, { useState } from 'react' import { StyleSheet, ScrollView, View, Text } from 'react-native' import CustomCamera from '../components/CustomCamera' import CustomDropDown from '../components/CustomDropDown' -import CustomIconButton from '../components/CustomIconButton' import CustomImagePicker from '../components/CustomImagePicker' -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import SalamanderInfoModal from '../components/SalamanderInfoModal' +import { IconButton, Colors } from 'react-native-paper'; const CameraScreen = ({ navigation }) => { @@ -30,17 +30,22 @@ const CameraScreen = ({ navigation }) => { </View> <View style={styles.takeImage}> <CustomImagePicker /> - <CustomIconButton icon="camera" onPress={() => setShowCamera(true)} /> + <CustomCamera visible={isCameraMode} /> + <IconButton + icon="camera" + color={Colors.red500} + size={90} + onPress={() => setShowCamera(true)} + /> {isCameraMode && (<CustomCamera showModal={isCameraMode} setModalVisible={() => setShowCamera(false)} setError={(errorString) => setError(errorString)} - // save={true} - // setImage={(result) => setImage(result.uri)} />)} </View> - <MyButton + <CustomButton title="Confirm" + mode="contained" style={styles.button} onPress={() => setIsSalamanderInfoMode(true)} /> <SalamanderInfoModal visible={isSalamanderInfoMode} onCancel={cancelSalamanderInfoHandler}/> diff --git a/salamander-app/screens/ChangeEmailScreen.js b/salamander-app/screens/ChangeEmailScreen.js index 95db084d139917ba7965eb37f9e813d493ae59fb..b7471568101e226d29dd31631c208c17ce50cbb8 100644 --- a/salamander-app/screens/ChangeEmailScreen.js +++ b/salamander-app/screens/ChangeEmailScreen.js @@ -1,12 +1,12 @@ import React, { useState, useEffect } from 'react' import { StyleSheet, View, ScrollView, KeyboardAvoidingView } from 'react-native' -import { Appbar } from 'react-native-paper'; import { connect } from 'react-redux' import AccountData from '../components/AccountData' -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import { TextInput } from 'react-native-paper'; import { onEditEmail } from '../redux/index'; +import EditUserHeader from '../components/EditUserHeader'; const _ChangeEmailScreen = (props) => { @@ -25,8 +25,7 @@ const _ChangeEmailScreen = (props) => { return ( <ScrollView keyboardShouldPersistTaps='handled'> <KeyboardAvoidingView behavior='padding' style={{ flex: 1, alignItems: 'stretch'}}> - <Appbar.Header style={{justifyContent: "space-between", flexDirection: "row" }}> - </Appbar.Header> + <EditUserHeader source={require('../assets/images/ninaMiniLogo.png')}/> <AccountData currentLabel="Current Email" current={user.email} @@ -43,13 +42,13 @@ const _ChangeEmailScreen = (props) => { value={email} onSubmitEditing={editEmail} /> - <MyButton + <CustomButton style={styles.button} mode="contained" title="Confirm" onPress={() => onEditEmail({email: email})} /> - <MyButton + <CustomButton style={styles.button} mode="outlined" title="Cancel" diff --git a/salamander-app/screens/ChangeNameScreen.js b/salamander-app/screens/ChangeNameScreen.js index 16f785e88756e2cb48cb610767e1b94a2aa666d4..e34a673e3ccf0b93930e9a4b0c99ccc29978ed51 100644 --- a/salamander-app/screens/ChangeNameScreen.js +++ b/salamander-app/screens/ChangeNameScreen.js @@ -3,7 +3,7 @@ import { StyleSheet, View, ScrollView } from 'react-native' import AccountData from '../components/AccountData' import { connect } from 'react-redux' -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import { TextInput } from 'react-native-paper'; import { onEditName } from '../redux/index'; @@ -31,9 +31,10 @@ const _ChangeNameScreen = (props) => { onChangeText={name => setName(name)} value={name} /> - <MyButton + <CustomButton style={styles.button} title="Confirm" + mode="contained" onPress={() => onEditName({name: name})} /> </View> diff --git a/salamander-app/screens/ChangePasswordScreen.js b/salamander-app/screens/ChangePasswordScreen.js index fe62d1c3a373578fdb65026154fd807a3a2a4585..7ac3888695dfe1eba6922d717d662eab753e22db 100644 --- a/salamander-app/screens/ChangePasswordScreen.js +++ b/salamander-app/screens/ChangePasswordScreen.js @@ -1,10 +1,10 @@ import React, { useState } from 'react' import { StyleSheet, View, ScrollView, KeyboardAvoidingView } from 'react-native' -import { Appbar } from 'react-native-paper'; import APIKit from '../APIkit' -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import { TextInput } from 'react-native-paper'; +import EditUserHeader from '../components/EditUserHeader'; const ChangePasswordScreen = ({ navigation }) => { @@ -34,7 +34,7 @@ const ChangePasswordScreen = ({ navigation }) => { return ( <ScrollView keyboardShouldPersistTaps='handled'> <KeyboardAvoidingView style={{ flex: 1, alignItems: 'stretch'}}> - <Appbar.Header style={{justifyContent: "space-between", flexDirection: "row" }} /> + <EditUserHeader source={require('../assets/images/ninaMiniLogo.png')}/> <TextInput style={styles.textfield} mode="flat" @@ -56,13 +56,13 @@ const ChangePasswordScreen = ({ navigation }) => { value={confirmPassword} onSubmitEditing={() => console.log("Pressed")} /> - <MyButton + <CustomButton style={styles.button} title="Confirm" mode="contained" onPress={() => changePassword()} /> - <MyButton + <CustomButton style={styles.button} title="Cancel" mode="outlined" diff --git a/salamander-app/screens/DeleteAccountScreen.js b/salamander-app/screens/DeleteAccountScreen.js index ca52fc785ac1d4e9340d7dc07d77cb2aee2f1731..30e94de70a6d03cc25bca4392c3316ce1700337a 100644 --- a/salamander-app/screens/DeleteAccountScreen.js +++ b/salamander-app/screens/DeleteAccountScreen.js @@ -1,11 +1,12 @@ import React from 'react' import { StyleSheet, Text, View, ScrollView, Alert } from 'react-native' -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import { Appbar } from 'react-native-paper'; import { onUserSignOut } from '../redux/index'; import { connect } from 'react-redux' import { AuthContext } from '../constants/context'; import APIKit from '../APIkit' +import EditUserHeader from '../components/EditUserHeader'; const _DeleteAccountScreen = (props) => { @@ -56,10 +57,20 @@ const _DeleteAccountScreen = (props) => { return ( <ScrollView> <View style={{ flex: 1, alignItems: 'stretch'}}> - <Appbar.Header style={{justifyContent: "space-between", flexDirection: "row" }} /> + <EditUserHeader source={require('../assets/images/ninaMiniLogo.png')}/> <Text style={styles.text}>Are you sure?</Text> - <MyButton style={styles.button} mode="contained" title="Delete Account" onPress={createTwoButtonAlert} /> - <MyButton style={styles.button} mode="outlined" title="Cancel" onPress={() => props.navigation.navigate("Profile")} /> + <CustomButton + style={styles.button} + mode="contained" + title="Delete Account" + onPress={createTwoButtonAlert} + /> + <CustomButton + style={styles.button} + mode="outlined" + title="Cancel" + onPress={() => props.navigation.navigate("Profile")} + /> </View> </ScrollView> ) diff --git a/salamander-app/screens/HomeScreen.js b/salamander-app/screens/HomeScreen.js index 9e313ed4912103c1e66b8ab85132b21d5172b51b..adc297efc1d595a46225e06a35a7ff8b35c1d74d 100644 --- a/salamander-app/screens/HomeScreen.js +++ b/salamander-app/screens/HomeScreen.js @@ -1,6 +1,6 @@ import React, {useEffect} from 'react' import {Dimensions, StyleSheet, View} from 'react-native' -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import MapView from "react-native-maps"; import { PROVIDER_GOOGLE } from "react-native-maps"; import { Marker, Circle } from "react-native-maps"; @@ -71,7 +71,7 @@ const _HomeScreen = (props) => { ))} <Marker coordinate={{latitude: lat, longitude: lng}}/> </MapView> - <MyButton title="Go to register location" onPress={() => setIsAddMode(true)} /> + <CustomButton mode="contained" title="Go to register location" onPress={() => setIsAddMode(true)} /> </View> ) } diff --git a/salamander-app/screens/ManageUsersScreen.js b/salamander-app/screens/ManageUsersScreen.js new file mode 100644 index 0000000000000000000000000000000000000000..2f66bb8b3c6a5d7a34b6201751fc766bb982c1a1 --- /dev/null +++ b/salamander-app/screens/ManageUsersScreen.js @@ -0,0 +1,37 @@ +import React from 'react' +import { StyleSheet, ScrollView, SafeAreaView, KeyboardAvoidingView } from 'react-native' + +import CustomButton from '../components/CustomButton' +import EditUserHeader from '../components/EditUserHeader'; + +const ManageUsersScreen = ({ navigation }) => { + return ( + <ScrollView keyboardShouldPersistTaps='handled'> + <KeyboardAvoidingView behavior='padding' style={{ flex: 1, alignItems: 'stretch'}}> + <EditUserHeader source={require('../assets/images/ninaMiniLogo.png')}/> + <CustomButton + style={styles.button} + mode="contained" + title="Confirm" + onPress={() => console.log("Pressed")} + /> + <CustomButton + style={styles.button} + mode="outlined" + title="Cancel" + onPress={() => navigation.navigate("Profile")} + /> + </KeyboardAvoidingView> + </ScrollView> + ) +} + +export default ManageUsersScreen + +const styles = StyleSheet.create({ + button: { + width: 150, + alignSelf: "center", + marginTop: 20, + }, +}) diff --git a/salamander-app/screens/PendingUsersScreen.js b/salamander-app/screens/PendingUsersScreen.js new file mode 100644 index 0000000000000000000000000000000000000000..c3cc5e246c646251198670ee1dbd1541e5d921be --- /dev/null +++ b/salamander-app/screens/PendingUsersScreen.js @@ -0,0 +1,86 @@ +import React, { useEffect, useState } from 'react' +import { StyleSheet, Text, View, FlatList, ScrollView, SafeAreaView, StatusBar } from 'react-native' +import { IconButton, Colors } from 'react-native-paper'; +import { Appbar } from 'react-native-paper'; + +import CustomButton from '../components/CustomButton' +import EditUserHeader from '../components/EditUserHeader'; +import APIKit from '../APIkit' +import PendingUser from '../components/PendingUser'; + + +const PendingUsersScreen = ({ navigation }) => { + + const [pendingUsers, setPendingUsers] = useState([]); + + const renderItem = ({ item }) => ( + <PendingUser email={item.email} id={item.id} getPendingUsers={getPendingUsers}/> + ); + + const getPendingUsers = () => { + APIKit.get('/pendingUsers') + .then(function (response) { + if (response.data.status === 200) { + setPendingUsers(response.data.users); + } + }) + .catch(function (response) { + //handle error + console.log(response); + }); + } + + useEffect(() => { + getPendingUsers(); + }, []); + + return ( + <SafeAreaView style={{ flex: 1, alignItems: 'stretch'}}> + <Appbar.Header style={styles.header}> + <Appbar.Content title="Pending Users" /> + </Appbar.Header> + <FlatList + data={pendingUsers} + renderItem={renderItem} + keyExtractor={item => item.id.toString()} + /> + <CustomButton + style={styles.button} + mode="outlined" + title="Cancel" + onPress={() => navigation.navigate("Profile")} + /> + </SafeAreaView> + + ) +} + +export default PendingUsersScreen + +const styles = StyleSheet.create({ + button: { + width: 150, + alignSelf: "center", + }, + buttonAction: { + width: 30, + height: 30, + marginEnd: 5, + + }, + item: { + margin: 5, + marginVertical: 8, + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + marginHorizontal: 16, + }, + buttons: { + flexDirection: "row", + alignSelf: "flex-end", + }, + title: { + fontSize: 16 + }, +}) diff --git a/salamander-app/screens/ProfileScreen.js b/salamander-app/screens/ProfileScreen.js index 5a964c0edd1a4612a16cc2d6890fe1749067b654..2ad921ba895ce4b869ece572f53814cd2e363b06 100644 --- a/salamander-app/screens/ProfileScreen.js +++ b/salamander-app/screens/ProfileScreen.js @@ -3,7 +3,7 @@ import { StyleSheet, Text, View, ScrollView } from 'react-native' import { Divider } from 'react-native-paper'; import { connect } from 'react-redux' -import MyTouchableOpacity from '../components/MyTouchableOpacity'; +import CustomTouchableOpacity from '../components/CustomTouchableOpacity'; import { AuthContext } from '../constants/context'; import { onUserSignOut } from '../redux/actions/UserActions'; @@ -23,14 +23,14 @@ const _ProfileScreen = (props) => { <View style={styles.container}> <Text style={styles.text}>Personal Data</Text> <Divider /> - <MyTouchableOpacity + <CustomTouchableOpacity title="Name" placeholder={user.name} icon="chevron-right" onPress={() => props.navigation.navigate('ChangeName')} /> <Divider /> - <MyTouchableOpacity + <CustomTouchableOpacity title="Email" placeholder={user.email} icon="chevron-right" @@ -42,7 +42,7 @@ const _ProfileScreen = (props) => { }} /> <Divider /> - <MyTouchableOpacity + <CustomTouchableOpacity title="Password" icon="chevron-right" onPress={() => { @@ -53,9 +53,33 @@ const _ProfileScreen = (props) => { }} /> <Divider /> + <Text style={styles.text}>Administrate</Text> + <Divider /> + <CustomTouchableOpacity + title="Pending Users" + icon="chevron-right" + onPress={() => { + props.navigation.navigate('Verify', { + screen: 'VerifyPassword', + params: { nextNavigation: 'PendingUsers' }, + }); + }} + /> + <Divider /> + <CustomTouchableOpacity + title="Manage Users" + icon="chevron-right" + onPress={() => { + props.navigation.navigate('Verify', { + screen: 'VerifyPassword', + params: { nextNavigation: 'ManageUsers' }, + }); + }} + /> + <Divider /> <Text style={styles.text}>Account Management</Text> <Divider /> - <MyTouchableOpacity + <CustomTouchableOpacity title="Delete Account" onPress={() => { props.navigation.navigate('Verify', { @@ -67,7 +91,7 @@ const _ProfileScreen = (props) => { <Divider /> <View style={styles.signOut}> <Divider /> - <MyTouchableOpacity style={styles.signOutPlaceholder} placeholder="Sign Out" onPress={() => onUserSignOut({signOutApp})}/> + <CustomTouchableOpacity style={styles.signOutPlaceholder} placeholder="Sign Out" onPress={() => onUserSignOut({signOutApp})}/> <Divider /> </View> </View> @@ -88,7 +112,7 @@ export { ProfileScreen } const styles = StyleSheet.create({ container: { flex: 1, - paddingTop: 25, + paddingTop: 10, }, text: { paddingTop: 25, diff --git a/salamander-app/screens/RegisterLocationScreen.js b/salamander-app/screens/RegisterLocationScreen.js deleted file mode 100644 index 2affaffd9f103fbf857fa5f01d7e38e341ce104f..0000000000000000000000000000000000000000 --- a/salamander-app/screens/RegisterLocationScreen.js +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react' -import { StyleSheet, View, ScrollView, Text } from 'react-native' - -import MyTextField from '../components/MyTextField'; -import MyButton from '../components/MyButton'; - -const RegisterLocationScreen = () => { - - return ( - <ScrollView style={styles.scrollView}> - <View style={styles.container}> - <MyTextField style={styles.textfieldLocation} mode='flat' placeholder='Location name' label='Location name' /> - <View style={styles.radiusContainer}> - <MyTextField style={styles.textfieldRadius} mode='flat' placeholder='Radius' label='Radius'/> - <Text style={styles.radiusText}>Meter</Text> - </View> - <View style={styles.buttonContainer}> - <MyButton style={styles.button} title="Cancel" onPress={() => console.log("Pressed")} /> - <MyButton style={styles.button} title="Confirm" onPress={() => console.log("Pressed")} /> - </View> - </View> - </ScrollView> - ) -} - -export default RegisterLocationScreen - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingTop: 25, - }, - button: { - width: 150, - alignSelf: "center", - marginTop: 20, - marginBottom: 20 - }, - textfieldLocation: { - marginTop: 5, - margin: 20 - }, - textfieldRadius: { - flex: 1 - }, - buttonContainer: { - flexDirection: 'row', - justifyContent: 'space-between', - marginTop: 200, - marginEnd: 20, - marginStart: 20, - }, - radiusContainer: { - flexDirection: 'row', - justifyContent: 'center', - marginStart: 20 - }, - radiusText: { - flex: 1, - alignSelf: 'center', - fontSize: 20 - } -}) diff --git a/salamander-app/screens/SalamanderInfoScreen.js b/salamander-app/screens/SalamanderInfoScreen.js deleted file mode 100644 index d02237000dce05a6a431a9a2cfd68682fd7341dc..0000000000000000000000000000000000000000 --- a/salamander-app/screens/SalamanderInfoScreen.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react' -import { StyleSheet, Text, View } from 'react-native' - -const SalamanderInfoScreen = () => { - return ( - <View style={styles.container}> - <Text>Salamander Information</Text> - </View> - ) -} - -export default SalamanderInfoScreen - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - alignItems: "center" - } -}) diff --git a/salamander-app/screens/SignInScreen.js b/salamander-app/screens/SignInScreen.js index 67a9a2396e50d72bd0a80ec3dd1a1e42a7289e75..cf41ff7a97cae9f92a21a74a2a56d0b10663c28f 100644 --- a/salamander-app/screens/SignInScreen.js +++ b/salamander-app/screens/SignInScreen.js @@ -1,10 +1,20 @@ import React from 'react' -import { StyleSheet, Text, View, Image, ScrollView } from 'react-native' +import { + StyleSheet, + Text, + View, + Image, + SafeAreaView, + KeyboardAvoidingView, + TouchableWithoutFeedback, + Keyboard, + TouchableOpacity +} from 'react-native' import { connect } from 'react-redux' +import { TextInput } from 'react-native-paper'; -import MyButton from '../components/MyButton' +import CustomButton from '../components/CustomButton' import { AuthContext } from '../constants/context' -import MyTextField from '../components/MyTextField' import { onUserLogin } from '../redux/index'; const _SignInScreen = (props) => { @@ -21,46 +31,48 @@ const _SignInScreen = (props) => { const [password, setPassword] = React.useState(''); return ( - <ScrollView style={styles.scrollView}> - <View style={styles.container}> - <View style={styles.image}> - <Image - style={styles.logo} - source={require('../assets/images/ninaLogo.png')} + <KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : null} style={{ flex: 1 }}> + <TouchableWithoutFeedback onPress={Keyboard.dismiss}> + <SafeAreaView style={styles.container}> + <View style={styles.image}> + <Image + style={styles.logo} + source={require('../assets/images/ninaLogo.png')} + /> + </View> + <TextInput + style={styles.textfield} + mode='outlined' + placeholder='Email' + autofocus + type="email" + label='Email' + onChangeText={email => setEmail(email)} + value={email} /> - </View> - <MyTextField - style={styles.textfield} - mode='outlined' - placeholder='Email' - autofocus - type="email" - label='Email' - onChangeText={email => setEmail(email)} - value={email} - /> - <MyTextField - style={styles.textfield} - mode='outlined' secureTextEntry={true} - placeholder='Password' - label='password' - type='password' - onChangeText={password => setPassword(password)} - value={password} - /> - <MyButton - style={styles.button} - title="Sign In" - mode="contained" - onPress={() => onUserLogin({ email: email, password: password, signInApp})} - /> - <Text - style={styles.text} - onPress={() => props.navigation.navigate("SignUp")}> - Don't have a user? - </Text> - </View> - </ScrollView> + <TextInput + style={styles.textfield} + mode='outlined' secureTextEntry={true} + placeholder='Password' + label='password' + type='password' + onChangeText={password => setPassword(password)} + value={password} + /> + <CustomButton + style={styles.button} + title="Sign In" + mode="contained" + onPress={() => onUserLogin({ email: email, password: password, signInApp})} + /> + <TouchableOpacity onPress={() => props.navigation.navigate("SignUp")}> + <Text style={styles.text}> + Don't have a user? + </Text> + </TouchableOpacity> + </SafeAreaView> + </TouchableWithoutFeedback> + </KeyboardAvoidingView> ) } @@ -79,12 +91,14 @@ export { SignInScreen } const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: "lightblue", - justifyContent: 'center', - padding: 40 + alignItems: 'stretch', + justifyContent: "center", + backgroundColor: 'lightblue', }, textfield: { margin: 3, + width: 300, + alignSelf: "center" }, button: { marginTop: 15, diff --git a/salamander-app/screens/SignUpScreen.js b/salamander-app/screens/SignUpScreen.js index f787027ef345ad7b292a1e345e9f2febff8ba7aa..335908de3ae36f7cf5bbfb8bf2242faf45d97f28 100644 --- a/salamander-app/screens/SignUpScreen.js +++ b/salamander-app/screens/SignUpScreen.js @@ -1,7 +1,19 @@ import React from 'react' -import { StyleSheet, Text, View, Image, ScrollView } from 'react-native' -import MyTextField from '../components/MyTextField' -import MyButton from '../components/MyButton' +import { + StyleSheet, + Text, + View, + Image, + Keyboard, + TouchableWithoutFeedback, + KeyboardAvoidingView, + Platform, + SafeAreaView, + TouchableOpacity +} from 'react-native' +import { TextInput } from 'react-native-paper'; + +import CustomButton from '../components/CustomButton' import APIKit from '../APIkit' const SignUpScreen = ({ navigation }) => { @@ -10,6 +22,7 @@ const SignUpScreen = ({ navigation }) => { const [email, setEmail] = React.useState(''); const [password, setPassword] = React.useState(''); const [confirmPassword, setConfirmPassword] = React.useState(''); + const signUp = () => { let bodyFormData = new FormData(); @@ -21,6 +34,9 @@ const SignUpScreen = ({ navigation }) => { APIKit.post('/user', bodyFormData) .then(function (response) { console.log(response.data.message); + if (response.data.status === 200) { + navigation.navigate("SignIn"); + } }) .catch(function (response) { //handle error @@ -29,60 +45,63 @@ const SignUpScreen = ({ navigation }) => { } return ( - <ScrollView style={styles.scrollView}> - <View style={styles.container}> - <View style={styles.image}> - <Image - style={styles.logo} - source={require('../assets/images/ninaLogo.png')} + <KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : null} style={{ flex: 1 }}> + <TouchableWithoutFeedback onPress={Keyboard.dismiss}> + <SafeAreaView style={styles.container}> + <View style={styles.image}> + <Image + style={styles.logo} + source={require('../assets/images/ninaLogo.png')} + /> + </View> + <TextInput + style={styles.textfield} + autoFocus={true} + mode='outlined' + placeholder='Name' + label='Name' + onChangeText={name => setName(name)} value={name} + /> + <TextInput + style={styles.textfield} + mode='outlined' + placeholder='Email' + label='Email' + onChangeText={email => setEmail(email)} + value={email} + /> + <TextInput + style={styles.textfield} + mode='outlined' + secureTextEntry={true} + placeholder='Password' + label='password' + onChangeText={password => setPassword(password)} + value={password} /> - </View> - <MyTextField - style={styles.textfield} - mode='outlined' - placeholder='Name' - label='Name' - onChangeText={name => setName(name)} value={name} - /> - <MyTextField - style={styles.textfield} - mode='outlined' - placeholder='Email' - label='Email' - onChangeText={email => setEmail(email)} - value={email} - /> - <MyTextField - style={styles.textfield} - mode='outlined' - secureTextEntry={true} - placeholder='Password' - label='password' - onChangeText={password => setPassword(password)} - value={password} - /> - <MyTextField - style={styles.textfield} - mode='outlined' - secureTextEntry={true} - placeholder='Confirm Password' - label='Confirm Password' - onChangeText={confirmPassword => setConfirmPassword(confirmPassword)} - value={confirmPassword} - /> - <MyButton - style={styles.button} - mode="contained" - title="Sign Up" - onPress={() => signUp()} - /> - <Text - style={styles.text} - onPress={() => navigation.navigate("SignIn")}> - Already have a user? - </Text> - </View> - </ScrollView> + <TextInput + style={styles.textfield} + mode='outlined' + secureTextEntry={true} + placeholder='Confirm Password' + label='Confirm Password' + onChangeText={confirmPassword => setConfirmPassword(confirmPassword)} + value={confirmPassword} + /> + <CustomButton + style={styles.button} + mode="contained" + title="Sign Up" + onPress={() => signUp()} + /> + <TouchableOpacity onPress={() => navigation.navigate("SignIn")}> + <Text style={styles.text}> + Already have a user? + </Text> + </TouchableOpacity> + </SafeAreaView> + </TouchableWithoutFeedback> + </KeyboardAvoidingView> ) } @@ -91,13 +110,16 @@ export default SignUpScreen const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: "lightblue", - justifyContent: 'center', - padding: 40 + alignItems: 'stretch', + justifyContent: "center", + backgroundColor: 'lightblue', }, textfield: { margin: 2, + width: 300, + alignSelf: "center" }, + button: { marginTop: 15, margin: 50 diff --git a/salamander-app/screens/VerifyPasswordScreen.js b/salamander-app/screens/VerifyPasswordScreen.js index 75e0b91c4380306c880b866d1dd5b93a1cfb2e16..68e965d0a7ea0ed6749ca9146627772131f26ed3 100644 --- a/salamander-app/screens/VerifyPasswordScreen.js +++ b/salamander-app/screens/VerifyPasswordScreen.js @@ -1,9 +1,11 @@ import React, { useState } from 'react' -import { StyleSheet, Text, View, ScrollView, KeyboardAvoidingView } from 'react-native' +import { StyleSheet, Text, ScrollView, KeyboardAvoidingView } from 'react-native' import { Appbar } from 'react-native-paper'; import { TextInput } from 'react-native-paper'; -import MyButton from '../components/MyButton'; +import CustomButton from '../components/CustomButton'; import APIKit from '../APIkit' +import EditUserHeader from '../components/EditUserHeader'; + const VerifyPasswordScreen = ({ route, navigation }) => { @@ -35,8 +37,7 @@ const VerifyPasswordScreen = ({ route, navigation }) => { return ( <ScrollView keyboardShouldPersistTaps='handled'> <KeyboardAvoidingView behavior='padding' style={{ flex: 1, alignItems: 'stretch'}}> - <Appbar.Header style={{justifyContent: "space-between", flexDirection: "row" }}> - </Appbar.Header> + <EditUserHeader source={require('../assets/images/ninaMiniLogo.png')}/> <Text style={styles.title}> Please verify your password @@ -53,13 +54,13 @@ const VerifyPasswordScreen = ({ route, navigation }) => { value={password} onSubmitEditing={verifyPassword} /> - <MyButton + <CustomButton style={styles.button} title="Confirm" mode="contained" onPress={() => verifyPassword()} /> - <MyButton + <CustomButton style={styles.button} title="Cancel" mode="outlined"