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:
@@ -2,6 +2,8 @@ import React, { useState } from 'react';
|
||||
import { X, Save, AlertCircle } from 'lucide-react';
|
||||
import { CatalogueProduct, ImportCatalogueProductRequest } from '../services/catalogueApi';
|
||||
import { useProductSubcategories } from '../hooks/useCatalogueImport';
|
||||
import { useFiestaProductCategories } from '../services/fiestaQueries';
|
||||
import { str as fstr } from '../services/fiestaApi';
|
||||
|
||||
interface ImportProductModalProps {
|
||||
product: CatalogueProduct;
|
||||
@@ -25,9 +27,18 @@ export default function ImportProductModal({
|
||||
const [taxPercent, setTaxPercent] = useState<string>('0');
|
||||
const [quantity, setQuantity] = useState<string>('1');
|
||||
|
||||
// Load subcategories for this tenant (optional: filter by categoryId if category picker is also dynamic)
|
||||
// The spec says "getproductsubcategories" with optional categoryid. We will fetch all for now and pick.
|
||||
const { data: subcategories = [], isLoading: isLoadingSubcats } = useProductSubcategories(tenantid);
|
||||
const { data: categoriesData = [], isLoading: isLoadingCategories } = useFiestaProductCategories();
|
||||
const categories = categoriesData.map((c: any) => ({
|
||||
categoryid: Number(c.categoryid),
|
||||
categoryname: fstr(c.categoryname),
|
||||
}));
|
||||
|
||||
// Subcategories are scoped to the selected category, so a product can't be
|
||||
// tagged with a subcategory that doesn't actually belong to its category.
|
||||
const { data: subcategories = [], isLoading: isLoadingSubcats } = useProductSubcategories(
|
||||
tenantid,
|
||||
categoryId ? Number(categoryId) : undefined,
|
||||
);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -78,19 +89,33 @@ export default function ImportProductModal({
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-semibold text-slate-600 uppercase tracking-wider">Category ID *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={categoryId}
|
||||
onChange={e => setCategoryId(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500/20 focus:border-purple-500 transition-colors"
|
||||
placeholder="e.g. 1"
|
||||
required
|
||||
/>
|
||||
<label className="text-xs font-semibold text-slate-600 uppercase tracking-wider">Category *</label>
|
||||
{isLoadingCategories ? (
|
||||
<div className="w-full px-3 py-2 border border-slate-200 rounded-lg text-slate-400">Loading...</div>
|
||||
) : (
|
||||
<select
|
||||
value={categoryId}
|
||||
onChange={e => {
|
||||
setCategoryId(e.target.value);
|
||||
setSubcategoryId(''); // subcategory list is about to change
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500/20 focus:border-purple-500 transition-colors bg-white"
|
||||
required
|
||||
>
|
||||
<option value="">Select category...</option>
|
||||
{categories.map((c) => (
|
||||
<option key={c.categoryid} value={c.categoryid}>
|
||||
{c.categoryname}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-semibold text-slate-600 uppercase tracking-wider">Subcategory *</label>
|
||||
{isLoadingSubcats ? (
|
||||
{!categoryId ? (
|
||||
<div className="w-full px-3 py-2 border border-slate-200 rounded-lg text-slate-400">Select a category first</div>
|
||||
) : isLoadingSubcats ? (
|
||||
<div className="w-full px-3 py-2 border border-slate-200 rounded-lg text-slate-400">Loading...</div>
|
||||
) : (
|
||||
<select
|
||||
@@ -102,7 +127,7 @@ export default function ImportProductModal({
|
||||
<option value="">Select subcategory...</option>
|
||||
{subcategories.map((s: any) => (
|
||||
<option key={s.subcategoryid || s.id} value={s.subcategoryid || s.id}>
|
||||
{s.subcategoryname || s.name} (Cat {s.categoryid || '?'})
|
||||
{s.subcategoryname || s.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user