Add container pickup notification

This commit is contained in:
Maarten 2024-08-20 16:54:52 +02:00
parent 8167a693a2
commit 2dc735ed92
4 changed files with 124 additions and 122 deletions

View file

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { SafeAreaView, ScrollView, StyleSheet, Switch, TouchableOpacity, } from 'react-native'; import { SafeAreaView, ScrollView, StyleSheet, Switch, TouchableOpacity } from 'react-native';
import { useNavigation } from '@react-navigation/native'; import { useNavigation, NavigationProp } from '@react-navigation/native';
import { DateTimePickerAndroid, DateTimePickerEvent } from '@react-native-community/datetimepicker'; import { DateTimePickerAndroid, DateTimePickerEvent } from '@react-native-community/datetimepicker';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -16,65 +16,94 @@ import { store } from '@/src/store/store';
import { setSession } from '@/src/store/dataStore'; import { setSession } from '@/src/store/dataStore';
import { ThemedIcon } from '@/src/components/themed/ThemedIcon'; import { ThemedIcon } from '@/src/components/themed/ThemedIcon';
interface NotificationType {
key: 'dayBefore' | 'sameDay' | 'pickup';
label: string;
defaultTime: string;
minTime?: string;
maxTime?: string;
}
interface NotificationsState {
[ key: string ]: {
enabled: boolean;
time: string;
};
}
export default function CategoryScreen() { export default function CategoryScreen() {
const colorScheme = useColorScheme() ?? 'light'; const colorScheme = useColorScheme() ?? 'light';
const navigation = useNavigation(); const navigation = useNavigation<NavigationProp<any>>();
const { token } = useToken(); const { token } = useToken();
const { t } = useTranslation(); const { t } = useTranslation();
const session = useSelector( (state: any) => state.data.session ); const session = useSelector( (state: any) => state.data.session );
const [ sessionSet, setSessionSet ] = useState( false ); const [ sessionSet, setSessionSet ] = useState( false );
const [ isDayBeforeEnabled, setIsDayBeforeEnabled ] = useState( true ); const notificationTypes: NotificationType[] = [
const [ dayBefore, setDayBefore ] = useState( '19:30' ); {
key: 'dayBefore',
label: t( "day-before" ),
defaultTime: '19:30',
minTime: '16:00',
},
{
key: 'sameDay',
label: t( "same-day" ),
defaultTime: '08:00',
maxTime: '09:00',
},
{
key: 'pickup',
label: t( "pickup" ),
defaultTime: '17:30',
minTime: '16:00',
},
];
const [ isSameDayEnabled, setIsSameDayEnabled ] = useState( false ); const [ notifications, setNotifications ] = useState<NotificationsState>(
const [ sameDay, setSameDay ] = useState( '08:00' ); notificationTypes.reduce( (acc, type) => {
acc[ type.key ] = { enabled: true, time: type.defaultTime };
return acc;
}, {} as NotificationsState )
);
let currentEdit = ''; let currentEdit: keyof NotificationsState = 'dayBefore';
// Set page title // Set page title
useEffect( () => { useEffect( () => {
// Set page title navigation.setOptions( { title: t( "notifications" ) } );
navigation.setOptions( { title: ( t( "notifications" ) ) } );
}, [] ); }, [] );
// Set session data // Set session data
useEffect( () => { useEffect( () => {
if (!sessionSet) { if (!sessionSet) {
if (session.notifications.dayBefore === 'off') { const newNotifications = { ...notifications };
setIsDayBeforeEnabled( false );
} else {
setIsDayBeforeEnabled( true );
setDayBefore( session.notifications.dayBefore );
}
if (session.notifications.sameDay === 'off') { notificationTypes.forEach( (type) => {
setIsSameDayEnabled( false ); const sessionTime = session.notifications[ type.key ];
} else { if (sessionTime === 'off') {
setIsSameDayEnabled( true ); newNotifications[ type.key ].enabled = false;
setSameDay( session.notifications.sameDay ); } else {
} newNotifications[ type.key ].enabled = true;
newNotifications[ type.key ].time = sessionTime;
}
} );
setNotifications( newNotifications );
setSessionSet( true );
} }
setSessionSet( true );
}, [ session ] ); }, [ session ] );
// Update session when something changes // Update session when something changes
useEffect( () => { useEffect( () => {
updateSession(); updateSession();
}, [ isSameDayEnabled, sameDay, isDayBeforeEnabled, dayBefore ] ); }, [ notifications ] );
// Open time picker // Open time picker
const selectTime = (type: string) => { const selectTime = (typeKey: keyof NotificationsState) => {
currentEdit = type; currentEdit = typeKey;
const time = new Date( `1970-01-01T${notifications[ typeKey ].time}` );
let time;
if (type === 'dayBefore') {
time = new Date( `1970-01-01T${dayBefore}` );
} else {
time = new Date( `1970-01-01T${sameDay}` );
}
if (time) { if (time) {
DateTimePickerAndroid.open( { DateTimePickerAndroid.open( {
@ -86,128 +115,104 @@ export default function CategoryScreen() {
negativeButton: { label: t( "close" ) }, negativeButton: { label: t( "close" ) },
} ); } );
} }
} };
// Set selected time // Set selected time
const onChange = (event: DateTimePickerEvent, selectedDate?: Date) => { const onChange = (event: DateTimePickerEvent, selectedDate?: Date) => {
if (selectedDate) { if (selectedDate) {
// Format to time string
const hours = selectedDate.getHours().toString().padStart( 2, '0' ); const hours = selectedDate.getHours().toString().padStart( 2, '0' );
const minutes = selectedDate.getMinutes().toString().padStart( 2, '0' ); const minutes = selectedDate.getMinutes().toString().padStart( 2, '0' );
const timeString = `${hours}:${minutes}`; const timeString = `${hours}:${minutes}`;
if (currentEdit === 'dayBefore') { const notification = notificationTypes.find( nt => nt.key === currentEdit )!;
const minDate = new Date( `1970-01-01T16:00` );
if (notification.minTime) {
const minDate = new Date( `1970-01-01T${notification.minTime}` );
if (minDate > selectedDate) { if (minDate > selectedDate) {
Message.error( t( "notifications-before-16-00" ) ); Message.error( t( "notifications-before-16-00" ) );
return; return;
} }
} else { } else if (notification.minTime) {
const minDate = new Date( `1970-01-01T09:00` ); const maxDate = new Date( `1970-01-01T${notification.minTime}` );
if (minDate < selectedDate) { if (maxDate < selectedDate) {
Message.error( t( "notifications-after-09-00" ) ); Message.error( t( "notifications-after-09-00" ) );
return; return;
} }
} }
if (currentEdit === 'dayBefore') {
setDayBefore( timeString ); setNotifications( (prev) => ( {
} else { ...prev,
setSameDay( timeString ) [ currentEdit ]: { ...prev[ currentEdit ], time: timeString }
} } ) );
} }
}; };
const toggleDate = (type: string) => { // Enable/disable date
if (type === 'dayBefore') { const toggleDate = (typeKey: keyof NotificationsState) => {
setIsDayBeforeEnabled( !isDayBeforeEnabled ) setNotifications( (prev) => ( {
} else { ...prev,
setIsSameDayEnabled( !isSameDayEnabled ) [ typeKey ]: { ...prev[ typeKey ], enabled: !prev[ typeKey ].enabled }
} } ) );
} };
// Update session data in API
const updateSession = () => { const updateSession = () => {
if (!sessionSet) { if (!sessionSet) return;
return;
}
const postData = { const postData: { token: string; [ key: string ]: string } = {
token: token, token: token!,
notification_day_before: isDayBeforeEnabled ? dayBefore : 'off',
notification_same_day: isSameDayEnabled ? sameDay : 'off',
}; };
notificationTypes.forEach( (type) => {
postData[ `notification_${convertCase( type.key )}` ] = notifications[ type.key ].enabled ? notifications[ type.key ].time : 'off';
} );
Request.post( 'sessions/update', postData ).then( (response) => { Request.post( 'sessions/update', postData ).then( (response) => {
if (response.success) { if (response.success) {
store.dispatch( setSession( response.session ) ); store.dispatch( setSession( response.session ) );
} else { } else {
Message.error( t( "something-went-wrong" ) ); Message.error( t( "something-went-wrong" ) );
} }
} ) } );
};
// Convert camel case to snake case
const convertCase = (camelCaseString: string) => {
return camelCaseString
.replace( /([A-Z])/g, '_$1' ) // Insert an underscore before each uppercase letter
.toLowerCase();
} }
return ( return (
<SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background }}> <SafeAreaView style={{ flex: 1, backgroundColor: Colors[ colorScheme ].background }}>
<ScrollView style={styles.container}> <ScrollView style={styles.container}>
<ThemedView style={styles.listContainer}> <ThemedView style={styles.listContainer}>
<ThemedView style={styles.listItem}> {notificationTypes.map( (type) => (
<ThemedView style={styles.listTitle}> <ThemedView key={type.key} style={styles.listItem}>
<Switch <ThemedView style={styles.listTitle}>
trackColor={{ false: '#767577', true: Colors[ colorScheme ].tint }} <Switch
thumbColor={'#fff'} trackColor={{ false: '#767577', true: Colors[ colorScheme ].tint }}
value={isDayBeforeEnabled} thumbColor={'#fff'}
style={styles.listSwitch} value={notifications[ type.key ].enabled}
onValueChange={() => toggleDate( 'dayBefore' )} style={styles.listSwitch}
/> onValueChange={() => toggleDate( type.key )}
<ThemedText type="defaultSemiBold">{t( "day-before" )}</ThemedText> />
</ThemedView> <ThemedText type="defaultSemiBold">{type.label}</ThemedText>
</ThemedView>
{isDayBeforeEnabled ? {notifications[ type.key ].enabled ? (
( <TouchableOpacity style={styles.listEdit} onPress={() => selectTime( type.key )}>
<TouchableOpacity style={styles.listEdit} onPress={() => selectTime( 'dayBefore' )}> <ThemedText style={styles.listEditText}>{t( "at" )} {notifications[ type.key ].time}</ThemedText>
<ThemedText style={styles.listEditText}>{t( "at" )} {dayBefore}</ThemedText>
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/> <ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity> </TouchableOpacity>
) : ) : (
(
<ThemedText style={styles.listEdit}>
<ThemedText style={styles.listEditText}>{t( "off" )}</ThemedText>
</ThemedText>
)
}
</ThemedView>
<ThemedView style={styles.listItem}>
<ThemedView style={styles.listTitle}>
<Switch
trackColor={{ false: '#767577', true: Colors[ colorScheme ].tint }}
thumbColor={'#fff'}
value={isSameDayEnabled}
style={styles.listSwitch}
onValueChange={() => toggleDate( 'sameDay' )}
/>
<ThemedText type="defaultSemiBold">{t( "same-day" )}</ThemedText>
</ThemedView>
{isSameDayEnabled ?
(
<TouchableOpacity style={styles.listEdit} onPress={() => selectTime( 'sameDay' )}>
<ThemedText style={styles.listEditText}>{t( "at" )} {sameDay}</ThemedText>
<ThemedIcon size={18} name="chevron-forward" style={styles.listEditIcon}/>
</TouchableOpacity>
) :
(
<ThemedView style={styles.listEdit}> <ThemedView style={styles.listEdit}>
<ThemedText style={styles.listEditText}>{t( "off" )}</ThemedText> <ThemedText style={styles.listEditText}>{t( "off" )}</ThemedText>
</ThemedView> </ThemedView>
) )}
} </ThemedView>
) )}
</ThemedView>
</ThemedView> </ThemedView>
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
@ -218,9 +223,6 @@ const styles = StyleSheet.create( {
container: { container: {
padding: 25, padding: 25,
}, },
htmlContainer: {
paddingBottom: 50,
},
listContainer: { listContainer: {
paddingBottom: 10 paddingBottom: 10
}, },
@ -236,9 +238,6 @@ const styles = StyleSheet.create( {
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomColor: '#f2f2f2', borderBottomColor: '#f2f2f2',
}, },
listIcon: {
marginRight: 15,
},
listTitle: { listTitle: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
@ -260,4 +259,4 @@ const styles = StyleSheet.create( {
listEditIcon: { listEditIcon: {
marginLeft: 10, marginLeft: 10,
}, },
} ) } );

View file

@ -86,10 +86,11 @@
} }
}, },
"choose": "Choose", "choose": "Choose",
"notifications-before-16-00": "Meldingen voor 16:00 worden niet ondersteund", "notifications-before-16-00": "Notifications before 16:00 are not supported",
"notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund", "notifications-after-09-00": "Notifications after 09:00 are not supported",
"day-before": "A day before", "day-before": "A day before",
"same-day": "At the same day", "same-day": "At the same day",
"pickup": "Pickup container",
"off": "Off", "off": "Off",
"at": "at", "at": "at",
"internet": { "internet": {

View file

@ -90,6 +90,7 @@
"notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund", "notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund",
"day-before": "Dag van te voren", "day-before": "Dag van te voren",
"same-day": "Op de ophaaldag", "same-day": "Op de ophaaldag",
"pickup": "Kliko ophalen",
"off": "Uit", "off": "Uit",
"at": "Om", "at": "Om",
"internet": { "internet": {

View file

@ -23,6 +23,7 @@ const dataStore = createSlice( {
notifications: { notifications: {
dayBefore: 'off', dayBefore: 'off',
sameDay: 'off', sameDay: 'off',
pickup: 'off',
}, },
}, },
reloadCalendar: true, reloadCalendar: true,