Kliko/app/(tabs)/settings.tsx
2024-08-13 08:55:25 +02:00

357 lines
13 KiB
TypeScript

import React, { useEffect, useRef, useState } from 'react';
import {
StyleSheet,
ScrollView,
SafeAreaView,
StatusBar,
TouchableOpacity,
Alert, Image,
} from 'react-native';
import { useRouter } from 'expo-router';
import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { BottomSheet, BottomSheetRefType } from 'react-native-select-bottom-list';
import { ThemedText } from '@/lib/components/ThemedText';
import { ThemedView } from '@/lib/components/ThemedView';
import { Colors } from '@/lib/constants/Colors';
import { useColorScheme } from '@/lib/hooks/useColorScheme';
import { useToken } from '@/lib/context/AppProvider';
import { Message } from '@/lib/services/message';
import { Request } from '@/lib/services/request';
import CustomModal from '@/lib/components/EditModal';
import { store } from '@/lib/store/store';
import { setSession, setReloadCalendar } from '@/lib/store/dataStore';
import { ThemedIcon } from '@/lib/components/ThemedIcon';
import List from '@/lib/components/List';
export default function SettingsScreen() {
const colorScheme = useColorScheme() ?? 'light';
const { token, setToken } = useToken();
const { t, i18n } = useTranslation();
const session = useSelector( (state: any) => state.data.session );
const router = useRouter();
// 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 );
// Language
const [ language, setLanguage ] = useState( 'nl' );
const sheetRef = useRef<BottomSheetRefType>( null );
useEffect( () => {
setSessionData( session );
}, [ 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 );
// Language
setLanguage( session.language );
}
// Handle save settings
const handleSave = (inputValues: Record<string, string>) => {
let postData: any = { token: token };
if (inputValues.name) {
postData[ 'name' ] = inputValues.name;
}
let addressChanged = false;
if (inputValues.zipcode) {
postData[ 'zipcode' ] = inputValues.zipcode;
addressChanged = true;
}
if (inputValues.houseNumber) {
postData[ 'houseNumber' ] = inputValues.houseNumber;
addressChanged = true;
}
if (inputValues.language) {
postData[ 'language' ] = inputValues.language;
}
Request.post( 'sessions/update', postData )
.then( (response) => {
if (response.success) {
setSessionData( response.session );
// Save to store
store.dispatch( setSession( response.session ) )
store.dispatch( setReloadCalendar( addressChanged ) )
Message.success( t( "saved" ) )
} else {
Message.error( response.message );
}
} );
};
const openLanguageSelect = () => {
sheetRef.current?.open();
}
const changeLanguage = (lang: string) => {
sheetRef.current?.close();
i18n.changeLanguage( lang ).then( () => {
setLanguage( lang );
handleSave( { language: lang } );
} );
}
// Remove session data and logout
const logout = () => {
Alert.alert( t( "logout" ), t( "are-you-sure" ), [
{
text: t( "cancel" ),
style: 'cancel',
},
{
text: t( "ja" ),
onPress: () => {
Request.post( 'sessions/delete' ).then( (response) => {
if (!response.success) {
Message.success( t( "logged-out" ) );
setToken( null );
router.replace( '/(onboarding)/start' );
} else {
Message.error( t( "something-went-wrong" ) )
}
} )
}
},
] );
}
return (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background }}>
<ThemedView style={styles.container}>
<ScrollView>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">{t( "settings" )}</ThemedText>
</ThemedView>
<ThemedView style={styles.listContainer}>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<ThemedIcon name="person-outline" size={20} style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">{t( "name" )}</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit} onPress={() => setNameModalVisible( true )}>
<ThemedText style={styles.listEditText}>{name}</ThemedText>
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<ThemedIcon size={20} name="trail-sign-outline" style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">{t( "address" )}</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit} onPress={() => setAddressModalVisible( true )}>
<ThemedText style={styles.listEditText}>{street} {houseNumber}. {city}</ThemedText>
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<ThemedIcon size={20} name="notifications-outline" style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">{t( "notifications" )}</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit} onPress={() => router.push( '/(settings)/notifications' )}>
<ThemedText style={styles.listEditText}>{t( "change" )}</ThemedText>
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<ThemedIcon size={20} name="language-outline" style={styles.listIcon}/>
<ThemedText type="defaultSemiBold">{t( "language" )}</ThemedText>
</ThemedView>
<TouchableOpacity style={styles.listEdit} onPress={openLanguageSelect}>
<ThemedText style={styles.listEditText}>{t( "languages." + language )}</ThemedText>
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
</ThemedView>
</ThemedView>
<ThemedText>
<TouchableOpacity onPress={logout}>
<ThemedText type="defaultSemiBold" style={styles.logout}>
{t( "logout" )}
</ThemedText>
</TouchableOpacity>
</ThemedText>
</ScrollView>
</ThemedView>
<CustomModal
title={t( "modal.name.title" )}
visible={nameModalVisible}
onClose={() => setNameModalVisible( false )}
onSave={handleSave}
fields={[
{
name: 'name',
placeholder: t( "modal.name.your-name" ),
defaultValue: name,
},
]}
/>
<CustomModal
title={t( "modal.address.title" )}
visible={addressModalVisible}
onClose={() => setAddressModalVisible( false )}
onSave={handleSave}
fields={[
{
name: 'zipcode',
title: t( "modal.address.zipcode" ),
placeholder: t( "modal.address.your-zipcode" ),
defaultValue: zipcode,
},
{
name: 'houseNumber',
title: t( "modal.address.house-number" ),
placeholder: t( "modal.address.your-house-number" ),
defaultValue: houseNumber,
},
]}
/>
<BottomSheet ref={sheetRef} presentationStyle={'overFullScreen'}>
<ThemedView>
<List
data={[
{
name: t( "languages.nl" ),
key: "nl",
},
{
name: t( "languages.en" ),
key: "en",
}
]}
viewStyle={styles.languagesList}
renderItem={(item: any, index: any) => (
<ThemedView>
{item.key === language ?
(
<TouchableOpacity style={styles.languagesListItem} key={index} onPress={() => changeLanguage( item.key )}>
<ThemedText type="defaultSemiBold">{item.name}</ThemedText>
<ThemedIcon name="checkmark" size={18}/>
</TouchableOpacity>
) : (
<TouchableOpacity style={styles.languagesListItem} key={index} onPress={() => changeLanguage( item.key )}>
<ThemedText type="default">{item.name}</ThemedText>
</TouchableOpacity>
)
}
</ThemedView>
)}
/>
</ThemedView>
</BottomSheet>
</SafeAreaView>
);
}
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,
},
languagesList: {
display: 'flex',
flexDirection: 'column',
padding: 25,
},
languagesListItem: {
display: 'flex',
gap: 8,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingBottom: 15,
marginBottom: 15,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
}
} );