Rename some columns to match backend

This commit is contained in:
2025-01-15 01:28:05 -05:00
parent 0425912d3e
commit e47d30080d
3 changed files with 48 additions and 248 deletions

View File

@@ -238,13 +238,21 @@ export function ProductDetail({ productId, onClose }: ProductDetailProps) {
<h3 className="font-semibold mb-2">Basic Information</h3>
<dl className="space-y-2">
<div>
<dt className="text-sm text-muted-foreground">Brand</dt>
<dt className="text-sm text-muted-foreground">Company</dt>
<dd>{product?.brand || "N/A"}</dd>
</div>
<div>
<dt className="text-sm text-muted-foreground">Vendor</dt>
<dt className="text-sm text-muted-foreground">Supplier</dt>
<dd>{product?.vendor || "N/A"}</dd>
</div>
<div>
<dt className="text-sm text-muted-foreground">Supplier #</dt>
<dd>{product?.vendor_reference || "N/A"}</dd>
</div>
<div>
<dt className="text-sm text-muted-foreground">UPC</dt>
<dd>{product?.barcode || "N/A"}</dd>
</div>
<div>
<dt className="text-sm text-muted-foreground">Categories</dt>
<dd className="flex flex-wrap gap-2">
@@ -276,7 +284,7 @@ export function ProductDetail({ productId, onClose }: ProductDetailProps) {
<dd>${formatPrice(product?.price)}</dd>
</div>
<div>
<dt className="text-sm text-muted-foreground">Regular Price</dt>
<dt className="text-sm text-muted-foreground">Default Price</dt>
<dd>${formatPrice(product?.regular_price)}</dd>
</div>
<div>
@@ -294,7 +302,7 @@ export function ProductDetail({ productId, onClose }: ProductDetailProps) {
<h3 className="font-semibold mb-2">Stock Status</h3>
<dl className="space-y-2">
<div>
<dt className="text-sm text-muted-foreground">Current Stock</dt>
<dt className="text-sm text-muted-foreground">Shelf Count</dt>
<dd className="text-2xl font-semibold">{product?.stock_quantity}</dd>
</div>
<div>
@@ -395,7 +403,7 @@ export function ProductDetail({ productId, onClose }: ProductDetailProps) {
<h3 className="font-semibold mb-2">Current Stock</h3>
<dl className="grid grid-cols-3 gap-4">
<div>
<dt className="text-sm text-muted-foreground">Stock Quantity</dt>
<dt className="text-sm text-muted-foreground">Shelf Count</dt>
<dd className="text-2xl font-semibold">{product?.stock_quantity}</dd>
</div>
<div>

View File

@@ -1,185 +0,0 @@
import { useState } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
DialogDescription,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
interface Product {
product_id: string;
title: string;
sku: string;
stock_quantity: number;
price: number;
regular_price: number;
cost_price: number;
vendor: string;
brand: string;
categories: string;
visible: boolean;
managing_stock: boolean;
}
interface ProductEditDialogProps {
product: Product | null;
open: boolean;
onOpenChange: (open: boolean) => void;
onSave: (product: Product) => void;
}
export function ProductEditDialog({
product,
open,
onOpenChange,
onSave,
}: ProductEditDialogProps) {
const [formData, setFormData] = useState<Partial<Product>>(product || {});
const handleChange = (field: keyof Product, value: any) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (product && formData) {
onSave({ ...product, ...formData });
}
onOpenChange(false);
};
if (!product) return null;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit Product - {product.title}</DialogTitle>
<DialogDescription>
Make changes to the product details below.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4 py-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="title">Title</Label>
<Input
id="title"
value={formData.title || ""}
onChange={(e) => handleChange("title", e.target.value)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="sku">SKU</Label>
<Input
id="sku"
value={formData.sku || ""}
onChange={(e) => handleChange("sku", e.target.value)}
/>
</div>
</div>
<div className="grid grid-cols-3 gap-4">
<div className="space-y-2">
<Label htmlFor="price">Price</Label>
<Input
id="price"
type="number"
step="0.01"
value={formData.price || ""}
onChange={(e) => handleChange("price", parseFloat(e.target.value))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="regular_price">Regular Price</Label>
<Input
id="regular_price"
type="number"
step="0.01"
value={formData.regular_price || ""}
onChange={(e) => handleChange("regular_price", parseFloat(e.target.value))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="cost_price">Cost Price</Label>
<Input
id="cost_price"
type="number"
step="0.01"
value={formData.cost_price || ""}
onChange={(e) => handleChange("cost_price", parseFloat(e.target.value))}
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="vendor">Vendor</Label>
<Input
id="vendor"
value={formData.vendor || ""}
onChange={(e) => handleChange("vendor", e.target.value)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="brand">Brand</Label>
<Input
id="brand"
value={formData.brand || ""}
onChange={(e) => handleChange("brand", e.target.value)}
/>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="categories">Categories</Label>
<Input
id="categories"
value={formData.categories || ""}
onChange={(e) => handleChange("categories", e.target.value)}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="stock_quantity">Stock Quantity</Label>
<Input
id="stock_quantity"
type="number"
value={formData.stock_quantity || ""}
onChange={(e) => handleChange("stock_quantity", parseInt(e.target.value))}
/>
</div>
<div className="flex items-center space-x-2 pt-8">
<Switch
id="managing_stock"
checked={formData.managing_stock}
onCheckedChange={(checked) => handleChange("managing_stock", checked)}
/>
<Label htmlFor="managing_stock">Track Stock</Label>
</div>
</div>
<div className="flex items-center space-x-2">
<Switch
id="visible"
checked={formData.visible}
onCheckedChange={(checked) => handleChange("visible", checked)}
/>
<Label htmlFor="visible">Visible</Label>
</div>
<DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}

View File

@@ -72,84 +72,61 @@ interface Product {
lead_time_status?: string;
}
// Column definition interface
// Column definition type
interface ColumnDef {
key: keyof Product | 'image';
label: string;
group: string;
format?: (value: any) => string | number;
width?: string;
noLabel?: boolean;
width?: string;
format?: (value: any) => string;
}
// Define available columns with grouping
// Define available columns with their groups
const AVAILABLE_COLUMNS: ColumnDef[] = [
// Image (special column)
{ key: 'image', label: 'Image', group: 'Basic Info', noLabel: true, width: 'w-[60px]' },
// Basic Info Group
{ key: 'title', label: 'Title', group: 'Basic Info' },
{ key: 'brand', label: 'Brand', group: 'Basic Info' },
{ key: 'categories', label: 'Categories', group: 'Basic Info' },
{ key: 'vendor', label: 'Vendor', group: 'Basic Info' },
{ key: 'vendor_reference', label: 'Vendor Reference', group: 'Basic Info' },
{ key: 'barcode', label: 'Barcode', group: 'Basic Info' },
// Inventory Group
{ key: 'stock_quantity', label: 'Stock Quantity', group: 'Inventory', format: (v) => v?.toString() ?? '-' },
{ key: 'stock_status', label: 'Stock Status', group: 'Inventory' },
{ key: 'days_of_inventory', label: 'Days of Inventory', group: 'Inventory', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'reorder_point', label: 'Reorder Point', group: 'Inventory', format: (v) => v?.toString() ?? '-' },
{ key: 'safety_stock', label: 'Safety Stock', group: 'Inventory', format: (v) => v?.toString() ?? '-' },
{ key: 'moq', label: 'MOQ', group: 'Inventory', format: (v) => v?.toString() ?? '-' },
{ key: 'uom', label: 'UOM', group: 'Inventory', format: (v) => v?.toString() ?? '-' },
// Pricing Group
{ key: 'title', label: 'Name', group: 'Basic Info' },
{ key: 'SKU', label: 'SKU', group: 'Basic Info' },
{ key: 'brand', label: 'Company', group: 'Basic Info' },
{ key: 'vendor', label: 'Supplier', group: 'Basic Info' },
{ key: 'vendor_reference', label: 'Supplier #', group: 'Basic Info' },
{ key: 'barcode', label: 'UPC', group: 'Basic Info' },
{ key: 'stock_quantity', label: 'Shelf Count', group: 'Stock', format: (v) => v?.toString() ?? '-' },
{ key: 'stock_status', label: 'Stock Status', group: 'Stock' },
{ key: 'days_of_inventory', label: 'Days of Stock', group: 'Stock', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'abc_class', label: 'ABC Class', group: 'Stock' },
{ key: 'price', label: 'Price', group: 'Pricing', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'regular_price', label: 'Regular Price', group: 'Pricing', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'cost_price', label: 'Cost Price', group: 'Pricing', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'regular_price', label: 'Default Price', group: 'Pricing', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'cost_price', label: 'Cost', group: 'Pricing', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'landing_cost_price', label: 'Landing Cost', group: 'Pricing', format: (v) => v?.toFixed(2) ?? '-' },
// Sales Metrics Group
{ key: 'daily_sales_avg', label: 'Daily Sales Avg', group: 'Sales Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'weekly_sales_avg', label: 'Weekly Sales Avg', group: 'Sales Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'monthly_sales_avg', label: 'Monthly Sales Avg', group: 'Sales Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'avg_quantity_per_order', label: 'Avg Qty per Order', group: 'Sales Metrics', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'number_of_orders', label: 'Number of Orders', group: 'Sales Metrics', format: (v) => v?.toString() ?? '-' },
{ key: 'first_sale_date', label: 'First Sale', group: 'Sales Metrics' },
{ key: 'last_sale_date', label: 'Last Sale', group: 'Sales Metrics' },
// Financial Metrics Group
{ key: 'avg_margin_percent', label: 'Avg Margin %', group: 'Financial Metrics', format: (v) => v ? `${v.toFixed(1)}%` : '-' },
{ key: 'total_revenue', label: 'Total Revenue', group: 'Financial Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'inventory_value', label: 'Inventory Value', group: 'Financial Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'cost_of_goods_sold', label: 'COGS', group: 'Financial Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'gross_profit', label: 'Gross Profit', group: 'Financial Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'gmroi', label: 'GMROI', group: 'Financial Metrics', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'turnover_rate', label: 'Turnover Rate', group: 'Financial Metrics', format: (v) => v?.toFixed(2) ?? '-' },
// Purchase & Lead Time Group
{ key: 'avg_lead_time_days', label: 'Avg Lead Time (Days)', group: 'Purchase & Lead Time', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'current_lead_time', label: 'Current Lead Time', group: 'Purchase & Lead Time', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'target_lead_time', label: 'Target Lead Time', group: 'Purchase & Lead Time', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'lead_time_status', label: 'Lead Time Status', group: 'Purchase & Lead Time' },
{ key: 'last_purchase_date', label: 'Last Purchase', group: 'Purchase & Lead Time' },
{ key: 'last_received_date', label: 'Last Received', group: 'Purchase & Lead Time' },
// Classification Group
{ key: 'abc_class', label: 'ABC Class', group: 'Classification' },
{ key: 'daily_sales_avg', label: 'Daily Sales', group: 'Sales', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'weekly_sales_avg', label: 'Weekly Sales', group: 'Sales', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'monthly_sales_avg', label: 'Monthly Sales', group: 'Sales', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'first_sale_date', label: 'First Sale', group: 'Sales' },
{ key: 'last_sale_date', label: 'Last Sale', group: 'Sales' },
{ key: 'gmroi', label: 'GMROI', group: 'Financial', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'turnover_rate', label: 'Turnover Rate', group: 'Financial', format: (v) => v?.toFixed(2) ?? '-' },
{ key: 'avg_margin_percent', label: 'Margin %', group: 'Financial', format: (v) => v ? `${v.toFixed(1)}%` : '-' },
{ key: 'current_lead_time', label: 'Current Lead Time', group: 'Lead Time', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'target_lead_time', label: 'Target Lead Time', group: 'Lead Time', format: (v) => v?.toFixed(1) ?? '-' },
{ key: 'lead_time_status', label: 'Lead Time Status', group: 'Lead Time' },
{ key: 'last_purchase_date', label: 'Last Purchase', group: 'Lead Time' },
];
// Default visible columns
const DEFAULT_VISIBLE_COLUMNS: (keyof Product | 'image')[] = [
'image',
'title',
'SKU',
'brand',
'vendor',
'stock_quantity',
'stock_status',
'price',
'vendor',
'brand',
'categories',
'regular_price',
'daily_sales_avg',
'weekly_sales_avg',
'monthly_sales_avg',
];
export function Products() {