Edit name + address for session

This commit is contained in:
Maarten 2024-08-08 13:13:39 +02:00
parent f9a78a5c37
commit fe82b69997
8 changed files with 419 additions and 70 deletions

View file

@ -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<any | null>([]);
@ -42,7 +45,7 @@ export default function HomeScreen() {
}
})
}
}, [token]);
}, [isFocused]);
return (
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>

View file

@ -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 (
<SafeAreaView style={{flex: 1, backgroundColor: Colors[colorScheme].background,}}>
<View style={styles.container}>
<ScrollView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Instellingen</ThemedText>
</ThemedView>
</ScrollView>
</View>
</SafeAreaView>
);
// 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<string, string>) => {
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 (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background }}>
<ThemedView style={styles.container}>
<ScrollView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Instellingen</ThemedText>
</ThemedView>
<ThemedView style={styles.listContainer}>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<Ionicons size={20} name="person-outline" style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">Naam</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit} onPress={() => setNameModalVisible( true )}>
<ThemedText style={styles.listEditText}>{name}</ThemedText>
<Ionicons size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<Ionicons size={20} name="trail-sign-outline" style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">Adres</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit} onPress={() => setAddressModalVisible( true )}>
<ThemedText style={styles.listEditText}>{street} {houseNumber}. {city}</ThemedText>
<Ionicons size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<Ionicons size={20} name="notifications-outline" style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">Notificaties</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit}>
<Ionicons size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
</ThemedView>
<ThemedText>
<TouchableOpacity onPress={logout}>
<ThemedText type="defaultSemiBold" style={styles.logout}>
Uitloggen
</ThemedText>
</TouchableOpacity>
</ThemedText>
</ScrollView>
</ThemedView>
<CustomModal
title="Naam wijzigen"
visible={nameModalVisible}
onClose={() => setNameModalVisible( false )}
onSave={handleSave}
fields={[
{
name: 'name',
placeholder: 'Je naam',
defaultValue: name,
},
]}
/>
<CustomModal
title="Adres wijzigen"
visible={addressModalVisible}
onClose={() => setAddressModalVisible( false )}
onSave={handleSave}
fields={[
{
name: 'zipcode',
title: 'Postcode',
placeholder: 'Je postcode',
defaultValue: zipcode,
},
{
name: 'houseNumber',
title: 'Huisnummer',
placeholder: 'Je huis nummer',
defaultValue: houseNumber,
},
]}
/>
</SafeAreaView>
);
}
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,
},
} );

View file

@ -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');
}

148
components/EditModal.tsx Normal file
View file

@ -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<string, string>) => void;
fields: Field[];
}
const CustomModal: React.FC<EditModalProps> = ({ title, visible, onClose, onSave, fields }) => {
const colorScheme = useColorScheme() ?? 'light';
const [ inputValues, setInputValues ] = useState<Record<string, string>>( {} );
useEffect( () => {
const initialValues: Record<string, string> = {};
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 (
<Modal isVisible={visible}>
<ThemedView style={{ ...styles.view, backgroundColor: Colors[ colorScheme ].background }}>
<ThemedText style={styles.text}>{title ? title : 'Pas je gegevens aan:'}</ThemedText>
{fields.map( (field, index) => (
<ThemedView key={index} style={styles.inputContainer}>
{field.title && <ThemedText style={styles.inputTitle}>{field.title}</ThemedText>}
<TextInput
style={styles.input}
placeholder={field.placeholder}
onChangeText={(text) => handleInputChange( field.name, text )}
value={inputValues[ field.name ] || ''}
/>
</ThemedView>
) )}
<ThemedView style={styles.buttonContainer}>
<TouchableOpacity onPress={onClose || ( () => {
} )}>
<ThemedText style={[ styles.textStyle, styles.buttonClose ]}>Annuleren</ThemedText>
</TouchableOpacity>
<TouchableOpacity style={styles.buttonSave} onPress={handleSave}>
<ThemedText style={styles.textStyle}>Opslaan</ThemedText>
</TouchableOpacity>
</ThemedView>
</ThemedView>
</Modal>
);
};
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;

View file

@ -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 (
<Animated.View style={animatedStyle}>
<ThemedText style={styles.text}>👋</ThemedText>
</Animated.View>
);
}
const styles = StyleSheet.create({
text: {
fontSize: 28,
lineHeight: 32,
marginTop: -6,
},
});

View file

@ -8,8 +8,10 @@ const tintColorDark = '#76af2a';
export const Colors = {
// Base
tint: tintColorLight,
black: '#000',
white: '#fff',
red: '#ff0000',
light: {
// Main

2
expo-env.d.ts vendored
View file

@ -1,3 +1,3 @@
declare module 'react-native-calendar-picker';
/// <reference types="expo/types" />
// NOTE: This file should not be edited and should be in your git ignore

View file

@ -39,6 +39,8 @@ export class Message {
type: type,
text1: message,
position: 'bottom',
visibilityTime: 2000,
autoHide: true,
})
}