@base44/app-plugin-commerce 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/base44/agents/commerce/StoreAdmin.jsonc +7 -7
- package/base44/entities/commerce.Order.jsonc +1 -1
- package/base44/entities/commerce.PaymentGateway.jsonc +3 -3
- package/base44/entities/commerce.Product.jsonc +9 -45
- package/base44/entities/commerce.ProductAttribute.jsonc +7 -19
- package/base44/entities/commerce.ProductAttributeTerm.jsonc +4 -10
- package/base44/entities/commerce.ProductTag.jsonc +1 -8
- package/base44/entities/commerce.ProductVariation.jsonc +1 -1
- package/base44/entities/commerce.StoreSettings.jsonc +1 -1
- package/base44/functions/commerce/admin-products/entry.ts +107 -35
- package/base44/functions/commerce/admin-refunds/entry.ts +1 -1
- package/base44/functions/commerce/admin-reports/entry.ts +1 -1
- package/base44/functions/commerce/admin-tools/entry.ts +4 -3
- package/base44/functions/commerce/payments/entry.ts +0 -2
- package/base44/functions/commerce/seed-store/defaults.ts +13 -39
- package/base44/functions/commerce/seed-store/entry.ts +47 -35
- package/base44/functions/commerce/seed-store/sample-data.ts +28 -66
- package/base44/functions/commerce/storefront-cart/entry.ts +0 -7
- package/base44/functions/commerce/storefront-catalog/entry.ts +12 -21
- package/base44/functions/commerce/storefront-checkout/entry.ts +5 -12
- package/base44/shared/commerce/coupons.ts +4 -7
- package/base44/shared/commerce/email-templates.ts +15 -13
- package/base44/shared/commerce/emails.ts +4 -3
- package/base44/shared/commerce/payments.ts +8 -20
- package/base44/shared/commerce/products.ts +24 -0
- package/base44/shared/commerce/settings.ts +2 -3
- package/base44/shared/commerce/stock.ts +2 -4
- package/base44/shared/commerce/totals.ts +37 -42
- package/package.json +1 -1
- package/scripts/install.js +21 -4
- package/skills/commerce/SKILL.md +6 -5
- package/skills/commerce/docs/api-admin.md +16 -14
- package/skills/commerce/docs/api-storefront.md +39 -35
- package/skills/commerce/installation-guidelines.md +4 -3
- package/skills/commerce/post-installation.md +22 -25
- package/skills/commerce/references/admin-product-form.md +56 -0
- package/skills/commerce/references/emails.md +4 -3
- package/skills/commerce/references/guest-access-security.md +2 -2
- package/skills/commerce/references/limits-and-performance.md +1 -1
- package/skills/commerce/references/online-payments.md +8 -8
- package/skills/commerce/references/product-render.md +25 -23
- package/skills/commerce/references/storefront-product-page.md +9 -9
- package/skills/commerce/references/webhooks.md +3 -1
- package/src/commerce/admin/README.md +4 -4
- package/src/commerce/admin/context/BasePathContext.jsx +5 -5
- package/src/commerce/admin/context/SettingsContext.jsx +4 -4
- package/src/commerce/admin/index.jsx +3 -3
- package/src/commerce/admin/layout/Sidebar.jsx +1 -9
- package/src/commerce/admin/lib/constants.js +0 -7
- package/src/commerce/admin/lib/paths.js +6 -6
- package/src/commerce/admin/lib/product-utils.js +18 -15
- package/src/commerce/admin/pages/orders/components/AddProductDialog.jsx +8 -8
- package/src/commerce/admin/pages/products/ProductEditor.jsx +10 -12
- package/src/commerce/admin/pages/products/ProductsList.jsx +3 -15
- package/src/commerce/admin/pages/products/components/AttributesSection.jsx +426 -0
- package/src/commerce/admin/pages/products/components/ProductDataPanel.jsx +33 -69
- package/src/commerce/admin/pages/products/components/TaxonomyPanel.jsx +1 -1
- package/src/commerce/admin/pages/products/components/tabs/LinkedTab.jsx +1 -14
- package/src/commerce/admin/pages/products/components/tabs/ModifiersTab.jsx +19 -0
- package/src/commerce/admin/pages/products/components/tabs/PriceInventoryTab.jsx +728 -0
- package/src/commerce/admin/pages/reports/Reports.jsx +3 -3
- package/src/commerce/admin/pages/settings/EmailsSettings.jsx +12 -14
- package/src/commerce/admin/pages/settings/GeneralSettings.jsx +6 -116
- package/src/commerce/admin/pages/settings/PaymentsSettings.jsx +101 -62
- package/src/commerce/admin/pages/settings/SettingsLayout.jsx +2 -6
- package/src/commerce/admin/pages/settings/TaxSettings.jsx +0 -1
- package/src/commerce/admin/pages/status/WebhookEditor.jsx +3 -3
- package/src/commerce/admin/pages/status/Webhooks.jsx +2 -2
- package/src/commerce/admin/routes.jsx +10 -19
- package/src/commerce/utils/index.js +2 -2
- package/src/commerce/utils/shipping-promos.js +9 -6
- package/src/commerce/utils/variants.js +21 -21
- package/src/commerce/admin/pages/products/AttributeTerms.jsx +0 -180
- package/src/commerce/admin/pages/products/Attributes.jsx +0 -183
- package/src/commerce/admin/pages/products/Tags.jsx +0 -150
- package/src/commerce/admin/pages/products/components/tabs/AdvancedTab.jsx +0 -48
- package/src/commerce/admin/pages/products/components/tabs/AttributesTab.jsx +0 -208
- package/src/commerce/admin/pages/products/components/tabs/ExternalTab.jsx +0 -41
- package/src/commerce/admin/pages/products/components/tabs/GeneralTab.jsx +0 -103
- package/src/commerce/admin/pages/products/components/tabs/InventoryTab.jsx +0 -93
- package/src/commerce/admin/pages/products/components/tabs/ShippingTab.jsx +0 -86
- package/src/commerce/admin/pages/products/components/tabs/VariationsTab.jsx +0 -377
|
@@ -155,8 +155,8 @@ function SetupScreen({ onDone }) {
|
|
|
155
155
|
onChange={(e) => setStoreName(e.target.value)}
|
|
156
156
|
/>
|
|
157
157
|
<p className="text-xs text-muted-foreground">
|
|
158
|
-
|
|
159
|
-
Editable later in Settings →
|
|
158
|
+
Used in the subject and as the sender name on every transactional email.
|
|
159
|
+
Editable later in Settings → Emails.
|
|
160
160
|
</p>
|
|
161
161
|
</div>
|
|
162
162
|
{hasProducts === false && (
|
|
@@ -171,8 +171,8 @@ function SetupScreen({ onDone }) {
|
|
|
171
171
|
Include sample data
|
|
172
172
|
</Label>
|
|
173
173
|
<p className="text-xs text-muted-foreground">
|
|
174
|
-
Adds demo categories, products (
|
|
175
|
-
|
|
174
|
+
Adds demo categories, 10 products (three with size/colour variants, one
|
|
175
|
+
downloadable) and coupons so you can explore the admin.
|
|
176
176
|
</p>
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|
|
@@ -10,15 +10,15 @@ import { BasePathProvider } from "./context/BasePathContext";
|
|
|
10
10
|
* The store admin application.
|
|
11
11
|
*
|
|
12
12
|
* Mount inside your app's router:
|
|
13
|
-
* <Route path="/admin/*" element={<AdminApp />} />
|
|
13
|
+
* <Route path="/store-admin/*" element={<AdminApp />} />
|
|
14
14
|
*
|
|
15
|
-
* If mounted somewhere other than /admin, pass the prefix:
|
|
15
|
+
* If mounted somewhere other than /store-admin, pass the prefix:
|
|
16
16
|
* <Route path="/backoffice/*" element={<AdminApp basePath="/backoffice" />} />
|
|
17
17
|
*
|
|
18
18
|
* Requires an authenticated user with role "admin" (enforced by AuthGuard,
|
|
19
19
|
* and independently by entity RLS + requireAdmin() in backend functions).
|
|
20
20
|
*/
|
|
21
|
-
export default function AdminApp({ basePath = "/admin" }) {
|
|
21
|
+
export default function AdminApp({ basePath = "/store-admin" }) {
|
|
22
22
|
return (
|
|
23
23
|
<BasePathProvider value={basePath}>
|
|
24
24
|
<Toaster richColors position="top-right" />
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
ShoppingCart,
|
|
11
11
|
Sparkles,
|
|
12
12
|
Users,
|
|
13
|
-
Webhook,
|
|
14
13
|
} from "lucide-react";
|
|
15
14
|
import { call } from "../lib/api";
|
|
16
15
|
import { useAdminHref } from "../context/BasePathContext";
|
|
@@ -30,8 +29,6 @@ const NAV = [
|
|
|
30
29
|
items: [
|
|
31
30
|
{ label: "All Products", path: "products", end: true },
|
|
32
31
|
{ label: "Categories", path: "products/categories" },
|
|
33
|
-
{ label: "Tags", path: "products/tags" },
|
|
34
|
-
{ label: "Attributes", path: "products/attributes" },
|
|
35
32
|
{ label: "Reviews", path: "products/reviews" },
|
|
36
33
|
],
|
|
37
34
|
},
|
|
@@ -43,11 +40,6 @@ const NAV = [
|
|
|
43
40
|
{
|
|
44
41
|
items: [{ label: "Settings", path: "settings", icon: Settings }],
|
|
45
42
|
},
|
|
46
|
-
{
|
|
47
|
-
title: "Status",
|
|
48
|
-
icon: Webhook,
|
|
49
|
-
items: [{ label: "Webhooks", path: "webhooks" }],
|
|
50
|
-
},
|
|
51
43
|
];
|
|
52
44
|
|
|
53
45
|
/** Left navigation. `onNavigate` closes the mobile sheet; `onOpenBot` opens the StoreAdmin bot panel. */
|
|
@@ -78,7 +70,7 @@ export default function Sidebar({ onNavigate, onOpenBot }) {
|
|
|
78
70
|
<div className="flex h-full flex-col">
|
|
79
71
|
<div className="flex h-14 items-center gap-2 border-b px-4">
|
|
80
72
|
<Package className="h-5 w-5 text-primary" />
|
|
81
|
-
<span className="font-semibold">Store
|
|
73
|
+
<span className="font-semibold">Store Management</span>
|
|
82
74
|
</div>
|
|
83
75
|
<nav className="flex-1 space-y-4 overflow-y-auto p-3">
|
|
84
76
|
{NAV.map((group, gi) => (
|
|
@@ -17,13 +17,6 @@ export const PRODUCT_STATUSES = [
|
|
|
17
17
|
{ value: "publish", label: "Published", color: "bg-green-100 text-green-800 border-green-200" },
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
-
export const PRODUCT_TYPES = [
|
|
21
|
-
{ value: "simple", label: "Simple product" },
|
|
22
|
-
{ value: "grouped", label: "Grouped product" },
|
|
23
|
-
{ value: "external", label: "External/Affiliate product" },
|
|
24
|
-
{ value: "variable", label: "Variable product" },
|
|
25
|
-
];
|
|
26
|
-
|
|
27
20
|
export const CATALOG_VISIBILITIES = [
|
|
28
21
|
{ value: "visible", label: "Shop and search results" },
|
|
29
22
|
{ value: "catalog", label: "Shop only" },
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Mount-path handling for the admin app.
|
|
3
3
|
*
|
|
4
|
-
* The admin is mounted with a splat route — `<Route path="/admin/*">` — and both
|
|
4
|
+
* The admin is mounted with a splat route — `<Route path="/store-admin/*">` — and both
|
|
5
5
|
* halves of that pattern leak into places they shouldn't: the `basePath` prop
|
|
6
|
-
* gets the pattern pasted in verbatim, and the literal URL `/admin/*` gets
|
|
6
|
+
* gets the pattern pasted in verbatim, and the literal URL `/store-admin/*` gets
|
|
7
7
|
* opened (pattern copied into the address bar, or a nav link built from the
|
|
8
8
|
* route table). Neither is a real page, so both are normalized here rather than
|
|
9
9
|
* dead-ending the admin.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
/** Strip a trailing route splat and slashes: "/admin/*" → "/admin". */
|
|
13
|
-
export function normalizeBasePath(value, fallback = "/admin") {
|
|
12
|
+
/** Strip a trailing route splat and slashes: "/store-admin/*" → "/store-admin". */
|
|
13
|
+
export function normalizeBasePath(value, fallback = "/store-admin") {
|
|
14
14
|
const clean = String(value ?? "")
|
|
15
15
|
.replace(/\/+\*+$/, "")
|
|
16
16
|
.replace(/\/+$/, "");
|
|
@@ -21,8 +21,8 @@ export function normalizeBasePath(value, fallback = "/admin") {
|
|
|
21
21
|
* Is this leftover path (the `*` param of the catch-all route) nothing but
|
|
22
22
|
* route-*pattern* segments — `*`, its percent-encoded form, or `:param`?
|
|
23
23
|
*
|
|
24
|
-
* `/admin/*` → true (send them to the dashboard)
|
|
25
|
-
* `/admin/ordrs` → false (a genuine 404)
|
|
24
|
+
* `/store-admin/*` → true (send them to the dashboard)
|
|
25
|
+
* `/store-admin/ordrs` → false (a genuine 404)
|
|
26
26
|
*/
|
|
27
27
|
export function isMountPatternPath(rest) {
|
|
28
28
|
const segments = String(rest ?? "")
|
|
@@ -9,20 +9,20 @@ export function slugify(name) {
|
|
|
9
9
|
.replace(/^-+|-+$/g, "");
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A product sells variants because it carries attributes — every entry in
|
|
14
|
+
* `attributes[]` is a variant axis, so attaching one is the whole declaration.
|
|
15
|
+
* Descriptive properties are `meta_data` (modifiers), not attributes.
|
|
16
|
+
*/
|
|
17
|
+
export const isVariable = (p) => (p?.attributes ?? []).length > 0;
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
|
-
* Cartesian product of
|
|
20
|
+
* Cartesian product of every attribute that has options.
|
|
19
21
|
* Returns [{attributes: [{attribute_id, name, option}]}] — one entry per combo.
|
|
20
|
-
* Returns [] when no
|
|
22
|
+
* Returns [] when no attribute has options yet.
|
|
21
23
|
*/
|
|
22
24
|
export function generateVariationCombos(attributes) {
|
|
23
|
-
const varAttrs = (attributes || []).filter(
|
|
24
|
-
(a) => a.variation && (a.options || []).length > 0
|
|
25
|
-
);
|
|
25
|
+
const varAttrs = (attributes || []).filter((a) => (a.options || []).length > 0);
|
|
26
26
|
if (!varAttrs.length) return [];
|
|
27
27
|
const combos = varAttrs.reduce(
|
|
28
28
|
(acc, attr) =>
|
|
@@ -44,12 +44,15 @@ export function variationLabel(variation) {
|
|
|
44
44
|
.join(" / ") || "Any";
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/** Order-independent identity of a variation's attribute combination. */
|
|
48
|
+
export function comboKey(variation) {
|
|
49
|
+
return (variation?.attributes || [])
|
|
50
|
+
.map((x) => `${(x.name || "").toLowerCase()}=${(x.option || "").toLowerCase()}`)
|
|
51
|
+
.sort()
|
|
52
|
+
.join("|");
|
|
53
|
+
}
|
|
54
|
+
|
|
47
55
|
/** True when two variations have the same attribute combo. */
|
|
48
56
|
export function sameCombo(a, b) {
|
|
49
|
-
|
|
50
|
-
(v?.attributes || [])
|
|
51
|
-
.map((x) => `${(x.name || "").toLowerCase()}=${(x.option || "").toLowerCase()}`)
|
|
52
|
-
.sort()
|
|
53
|
-
.join("|");
|
|
54
|
-
return key(a) === key(b);
|
|
57
|
+
return comboKey(a) === comboKey(b);
|
|
55
58
|
}
|
|
@@ -20,11 +20,11 @@ import { Loader2 } from "lucide-react";
|
|
|
20
20
|
|
|
21
21
|
import { call, base44 } from "../../../lib/api";
|
|
22
22
|
import SearchSelect from "../../../components/SearchSelect";
|
|
23
|
-
import { variationLabel } from "../../../lib/product-utils";
|
|
23
|
+
import { isVariable, variationLabel } from "../../../lib/product-utils";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Two-step product picker for the order editor:
|
|
27
|
-
* product search → (
|
|
27
|
+
* product search → (products with variants only) variant select → quantity.
|
|
28
28
|
*
|
|
29
29
|
* Props: { open, onOpenChange, onAdd({product, variation|null, quantity}) }
|
|
30
30
|
*/
|
|
@@ -50,7 +50,7 @@ export default function AddProductDialog({ open, onOpenChange, onAdd }) {
|
|
|
50
50
|
return rows.map((p) => ({
|
|
51
51
|
value: p.id,
|
|
52
52
|
label: p.name,
|
|
53
|
-
meta:
|
|
53
|
+
meta: p.sku ? `SKU: ${p.sku}` : undefined,
|
|
54
54
|
product: p,
|
|
55
55
|
}));
|
|
56
56
|
};
|
|
@@ -59,7 +59,7 @@ export default function AddProductDialog({ open, onOpenChange, onAdd }) {
|
|
|
59
59
|
setPicked(opt);
|
|
60
60
|
setVariations(null);
|
|
61
61
|
setVariationId("");
|
|
62
|
-
if (opt?.product
|
|
62
|
+
if (isVariable(opt?.product)) {
|
|
63
63
|
setLoadingVariations(true);
|
|
64
64
|
try {
|
|
65
65
|
const rows = await base44.entities["commerce.ProductVariation"].filter({ product_id: opt.value }, "menu_order", 200);
|
|
@@ -70,11 +70,11 @@ export default function AddProductDialog({ open, onOpenChange, onAdd }) {
|
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
const
|
|
74
|
-
const canAdd = picked && quantity > 0 && (!
|
|
73
|
+
const hasVariants = isVariable(picked?.product);
|
|
74
|
+
const canAdd = picked && quantity > 0 && (!hasVariants || variationId);
|
|
75
75
|
|
|
76
76
|
const submit = () => {
|
|
77
|
-
const variation =
|
|
77
|
+
const variation = hasVariants ? (variations || []).find((v) => v.id === variationId) : null;
|
|
78
78
|
onAdd({ product: picked.product, variation, quantity });
|
|
79
79
|
onOpenChange(false);
|
|
80
80
|
};
|
|
@@ -97,7 +97,7 @@ export default function AddProductDialog({ open, onOpenChange, onAdd }) {
|
|
|
97
97
|
/>
|
|
98
98
|
</div>
|
|
99
99
|
|
|
100
|
-
{
|
|
100
|
+
{hasVariants && (
|
|
101
101
|
<div className="grid gap-1.5">
|
|
102
102
|
<Label>Variation</Label>
|
|
103
103
|
{loadingVariations ? (
|
|
@@ -11,7 +11,7 @@ import { useAdminHref } from "../../context/BasePathContext";
|
|
|
11
11
|
import PageHeader from "../../components/PageHeader";
|
|
12
12
|
import MediaUploader from "../../components/MediaUploader";
|
|
13
13
|
import RichTextarea from "../../components/RichTextarea";
|
|
14
|
-
import { slugify
|
|
14
|
+
import { slugify } from "../../lib/product-utils";
|
|
15
15
|
import ProductDataPanel from "./components/ProductDataPanel";
|
|
16
16
|
import TaxonomyPanel from "./components/TaxonomyPanel";
|
|
17
17
|
import PublishBox from "./components/PublishBox";
|
|
@@ -19,7 +19,6 @@ import PublishBox from "./components/PublishBox";
|
|
|
19
19
|
const NEW_PRODUCT = {
|
|
20
20
|
name: "",
|
|
21
21
|
slug: "",
|
|
22
|
-
type: "simple",
|
|
23
22
|
status: "draft",
|
|
24
23
|
featured: false,
|
|
25
24
|
catalog_visibility: "visible",
|
|
@@ -35,8 +34,6 @@ const NEW_PRODUCT = {
|
|
|
35
34
|
downloads: [],
|
|
36
35
|
download_limit: -1,
|
|
37
36
|
download_expiry: -1,
|
|
38
|
-
external_url: "",
|
|
39
|
-
button_text: "",
|
|
40
37
|
tax_status: "taxable",
|
|
41
38
|
tax_class: "standard",
|
|
42
39
|
manage_stock: false,
|
|
@@ -48,17 +45,13 @@ const NEW_PRODUCT = {
|
|
|
48
45
|
weight: null,
|
|
49
46
|
dimensions: { length: null, width: null, height: null },
|
|
50
47
|
shipping_class_id: "",
|
|
51
|
-
reviews_allowed: true,
|
|
52
48
|
upsell_ids: [],
|
|
53
49
|
cross_sell_ids: [],
|
|
54
|
-
grouped_products: [],
|
|
55
|
-
purchase_note: "",
|
|
56
50
|
category_ids: [],
|
|
57
51
|
tag_ids: [],
|
|
58
52
|
images: [],
|
|
59
53
|
attributes: [],
|
|
60
54
|
default_attributes: [],
|
|
61
|
-
menu_order: 0,
|
|
62
55
|
meta_data: [],
|
|
63
56
|
};
|
|
64
57
|
|
|
@@ -83,7 +76,10 @@ export default function ProductEditor() {
|
|
|
83
76
|
() => base44.entities["commerce.ProductTag"].list(undefined, 1000),
|
|
84
77
|
[]
|
|
85
78
|
);
|
|
86
|
-
const { data: attributes } = useAsync(
|
|
79
|
+
const { data: attributes, refetch: refreshAttributes } = useAsync(
|
|
80
|
+
() => base44.entities["commerce.ProductAttribute"].list("order", 500),
|
|
81
|
+
[]
|
|
82
|
+
);
|
|
87
83
|
const { data: shippingClasses } = useAsync(() => base44.entities["commerce.ShippingClass"].list(undefined, 500), []);
|
|
88
84
|
const { data: taxClasses } = useAsync(() => base44.entities["commerce.TaxClass"].list(undefined, 100), []);
|
|
89
85
|
|
|
@@ -127,8 +123,7 @@ export default function ProductEditor() {
|
|
|
127
123
|
}
|
|
128
124
|
setSaving(true);
|
|
129
125
|
try {
|
|
130
|
-
const payload = { product: { ...product, name: product.name.trim() } };
|
|
131
|
-
if (isVariable(product)) payload.variations = variations;
|
|
126
|
+
const payload = { product: { ...product, name: product.name.trim() }, variations };
|
|
132
127
|
const data = await call("admin-products", "save", payload);
|
|
133
128
|
const savedId = data?.product?.id || data?.id || id;
|
|
134
129
|
toast.success(isNew ? "Product created" : "Product saved");
|
|
@@ -162,7 +157,10 @@ export default function ProductEditor() {
|
|
|
162
157
|
);
|
|
163
158
|
}
|
|
164
159
|
|
|
165
|
-
const refs = {
|
|
160
|
+
const refs = {
|
|
161
|
+
categories, tags, attributes, shippingClasses, taxClasses,
|
|
162
|
+
refreshCategories, refreshTags, refreshAttributes,
|
|
163
|
+
};
|
|
166
164
|
|
|
167
165
|
return (
|
|
168
166
|
<div className="space-y-4">
|
|
@@ -32,7 +32,7 @@ import SearchSelect from "../../components/SearchSelect";
|
|
|
32
32
|
import StatusBadge from "../../components/StatusBadge";
|
|
33
33
|
import MoneyInput from "../../components/MoneyInput";
|
|
34
34
|
import ConfirmDialog from "../../components/ConfirmDialog";
|
|
35
|
-
import {
|
|
35
|
+
import { PRODUCT_STATUSES, STOCK_STATUSES, statusMeta } from "../../lib/constants";
|
|
36
36
|
import { formatDate } from "../../lib/format";
|
|
37
37
|
|
|
38
38
|
const ALL = "all";
|
|
@@ -123,7 +123,6 @@ export default function ProductsList() {
|
|
|
123
123
|
|
|
124
124
|
const [q, setQ] = useState("");
|
|
125
125
|
const [category, setCategory] = useState(null);
|
|
126
|
-
const [type, setType] = useState(ALL);
|
|
127
126
|
const [stock, setStock] = useState(ALL);
|
|
128
127
|
const [selected, setSelected] = useState([]);
|
|
129
128
|
const [quickEdit, setQuickEdit] = useState(null);
|
|
@@ -145,7 +144,6 @@ export default function ProductsList() {
|
|
|
145
144
|
const data = await call("admin-products", "search", {
|
|
146
145
|
q: debouncedQ || undefined,
|
|
147
146
|
category_id: category?.value || undefined,
|
|
148
|
-
type: type === ALL ? undefined : type,
|
|
149
147
|
stock_status: stock === ALL ? undefined : stock,
|
|
150
148
|
sort,
|
|
151
149
|
limit,
|
|
@@ -154,14 +152,13 @@ export default function ProductsList() {
|
|
|
154
152
|
return data?.rows || data || [];
|
|
155
153
|
}
|
|
156
154
|
const query = {};
|
|
157
|
-
if (type !== ALL) query.type = type;
|
|
158
155
|
if (stock !== ALL) query.stock_status = stock;
|
|
159
156
|
return base44.entities["commerce.Product"].filter(query, sort, limit, skip);
|
|
160
157
|
},
|
|
161
|
-
[usingSearch, debouncedQ, category,
|
|
158
|
+
[usingSearch, debouncedQ, category, stock]
|
|
162
159
|
);
|
|
163
160
|
|
|
164
|
-
const list = usePagedList(fetcher, { deps: [debouncedQ, category?.value,
|
|
161
|
+
const list = usePagedList(fetcher, { deps: [debouncedQ, category?.value, stock] });
|
|
165
162
|
|
|
166
163
|
const toggleFeatured = async (row) => {
|
|
167
164
|
await call("admin-products", "save", { product: { id: row.id, featured: !row.featured } });
|
|
@@ -322,15 +319,6 @@ export default function ProductsList() {
|
|
|
322
319
|
.map((c) => ({ value: c.id, label: c.name }))
|
|
323
320
|
}
|
|
324
321
|
/>
|
|
325
|
-
<Select value={type} onValueChange={setType}>
|
|
326
|
-
<SelectTrigger className="w-44"><SelectValue /></SelectTrigger>
|
|
327
|
-
<SelectContent>
|
|
328
|
-
<SelectItem value={ALL}>All types</SelectItem>
|
|
329
|
-
{PRODUCT_TYPES.map((t) => (
|
|
330
|
-
<SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>
|
|
331
|
-
))}
|
|
332
|
-
</SelectContent>
|
|
333
|
-
</Select>
|
|
334
322
|
<Select value={stock} onValueChange={setStock}>
|
|
335
323
|
<SelectTrigger className="w-40"><SelectValue /></SelectTrigger>
|
|
336
324
|
<SelectContent>
|