inventory page

This commit is contained in:
2026-07-23 16:05:38 +05:30
parent c6649c9c8f
commit 92165b986c
9 changed files with 150 additions and 71 deletions

View File

@@ -97,6 +97,11 @@ export default function InventoryView({
[locationsQ.data],
);
// The admin catalogue (imports, curation) is scoped to this tenant's own
// primary/hub outlet — not the hardcoded Fiesta defaults, so onboarded
// tenants other than Fiesta see their own imports reflected here.
const primaryLocationId = locations[0]?.locationid ?? FIESTA_PRIMARY_LOCATION_ID;
const storesStock = useFiestaStoresStock(
tenantId,
locations.map(({ locationid, locationname }) => ({ locationid, locationname })),
@@ -113,11 +118,11 @@ export default function InventoryView({
const allStoreRows = storesStock.flatMap((s) => s.rows);
const [activeTab, setActiveTab] = useState<'catalog' | 'requests' | 'global_catalogue'>('catalog');
const [isLocalSidebarOpen, setIsLocalSidebarOpen] = useState(true);
const [isLocalSidebarOpen, setIsLocalSidebarOpen] = useState(false);
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
const [hoveredAdminProduct, setHoveredAdminProduct] = useState<ProductMatrixItem | null>(null);
const [localSearch, setLocalSearch] = useState('');
const storeCat = useStoreCatalogue();
const storeCat = useStoreCatalogue(tenantId, primaryLocationId);
const [importPrice, setImportPrice] = useState<string>('');
const [isSettingPrice, setIsSettingPrice] = useState(false);
const [addingPriceProdId, setAddingPriceProdId] = useState<string | null>(null);
@@ -613,7 +618,10 @@ export default function InventoryView({
disabled={!cardImportPrice || Number(cardImportPrice) <= 0}
onClick={(e) => {
e.stopPropagation();
storeCat.add({ productid: prod.id, name: prod.name, image: prod.image, category: prod.category, sku: prod.sku, price: Number(cardImportPrice), unit: prod.exposure, qty: 1, status: 'Active' });
// qty: 0 — publishing to the catalogue is a listing/pricing action,
// not a stock delivery. Real quantity only lands via the
// request → approve → Mark as Received flow.
storeCat.add({ productid: prod.id, name: prod.name, image: prod.image, category: prod.category, sku: prod.sku, price: Number(cardImportPrice), unit: prod.exposure, qty: 0, status: 'Active' });
setAddingPriceProdId(null);
}}
className="flex-1 py-1 bg-[#662582] text-white text-[9px] font-bold disabled:opacity-50"
@@ -746,6 +754,7 @@ export default function InventoryView({
const isRejected = req.pickData.status === 'Rejected';
const isPending = req.pickData.status === 'Pending';
const isCancelled = req.pickData.status === 'Cancelled';
const isReceived = req.pickData.status === 'Received';
return (
<tr
@@ -787,15 +796,17 @@ export default function InventoryView({
</td>
<td className="px-5 py-4 whitespace-nowrap">
<span className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-bold border ${
isApproved ? 'bg-emerald-50 text-emerald-700 border-emerald-200' :
isRejected ? 'bg-rose-50 text-rose-700 border-rose-200' :
isCancelled ? 'bg-slate-50 text-slate-700 border-slate-200' :
isReceived ? 'bg-indigo-50 text-indigo-700 border-indigo-200' :
isApproved ? 'bg-emerald-50 text-emerald-700 border-emerald-200' :
isRejected ? 'bg-rose-50 text-rose-700 border-rose-200' :
isCancelled ? 'bg-slate-50 text-slate-700 border-slate-200' :
'bg-amber-50 text-amber-700 border-amber-200'
}`}>
<span className={`w-1.5 h-1.5 rounded-full ${
isApproved ? 'bg-emerald-500' :
isRejected ? 'bg-rose-500' :
isCancelled ? 'bg-slate-400' :
isReceived ? 'bg-indigo-500' :
isApproved ? 'bg-emerald-500' :
isRejected ? 'bg-rose-500' :
isCancelled ? 'bg-slate-400' :
'bg-amber-500 animate-pulse'
}`} />
{req.pickData.status || '—'}
@@ -843,7 +854,7 @@ export default function InventoryView({
<div className="flex-1 flex flex-col min-h-0 overflow-hidden animate-in fade-in duration-300">
<CatalogueBrowser
tenantid={tenantId}
locationid={FIESTA_PRIMARY_LOCATION_ID}
locationid={primaryLocationId}
onClose={() => setActiveTab('catalog')}
/>
</div>
@@ -940,19 +951,24 @@ export default function InventoryView({
</div>
</div>
<button
<button
disabled={!importPrice || Number(importPrice) <= 0}
onClick={() => {
storeCat.add({
productid: selectedAdminProduct.id,
name: selectedAdminProduct.name,
image: selectedAdminProduct.image,
category: selectedAdminProduct.category,
sku: selectedAdminProduct.sku,
price: Number(importPrice),
unit: selectedAdminProduct.exposure || 'Pc',
qty: 1,
status: 'Active'
// First-time publish gets qty 0 — it's a listing/pricing action, not a
// stock delivery; real quantity only lands via Mark as Received. If this
// product is already published, preserve its existing qty so a mere price
// edit here doesn't zero out stock that's since been received.
const existingQty = storeCat.items.find(i => i.productid === selectedAdminProduct.id)?.qty ?? 0;
storeCat.add({
productid: selectedAdminProduct.id,
name: selectedAdminProduct.name,
image: selectedAdminProduct.image,
category: selectedAdminProduct.category,
sku: selectedAdminProduct.sku,
price: Number(importPrice),
unit: selectedAdminProduct.exposure || 'Pc',
qty: existingQty,
status: 'Active'
});
}}
className="w-full flex items-center justify-center gap-2 py-3 rounded-xl text-xs font-extrabold transition-all bg-[#662582] hover:bg-[#531e6a] text-white shadow-md disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"