import { useCallback, useRef } from 'react' import { Briefcase, Plus, X } from 'lucide-react' import type { PackingState } from './usePackingListPanel' import { bagFillPct, bagLoadSummary, packedWeight, perPersonLoads } from './packingListPanel.helpers' import { BagCard } from './PackingListPanelBagCard' import { PackingWeightSummary } from './PackingWeightSummary' import { COMPOSER, composerConfirm, useDismissOnOutside } from './packingPopoverStyles' const kgOrG = (grams: number) => (grams >= 1000 ? `${(grams / 1000).toFixed(1)} kg` : `${grams} g`) /** * The bags beside the list, as a card like the categories: a tinted head band * with the add action, one block per bag between hairlines, what sits in no bag * as a quiet last row, and the total in a matching foot band. */ export function BagSidebar(S: PackingState) { const { t, bags, items, tripId, tripMembers, canEdit, currentUserId, handleDeleteBag, handleUpdateBag, handleSetBagMembers, showAddBag, setShowAddBag, newBagName, setNewBagName, handleCreateBag, unassignedWeightGrams, serverWeightsFresh, } = S // The ITEM LISTS still describe what you are carrying — an item someone shared // with you stays in your list, but they are the one bringing it (#1767). The // WEIGHTS no longer do: a bag's load is the bag's, whoever packed it (#2191). const { myItems, bagItemsOf, bagWeightOf, heaviestBagWeight, unassigned, unassignedWeight, totalWeight } = bagLoadSummary(bags, items, currentUserId, unassignedWeightGrams, serverWeightsFresh) const hairline = (first: boolean): React.CSSProperties => ({ borderTop: first ? 'none' : '1px solid var(--border-faint)' }) const composerRef = useRef(null) const closeComposer = useCallback(() => { setShowAddBag(false); setNewBagName('') }, [setShowAddBag, setNewBagName]) useDismissOnOutside(composerRef, showAddBag, closeComposer) return (
{t('packing.bags')} {canEdit && !showAddBag && ( )}
{canEdit && showAddBag && (
setNewBagName(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') void handleCreateBag(); if (e.key === 'Escape') closeComposer() }} placeholder={t('packing.bagName')} style={{ flex: 1, minWidth: 0, padding: '5px 0', border: 'none', fontSize: 'calc(12.5px * var(--fs-scale-body, 1))', fontWeight: 500, fontFamily: 'inherit', outline: 'none', color: 'var(--text-primary)', background: 'transparent' }} />
)}
{bags.map((bag, index) => { const bagItems = bagItemsOf(bag) const weight = bagWeightOf(bag) const pct = bagFillPct(weight, bag.weight_limit_grams, heaviestBagWeight) return (
handleDeleteBag(bag.id)} onUpdate={handleUpdateBag} onSetMembers={handleSetBagMembers} t={t} compact />
) })} {/* Whatever sits in no bag. Shown whenever there is weight to account for, even with no visible items: the total counts it either way (#2191). */} {(unassigned.length > 0 || unassignedWeight > 0) && (
{t('packing.noBag')} {unassigned.length} {kgOrG(unassignedWeight)}
)}
) }