Fix Global Catalogue browsing and import

Removes InventoryView's broken duplicate Global Catalogue tab, which
misused createproductlocation with catalogue ids that never match real
product ids (imports silently failed to land) and showed fabricated
Math.random() pricing/ratings. "Import Product" now routes to the
already-correct CatalogueBrowser instead.

Also fixes catalogueApi's product_count field mismatch (brand chip
counts were always blank), a pagination bug that capped the catalogue
at 100 of ~237 products with no way to see the rest, and replaces
ImportProductModal's free-text category id input with a real dropdown
scoped to the tenant's own categories, filtering subcategories to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Suriya
2026-07-16 17:31:29 +05:30
parent 11baf732b7
commit 32291cddbe
5 changed files with 73 additions and 651 deletions

View File

@@ -36,17 +36,19 @@ export interface ImportCatalogueProductRequest {
taxpercent: number;
}
async function apiGet<T>(url: URL): Promise<T[]> {
async function apiGet<T>(url: URL): Promise<{ items: T[]; total: number }> {
const res = await fetch(url, { headers: { Accept: 'application/json' } });
if (!res.ok) {
throw new Error(`Catalogue API failed: ${res.status} ${res.statusText}`);
}
const json = await res.json();
if (Array.isArray(json)) return json;
if (Array.isArray(json)) return { items: json, total: json.length };
if (json && typeof json === 'object' && 'details' in json) {
return json.details || [];
const items = json.details || [];
const total = typeof json.total === 'number' ? json.total : items.length;
return { items, total };
}
return [];
return { items: [], total: 0 };
}
// brand omitted → the entire catalogue, all brands merged.
@@ -59,9 +61,9 @@ export async function getCatalogueProducts(opts: {
if (keyword) url.searchParams.set("keyword", keyword);
url.searchParams.set("pageno", String(pageno));
url.searchParams.set("pagesize", String(pagesize));
const products = await apiGet<CatalogueProduct>(url);
return { products, total: products.length };
const { items, total } = await apiGet<CatalogueProduct>(url);
return { products: items, total };
}
// brand omitted → imported refs across every brand.
@@ -69,9 +71,9 @@ export async function getImportedCatalogueRefs(tenantid: number, brand?: string)
const url = new URL(`${API_BASE}/products/getimportedcatalogueproducts`);
url.searchParams.set("tenantid", String(tenantid));
if (brand) url.searchParams.set("brand", brand);
const refs = await apiGet<ImportedRef>(url);
return new Set(refs.map((r) => `${r.brand}:${r.catalogueid}`));
const { items } = await apiGet<ImportedRef>(url);
return new Set(items.map((r) => `${r.brand}:${r.catalogueid}`));
}
export async function importCatalogueProducts(items: ImportCatalogueProductRequest[]) {
@@ -102,16 +104,21 @@ export async function removeFromStoreCatalogue(tenantid: number, locationid: num
return json;
}
export interface CatalogueBrand {
brand: string;
product_count: number;
}
export async function getBrands() {
const url = new URL(`${API_BASE}/catalogue/getbrands`);
const brands = await apiGet<{ brand: string; count: number }>(url);
return brands;
const { items } = await apiGet<CatalogueBrand>(url);
return items;
}
export async function getProductSubcategories(tenantid: number, categoryid?: number) {
const url = new URL(`${API_BASE}/products/getproductsubcategories`);
url.searchParams.set("tenantid", String(tenantid));
if (categoryid) url.searchParams.set("categoryid", String(categoryid));
const subcategories = await apiGet<{ subcategoryid: number; subcategoryname: string }>(url);
return subcategories;
const { items } = await apiGet<{ subcategoryid: number; subcategoryname: string }>(url);
return items;
}