feat(#16): support custom placement when selecting other
All checks were successful
Luggage List Build / build-web (push) Successful in 40s
Luggage List Build / build-android (push) Successful in 7m26s
Luggage List Build / release (push) Successful in 15s

This commit is contained in:
2026-04-18 21:41:18 +02:00
parent 354a13e9a9
commit 063e5090ed
3 changed files with 52 additions and 5 deletions

View File

@@ -14,7 +14,7 @@ import TripsTab from './tabs/TripsTab';
import ItemsTab from './tabs/ItemsTab'; import ItemsTab from './tabs/ItemsTab';
import CheckupTab from './tabs/CheckupTab'; import CheckupTab from './tabs/CheckupTab';
import HistoryTab from './tabs/HistoryTab'; import HistoryTab from './tabs/HistoryTab';
import { emptyData, STORAGE_KEY } from './constants'; import { emptyData, ITEM_PLACEMENTS, STORAGE_KEY } from './constants';
import { findBestTripId, makeId, parseYMD, todayYMD } from './utils/date'; import { findBestTripId, makeId, parseYMD, todayYMD } from './utils/date';
import { styles } from './styles'; import { styles } from './styles';
@@ -34,6 +34,7 @@ const emptyItemForm = () => ({
category: '', category: '',
status: 'unpacked', status: 'unpacked',
placement: 'suitcase', placement: 'suitcase',
placementCustom: '',
lentTo: '', lentTo: '',
imageUri: '', imageUri: '',
imageQuality: 'balanced', imageQuality: 'balanced',
@@ -43,6 +44,7 @@ const emptyItemForm = () => ({
const emptyCheckupNoForm = () => ({ const emptyCheckupNoForm = () => ({
status: 'unpacked', status: 'unpacked',
placement: 'suitcase', placement: 'suitcase',
placementCustom: '',
lentTo: '', lentTo: '',
updateMasterList: false, updateMasterList: false,
}); });
@@ -430,13 +432,17 @@ export default function AppRoot() {
} }
function openEditItemModal(item) { function openEditItemModal(item) {
const existingPlacement = item.placement || 'suitcase';
const hasPresetPlacement = ITEM_PLACEMENTS.includes(existingPlacement);
setItemForm({ setItemForm({
id: item.id, id: item.id,
name: item.name || '', name: item.name || '',
description: item.description || '', description: item.description || '',
category: item.category || '', category: item.category || '',
status: item.status || 'unpacked', status: item.status || 'unpacked',
placement: item.placement || 'suitcase', placement: hasPresetPlacement ? existingPlacement : 'other',
placementCustom: hasPresetPlacement || existingPlacement === 'other' ? '' : existingPlacement,
lentTo: item.lentTo || '', lentTo: item.lentTo || '',
imageUri: item.imageUri || '', imageUri: item.imageUri || '',
imageQuality: item.imageQuality || 'balanced', imageQuality: item.imageQuality || 'balanced',
@@ -456,6 +462,12 @@ export default function AppRoot() {
return; return;
} }
const resolvedPlacement = itemForm.placement === 'other' ? itemForm.placementCustom.trim() : itemForm.placement;
if (!resolvedPlacement) {
showAlert('Missing location', 'Please enter a custom location for "other".');
return;
}
const now = Date.now(); const now = Date.now();
setData((prev) => { setData((prev) => {
@@ -467,7 +479,7 @@ export default function AppRoot() {
description: itemForm.description.trim(), description: itemForm.description.trim(),
category: itemForm.category.trim(), category: itemForm.category.trim(),
status: itemForm.status, status: itemForm.status,
placement: itemForm.placement, placement: resolvedPlacement,
lentTo: itemForm.status === 'lent-to' ? itemForm.lentTo.trim() : '', lentTo: itemForm.status === 'lent-to' ? itemForm.lentTo.trim() : '',
imageUri: itemForm.imageUri, imageUri: itemForm.imageUri,
imageQuality: itemForm.imageQuality, imageQuality: itemForm.imageQuality,
@@ -650,9 +662,14 @@ export default function AppRoot() {
function openCurrentCheckupNo() { function openCurrentCheckupNo() {
const entry = checkupCurrentEntry; const entry = checkupCurrentEntry;
if (!entry) return; if (!entry) return;
const existingPlacement = entry.current.placement || 'suitcase';
const hasPresetPlacement = ITEM_PLACEMENTS.includes(existingPlacement);
setCheckupNoForm({ setCheckupNoForm({
status: entry.current.status || 'unpacked', status: entry.current.status || 'unpacked',
placement: entry.current.placement || 'suitcase', placement: hasPresetPlacement ? existingPlacement : 'other',
placementCustom: hasPresetPlacement || existingPlacement === 'other' ? '' : existingPlacement,
lentTo: entry.current.lentTo || '', lentTo: entry.current.lentTo || '',
updateMasterList: false, updateMasterList: false,
}); });
@@ -663,9 +680,15 @@ export default function AppRoot() {
const entry = checkupCurrentEntry; const entry = checkupCurrentEntry;
if (!entry) return; if (!entry) return;
const resolvedPlacement = checkupNoForm.placement === 'other' ? checkupNoForm.placementCustom.trim() : checkupNoForm.placement;
if (!resolvedPlacement) {
showAlert('Missing location', 'Please enter a custom location for "other".');
return;
}
const patch = { const patch = {
status: checkupNoForm.status, status: checkupNoForm.status,
placement: checkupNoForm.placement, placement: resolvedPlacement,
lentTo: checkupNoForm.status === 'lent-to' ? checkupNoForm.lentTo.trim() : '', lentTo: checkupNoForm.status === 'lent-to' ? checkupNoForm.lentTo.trim() : '',
}; };

View File

@@ -103,6 +103,18 @@ export default function CheckupFlowModal({
/> />
</Field> </Field>
{noForm.placement === 'other' ? (
<Field label="Custom location">
<TextInput
style={styles.input}
value={noForm.placementCustom}
onChangeText={(v) => setNoForm((prev) => ({ ...prev, placementCustom: v }))}
placeholder="bath-kit"
placeholderTextColor="#6b7280"
/>
</Field>
) : null}
{noForm.status === 'lent-to' ? ( {noForm.status === 'lent-to' ? (
<Field label="Lent to"> <Field label="Lent to">
<TextInput <TextInput

View File

@@ -81,6 +81,18 @@ export default function ItemModal({
<ChipGroup options={ITEM_PLACEMENTS} value={itemForm.placement} onChange={(v) => updateItemForm('placement', v)} /> <ChipGroup options={ITEM_PLACEMENTS} value={itemForm.placement} onChange={(v) => updateItemForm('placement', v)} />
</Field> </Field>
{itemForm.placement === 'other' ? (
<Field label="Custom location">
<TextInput
style={styles.input}
value={itemForm.placementCustom}
onChangeText={(v) => updateItemForm('placementCustom', v)}
placeholder="bath-kit"
placeholderTextColor="#6b7280"
/>
</Field>
) : null}
{itemForm.status === 'lent-to' ? ( {itemForm.status === 'lent-to' ? (
<Field label="Lent to"> <Field label="Lent to">
<TextInput <TextInput