weegschaal-app/src/screens/HistoryScreen.tsx
eddy 4c34dff629 fix: sync refactor — fix 6 bugs + cache refresh na sync
- setDeletedAt update nu ook updatedAt (bug 2)
- getAllMeasurements filtert deletedAt IS NULL, nieuwe getAllMeasurementsForSync voor sync
- mergeMeasurements detecteert server deleted:true → deletedAt (bug 1)
- syncAll: pull-push split met remoteUpdatedMap, geen double-push (bug 3)
- hard delete alleen na API-succes (bug 4)
- DashboardScreen: refreshCache() na syncAll zodat UI niet op Laden blijft hangen
- deleteMeasurement() dead code verwijderd (bug 5)
- tests: 3 nieuwe testcases voor deleted → deletedAt mapping, 15/15 pass
2026-07-25 15:33:22 +02:00

113 lines
3.5 KiB
TypeScript

import React, { useCallback, useState } from 'react'
import { View, FlatList, StyleSheet, Text, RefreshControl, TouchableOpacity, Alert } from 'react-native'
import { useFocusEffect } from '@react-navigation/native'
import { initDatabase, getAllMeasurements, setDeletedAt, removeMeasurement } from '../database/db'
import { removeFromCache } from '../store/measurementStore'
import { Measurement } from '../types'
import { createApi } from '../sync/api'
import { getApiConfig } from './SettingsScreen'
import MeasurementRow from '../components/MeasurementRow'
type Props = { navigation: any }
export default function HistoryScreen({ navigation }: Props) {
const [measurements, setMeasurements] = useState<Measurement[]>([])
const [refreshing, setRefreshing] = useState(false)
const load = useCallback(async () => {
await initDatabase()
const all = await getAllMeasurements()
setMeasurements(all.filter(m => !m.deletedAt))
}, [])
useFocusEffect(
useCallback(() => {
load()
}, [load])
)
const onRefresh = useCallback(async () => {
setRefreshing(true)
await load()
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 setDeletedAt(m.id)
removeFromCache(m.id)
try {
const config = await getApiConfig()
if (config) {
await createApi(config).deleteMeasurement(m.id)
await removeMeasurement(m.id)
}
} catch {
await load()
return
}
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}
onPress={() => navigation.navigate('MeasurementDetail', { measurementId: item.id })}
/>
)}
contentContainerStyle={measurements.length === 0 ? styles.empty : undefined}
ListEmptyComponent={<Text style={styles.emptyText}>Nog geen metingen</Text>}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
/>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f5f5f5' },
count: { fontSize: 14, color: '#666', padding: 16, paddingBottom: 8 },
empty: { flex: 1, justifyContent: 'center', alignItems: 'center' },
emptyText: { fontSize: 16, color: '#999' },
})