feat: tap measurement in history to edit or delete

This commit is contained in:
Eddy de Vink 2026-06-28 00:41:34 +02:00
commit 4130bdd697
4 changed files with 104 additions and 22 deletions

View file

@ -1,12 +1,12 @@
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'
import { Measurement } from '../types'
type Props = { measurement: Measurement }
type Props = { measurement: Measurement; onPress: () => void }
export default function MeasurementRow({ measurement }: Props) {
export default function MeasurementRow({ measurement, onPress }: Props) {
return (
<View style={styles.row}>
<TouchableOpacity style={styles.row} onPress={onPress} activeOpacity={0.7}>
<View style={styles.left}>
<Text style={styles.date}>
{new Date(measurement.measuredAt).toLocaleDateString('nl-NL', {
@ -27,7 +27,7 @@ export default function MeasurementRow({ measurement }: Props) {
<Text style={styles.weight}>{measurement.weight.toFixed(1)} kg</Text>
<Text style={styles.detail}>BMI {measurement.bmi.toFixed(1)}</Text>
</View>
</View>
</TouchableOpacity>
)
}

View file

@ -77,3 +77,7 @@ export async function getUnsyncedMeasurements(): Promise<Measurement[]> {
)
return rows as Measurement[]
}
export async function deleteMeasurement(id: string): Promise<void> {
await db!.runAsync('DELETE FROM measurements WHERE id = ?', [id])
}

View file

@ -1,11 +1,13 @@
import React, { useCallback, useState } from 'react'
import { View, FlatList, StyleSheet, Text, RefreshControl } from 'react-native'
import { View, FlatList, StyleSheet, Text, RefreshControl, Alert } from 'react-native'
import { useFocusEffect } from '@react-navigation/native'
import { initDatabase, getAllMeasurements } from '../database/db'
import { initDatabase, getAllMeasurements, deleteMeasurement } from '../database/db'
import { Measurement } from '../types'
import MeasurementRow from '../components/MeasurementRow'
export default function HistoryScreen() {
type Props = { navigation: any }
export default function HistoryScreen({ navigation }: Props) {
const [measurements, setMeasurements] = useState<Measurement[]>([])
const [refreshing, setRefreshing] = useState(false)
@ -27,13 +29,59 @@ export default function HistoryScreen() {
setRefreshing(false)
}, [load])
const handlePress = (m: Measurement) => {
const date = new Date(m.measuredAt).toLocaleDateString('nl-NL')
Alert.alert(
date,
`${m.weight.toFixed(1)} kg · BMI ${m.bmi.toFixed(1)}`,
[
{ text: 'Annuleren', style: 'cancel' },
{
text: 'Wijzigen',
onPress: () => navigation.navigate('NewMeasurement', { measurement: m }),
},
{
text: 'Verwijderen',
style: 'destructive',
onPress: () => confirmDelete(m),
},
]
)
}
const confirmDelete = (m: Measurement) => {
const date = new Date(m.measuredAt).toLocaleDateString('nl-NL')
Alert.alert(
'Verwijderen?',
`Meting van ${date} definitief verwijderen?`,
[
{ text: 'Annuleren', style: 'cancel' },
{
text: 'Ja, verwijderen',
style: 'destructive',
onPress: async () => {
await initDatabase()
await deleteMeasurement(m.id)
try {
const { syncAll } = await import('../sync/syncService')
await syncAll()
} catch {}
load()
},
},
]
)
}
return (
<View style={styles.container}>
<Text style={styles.count}>{measurements.length} metingen</Text>
<FlatList
data={measurements}
keyExtractor={item => item.id}
renderItem={({ item }) => <MeasurementRow measurement={item} />}
renderItem={({ item }) => (
<MeasurementRow measurement={item} onPress={() => handlePress(item)} />
)}
contentContainerStyle={measurements.length === 0 ? styles.empty : undefined}
ListEmptyComponent={<Text style={styles.emptyText}>Nog geen metingen</Text>}
refreshControl={

View file

@ -1,34 +1,64 @@
import React, { useCallback, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { View, Text, Alert } from 'react-native'
import { useFocusEffect } from '@react-navigation/native'
import MeasurementForm from '../components/MeasurementForm'
import { Measurement } from '../types'
import { initDatabase, insertMeasurement, getLatestMeasurement, getMeasurementByDate, upsertMeasurement } from '../database/db'
import {
initDatabase,
insertMeasurement,
getLatestMeasurement,
getMeasurementByDate,
upsertMeasurement,
} from '../database/db'
type Props = {
navigation: any
route: any
}
export default function NewMeasurementScreen({ navigation }: Props) {
export default function NewMeasurementScreen({ navigation, route }: Props) {
const editing = route.params?.measurement as Measurement | undefined
const [latest, setLatest] = useState<Partial<Measurement> | undefined>(undefined)
const [loaded, setLoaded] = useState(false)
useFocusEffect(
useCallback(() => {
let cancelled = false
const load = async () => {
await initDatabase()
if (editing) {
if (!cancelled) {
setLatest(editing)
setLoaded(true)
}
} else {
const m = await getLatestMeasurement()
if (!cancelled) {
setLatest(m || {})
setLoaded(true)
}
}
}
load()
return () => { cancelled = true }
}, [])
}, [editing])
)
useEffect(() => {
if (editing) {
navigation.setOptions({ title: 'Meting wijzigen' })
}
}, [editing, navigation])
const handleSubmit = async (m: Measurement) => {
await initDatabase()
if (editing) {
m.id = editing.id
m.createdAt = editing.createdAt
await upsertMeasurement(m)
doSync()
return
}
const existing = await getMeasurementByDate(m.measuredAt)
if (existing) {
Alert.alert(
@ -36,11 +66,7 @@ export default function NewMeasurementScreen({ navigation }: Props) {
`Er bestaat al een meting van ${new Date(m.measuredAt).toLocaleDateString('nl-NL')}. Overschrijven?`,
[
{ text: 'Annuleren', style: 'cancel' },
{
text: 'Overschrijven',
style: 'destructive',
onPress: () => doSave(m, existing.id),
},
{ text: 'Overschrijven', style: 'destructive', onPress: () => doSave(m, existing.id) },
]
)
return
@ -55,6 +81,10 @@ export default function NewMeasurementScreen({ navigation }: Props) {
} else {
await insertMeasurement(m)
}
doSync()
}
const doSync = async () => {
try {
const { syncAll } = await import('../sync/syncService')
await syncAll()
@ -68,7 +98,7 @@ export default function NewMeasurementScreen({ navigation }: Props) {
}
}
if (latest === undefined) {
if (!loaded) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5f5f5' }}>
<Text style={{ color: '#999' }}>Laden...</Text>