import React, { useRef } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Switch } from 'react-native'; import { Controller, Control, useWatch } from 'react-hook-form'; import { TaskFormData } from '@/types'; import { useSettings } from '@/theme'; import DateTimeInput from '@/components/DateTimeInput'; import { WheelTimePicker } from '@/components/WheelTimePicker'; import Svg, { Path, Circle } from 'react-native-svg'; import { format } from 'date-fns'; interface DateTimePickerComponentProps { control: Control; } export function DateTimePickerComponent({ control }: DateTimePickerComponentProps) { const { theme } = useSettings(); const [picker, setPicker] = React.useState<'date' | 'time' | 'endTime' | null>(null); const dateRef = useRef<((value: Date | null) => void) | null>(null); const timeRef = useRef<((value: string) => void) | null>(null); const endTimeRef = useRef<((value: string) => void) | null>(null); const allDay = useWatch({ control, name: 'allDay' }) ?? false; const dueDate = useWatch({ control, name: 'dueDate' }) ?? null; const startTime = useWatch({ control, name: 'dueTime' }) ?? ''; const endTime = useWatch({ control, name: 'endTime' }) ?? ''; const endTimeInvalid = startTime !== '' && endTime !== '' && endTime <= startTime; const setDateValue = (value: Date | null) => dateRef.current?.(value); const setTimeValue = (value: string) => timeRef.current?.(value); const setEndTimeValue = (value: string) => endTimeRef.current?.(value); const handlePickerDismiss = () => setPicker(null); const renderTimeButton = ( fieldName: 'dueTime' | 'endTime', ref: React.MutableRefObject<((value: string) => void) | null>, placeholder: string, onPress: () => void ) => ( { ref.current = field.onChange; return ( {field.value ? formatTime12(field.value) : placeholder} {field.value ? ( { if (fieldName === 'dueTime') { field.onChange(''); endTimeRef.current?.(''); } else { field.onChange(''); } }} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }} > ) : null} ); }} /> ); return ( Date & Time { dateRef.current = field.onChange; return ( setPicker('date')} activeOpacity={0.8} > {field.value ? format(field.value, 'MMM d, yyyy') : 'Due Date'} {field.value ? ( setDateValue(null)} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }} > ) : null} ); }} /> ( All Day { field.onChange(value); if (value) { timeRef.current?.(''); endTimeRef.current?.(''); } }} /> )} /> {!allDay && ( <> {renderTimeButton('dueTime', timeRef, 'Start Time', () => setPicker('time'))} {renderTimeButton('endTime', endTimeRef, 'End Time', () => setPicker('endTime'))} {endTimeInvalid && ( {endTime === startTime ? 'The end time is the same as the start time.' : 'The end time is before the start time.'} )} )} { if (selectedDate) { setDateValue(selectedDate); } }} onDismiss={handlePickerDismiss} /> { if (picker === 'endTime') { setEndTimeValue(time); } else { setTimeValue(time); } handlePickerDismiss(); }} onDismiss={handlePickerDismiss} /> ); } function formatTime12(time: string): string { const [hours, minutes] = time.split(':').map(Number); if (Number.isNaN(hours) || Number.isNaN(minutes)) return time; const period = hours >= 12 ? 'PM' : 'AM'; const h = hours % 12 === 0 ? 12 : hours % 12; return `${h}:${String(minutes).padStart(2, '0')} ${period}`; } const styles = StyleSheet.create({ container: { gap: 8, }, label: { fontSize: 14, fontWeight: '600', }, dateRow: { flexDirection: 'row', alignItems: 'center', }, allDayRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 14, }, allDayLabel: { fontSize: 15, fontWeight: '500', }, timeRow: { flexDirection: 'row', alignItems: 'center', gap: 8, }, pickerButton: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: 8, paddingVertical: 14, paddingHorizontal: 12, borderRadius: 12, borderWidth: 1, minHeight: 52, }, pickerText: { fontSize: 15, flex: 1, flexShrink: 1, }, pickerTextFilled: { fontWeight: '500', }, clearButton: { padding: 4, }, warningRow: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingVertical: 8, paddingHorizontal: 12, borderRadius: 10, borderWidth: 1, }, warningText: { fontSize: 13, fontWeight: '500', flex: 1, }, });