From d40bd6a41cc9174782303493f7df05a354156f3d Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 18 Apr 2026 14:34:05 +0200 Subject: [PATCH] feat: add history long-press delete and quick item status actions --- src/AppRoot.js | 40 ++++++++++++++++++++++++++++++++++++++ src/components/ItemCard.js | 15 +++++++++++++- src/styles.js | 25 ++++++++++++++++++++++++ src/tabs/CheckupTab.js | 2 +- src/tabs/HistoryTab.js | 29 +++++++++++++++++++++++---- src/tabs/ItemsTab.js | 18 +++++++++++++++-- 6 files changed, 121 insertions(+), 8 deletions(-) diff --git a/src/AppRoot.js b/src/AppRoot.js index 29e5c5a..e32a209 100644 --- a/src/AppRoot.js +++ b/src/AppRoot.js @@ -358,6 +358,44 @@ export default function AppRoot() { }); } + function quickSetItemStatus(itemId, status) { + if (!selectedTripId) return; + setData((prev) => { + const items = prev.itemsByTrip[selectedTripId] || []; + return { + ...prev, + itemsByTrip: { + ...prev.itemsByTrip, + [selectedTripId]: items.map((item) => + item.id === itemId + ? { + ...item, + status, + lentTo: status === 'lent-to' ? item.lentTo : '', + updatedAt: Date.now(), + } + : item + ), + }, + }; + }); + } + + function deleteCheckup(checkupId) { + if (!selectedTripId) return; + setData((prev) => { + const existing = prev.checkupsByTrip[selectedTripId] || []; + return { + ...prev, + checkupsByTrip: { + ...prev.checkupsByTrip, + [selectedTripId]: existing.filter((checkup) => checkup.id !== checkupId), + }, + }; + }); + setSelectedCheckupId((prev) => (prev === checkupId ? null : prev)); + } + function createFreshCheckupSession() { if (!selectedTripItems.length) { setCheckupSession([]); @@ -564,6 +602,7 @@ export default function AppRoot() { openAddItemModal={openAddItemModal} openEditItemModal={openEditItemModal} deleteItem={deleteItem} + quickSetItemStatus={quickSetItemStatus} /> )} @@ -584,6 +623,7 @@ export default function AppRoot() { selectedTripCheckups={selectedTripCheckups} selectedCheckupId={selectedCheckupId} setSelectedCheckupId={setSelectedCheckupId} + onDeleteCheckup={deleteCheckup} /> )} diff --git a/src/components/ItemCard.js b/src/components/ItemCard.js index 4b43003..2c18442 100644 --- a/src/components/ItemCard.js +++ b/src/components/ItemCard.js @@ -7,7 +7,10 @@ function statusAccent(status) { return STATUS_COLORS[status] || '#64748b'; } -export default function ItemCard({ item, onEdit, onDelete }) { +export default function ItemCard({ item, onEdit, onDelete, onQuickPack, onQuickUnpack }) { + const isPacked = item.status === 'packed'; + const isUnpacked = item.status === 'unpacked'; + return ( @@ -29,6 +32,16 @@ export default function ItemCard({ item, onEdit, onDelete }) { + + + + Pack + + + Unpack + + + {item.imageUri ? : null} diff --git a/src/styles.js b/src/styles.js index f87c42a..cb100b6 100644 --- a/src/styles.js +++ b/src/styles.js @@ -271,6 +271,31 @@ export const styles = StyleSheet.create({ marginTop: 2, fontSize: 13, }, + quickStatusRow: { + flexDirection: 'row', + gap: 8, + marginTop: 2, + }, + quickStatusBtn: { + paddingVertical: 6, + paddingHorizontal: 12, + borderRadius: 999, + borderWidth: 1, + borderColor: '#334155', + backgroundColor: '#0b1220', + }, + quickStatusBtnActive: { + borderColor: '#60a5fa', + backgroundColor: '#1d2a3a', + }, + quickStatusBtnText: { + color: '#cbd5e1', + fontWeight: '700', + fontSize: 12, + }, + quickStatusBtnTextActive: { + color: '#dbeafe', + }, answerRow: { marginTop: 8, diff --git a/src/tabs/CheckupTab.js b/src/tabs/CheckupTab.js index 8679d95..af6e2c6 100644 --- a/src/tabs/CheckupTab.js +++ b/src/tabs/CheckupTab.js @@ -15,7 +15,7 @@ export default function CheckupTab({ Check-Up - Restart + Check-up diff --git a/src/tabs/HistoryTab.js b/src/tabs/HistoryTab.js index 0d87f8d..d6043f8 100644 --- a/src/tabs/HistoryTab.js +++ b/src/tabs/HistoryTab.js @@ -1,8 +1,25 @@ import React from 'react'; -import { Pressable, Text, View } from 'react-native'; +import { Alert, Pressable, Text, View } from 'react-native'; import { styles } from '../styles'; -export default function HistoryTab({ selectedTrip, selectedTripCheckups, selectedCheckupId, setSelectedCheckupId }) { +export default function HistoryTab({ + selectedTrip, + selectedTripCheckups, + selectedCheckupId, + setSelectedCheckupId, + onDeleteCheckup, +}) { + function askDelete(checkup) { + Alert.alert('Delete check-up?', 'This snapshot will be removed from history.', [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Delete', + style: 'destructive', + onPress: () => onDeleteCheckup(checkup.id), + }, + ]); + } + return ( History @@ -13,13 +30,17 @@ export default function HistoryTab({ selectedTrip, selectedTripCheckups, selecte {selectedTripCheckups.map((checkup) => ( - setSelectedCheckupId((prev) => (prev === checkup.id ? null : checkup.id))}> + setSelectedCheckupId((prev) => (prev === checkup.id ? null : checkup.id))} + onLongPress={() => askDelete(checkup)} + delayLongPress={280} + > {new Date(checkup.createdAt).toLocaleString()} {checkup.snapshot.length} items · correct: {checkup.stats?.correct ?? checkup.snapshot.filter((x) => x.result === 'correct').length} · bad:{' '} {checkup.stats?.bad ?? checkup.snapshot.filter((x) => x.result === 'bad').length} - {selectedCheckupId === checkup.id ? 'Tap to collapse' : 'Tap to open'} + {selectedCheckupId === checkup.id ? 'Tap to collapse' : 'Tap to open'} · long hold to delete {selectedCheckupId === checkup.id ? ( diff --git a/src/tabs/ItemsTab.js b/src/tabs/ItemsTab.js index 21da4f3..7c2abc4 100644 --- a/src/tabs/ItemsTab.js +++ b/src/tabs/ItemsTab.js @@ -3,7 +3,14 @@ import { Pressable, Text, View } from 'react-native'; import ItemCard from '../components/ItemCard'; import { styles } from '../styles'; -export default function ItemsTab({ selectedTrip, selectedTripItems, openAddItemModal, openEditItemModal, deleteItem }) { +export default function ItemsTab({ + selectedTrip, + selectedTripItems, + openAddItemModal, + openEditItemModal, + deleteItem, + quickSetItemStatus, +}) { return ( @@ -17,7 +24,14 @@ export default function ItemsTab({ selectedTrip, selectedTripItems, openAddItemM {selectedTripItems.length === 0 && selectedTrip ? No items yet. : null} {selectedTripItems.map((item) => ( - + quickSetItemStatus(item.id, 'packed')} + onQuickUnpack={() => quickSetItemStatus(item.id, 'unpacked')} + /> ))} );