admin: reorder drinks per bar
This commit is contained in:
parent
02c7e9b5fd
commit
4904ff0032
1 changed files with 73 additions and 20 deletions
|
|
@ -191,6 +191,74 @@ function Drinks() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BarDrinkEditor({
|
||||||
|
bar,
|
||||||
|
allDrinks,
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
|
bar: BarRow;
|
||||||
|
allDrinks: Drink[];
|
||||||
|
onChange: (ids: number[]) => void;
|
||||||
|
}) {
|
||||||
|
const byId = new Map(allDrinks.map(d => [d.id, d]));
|
||||||
|
const selected = bar.drink_ids.filter(id => {
|
||||||
|
const d = byId.get(id);
|
||||||
|
return d && !d.archived;
|
||||||
|
});
|
||||||
|
const available = allDrinks.filter(d => !d.archived && !selected.includes(d.id));
|
||||||
|
|
||||||
|
function move(idx: number, dir: -1 | 1) {
|
||||||
|
const j = idx + dir;
|
||||||
|
if (j < 0 || j >= selected.length) return;
|
||||||
|
const next = selected.slice();
|
||||||
|
[next[idx], next[j]] = [next[j]!, next[idx]!];
|
||||||
|
onChange(next);
|
||||||
|
}
|
||||||
|
function remove(idx: number) {
|
||||||
|
onChange(selected.filter((_, i) => i !== idx));
|
||||||
|
}
|
||||||
|
function add(id: number) {
|
||||||
|
onChange([...selected, id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div style="margin-top:8px; font-size:14px; opacity:0.7">Aktive Getränke (Reihenfolge)</div>
|
||||||
|
<table style="margin-bottom:8px">
|
||||||
|
<tbody>
|
||||||
|
{selected.length === 0 && (
|
||||||
|
<tr><td class="muted" colSpan={2}>Keine</td></tr>
|
||||||
|
)}
|
||||||
|
{selected.map((id, idx) => {
|
||||||
|
const d = byId.get(id);
|
||||||
|
if (!d) return null;
|
||||||
|
return (
|
||||||
|
<tr key={id}>
|
||||||
|
<td style="width:60%">{idx + 1}. {d.name}</td>
|
||||||
|
<td>
|
||||||
|
<button onClick={() => move(idx, -1)} disabled={idx === 0}>↑</button>
|
||||||
|
<button onClick={() => move(idx, 1)} disabled={idx === selected.length - 1}>↓</button>
|
||||||
|
<button onClick={() => remove(idx)}>×</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{available.length > 0 && (
|
||||||
|
<>
|
||||||
|
<div style="font-size:14px; opacity:0.7">Hinzufügen</div>
|
||||||
|
<div class="row">
|
||||||
|
{available.map(d => (
|
||||||
|
<button key={d.id} onClick={() => add(d.id)}>+ {d.name}</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function Bars() {
|
function Bars() {
|
||||||
const [bars, setBars] = useState<BarRow[]>([]);
|
const [bars, setBars] = useState<BarRow[]>([]);
|
||||||
const [drinks, setDrinks] = useState<Drink[]>([]);
|
const [drinks, setDrinks] = useState<Drink[]>([]);
|
||||||
|
|
@ -253,26 +321,11 @@ function Bars() {
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<BarDrinkEditor
|
||||||
{drinks.filter(d => !d.archived).map(d => {
|
bar={b}
|
||||||
const checked = b.drink_ids.includes(d.id);
|
allDrinks={drinks}
|
||||||
return (
|
onChange={(ids) => patch(b.id, { drink_ids: ids } as any)}
|
||||||
<label key={d.id}>
|
/>
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={checked}
|
|
||||||
onChange={() => {
|
|
||||||
const next = checked
|
|
||||||
? b.drink_ids.filter(x => x !== d.id)
|
|
||||||
: [...b.drink_ids, d.id];
|
|
||||||
patch(b.id, { drink_ids: next } as any);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{d.name}
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue