I try to make a date picker that appears when clicking on a field with an icon and the current date in string format.
I use React Native, React Hook Form and @react-native-community/datetimepicker.
By chance I found an intersting answser there on an unrelated question: https://stackoverflow.com/a/61929764/9927519
I implemented it like that:
const MyComponent = () => {
const { userData } = useContext(UserDataContext)
const [isPickerOpen, setIsPickerOpen] = useState(false)
const parsedBirthday = (userData && userData.birthday && userData.birthday.toDate()) || new Date()
const [birthday, setBirthday] = useState(parsedBirthday)
// Validation schema
const schema = yup.object({
birthday: yup.date(),
})
const { control, handleSubmit, errors } = useForm({resolver: yupResolver(schema)})
const onSubmit = async (data: any) => {
console.log(data)
}
const datePickerHandler = (selectedDate: Date) => {
const currentDate = selectedDate || birthday
if (Platform.OS === 'android') setIsPickerOpen(false)
setBirthday(currentDate)
}
const showDatePicker = () => {
setIsPickerOpen(true)
}
return (
<View style={styles.fieldContainer}>
<Text style={styles.helper}>Birthday</Text>
<TouchableHighlight activeOpacity={0.6} underlayColor="#DDDDDD" onPress={showDatePicker} style={styles.birthday}>
<>
<Icon name="calendar-edit" size={32} color={colors.black} />
<Controller
control={control}
render={({ onChange, onBlur, value }) => (
<TextInput
style={styles.birthdayText}
value={birthday.toLocaleDateString()}
editable={false}
pointerEvents="none"
onTouchStart={() => showDatePicker()}
/>
)}
name="birthdayString"
defaultValue={birthday.toLocaleDateString() || new Date().toLocaleDateString()}
/>
</>
</TouchableHighlight>
{/* Date picker */}
{isPickerOpen && (
<Controller
control={control}
render={({ onChange, onBlur, value }) => (
<>
<View>
<DateTimePicker
minimumDate={new Date(1901, 0, 1)}
maximumDate={new Date()}
value={value}
mode="date"
display="default"
onChange={(event, value) => {
datePickerHandler(value)
}}
/>
</View>
</>
)}
name="birthday"
defaultValue={birthday}
/>
)}
<Text style={styles.errorText}>{errors?.birthday}</Text>
</View>
)
This one is a bit hard due to the fact that the picker is unmounted when the values are submitted. Then, we need a TextInput component to hold the value.
I wonder if there is a better approach. I have some little concerns:
- I convert a string into a date, then into string, then I will need to convert it back into a date when submiting... Actually .toLocaleDateString will make submiting very complex. This could be an issue for internationalization.
- onTouchStart is not working with a mouse, only with touch devices. That could be an issue with chromebooks.