From fe82b69997639c76bf95df3e3df7f026b00e3cf4 Mon Sep 17 00:00:00 2001 From: Maarten Date: Thu, 8 Aug 2024 13:13:39 +0200 Subject: [PATCH] Edit name + address for session --- app/(tabs)/index.tsx | 5 +- app/(tabs)/settings.tsx | 290 +++++++++++++++++++++++++++++++++++---- app/index.tsx | 3 +- components/EditModal.tsx | 148 ++++++++++++++++++++ components/HelloWave.tsx | 37 ----- constants/Colors.ts | 2 + expo-env.d.ts | 2 +- services/message.tsx | 2 + 8 files changed, 419 insertions(+), 70 deletions(-) create mode 100644 components/EditModal.tsx delete mode 100644 components/HelloWave.tsx diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index ff85f5e..63268d0 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,5 +1,6 @@ import React, {useEffect, useState} from 'react'; import {StyleSheet, ScrollView, SafeAreaView, View, StatusBar, TouchableOpacity, Image} from 'react-native'; +// @ts-ignore import CalendarPicker from 'react-native-calendar-picker'; import Ionicons from '@expo/vector-icons/Ionicons'; @@ -10,9 +11,11 @@ import {useColorScheme} from '@/hooks/useColorScheme'; import {useToken} from '@/context/AppProvider'; import {Request} from '@/services/request'; import List from '@/components/List'; +import { useIsFocused } from '@react-navigation/core'; export default function HomeScreen() { const colorScheme = useColorScheme() ?? 'light'; + const isFocused = useIsFocused(); const {token, isLoading} = useToken(); const [name, setName] = useState(' '); // Default empty space to prevent layout shifting const [dates, setDates] = useState([]); @@ -42,7 +45,7 @@ export default function HomeScreen() { } }) } - }, [token]); + }, [isFocused]); return ( diff --git a/app/(tabs)/settings.tsx b/app/(tabs)/settings.tsx index d1b6d49..4e83b58 100644 --- a/app/(tabs)/settings.tsx +++ b/app/(tabs)/settings.tsx @@ -1,36 +1,266 @@ -import {StyleSheet, ScrollView, SafeAreaView, View, StatusBar} from 'react-native'; +import React, { useEffect, useState } from 'react'; +import { + StyleSheet, + ScrollView, + SafeAreaView, + StatusBar, + TouchableOpacity, + Alert, + TextInput, +} from 'react-native'; +import { useRouter } from 'expo-router'; +import Ionicons from '@expo/vector-icons/Ionicons'; -import {ThemedText} from '@/components/ThemedText'; -import {ThemedView} from '@/components/ThemedView'; -import {Colors} from '@/constants/Colors'; -import {useColorScheme} from '@/hooks/useColorScheme'; -import React from 'react'; +import { ThemedText } from '@/components/ThemedText'; +import { ThemedView } from '@/components/ThemedView'; +import { Colors } from '@/constants/Colors'; +import { useColorScheme } from '@/hooks/useColorScheme'; +import { useToken } from '@/context/AppProvider'; +import { Message } from '@/services/message'; +import { Request } from '@/services/request'; +import CustomModal from '@/components/EditModal'; +import { err } from 'react-native-svg'; export default function SettingsScreen() { - const colorScheme = useColorScheme() ?? 'light'; + const colorScheme = useColorScheme() ?? 'light'; + const { token, isLoading } = useToken(); + const router = useRouter(); - return ( - - - - - Instellingen - - - - - ); + // Name + const [ name, setName ] = useState( '' ); + const [ nameModalVisible, setNameModalVisible ] = useState( false ); + + // Address + const [ zipcode, setZipcode ] = React.useState( '6715GA' ); + const [ houseNumber, setHouseNumber ] = React.useState( '3' ); + const [ street, setStreet ] = React.useState( '3' ); + const [ city, setCity ] = React.useState( '3' ); + const [ addressModalVisible, setAddressModalVisible ] = useState( false ); + + useEffect( () => { + // Load current session + if (token) { + Request.post( 'sessions/get', { token: token } ).then( (response) => { + if (response.success) { + const { session } = response; + + setSessionData( session ); + } + } ) + } + }, [] ); + + // Set session data in view + const setSessionData = (session: any) => { + // Name + setName( session.name ) + + // Address + setZipcode( session.address.zipcode ); + setHouseNumber( session.address.houseNumber ); + setStreet( session.address.street ); + setCity( session.address.city ); + } + + // Handle + const handleSave = (inputValues: Record) => { + let postData: any = {token: token}; + + if (inputValues.name) { + postData[ 'name' ] = inputValues.name; + } + + if (inputValues.zipcode) { + postData[ 'zipcode' ] = inputValues.zipcode; + } + + if (inputValues.houseNumber) { + postData[ 'houseNumber' ] = inputValues.houseNumber; + } + + Request.post( 'sessions/update', postData ) + .then( (response) => { + console.log('save', response); + + if (response.success) { + setSessionData( response.session ); + + Message.success( 'Opgeslagen!' ) + } else { + Message.error( response.message ); + } + } ) + .catch((error) => { + console.log('error', error); + }) + }; + + const logout = () => { + Alert.alert( 'Uitloggen', 'Weet je het zeker?', [ + { + text: 'Annuleren', + style: 'cancel', + }, + { + text: 'Ja', + onPress: () => { + Request.post( 'sessions/delete' ).then( (response) => { + console.log( 'sessions delete', response ); + if (!response.success) { + Message.success( 'Je bent uitgelogd' ) + + router.replace( '/(onboarding)/start' ); + } else { + Message.error( 'Er is iets mis gegaan. Probeer het later opnieuw!' ) + } + } ) + } + }, + ] ); + } + + return ( + + + + + Instellingen + + + + + + + Naam + + + setNameModalVisible( true )}> + {name} + + + + + + + + Adres + + + setAddressModalVisible( true )}> + {street} {houseNumber}. {city} + + + + + + + + Notificaties + + + + + + + + + + + + Uitloggen + + + + + + + setNameModalVisible( false )} + onSave={handleSave} + fields={[ + { + name: 'name', + placeholder: 'Je naam', + defaultValue: name, + }, + ]} + /> + + setAddressModalVisible( false )} + onSave={handleSave} + fields={[ + { + name: 'zipcode', + title: 'Postcode', + placeholder: 'Je postcode', + defaultValue: zipcode, + }, + { + name: 'houseNumber', + title: 'Huisnummer', + placeholder: 'Je huis nummer', + defaultValue: houseNumber, + }, + ]} + /> + + ); } -const styles = StyleSheet.create({ - container: { - padding: 25, - marginTop: StatusBar.currentHeight, - }, - titleContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - paddingBottom: 8, - }, -}); +const styles = StyleSheet.create( { + container: { + padding: 25, + marginTop: StatusBar.currentHeight, + }, + titleContainer: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + paddingBottom: 8, + }, + listContainer: { + marginTop: 30, + paddingBottom: 10 + }, + listItem: { + flex: 1, + display: 'flex', + gap: 8, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingBottom: 20, + marginBottom: 20, + borderBottomWidth: 1, + borderBottomColor: '#f2f2f2', + }, + listIcon: { + marginRight: 15, + }, + listTitle: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + }, + listEdit: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'flex-end', + textAlign: 'right', + }, + listEditText: { + fontWeight: '300', + }, + listEditIcon: { + marginLeft: 10, + }, + logout: { + color: Colors.red, + }, +} ); diff --git a/app/index.tsx b/app/index.tsx index d621ab7..d1c96bb 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -21,7 +21,8 @@ export default function OnboardStartScreen() { const fetchData = async () => { const response = await Request.post('sessions/get', { token: token }); if (response.success) { - router.replace('/(tabs)'); + // @ts-ignore + router.replace('/(tabs)/settings'); } else { router.replace('/(onboarding)/start'); } diff --git a/components/EditModal.tsx b/components/EditModal.tsx new file mode 100644 index 0000000..a86f1ce --- /dev/null +++ b/components/EditModal.tsx @@ -0,0 +1,148 @@ +import React, { useEffect, useState } from 'react'; +import { + TextInput, + TouchableOpacity, + StyleSheet, +} from 'react-native'; +import Modal from "react-native-modal"; + +import { Colors } from '@/constants/Colors'; +import { ThemedView } from '@/components/ThemedView'; +import { ThemedText } from '@/components/ThemedText'; +import { useColorScheme } from '@/hooks/useColorScheme'; + +interface Field { + name: string; + title?: string; + placeholder: string; + defaultValue?: string; +} + +interface EditModalProps { + title?: string; + visible: boolean; + onClose?: () => void; + onSave: (inputValues: Record) => void; + fields: Field[]; +} + +const CustomModal: React.FC = ({ title, visible, onClose, onSave, fields }) => { + const colorScheme = useColorScheme() ?? 'light'; + const [ inputValues, setInputValues ] = useState>( {} ); + + useEffect( () => { + const initialValues: Record = {}; + fields.forEach( field => { + if (field.defaultValue) { + initialValues[ field.name ] = field.defaultValue; + } + } ); + setInputValues( initialValues ); + }, [ fields ] ); + + const handleInputChange = (name: string, value: string) => { + setInputValues( { ...inputValues, [ name ]: value } ); + }; + + const handleSave = () => { + onSave( inputValues ); + if (onClose) onClose(); + }; + + return ( + + + {title ? title : 'Pas je gegevens aan:'} + + {fields.map( (field, index) => ( + + {field.title && {field.title}} + handleInputChange( field.name, text )} + value={inputValues[ field.name ] || ''} + /> + + + ) )} + + + { + } )}> + Annuleren + + + + Opslaan + + + + + ); +}; + +const styles = StyleSheet.create( { + view: { + margin: 25, + borderRadius: 10, + paddingTop: 30, + paddingBottom: 30, + paddingLeft: 35, + paddingRight: 35, + alignItems: 'center', + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.25, + shadowRadius: 4, + elevation: 5, + }, + text: { + marginBottom: 15, + textAlign: 'center', + }, + inputContainer: { + width: '100%', + marginBottom: 15, + }, + inputTitle: { + fontSize: 16, + marginBottom: 5, + }, + input: { + height: 40, + borderColor: 'gray', + borderWidth: 1, + width: '100%', + paddingHorizontal: 10, + borderRadius: 5, + }, + buttonContainer: { + marginTop: 20, + flexDirection: 'row', + justifyContent: 'space-between', + width: '100%', + }, + buttonClose: { + color: Colors.red, + paddingTop: 8, + }, + buttonSave: { + backgroundColor: Colors.tint, + borderRadius: 5, + paddingTop: 10, + paddingBottom: 10, + paddingLeft: 40, + paddingRight: 40, + }, + textStyle: { + color: 'white', + fontWeight: 'bold', + textAlign: 'center', + }, +} ); + +export default CustomModal; \ No newline at end of file diff --git a/components/HelloWave.tsx b/components/HelloWave.tsx deleted file mode 100644 index f4b6ea5..0000000 --- a/components/HelloWave.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { StyleSheet } from 'react-native'; -import Animated, { - useSharedValue, - useAnimatedStyle, - withTiming, - withRepeat, - withSequence, -} from 'react-native-reanimated'; - -import { ThemedText } from '@/components/ThemedText'; - -export function HelloWave() { - const rotationAnimation = useSharedValue(0); - - rotationAnimation.value = withRepeat( - withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })), - 4 // Run the animation 4 times - ); - - const animatedStyle = useAnimatedStyle(() => ({ - transform: [{ rotate: `${rotationAnimation.value}deg` }], - })); - - return ( - - 👋 - - ); -} - -const styles = StyleSheet.create({ - text: { - fontSize: 28, - lineHeight: 32, - marginTop: -6, - }, -}); diff --git a/constants/Colors.ts b/constants/Colors.ts index c0c10f6..4f257de 100644 --- a/constants/Colors.ts +++ b/constants/Colors.ts @@ -8,8 +8,10 @@ const tintColorDark = '#76af2a'; export const Colors = { // Base + tint: tintColorLight, black: '#000', white: '#fff', + red: '#ff0000', light: { // Main diff --git a/expo-env.d.ts b/expo-env.d.ts index 0920e9f..5411fdd 100644 --- a/expo-env.d.ts +++ b/expo-env.d.ts @@ -1,3 +1,3 @@ -declare module 'react-native-calendar-picker'; +/// // NOTE: This file should not be edited and should be in your git ignore \ No newline at end of file diff --git a/services/message.tsx b/services/message.tsx index a307301..009def2 100644 --- a/services/message.tsx +++ b/services/message.tsx @@ -39,6 +39,8 @@ export class Message { type: type, text1: message, position: 'bottom', + visibilityTime: 2000, + autoHide: true, }) }