Adjust validation table, add custom fields
This commit is contained in:
@@ -411,8 +411,9 @@ export const ValidationStep = <T extends string>({ initialData, file, onBack }:
|
||||
</AlertDialogPortal>
|
||||
</AlertDialog>
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<div className="px-8 py-6">
|
||||
<div className="mb-8 flex flex-wrap items-center justify-between gap-2">
|
||||
<div className="h-full flex flex-col">
|
||||
<div className="px-8 pt-6">
|
||||
<div className="mb-6 flex flex-wrap items-center justify-between gap-2">
|
||||
<h2 className="text-3xl font-semibold text-foreground">
|
||||
{translations.validationStep.title}
|
||||
</h2>
|
||||
@@ -436,10 +437,12 @@ export const ValidationStep = <T extends string>({ initialData, file, onBack }:
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-md border overflow-hidden">
|
||||
<div className="overflow-x-auto">
|
||||
</div>
|
||||
<div className="px-8 pb-6 flex-1 min-h-0">
|
||||
<div className="rounded-md border h-full flex flex-col overflow-hidden">
|
||||
<div className="flex-1 overflow-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHeader className="sticky top-0 bg-muted z-10">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
@@ -497,7 +500,8 @@ export const ValidationStep = <T extends string>({ initialData, file, onBack }:
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t bg-muted px-8 py-4 mt-5">
|
||||
</div>
|
||||
<div className="border-t bg-muted px-8 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
{onBack && (
|
||||
<Button variant="outline" onClick={onBack}>
|
||||
|
||||
@@ -8,173 +8,345 @@ import { motion } from "framer-motion";
|
||||
|
||||
const IMPORT_FIELDS = [
|
||||
{
|
||||
label: "Name",
|
||||
key: "name",
|
||||
alternateMatches: ["product", "product name", "item name", "title"],
|
||||
label: "Supplier",
|
||||
key: "supplier",
|
||||
description: "Primary supplier/manufacturer of the product",
|
||||
fieldType: {
|
||||
type: "input",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Acme Corp", value: "acme" },
|
||||
{ label: "Global Supplies", value: "global" },
|
||||
{ label: "Best Manufacturers", value: "best" },
|
||||
{ label: "Quality Goods", value: "quality" },
|
||||
],
|
||||
},
|
||||
width: 200,
|
||||
validations: [{ rule: "required", errorMessage: "Supplier is required", level: "error" }],
|
||||
},
|
||||
example: "Widget X",
|
||||
description: "The name or title of the product",
|
||||
width: 300,
|
||||
validations: [
|
||||
{
|
||||
rule: "required",
|
||||
errorMessage: "Name is required",
|
||||
level: "error",
|
||||
},
|
||||
label: "UPC",
|
||||
key: "upc",
|
||||
description: "Universal Product Code/Barcode",
|
||||
alternateMatches: ["barcode", "bar code", "JAN", "EAN"],
|
||||
fieldType: { type: "input" },
|
||||
width: 150,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "UPC is required", level: "error" },
|
||||
{ rule: "unique", errorMessage: "UPC must be unique", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]+$", errorMessage: "UPC must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "SKU",
|
||||
key: "sku",
|
||||
alternateMatches: ["item number", "product code", "product id", "item id"],
|
||||
fieldType: {
|
||||
type: "input",
|
||||
},
|
||||
example: "WX-123",
|
||||
description: "Unique product identifier",
|
||||
label: "Supplier #",
|
||||
key: "supplier_no",
|
||||
description: "Supplier's product identifier",
|
||||
alternateMatches: ["sku", "item#", "mfg item #", "item"],
|
||||
fieldType: { type: "input" },
|
||||
width: 120,
|
||||
validations: [
|
||||
{
|
||||
rule: "required",
|
||||
errorMessage: "SKU is required",
|
||||
level: "error",
|
||||
},
|
||||
{
|
||||
rule: "unique",
|
||||
errorMessage: "SKU must be unique",
|
||||
level: "error",
|
||||
},
|
||||
{ rule: "required", errorMessage: "Supplier # is required", level: "error" },
|
||||
{ rule: "unique", errorMessage: "Supplier # must be unique", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Category",
|
||||
key: "category",
|
||||
alternateMatches: ["product category", "type", "product type"],
|
||||
label: "Notions #",
|
||||
key: "notions_no",
|
||||
description: "Internal notions number",
|
||||
fieldType: { type: "input" },
|
||||
width: 120,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "Notions # is required", level: "error" },
|
||||
{ rule: "unique", errorMessage: "Notions # must be unique", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]+$", errorMessage: "Notions # must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Name",
|
||||
key: "name",
|
||||
description: "Product name/title",
|
||||
alternateMatches: ["sku description"],
|
||||
fieldType: { type: "input" },
|
||||
width: 300,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "Name is required", level: "error" },
|
||||
{ rule: "unique", errorMessage: "Name must be unique", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Item Number",
|
||||
key: "item_number",
|
||||
description: "Internal item reference number",
|
||||
fieldType: { type: "input" },
|
||||
width: 120,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "Item Number is required", level: "error" },
|
||||
{ rule: "unique", errorMessage: "Item Number must be unique", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Image URL",
|
||||
key: "image_url",
|
||||
description: "Product image URL(s)",
|
||||
fieldType: { type: "input" },
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
label: "MSRP",
|
||||
key: "msrp",
|
||||
description: "Manufacturer's Suggested Retail Price",
|
||||
alternateMatches: ["retail", "retail price", "sugg retail", "price", "sugg. Retail"],
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "MSRP is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]*.?[0-9]+$", errorMessage: "MSRP must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Qty Per Unit",
|
||||
key: "qty_per_unit",
|
||||
description: "Quantity of items per individual unit",
|
||||
alternateMatches: ["inner pack", "inner", "min qty", "unit qty", "min. order qty"],
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "Qty Per Unit is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]+$", errorMessage: "Qty Per Unit must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Cost Each",
|
||||
key: "cost_each",
|
||||
description: "Wholesale cost per unit",
|
||||
alternateMatches: ["wholesale", "wholesale price"],
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "Cost Each is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]*.?[0-9]+$", errorMessage: "Cost Each must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Case Pack",
|
||||
key: "case_qty",
|
||||
description: "Number of units per case",
|
||||
alternateMatches: ["mc qty"],
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{ rule: "regex", value: "^[0-9]+$", errorMessage: "Case Pack must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Tax Category",
|
||||
key: "tax_cat",
|
||||
description: "Product tax category",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Electronics", value: "electronics" },
|
||||
{ label: "Clothing", value: "clothing" },
|
||||
{ label: "Food & Beverage", value: "food_beverage" },
|
||||
{ label: "Office Supplies", value: "office_supplies" },
|
||||
{ label: "Other", value: "other" },
|
||||
{ label: "Standard", value: "standard" },
|
||||
{ label: "Reduced", value: "reduced" },
|
||||
{ label: "Zero", value: "zero" },
|
||||
{ label: "Exempt", value: "exempt" },
|
||||
],
|
||||
},
|
||||
width: 150,
|
||||
validations: [
|
||||
{
|
||||
rule: "required",
|
||||
errorMessage: "Category is required",
|
||||
level: "error",
|
||||
},
|
||||
],
|
||||
example: "Electronics",
|
||||
description: "Product category",
|
||||
validations: [{ rule: "required", errorMessage: "Tax Category is required", level: "error" }],
|
||||
},
|
||||
{
|
||||
label: "Quantity",
|
||||
key: "quantity",
|
||||
alternateMatches: ["qty", "stock", "amount", "inventory", "stock level"],
|
||||
fieldType: {
|
||||
type: "input",
|
||||
label: "Company",
|
||||
key: "company",
|
||||
description: "Company/Brand name",
|
||||
fieldType: { type: "input" },
|
||||
width: 200,
|
||||
validations: [{ rule: "required", errorMessage: "Company is required", level: "error" }],
|
||||
},
|
||||
example: "100",
|
||||
description: "Current stock quantity",
|
||||
{
|
||||
label: "Line",
|
||||
key: "line",
|
||||
description: "Product line",
|
||||
fieldType: { type: "input" },
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
label: "Sub Line",
|
||||
key: "subline",
|
||||
description: "Product sub-line",
|
||||
fieldType: { type: "input" },
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
label: "Artist",
|
||||
key: "artist",
|
||||
description: "Artist/Designer name",
|
||||
fieldType: { type: "input" },
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
label: "ETA Date",
|
||||
key: "eta",
|
||||
description: "Estimated arrival date",
|
||||
alternateMatches: ["shipping month"],
|
||||
fieldType: { type: "input" },
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
label: "Weight",
|
||||
key: "weight",
|
||||
description: "Product weight (in lbs)",
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{
|
||||
rule: "required",
|
||||
errorMessage: "Quantity is required",
|
||||
level: "error",
|
||||
},
|
||||
{
|
||||
rule: "regex",
|
||||
value: "^[0-9]+$",
|
||||
errorMessage: "Quantity must be a positive number",
|
||||
level: "error",
|
||||
},
|
||||
{ rule: "required", errorMessage: "Weight is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]*.?[0-9]+$", errorMessage: "Weight must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Price",
|
||||
key: "price",
|
||||
alternateMatches: ["unit price", "cost", "selling price", "retail price"],
|
||||
fieldType: {
|
||||
type: "input",
|
||||
},
|
||||
example: "29.99",
|
||||
description: "Selling price per unit",
|
||||
label: "Length",
|
||||
key: "length",
|
||||
description: "Product length (in inches)",
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{
|
||||
rule: "required",
|
||||
errorMessage: "Price is required",
|
||||
level: "error",
|
||||
},
|
||||
{
|
||||
rule: "regex",
|
||||
value: "^\\d*\\.?\\d+$",
|
||||
errorMessage: "Price must be a valid number",
|
||||
level: "error",
|
||||
},
|
||||
{ rule: "required", errorMessage: "Length is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]*.?[0-9]+$", errorMessage: "Length must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "In Stock",
|
||||
key: "inStock",
|
||||
alternateMatches: ["available", "active", "status"],
|
||||
fieldType: {
|
||||
type: "checkbox",
|
||||
booleanMatches: {
|
||||
yes: true,
|
||||
no: false,
|
||||
"in stock": true,
|
||||
"out of stock": false,
|
||||
available: true,
|
||||
unavailable: false,
|
||||
},
|
||||
},
|
||||
width: 80,
|
||||
example: "Yes",
|
||||
description: "Whether the item is currently in stock",
|
||||
},
|
||||
{
|
||||
label: "Minimum Stock",
|
||||
key: "minStock",
|
||||
alternateMatches: ["min qty", "reorder point", "low stock level"],
|
||||
fieldType: {
|
||||
type: "input",
|
||||
},
|
||||
example: "10",
|
||||
description: "Minimum stock level before reorder",
|
||||
label: "Width",
|
||||
key: "width",
|
||||
description: "Product width (in inches)",
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{
|
||||
rule: "regex",
|
||||
value: "^[0-9]+$",
|
||||
errorMessage: "Minimum stock must be a positive number",
|
||||
level: "error",
|
||||
},
|
||||
{ rule: "required", errorMessage: "Width is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]*.?[0-9]+$", errorMessage: "Width must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Location",
|
||||
key: "location",
|
||||
alternateMatches: ["storage location", "warehouse", "shelf", "bin"],
|
||||
label: "Height",
|
||||
key: "height",
|
||||
description: "Product height (in inches)",
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{ rule: "required", errorMessage: "Height is required", level: "error" },
|
||||
{ rule: "regex", value: "^[0-9]*.?[0-9]+$", errorMessage: "Height must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Shipping Restrictions",
|
||||
key: "ship_restrictions",
|
||||
description: "Product shipping restrictions",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Warehouse A", value: "warehouse_a" },
|
||||
{ label: "Warehouse B", value: "warehouse_b" },
|
||||
{ label: "Store Front", value: "store_front" },
|
||||
{ label: "External Storage", value: "external" },
|
||||
{ label: "None", value: "none" },
|
||||
{ label: "Hazmat", value: "hazmat" },
|
||||
{ label: "Oversize", value: "oversize" },
|
||||
{ label: "Restricted", value: "restricted" },
|
||||
],
|
||||
},
|
||||
width: 150,
|
||||
validations: [{ rule: "required", errorMessage: "Shipping Restrictions is required", level: "error" }],
|
||||
},
|
||||
{
|
||||
label: "Country Of Origin",
|
||||
key: "coo",
|
||||
description: "2-letter country code (ISO)",
|
||||
alternateMatches: ["coo"],
|
||||
fieldType: { type: "input" },
|
||||
width: 100,
|
||||
validations: [
|
||||
{ rule: "regex", value: "^[A-Z]{2}$", errorMessage: "Country code must be 2 letters", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "HTS Code",
|
||||
key: "hts_code",
|
||||
description: "Harmonized Tariff Schedule code",
|
||||
alternateMatches: ["taric"],
|
||||
fieldType: { type: "input" },
|
||||
width: 120,
|
||||
validations: [
|
||||
{ rule: "regex", value: "^[0-9]+$", errorMessage: "HTS Code must be a number", level: "error" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Size Category",
|
||||
key: "size_cat",
|
||||
description: "Product size category",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Small", value: "small" },
|
||||
{ label: "Medium", value: "medium" },
|
||||
{ label: "Large", value: "large" },
|
||||
{ label: "Extra Large", value: "xl" },
|
||||
],
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
label: "Description",
|
||||
key: "description",
|
||||
description: "Detailed product description",
|
||||
fieldType: { type: "input" },
|
||||
width: 400,
|
||||
validations: [{ rule: "required", errorMessage: "Description is required", level: "error" }],
|
||||
},
|
||||
{
|
||||
label: "Private Notes",
|
||||
key: "priv_notes",
|
||||
description: "Internal notes about the product",
|
||||
fieldType: { type: "input" },
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
label: "Categories",
|
||||
key: "categories",
|
||||
description: "Product categories",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Art Supplies", value: "art" },
|
||||
{ label: "Crafts", value: "crafts" },
|
||||
{ label: "Home Decor", value: "home" },
|
||||
{ label: "Stationery", value: "stationery" },
|
||||
],
|
||||
},
|
||||
width: 200,
|
||||
validations: [{ rule: "required", errorMessage: "Categories is required", level: "error" }],
|
||||
},
|
||||
{
|
||||
label: "Themes",
|
||||
key: "themes",
|
||||
description: "Product themes/styles",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Modern", value: "modern" },
|
||||
{ label: "Vintage", value: "vintage" },
|
||||
{ label: "Nature", value: "nature" },
|
||||
{ label: "Abstract", value: "abstract" },
|
||||
],
|
||||
},
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
label: "Colors",
|
||||
key: "colors",
|
||||
description: "Product colors",
|
||||
fieldType: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Red", value: "red" },
|
||||
{ label: "Blue", value: "blue" },
|
||||
{ label: "Green", value: "green" },
|
||||
{ label: "Multi", value: "multi" },
|
||||
],
|
||||
},
|
||||
width: 150,
|
||||
example: "Warehouse A",
|
||||
description: "Storage location of the product",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user