client: long-press picker also offers quick-remove when already in cart

Fixes the rest of #70 - mara's answer: "when there are already drinks
in cart, i want to be able to remove them - so show negative numbers
there too."

Second row of -1..-5 buttons appears in the count picker only when the
long-pressed drink already has cart quantity (an empty-cart drink keeps
the original add-only picker - nothing to remove). Routed through
incLine (the qty-stepper's own clamp-at-zero-and-drop-the-line logic)
rather than addDrink's raw qty+n, so over-removing (e.g. -5 on a qty-3
line) drops the line cleanly instead of going negative - verified this
specific clamping behavior with a standalone reproduction of the logic
before trusting it. Remove buttons get the existing button.danger
styling (red), matching the app's established negative/removal
convention (Pfand-return tile, cart-line.return).

pnpm --filter client typecheck and build both clean.
This commit is contained in:
iris 2026-08-03 17:26:13 +02:00
commit 3c9fd3d55c

View file

@ -122,8 +122,14 @@ export function Sale({ config, onChangeBar }: Props) {
addDrink(d.id);
}
// Positive n adds (works on any drink, cart-empty or not). Negative n
// removes — routed through incLine rather than addDrink so it shares
// the qty-stepper's clamp-at-zero-and-drop-the-line behaviour instead
// of letting a line go negative (addDrink's raw `qty + n` would).
function pickCount(n: number) {
if (pickerDrink) addDrink(pickerDrink.id, n);
if (!pickerDrink) return;
if (n > 0) addDrink(pickerDrink.id, n);
else incLine(pickerDrink.id, n);
setPickerDrink(null);
}
@ -191,23 +197,43 @@ export function Sale({ config, onChangeBar }: Props) {
)}
</div>
{pickerDrink && (
<div class="picker-backdrop" onClick={() => setPickerDrink(null)}>
<div class="picker" onClick={e => e.stopPropagation()}>
<div class="picker-title">{pickerDrink.name}</div>
<div class="picker-grid">
{PICKER_COUNTS.map(n => (
<button key={n} class="picker-count" onClick={() => pickCount(n)}>
{n}
</button>
))}
{pickerDrink && (() => {
// #70: "when there are already drinks in cart, i want to be able
// to remove them" — the remove row only makes sense (and only
// appears) once there's cart quantity for this drink to remove;
// an empty-cart drink keeps the original add-only picker.
const cartQty = lines.find(l => l.drink_id === pickerDrink.id)?.qty ?? 0;
return (
<div class="picker-backdrop" onClick={() => setPickerDrink(null)}>
<div class="picker" onClick={e => e.stopPropagation()}>
<div class="picker-title">{pickerDrink.name}</div>
<div class="picker-grid">
{PICKER_COUNTS.map(n => (
<button key={n} class="picker-count" onClick={() => pickCount(n)}>
{n}
</button>
))}
</div>
{cartQty > 0 && (
<div class="picker-grid">
{PICKER_COUNTS.map(n => (
<button
key={-n}
class="picker-count danger"
onClick={() => pickCount(-n)}
>
{n}
</button>
))}
</div>
)}
<button class="picker-cancel" onClick={() => setPickerDrink(null)}>
Abbrechen
</button>
</div>
<button class="picker-cancel" onClick={() => setPickerDrink(null)}>
Abbrechen
</button>
</div>
</div>
)}
);
})()}
<div class="cart">
<div class="cart-items">