Add giftcard management
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
|
||||
type CartItem = {
|
||||
id: string;
|
||||
label: string;
|
||||
price: number;
|
||||
qty: number;
|
||||
};
|
||||
|
||||
let cart = $state<CartItem[]>([]);
|
||||
let giftCardAmount = $state('25');
|
||||
let showGiftCardInput = $state(false);
|
||||
|
||||
let subtotal = $derived(cart.reduce((sum, item) => sum + item.price * item.qty, 0));
|
||||
let itemCount = $derived(cart.reduce((sum, item) => sum + item.qty, 0));
|
||||
|
||||
function formatCurrency(n: number): string {
|
||||
return new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' }).format(n);
|
||||
}
|
||||
|
||||
function addItem(label: string, price: number) {
|
||||
const existing = cart.find(i => i.label === label);
|
||||
if (existing) {
|
||||
existing.qty++;
|
||||
} else {
|
||||
cart = [...cart, { id: crypto.randomUUID(), label, price, qty: 1 }];
|
||||
}
|
||||
}
|
||||
|
||||
function addGiftCard() {
|
||||
const amt = parseFloat(giftCardAmount);
|
||||
if (isNaN(amt) || amt <= 0) return;
|
||||
addItem('Gift Card', amt);
|
||||
giftCardAmount = '25';
|
||||
showGiftCardInput = false;
|
||||
}
|
||||
|
||||
function removeItem(id: string) {
|
||||
cart = cart.filter(i => i.id !== id);
|
||||
}
|
||||
|
||||
function updateQty(id: string, delta: number) {
|
||||
cart = cart.map(i => {
|
||||
if (i.id !== id) return i;
|
||||
const next = i.qty + delta;
|
||||
return next <= 0 ? null : { ...i, qty: next };
|
||||
}).filter((i): i is CartItem => i !== null);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="rounded-xl border bg-card">
|
||||
<div class="flex items-center justify-between border-b border-gray-200 px-5 py-4">
|
||||
<h3 class="text-base font-semibold">Till Sales</h3>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 p-4 sm:grid-cols-3">
|
||||
<Button variant="outline" size="sm" class="justify-start gap-2" onclick={() => addItem('Cuticle Oil', 8)}>
|
||||
Cuticle Oil - £8
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" class="justify-start gap-2" onclick={() => addItem('Nail Files (Pack)', 5)}>
|
||||
Nail Files - £5
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" class="justify-start gap-2" onclick={() => addItem('Hand Cream', 6)}>
|
||||
Hand Cream - £6
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" class="justify-start gap-2" onclick={() => addItem('Base Coat', 7)}>
|
||||
Base Coat - £7
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" class="justify-start gap-2" onclick={() => addItem('Top Coat', 7)}>
|
||||
Top Coat - £7
|
||||
</Button>
|
||||
<div class="relative">
|
||||
{#if showGiftCardInput}
|
||||
<div class="flex gap-1">
|
||||
<div class="relative flex-1">
|
||||
<span class="absolute left-2 top-1/2 -translate-y-1/2 text-xs text-gray-400">£</span>
|
||||
<Input
|
||||
type="text"
|
||||
inputmode="decimal"
|
||||
bind:value={giftCardAmount}
|
||||
class="h-9 pl-5 text-sm"
|
||||
onkeydown={(e) => { if (e.key === 'Enter') addGiftCard(); }}
|
||||
/>
|
||||
</div>
|
||||
<Button size="sm" variant="outline" onclick={addGiftCard} class="h-9 px-2 text-xs">Add</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Button variant="outline" size="sm" class="w-full justify-start gap-2" onclick={() => showGiftCardInput = true}>
|
||||
Gift Card
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div class="px-4 py-3">
|
||||
{#if cart.length === 0}
|
||||
<p class="py-6 text-center text-sm text-muted-foreground">Tap items above to add them to the sale.</p>
|
||||
{:else}
|
||||
<div class="max-h-48 space-y-1 overflow-y-auto">
|
||||
{#each cart as item (item.id)}
|
||||
<div class="flex items-center justify-between rounded-md border px-3 py-2 text-sm">
|
||||
<div class="min-w-0 flex-1">
|
||||
<span class="font-medium text-card-foreground">{item.label}</span>
|
||||
<span class="ml-2 text-xs text-muted-foreground">{formatCurrency(item.price)} each</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-6 w-6 items-center justify-center rounded border text-xs text-muted-foreground hover:bg-accent"
|
||||
onclick={() => updateQty(item.id, -1)}
|
||||
>
|
||||
−
|
||||
</button>
|
||||
<span class="w-5 text-center text-sm font-semibold tabular-nums">{item.qty}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-6 w-6 items-center justify-center rounded border text-xs text-muted-foreground hover:bg-accent"
|
||||
onclick={() => updateQty(item.id, 1)}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<span class="w-14 text-right text-sm font-semibold tabular-nums">{formatCurrency(item.price * item.qty)}</span>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Remove item"
|
||||
class="ml-1 flex h-6 w-6 items-center justify-center rounded text-xs text-muted-foreground hover:bg-red-50 hover:text-red-600"
|
||||
onclick={() => removeItem(item.id)}
|
||||
>
|
||||
<svg class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<Separator class="my-3" />
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-muted-foreground">
|
||||
{itemCount} item{itemCount !== 1 ? 's' : ''}
|
||||
</span>
|
||||
<span class="text-lg font-bold tabular-nums">{formatCurrency(subtotal)}</span>
|
||||
</div>
|
||||
|
||||
<Button class="mt-3 w-full" disabled>
|
||||
Charge {formatCurrency(subtotal)}
|
||||
</Button>
|
||||
<p class="mt-1 text-xs text-muted-foreground">Payment flow and backend integration coming soon.</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user