feat: polish UI, fix top inset, and add check-up correctness stats
All checks were successful
Luggage List Build / build-web (push) Successful in 38s
Luggage List Build / build-android (push) Successful in 6m16s
Luggage List Build / release (push) Successful in 14s

This commit is contained in:
2026-04-18 13:23:19 +02:00
parent 30ee53fe75
commit f34ffe39c0
6 changed files with 103 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Alert, KeyboardAvoidingView, Platform, SafeAreaView, ScrollView, Text, View } from 'react-native';
import { Alert, KeyboardAvoidingView, Platform, SafeAreaView, ScrollView, StatusBar as RNStatusBar, Text, View } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as ImagePicker from 'expo-image-picker';
import { StatusBar } from 'expo-status-bar';
@@ -63,6 +63,8 @@ export default function AppRoot() {
const [selectedCheckupId, setSelectedCheckupId] = useState(null);
const topInset = Platform.OS === 'android' ? (RNStatusBar.currentHeight || 0) + 10 : 0;
const selectedTrip = useMemo(() => data.trips.find((trip) => trip.id === selectedTripId) || null, [data.trips, selectedTripId]);
const selectedTripItems = useMemo(() => {
@@ -80,6 +82,14 @@ export default function AppRoot() {
[data.trips, data.defaultTemplateTripId]
);
const checkupStats = useMemo(() => {
const total = checkupSession.length;
const correct = checkupSession.filter((entry) => entry.result === 'correct').length;
const bad = checkupSession.filter((entry) => entry.result === 'bad').length;
const pending = total - correct - bad;
return { total, correct, bad, pending };
}, [checkupSession]);
useEffect(() => {
(async () => {
try {
@@ -347,13 +357,16 @@ export default function AppRoot() {
lentTo: item.lentTo || '',
},
confirmed: false,
result: 'pending',
}));
setCheckupSession(fresh);
}
function answerCheckupYes(itemId) {
setCheckupSession((prev) => prev.map((entry) => (entry.itemId === itemId ? { ...entry, confirmed: true } : entry)));
setCheckupSession((prev) =>
prev.map((entry) => (entry.itemId === itemId ? { ...entry, confirmed: true, result: 'correct' } : entry))
);
}
function openFixModal(itemId) {
@@ -387,6 +400,7 @@ export default function AppRoot() {
...entry,
current: patch,
confirmed: true,
result: 'bad',
}
: entry
)
@@ -443,6 +457,7 @@ export default function AppRoot() {
status: entry.current.status,
placement: entry.current.placement,
lentTo: entry.current.status === 'lent-to' ? entry.current.lentTo : '',
result: entry.result || 'pending',
}));
setData((prev) => {
@@ -457,6 +472,10 @@ export default function AppRoot() {
id: makeId('checkup'),
createdAt: Date.now(),
snapshot,
stats: {
correct: snapshot.filter((entry) => entry.result === 'correct').length,
bad: snapshot.filter((entry) => entry.result === 'bad').length,
},
},
],
},
@@ -480,7 +499,7 @@ export default function AppRoot() {
if (!loaded) {
return (
<SafeAreaView style={styles.safe}>
<SafeAreaView style={[styles.safe, { paddingTop: topInset }]}>
<StatusBar style="light" translucent={false} />
<View style={styles.center}>
<Text style={styles.muted}>Loading local data...</Text>
@@ -490,7 +509,7 @@ export default function AppRoot() {
}
return (
<SafeAreaView style={styles.safe}>
<SafeAreaView style={[styles.safe, { paddingTop: topInset }]}>
<StatusBar style="light" translucent={false} />
<KeyboardAvoidingView style={styles.flex} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
@@ -500,7 +519,6 @@ export default function AppRoot() {
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
<View style={styles.statusSpacer} />
<TripPicker trips={data.trips} selectedTripId={selectedTripId} onChooseTrip={setSelectedTripId} />
{tab === 'trips' && (
@@ -534,6 +552,7 @@ export default function AppRoot() {
{tab === 'checkup' && (
<CheckupTab
checkupSession={checkupSession}
checkupStats={checkupStats}
answerCheckupYes={answerCheckupYes}
openFixModal={openFixModal}
createFreshCheckupSession={createFreshCheckupSession}