feat: add date picker as first field in measurement form

This commit is contained in:
Eddy de Vink 2026-06-27 23:02:51 +02:00
commit ad108b3b16
4 changed files with 66 additions and 2 deletions

View file

@ -23,7 +23,8 @@
}, },
"plugins": [ "plugins": [
"expo-sqlite", "expo-sqlite",
"expo-secure-store" "expo-secure-store",
"@react-native-community/datetimepicker"
] ]
} }
} }

24
package-lock.json generated
View file

@ -8,6 +8,7 @@
"name": "weegschaal-app", "name": "weegschaal-app",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@react-native-community/datetimepicker": "8.4.4",
"@react-navigation/native": "^7.3.4", "@react-navigation/native": "^7.3.4",
"@react-navigation/native-stack": "^7.17.6", "@react-navigation/native-stack": "^7.17.6",
"expo": "~54.0.0", "expo": "~54.0.0",
@ -2780,6 +2781,29 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"node_modules/@react-native-community/datetimepicker": {
"version": "8.4.4",
"resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-8.4.4.tgz",
"integrity": "sha512-bc4ZixEHxZC9/qf5gbdYvIJiLZ5CLmEsC3j+Yhe1D1KC/3QhaIfGDVdUcid0PdlSoGOSEq4VlB93AWyetEyBSQ==",
"license": "MIT",
"dependencies": {
"invariant": "^2.2.4"
},
"peerDependencies": {
"expo": ">=52.0.0",
"react": "*",
"react-native": "*",
"react-native-windows": "*"
},
"peerDependenciesMeta": {
"expo": {
"optional": true
},
"react-native-windows": {
"optional": true
}
}
},
"node_modules/@react-native/assets-registry": { "node_modules/@react-native/assets-registry": {
"version": "0.81.5", "version": "0.81.5",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz",

View file

@ -3,6 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"main": "index.ts", "main": "index.ts",
"dependencies": { "dependencies": {
"@react-native-community/datetimepicker": "8.4.4",
"@react-navigation/native": "^7.3.4", "@react-navigation/native": "^7.3.4",
"@react-navigation/native-stack": "^7.17.6", "@react-navigation/native-stack": "^7.17.6",
"expo": "~54.0.0", "expo": "~54.0.0",

View file

@ -1,5 +1,6 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { View, Text, TextInput, TouchableOpacity, StyleSheet, KeyboardAvoidingView, Platform, ScrollView } from 'react-native' import { View, Text, TextInput, TouchableOpacity, StyleSheet, KeyboardAvoidingView, Platform, ScrollView } from 'react-native'
import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker'
import { Measurement } from '../types' import { Measurement } from '../types'
import { generateId } from '../utils/uuid' import { generateId } from '../utils/uuid'
@ -20,6 +21,11 @@ const fields: { key: keyof Measurement; label: string; placeholder: string; keyb
] ]
export default function MeasurementForm({ onSubmit, initialValues }: Props) { export default function MeasurementForm({ onSubmit, initialValues }: Props) {
const [pickerOpen, setPickerOpen] = useState(false)
const [measurementDate, setMeasurementDate] = useState<Date>(() => {
if (initialValues?.measuredAt) return new Date(initialValues.measuredAt)
return new Date()
})
const [values, setValues] = useState<Record<string, string>>(() => { const [values, setValues] = useState<Record<string, string>>(() => {
const init: Record<string, string> = {} const init: Record<string, string> = {}
for (const f of fields) { for (const f of fields) {
@ -40,7 +46,7 @@ export default function MeasurementForm({ onSubmit, initialValues }: Props) {
muscleMass: parseFloat(values.muscleMass) || 0, muscleMass: parseFloat(values.muscleMass) || 0,
visceralFat: parseInt(values.visceralFat, 10) || 0, visceralFat: parseInt(values.visceralFat, 10) || 0,
bmr: parseFloat(values.bmr) || 0, bmr: parseFloat(values.bmr) || 0,
measuredAt: now, measuredAt: measurementDate.toISOString(),
createdAt: now, createdAt: now,
updatedAt: now, updatedAt: now,
syncStatus: 'local', syncStatus: 'local',
@ -52,9 +58,39 @@ export default function MeasurementForm({ onSubmit, initialValues }: Props) {
setValues(prev => ({ ...prev, [key]: value })) setValues(prev => ({ ...prev, [key]: value }))
} }
const onDateChange = (_event: DateTimePickerEvent, selectedDate?: Date) => {
setPickerOpen(false)
if (selectedDate) {
setMeasurementDate(selectedDate)
}
}
return ( return (
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={styles.container}> <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={styles.container}>
<ScrollView contentContainerStyle={styles.scroll}> <ScrollView contentContainerStyle={styles.scroll}>
<View style={styles.field}>
<Text style={styles.label}>Datum</Text>
<TouchableOpacity style={styles.dateButton} onPress={() => setPickerOpen(true)}>
<Text style={styles.dateButtonText}>
{measurementDate.toLocaleDateString('nl-NL', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
})}
</Text>
</TouchableOpacity>
</View>
{pickerOpen && (
<DateTimePicker
value={measurementDate}
mode="date"
display="default"
onChange={onDateChange}
/>
)}
{fields.map(f => ( {fields.map(f => (
<View key={f.key} style={styles.field}> <View key={f.key} style={styles.field}>
<Text style={styles.label}>{f.label}</Text> <Text style={styles.label}>{f.label}</Text>
@ -82,6 +118,8 @@ const styles = StyleSheet.create({
field: { marginBottom: 12 }, field: { marginBottom: 12 },
label: { fontSize: 14, fontWeight: '600', color: '#333', marginBottom: 4 }, label: { fontSize: 14, fontWeight: '600', color: '#333', marginBottom: 4 },
input: { backgroundColor: '#fff', borderRadius: 8, padding: 12, fontSize: 16, borderWidth: 1, borderColor: '#ddd' }, input: { backgroundColor: '#fff', borderRadius: 8, padding: 12, fontSize: 16, borderWidth: 1, borderColor: '#ddd' },
dateButton: { backgroundColor: '#fff', borderRadius: 8, padding: 12, borderWidth: 1, borderColor: '#ddd' },
dateButtonText: { fontSize: 16, color: '#333' },
button: { backgroundColor: '#4CAF50', padding: 16, borderRadius: 8, alignItems: 'center', marginTop: 8 }, button: { backgroundColor: '#4CAF50', padding: 16, borderRadius: 8, alignItems: 'center', marginTop: 8 },
buttonText: { color: '#fff', fontSize: 16, fontWeight: '700' }, buttonText: { color: '#fff', fontSize: 16, fontWeight: '700' },
}) })