diff --git a/client/src/components/VendorFilter.tsx b/client/src/components/VendorFilter.tsx new file mode 100644 index 0000000..0d4aa9a --- /dev/null +++ b/client/src/components/VendorFilter.tsx @@ -0,0 +1,53 @@ +import React, { useEffect, useState } from "react"; +import { api } from "../api/client"; +import { useAuth } from "../context/AuthContext"; + +interface Vendor { id: string; name: string; } + +interface Props { + vendorId: string; + onChange: (vendorId: string) => void; +} + +/** + * Dropdown that lets admin users switch vendor context. + * Renders nothing for non-admin roles. + */ +export function VendorFilter({ vendorId, onChange }: Props) { + const { user } = useAuth(); + const [vendors, setVendors] = useState([]); + + useEffect(() => { + if (user?.role !== "admin") return; + api.get<{ data: Vendor[] }>("/vendors?limit=200") + .then((r) => setVendors(r.data)) + .catch(console.error); + }, [user?.role]); + + if (user?.role !== "admin" || vendors.length === 0) return null; + + return ( +
+ Vendor: + +
+ ); +} + +const sel: React.CSSProperties = { + border: "1px solid var(--color-border)", + borderRadius: "var(--radius)", + padding: "5px 8px", + fontSize: 13, + background: "var(--color-surface)", + cursor: "pointer", + minWidth: 140, +}; diff --git a/client/src/pages/CatalogPage.tsx b/client/src/pages/CatalogPage.tsx index bb389cb..b26c856 100644 --- a/client/src/pages/CatalogPage.tsx +++ b/client/src/pages/CatalogPage.tsx @@ -1,9 +1,11 @@ import React, { useEffect, useState, useCallback } from "react"; import { api } from "../api/client"; +import { useAuth } from "../context/AuthContext"; import { Table } from "../components/Table"; import { Modal } from "../components/Modal"; import { PageHeader } from "../components/PageHeader"; import { FormField, inputStyle, Btn } from "../components/FormField"; +import { VendorFilter } from "../components/VendorFilter"; interface Category { id: string; name: string; } interface Tax { id: string; name: string; rate: number; } @@ -16,31 +18,36 @@ interface ApiList { data: T[]; } type Tab = "products" | "categories" | "taxes"; export default function CatalogPage() { + const { user } = useAuth(); const [tab, setTab] = useState("products"); + const [vendorId, setVendorId] = useState(user?.vendorId ?? ""); return (
- +
+ + +
{(["products", "categories", "taxes"] as Tab[]).map((t) => ( - ))}
- {tab === "products" && } - {tab === "categories" && } - {tab === "taxes" && } + {tab === "products" && } + {tab === "categories" && } + {tab === "taxes" && }
); } +function qs(vendorId: string) { + return vendorId ? `?vendorId=${encodeURIComponent(vendorId)}` : ""; +} + // ─── Products ────────────────────────────────────────────────────────────── -function ProductsTab() { +function ProductsTab({ vendorId }: { vendorId: string }) { const [products, setProducts] = useState([]); const [categories, setCategories] = useState([]); const [taxes, setTaxes] = useState([]); @@ -53,16 +60,17 @@ function ProductsTab() { const load = useCallback(async () => { setLoading(true); + const q = qs(vendorId); const [p, c, t] = await Promise.all([ - api.get>("/products"), - api.get>("/categories"), - api.get>("/taxes"), + api.get>(`/products${q}`), + api.get>(`/categories${q}`), + api.get>(`/taxes${q}`), ]); setProducts(p.data); setCategories(c.data); setTaxes(t.data); setLoading(false); - }, []); + }, [vendorId]); useEffect(() => { load(); }, [load]); @@ -70,8 +78,7 @@ function ProductsTab() { const openEdit = (p: Product) => { setSelected(p); setForm({ name: p.name, sku: p.sku ?? "", price: String(p.price), categoryId: p.category?.id ?? "", taxId: p.tax?.id ?? "", description: p.description ?? "" }); - setError(""); - setModal("edit"); + setError(""); setModal("edit"); }; const handleSubmit = async (e: React.FormEvent) => { @@ -80,8 +87,9 @@ function ProductsTab() { setError(""); try { const payload = { ...form, price: parseFloat(form.price), categoryId: form.categoryId || null, taxId: form.taxId || null }; - if (modal === "create") await api.post("/products", payload); - else if (selected) await api.put(`/products/${selected.id}`, payload); + const q = qs(vendorId); + if (modal === "create") await api.post(`/products${q}`, payload); + else if (selected) await api.put(`/products/${selected.id}${q}`, payload); setModal(null); load(); } catch (err) { setError(err instanceof Error ? err.message : "Save failed"); } @@ -110,9 +118,7 @@ function ProductsTab() { return ( <> -
- + Add Product -
+
+ Add Product
{modal && ( setModal(null)}> @@ -122,12 +128,8 @@ function ProductsTab() {
- - - - - - + +