diff --git a/app/(settings)/notifications.tsx b/app/(settings)/notifications.tsx index 652b1b6..d74d5aa 100644 --- a/app/(settings)/notifications.tsx +++ b/app/(settings)/notifications.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; -import { SafeAreaView, ScrollView, StyleSheet, Switch, TouchableOpacity, } from 'react-native'; -import { useNavigation } from '@react-navigation/native'; +import { SafeAreaView, ScrollView, StyleSheet, Switch, TouchableOpacity } from 'react-native'; +import { useNavigation, NavigationProp } from '@react-navigation/native'; import { DateTimePickerAndroid, DateTimePickerEvent } from '@react-native-community/datetimepicker'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; @@ -16,65 +16,94 @@ import { store } from '@/src/store/store'; import { setSession } from '@/src/store/dataStore'; 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() { const colorScheme = useColorScheme() ?? 'light'; - const navigation = useNavigation(); + const navigation = useNavigation>(); const { token } = useToken(); const { t } = useTranslation(); const session = useSelector( (state: any) => state.data.session ); const [ sessionSet, setSessionSet ] = useState( false ); - const [ isDayBeforeEnabled, setIsDayBeforeEnabled ] = useState( true ); - const [ dayBefore, setDayBefore ] = useState( '19:30' ); + const notificationTypes: NotificationType[] = [ + { + 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 [ sameDay, setSameDay ] = useState( '08:00' ); + const [ notifications, setNotifications ] = useState( + 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 useEffect( () => { - // Set page title - navigation.setOptions( { title: ( t( "notifications" ) ) } ); + navigation.setOptions( { title: t( "notifications" ) } ); }, [] ); // Set session data useEffect( () => { if (!sessionSet) { - if (session.notifications.dayBefore === 'off') { - setIsDayBeforeEnabled( false ); - } else { - setIsDayBeforeEnabled( true ); - setDayBefore( session.notifications.dayBefore ); - } + const newNotifications = { ...notifications }; - if (session.notifications.sameDay === 'off') { - setIsSameDayEnabled( false ); - } else { - setIsSameDayEnabled( true ); - setSameDay( session.notifications.sameDay ); - } + notificationTypes.forEach( (type) => { + const sessionTime = session.notifications[ type.key ]; + if (sessionTime === 'off') { + newNotifications[ type.key ].enabled = false; + } else { + newNotifications[ type.key ].enabled = true; + newNotifications[ type.key ].time = sessionTime; + } + } ); + + setNotifications( newNotifications ); + setSessionSet( true ); } - - setSessionSet( true ); }, [ session ] ); // Update session when something changes useEffect( () => { updateSession(); - }, [ isSameDayEnabled, sameDay, isDayBeforeEnabled, dayBefore ] ); + }, [ notifications ] ); // Open time picker - const selectTime = (type: string) => { - currentEdit = type; - - let time; - if (type === 'dayBefore') { - time = new Date( `1970-01-01T${dayBefore}` ); - } else { - time = new Date( `1970-01-01T${sameDay}` ); - } + const selectTime = (typeKey: keyof NotificationsState) => { + currentEdit = typeKey; + const time = new Date( `1970-01-01T${notifications[ typeKey ].time}` ); if (time) { DateTimePickerAndroid.open( { @@ -86,128 +115,104 @@ export default function CategoryScreen() { negativeButton: { label: t( "close" ) }, } ); } - } + }; // Set selected time const onChange = (event: DateTimePickerEvent, selectedDate?: Date) => { if (selectedDate) { - // Format to time string const hours = selectedDate.getHours().toString().padStart( 2, '0' ); const minutes = selectedDate.getMinutes().toString().padStart( 2, '0' ); const timeString = `${hours}:${minutes}`; - if (currentEdit === 'dayBefore') { - const minDate = new Date( `1970-01-01T16:00` ); + const notification = notificationTypes.find( nt => nt.key === currentEdit )!; + + if (notification.minTime) { + const minDate = new Date( `1970-01-01T${notification.minTime}` ); if (minDate > selectedDate) { Message.error( t( "notifications-before-16-00" ) ); - return; } - } else { - const minDate = new Date( `1970-01-01T09:00` ); - if (minDate < selectedDate) { + } else if (notification.minTime) { + const maxDate = new Date( `1970-01-01T${notification.minTime}` ); + if (maxDate < selectedDate) { Message.error( t( "notifications-after-09-00" ) ); - return; } } - if (currentEdit === 'dayBefore') { - setDayBefore( timeString ); - } else { - setSameDay( timeString ) - } + + setNotifications( (prev) => ( { + ...prev, + [ currentEdit ]: { ...prev[ currentEdit ], time: timeString } + } ) ); } }; - const toggleDate = (type: string) => { - if (type === 'dayBefore') { - setIsDayBeforeEnabled( !isDayBeforeEnabled ) - } else { - setIsSameDayEnabled( !isSameDayEnabled ) - } - } + // Enable/disable date + const toggleDate = (typeKey: keyof NotificationsState) => { + setNotifications( (prev) => ( { + ...prev, + [ typeKey ]: { ...prev[ typeKey ], enabled: !prev[ typeKey ].enabled } + } ) ); + }; + // Update session data in API const updateSession = () => { - if (!sessionSet) { - return; - } + if (!sessionSet) return; - const postData = { - token: token, - notification_day_before: isDayBeforeEnabled ? dayBefore : 'off', - notification_same_day: isSameDayEnabled ? sameDay : 'off', + const postData: { token: string; [ key: string ]: string } = { + token: token!, }; + notificationTypes.forEach( (type) => { + postData[ `notification_${convertCase( type.key )}` ] = notifications[ type.key ].enabled ? notifications[ type.key ].time : 'off'; + } ); + Request.post( 'sessions/update', postData ).then( (response) => { if (response.success) { store.dispatch( setSession( response.session ) ); } else { 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 ( - - - toggleDate( 'dayBefore' )} - /> - {t( "day-before" )} - + {notificationTypes.map( (type) => ( + + + toggleDate( type.key )} + /> + {type.label} + - {isDayBeforeEnabled ? - ( - selectTime( 'dayBefore' )}> - {t( "at" )} {dayBefore} + {notifications[ type.key ].enabled ? ( + selectTime( type.key )}> + {t( "at" )} {notifications[ type.key ].time} - ) : - ( - - {t( "off" )} - - ) - } - - - - - - - toggleDate( 'sameDay' )} - /> - {t( "same-day" )} - - - {isSameDayEnabled ? - ( - selectTime( 'sameDay' )}> - {t( "at" )} {sameDay} - - - ) : - ( + ) : ( {t( "off" )} - ) - } - - + )} + + ) )} @@ -218,9 +223,6 @@ const styles = StyleSheet.create( { container: { padding: 25, }, - htmlContainer: { - paddingBottom: 50, - }, listContainer: { paddingBottom: 10 }, @@ -236,9 +238,6 @@ const styles = StyleSheet.create( { borderBottomWidth: 1, borderBottomColor: '#f2f2f2', }, - listIcon: { - marginRight: 15, - }, listTitle: { flex: 1, flexDirection: 'row', @@ -260,4 +259,4 @@ const styles = StyleSheet.create( { listEditIcon: { marginLeft: 10, }, -} ) \ No newline at end of file +} ); diff --git a/assets/languages/en.json b/assets/languages/en.json index 1f44fc2..dec878c 100644 --- a/assets/languages/en.json +++ b/assets/languages/en.json @@ -86,10 +86,11 @@ } }, "choose": "Choose", - "notifications-before-16-00": "Meldingen voor 16:00 worden niet ondersteund", - "notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund", + "notifications-before-16-00": "Notifications before 16:00 are not supported", + "notifications-after-09-00": "Notifications after 09:00 are not supported", "day-before": "A day before", "same-day": "At the same day", + "pickup": "Pickup container", "off": "Off", "at": "at", "internet": { diff --git a/assets/languages/nl.json b/assets/languages/nl.json index 232ce61..bb209ee 100644 --- a/assets/languages/nl.json +++ b/assets/languages/nl.json @@ -90,6 +90,7 @@ "notifications-after-09-00": "Meldingen na 09:00 worden niet ondersteund", "day-before": "Dag van te voren", "same-day": "Op de ophaaldag", + "pickup": "Kliko ophalen", "off": "Uit", "at": "Om", "internet": { diff --git a/src/store/dataStore.tsx b/src/store/dataStore.tsx index dba6c8a..8eab651 100644 --- a/src/store/dataStore.tsx +++ b/src/store/dataStore.tsx @@ -23,6 +23,7 @@ const dataStore = createSlice( { notifications: { dayBefore: 'off', sameDay: 'off', + pickup: 'off', }, }, reloadCalendar: true,