58 lines
3.6 KiB
TypeScript
58 lines
3.6 KiB
TypeScript
import { useEffect, useState } from 'react'
|
||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||
import { Boxes } from 'lucide-react'
|
||
import { getStores, getStoreInventory, toggleStoreInventory, adjustStoreInventory } from '../api/client'
|
||
|
||
export default function Inventory() {
|
||
const qc = useQueryClient()
|
||
const [storeId, setStoreId] = useState<number>(0)
|
||
const { data: stores } = useQuery({ queryKey: ['inv-stores'], queryFn: () => getStores(false) })
|
||
useEffect(() => { if (!storeId && stores?.length) setStoreId(stores[0].id) }, [stores])
|
||
const { data: inv } = useQuery({ queryKey: ['store-inv', storeId], queryFn: () => getStoreInventory(storeId), enabled: !!storeId })
|
||
|
||
const toggle = async (pid: number, available: boolean) => { await toggleStoreInventory(storeId, pid, !available).catch(() => {}); qc.invalidateQueries({ queryKey: ['store-inv', storeId] }) }
|
||
const adjust = async (pid: number, delta: number) => { await adjustStoreInventory(storeId, pid, delta).catch(() => {}); qc.invalidateQueries({ queryKey: ['store-inv', storeId] }) }
|
||
|
||
return (
|
||
<div>
|
||
<div className="flex items-center justify-between mb-5">
|
||
<div className="flex items-center gap-2"><Boxes className="text-brand" size={22} /><h1 className="text-xl font-bold">Store Inventory (ON/OFF)</h1></div>
|
||
<select value={storeId} onChange={e => setStoreId(Number(e.target.value))} className="bg-card border border-edge rounded-lg px-3 py-2 text-sm">
|
||
{(stores || []).map((s: any) => <option key={s.id} value={s.id}>{s.name}</option>)}
|
||
</select>
|
||
</div>
|
||
<p className="text-xs text-slate-500 mb-3">Switching to OFF immediately marks the item as out of stock in that store's area.</p>
|
||
<div className="bg-card border border-edge rounded-xl overflow-hidden">
|
||
<table className="w-full text-sm">
|
||
<thead><tr className="text-slate-400 text-xs border-b border-edge bg-panel">
|
||
<th className="text-left p-3">Product</th><th className="text-right">Stock</th><th className="text-center">Adjust</th><th className="text-center">Sale</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
{(inv || []).map((r: any) => {
|
||
const available = r.available !== false
|
||
return (
|
||
<tr key={r.productId || r.id} className="border-b border-edge/50 hover:bg-panel/50">
|
||
<td className="p-3">{r.productName || `Product #${r.productId}`}</td>
|
||
<td className="text-right text-slate-300">{r.stock ?? r.quantity ?? '-'}</td>
|
||
<td className="text-center">
|
||
<div className="inline-flex items-center gap-1">
|
||
<button onClick={() => adjust(r.productId, -1)} className="w-6 h-6 rounded bg-panel border border-edge text-slate-300">−</button>
|
||
<button onClick={() => adjust(r.productId, +1)} className="w-6 h-6 rounded bg-panel border border-edge text-slate-300">+</button>
|
||
</div>
|
||
</td>
|
||
<td className="text-center">
|
||
<button onClick={() => toggle(r.productId, available)} className={`px-3 py-1 rounded-full text-xs ${available ? 'bg-emerald-500/15 text-emerald-400' : 'bg-rose-500/15 text-rose-400'}`}>
|
||
{available ? 'ON' : 'OFF'}
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
)
|
||
})}
|
||
{!(inv || []).length && <tr><td colSpan={4} className="text-center text-slate-500 py-8">No inventory items found.</td></tr>}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|