import React, { useEffect, useState } from 'react'; 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'; import { Colors } from '@/src/constants/Colors'; import { useColorScheme } from '@/src/hooks/useColorScheme'; import { ThemedView } from '@/src/components/themed/ThemedView'; import { ThemedText } from '@/src/components/themed/ThemedText'; import { Request } from '@/src/services/request'; import { useToken } from '@/src/context/AppProvider'; import { Message } from '@/src/services/message'; 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 { token } = useToken(); const { t } = useTranslation(); const session = useSelector( (state: any) => state.data.session ); const [ sessionSet, setSessionSet ] = useState( false ); 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 [ notifications, setNotifications ] = useState( notificationTypes.reduce( (acc, type) => { acc[ type.key ] = { enabled: true, time: type.defaultTime }; return acc; }, {} as NotificationsState ) ); let currentEdit: keyof NotificationsState = 'dayBefore'; // Set page title useEffect( () => { navigation.setOptions( { title: t( "notifications" ) } ); }, [] ); // Set session data useEffect( () => { if (!sessionSet) { const newNotifications = { ...notifications }; 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 ); } }, [ session ] ); // Update session when something changes useEffect( () => { updateSession(); }, [ notifications ] ); // Open time picker const selectTime = (typeKey: keyof NotificationsState) => { currentEdit = typeKey; const time = new Date( `1970-01-01T${notifications[ typeKey ].time}` ); if (time) { DateTimePickerAndroid.open( { value: time, onChange, mode: 'time', is24Hour: true, positiveButton: { label: t( "choose" ) }, negativeButton: { label: t( "close" ) }, } ); } }; // Set selected time const onChange = (event: DateTimePickerEvent, selectedDate?: Date) => { if (selectedDate) { const hours = selectedDate.getHours().toString().padStart( 2, '0' ); const minutes = selectedDate.getMinutes().toString().padStart( 2, '0' ); const timeString = `${hours}:${minutes}`; 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 if (notification.minTime) { const maxDate = new Date( `1970-01-01T${notification.minTime}` ); if (maxDate < selectedDate) { Message.error( t( "notifications-after-09-00" ) ); return; } } setNotifications( (prev) => ( { ...prev, [ currentEdit ]: { ...prev[ currentEdit ], time: timeString } } ) ); } }; // 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; 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 ( {notificationTypes.map( (type) => ( toggleDate( type.key )} /> {type.label} {notifications[ type.key ].enabled ? ( selectTime( type.key )}> {t( "at" )} {notifications[ type.key ].time} ) : ( {t( "off" )} )} ) )} ); } const styles = StyleSheet.create( { container: { padding: 25, }, listContainer: { paddingBottom: 10 }, listItem: { flex: 1, display: 'flex', gap: 8, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingBottom: 20, marginBottom: 20, borderBottomWidth: 1, borderBottomColor: '#f2f2f2', }, listTitle: { flex: 1, flexDirection: 'row', alignItems: 'center', }, listSwitch: { marginRight: 5, }, listEdit: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', textAlign: 'right', }, listEditText: { fontWeight: '300', }, listEditIcon: { marginLeft: 10, }, } );