feat: Trip-specific bag selection with duration-based Carry-On vs Checked Bag auto-matching

This commit is contained in:
airent106 committed 2026-10-15 22:57:08 -06:00
1 parent be586ea386
commit 2d709cfd9b
5 files changed
+506 -70

No files matched your search

+75 -15
View File
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { BagType, PackingItem, LuggageConfig, CustomBag } from '../types';
import { sound } from '../utils/audio';
import {
@@ -11,7 +11,9 @@ import {
Settings2,
Camera,
Compass,
Tag
Tag,
Check,
Luggage
} from 'lucide-react';
interface BagOverviewProps {
@@ -19,7 +21,9 @@ interface BagOverviewProps {
selectedBag: BagType | 'all';
onSelectBag: (bag: BagType | 'all') => void;
luggageConfig: LuggageConfig;
activeTripBags: CustomBag[];
customBags: CustomBag[];
onToggleTripBag: (bagId: BagType) => void;
onEditBags: () => void;
}
@@ -46,35 +50,48 @@ export const BagOverview: React.FC<BagOverviewProps> = ({
items,
selectedBag,
onSelectBag,
luggageConfig,
activeTripBags,
customBags,
onToggleTripBag,
onEditBags,
}) => {
// Filter bags based on luggage mode if it's a default bag
const visibleBags = customBags.filter((b) => {
if (b.id === 'carry_on' && luggageConfig === 'backpack_only') return false;
if (b.id === 'checked' && luggageConfig !== 'checked_bag') return false;
return true;
});
const [showTripBagPicker, setShowTripBagPicker] = useState(false);
const visibleBags = activeTripBags;
return (
<div className="mb-6">
<div className="flex items-center justify-between mb-2 flex-wrap gap-2">
<div className="flex items-center gap-2">
<div className="flex items-center gap-1.5 sm:gap-2 flex-wrap">
<span className="font-mono text-xs uppercase font-bold text-ink tracking-wider">
LUGGAGE ALLOCATION // "WHAT GOES IN WHAT BAG"
TRIP BAGS ({visibleBags.length}/{customBags.length})
</span>
<button
type="button"
onClick={() => {
sound.playClick();
setShowTripBagPicker(!showTripBagPicker);
}}
className={`font-mono text-[11px] font-bold px-2 py-0.5 border border-ink transition-colors flex items-center gap-1 shadow-xs ${
showTripBagPicker
? 'bg-ink text-canary'
: 'bg-canary/80 hover:bg-canary text-ink'
}`}
title="Select which bags are going on this specific trip"
>
<Luggage size={12} />
<span>SELECT TRIP BAGS</span>
</button>
<button
type="button"
onClick={() => {
sound.playClick();
onEditBags();
}}
className="font-mono text-[11px] font-bold px-2 py-0.5 border border-ink bg-white hover:bg-canary text-ink transition-colors flex items-center gap-1 shadow-xs"
title="Add, rename, or reconfigure bags"
className="font-mono text-[11px] font-bold px-2 py-0.5 border border-ink bg-white hover:bg-ticket-200 text-ink transition-colors flex items-center gap-1 shadow-xs"
title="Add, rename, or reconfigure your global bag pool"
>
<Settings2 size={12} />
<span>EDIT BAGS</span>
<span>EDIT BAG POOL</span>
</button>
</div>
@@ -91,10 +108,53 @@ export const BagOverview: React.FC<BagOverviewProps> = ({
}`}
>
<Layers size={13} />
<span>VIEW ALL BAGS ({items.length})</span>
<span>VIEW ALL ({items.length})</span>
</button>
</div>
{/* Inline Trip Bag Loadout Switcher */}
{showTripBagPicker && (
<div className="mb-3 p-3 bg-ticket-100 border-2 border-ink shadow-card-hard-sm animate-in fade-in duration-100">
<div className="flex items-center justify-between mb-2">
<span className="font-mono text-[11px] font-bold uppercase text-ink">
WHICH BAGS ARE GOING ON THIS TRIP? (UNCHECKED BAGS AUTOMATICALLY MOVE ITEMS TO YOUR MAIN BAG)
</span>
</div>
<div className="flex flex-wrap gap-2">
{customBags.map((bag) => {
const isBringing = visibleBags.some((b) => b.id === bag.id);
return (
<button
type="button"
key={bag.id}
onClick={() => {
sound.playClick();
onToggleTripBag(bag.id);
}}
className={`px-2.5 py-1.5 border-2 font-mono text-xs font-bold flex items-center gap-2 transition-all ${
isBringing
? 'bg-canary-light border-ink text-ink shadow-card-hard-sm'
: 'bg-white/60 border-ink/40 text-ink/50 hover:bg-white hover:text-ink'
}`}
>
<span
className={`w-4 h-4 border border-ink flex items-center justify-center ${
isBringing ? 'bg-ink text-canary' : 'bg-white'
}`}
>
{isBringing && <Check size={11} strokeWidth={3} />}
</span>
<span>{bag.label}</span>
<span className="text-[10px] bg-ink text-ticket-100 px-1 py-0.2">
{bag.tagCode}
</span>
</button>
);
})}
</div>
</div>
)}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-2 sm:gap-3">
{visibleBags.map((b) => {
const bagItems = items.filter((i) => i.bag === b.id);