@base44/app-plugin-commerce 0.1.3 → 0.1.5
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 +11 -11
- 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 +73 -121
- 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 +50 -166
- package/base44/functions/commerce/seed-store/sample-data.ts +28 -66
- package/base44/functions/commerce/seed-store/seed-catalog.ts +717 -0
- 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/catalog.ts +134 -0
- 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 +23 -7
- package/skills/commerce/SKILL.md +9 -7
- package/skills/commerce/docs/api-admin.md +20 -14
- package/skills/commerce/docs/api-storefront.md +39 -35
- package/skills/commerce/installation-guidelines.md +8 -7
- package/skills/commerce/post-installation.md +205 -84
- 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/reviews.md +20 -0
- 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
|
@@ -1,80 +1,51 @@
|
|
|
1
1
|
import React, { useMemo, useState } from "react";
|
|
2
2
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
|
3
3
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
4
|
-
import { Label } from "@/components/ui/label";
|
|
5
|
-
import {
|
|
6
|
-
Select,
|
|
7
|
-
SelectContent,
|
|
8
|
-
SelectItem,
|
|
9
|
-
SelectTrigger,
|
|
10
|
-
SelectValue,
|
|
11
|
-
} from "@/components/ui/select";
|
|
12
4
|
import { Separator } from "@/components/ui/separator";
|
|
13
5
|
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import ExternalTab from "./tabs/ExternalTab";
|
|
18
|
-
import InventoryTab from "./tabs/InventoryTab";
|
|
19
|
-
import ShippingTab from "./tabs/ShippingTab";
|
|
6
|
+
import { isVariable } from "../../../lib/product-utils";
|
|
7
|
+
import PriceInventoryTab from "./tabs/PriceInventoryTab";
|
|
8
|
+
import ModifiersTab from "./tabs/ModifiersTab";
|
|
20
9
|
import LinkedTab from "./tabs/LinkedTab";
|
|
21
|
-
import AttributesTab from "./tabs/AttributesTab";
|
|
22
|
-
import VariationsTab from "./tabs/VariationsTab";
|
|
23
10
|
import DownloadsTab from "./tabs/DownloadsTab";
|
|
24
|
-
import AdvancedTab from "./tabs/AdvancedTab";
|
|
25
11
|
|
|
26
12
|
/**
|
|
27
|
-
* The "Product data" panel:
|
|
28
|
-
*
|
|
13
|
+
* The "Product data" panel: vertical tabs. There is no product type, and nothing
|
|
14
|
+
* about a purchasable thing is split off into its own tab — Price & Inventory
|
|
15
|
+
* carries tax, the attributes, and a row per variant (or the product itself as
|
|
16
|
+
* its default variant), each row owning its price, stock and shipping.
|
|
29
17
|
*/
|
|
30
18
|
export default function ProductDataPanel({ product, up, refs, variations, setVariations }) {
|
|
31
19
|
const tabs = useMemo(() => {
|
|
32
|
-
const list = [];
|
|
33
|
-
if (
|
|
34
|
-
list.push({ id: "inventory", label: "Inventory" });
|
|
35
|
-
if (!product.virtual && !isExternal(product)) list.push({ id: "shipping", label: "Shipping" });
|
|
20
|
+
const list = [{ id: "price", label: "Price & Inventory" }, { id: "modifiers", label: "Modifiers" }];
|
|
21
|
+
if (product.downloadable) list.push({ id: "downloads", label: "Downloads" });
|
|
36
22
|
list.push({ id: "linked", label: "Linked products" });
|
|
37
|
-
list.push({ id: "attributes", label: "Attributes" });
|
|
38
|
-
if (isVariable(product)) list.push({ id: "variations", label: "Variations" });
|
|
39
|
-
if (product.downloadable && !isGrouped(product) && !isExternal(product))
|
|
40
|
-
list.push({ id: "downloads", label: "Downloads" });
|
|
41
|
-
list.push({ id: "advanced", label: "Advanced" });
|
|
42
23
|
return list;
|
|
43
24
|
}, [product]);
|
|
44
25
|
|
|
45
|
-
const [active, setActive] = useState("
|
|
26
|
+
const [active, setActive] = useState("price");
|
|
46
27
|
const activeTab = tabs.some((t) => t.id === active) ? active : tabs[0].id;
|
|
47
28
|
|
|
48
29
|
return (
|
|
49
30
|
<Card>
|
|
50
31
|
<CardHeader className="flex-row items-center gap-4 space-y-0 border-b py-3">
|
|
51
32
|
<span className="text-base font-semibold">Product data</span>
|
|
52
|
-
<
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
</label>
|
|
69
|
-
<label className="flex items-center gap-1.5">
|
|
70
|
-
<Checkbox
|
|
71
|
-
checked={product.downloadable}
|
|
72
|
-
onCheckedChange={(v) => up({ downloadable: Boolean(v) })}
|
|
73
|
-
/>
|
|
74
|
-
Downloadable
|
|
75
|
-
</label>
|
|
76
|
-
</div>
|
|
77
|
-
)}
|
|
33
|
+
<div className="flex items-center gap-4 text-sm">
|
|
34
|
+
<label className="flex items-center gap-1.5">
|
|
35
|
+
<Checkbox
|
|
36
|
+
checked={product.virtual}
|
|
37
|
+
onCheckedChange={(v) => up({ virtual: Boolean(v) })}
|
|
38
|
+
/>
|
|
39
|
+
Virtual
|
|
40
|
+
</label>
|
|
41
|
+
<label className="flex items-center gap-1.5">
|
|
42
|
+
<Checkbox
|
|
43
|
+
checked={product.downloadable}
|
|
44
|
+
onCheckedChange={(v) => up({ downloadable: Boolean(v) })}
|
|
45
|
+
/>
|
|
46
|
+
Downloadable
|
|
47
|
+
</label>
|
|
48
|
+
</div>
|
|
78
49
|
</CardHeader>
|
|
79
50
|
<CardContent className="p-0">
|
|
80
51
|
<div className="flex min-h-72 flex-col sm:flex-row">
|
|
@@ -97,18 +68,8 @@ export default function ProductDataPanel({ product, up, refs, variations, setVar
|
|
|
97
68
|
</nav>
|
|
98
69
|
|
|
99
70
|
<div className="min-w-0 flex-1 p-4">
|
|
100
|
-
{activeTab === "
|
|
101
|
-
|
|
102
|
-
<ExternalTab product={product} up={up} refs={refs} />
|
|
103
|
-
) : (
|
|
104
|
-
<GeneralTab product={product} up={up} refs={refs} />
|
|
105
|
-
))}
|
|
106
|
-
{activeTab === "inventory" && <InventoryTab product={product} up={up} />}
|
|
107
|
-
{activeTab === "shipping" && <ShippingTab product={product} up={up} refs={refs} />}
|
|
108
|
-
{activeTab === "linked" && <LinkedTab product={product} up={up} />}
|
|
109
|
-
{activeTab === "attributes" && <AttributesTab product={product} up={up} refs={refs} />}
|
|
110
|
-
{activeTab === "variations" && (
|
|
111
|
-
<VariationsTab
|
|
71
|
+
{activeTab === "price" && (
|
|
72
|
+
<PriceInventoryTab
|
|
112
73
|
product={product}
|
|
113
74
|
up={up}
|
|
114
75
|
refs={refs}
|
|
@@ -116,13 +77,16 @@ export default function ProductDataPanel({ product, up, refs, variations, setVar
|
|
|
116
77
|
setVariations={setVariations}
|
|
117
78
|
/>
|
|
118
79
|
)}
|
|
80
|
+
{activeTab === "modifiers" && <ModifiersTab product={product} up={up} />}
|
|
119
81
|
{activeTab === "downloads" && <DownloadsTab product={product} up={up} />}
|
|
120
|
-
{activeTab === "
|
|
82
|
+
{activeTab === "linked" && <LinkedTab product={product} up={up} />}
|
|
121
83
|
</div>
|
|
122
84
|
</div>
|
|
123
85
|
<Separator />
|
|
124
86
|
<div className="px-4 py-2 text-xs text-muted-foreground">
|
|
125
|
-
|
|
87
|
+
{isVariable(product)
|
|
88
|
+
? `${(product.attributes || []).length} variant attribute(s) · ${(variations || []).length} variant(s)`
|
|
89
|
+
: "No variants"}
|
|
126
90
|
{product.virtual ? " · Virtual" : ""}
|
|
127
91
|
{product.downloadable ? " · Downloadable" : ""}
|
|
128
92
|
</div>
|
|
@@ -195,7 +195,7 @@ function TagsCard({ tags, selected, onChange, refresh }) {
|
|
|
195
195
|
}
|
|
196
196
|
setSaving(true);
|
|
197
197
|
try {
|
|
198
|
-
const created = await base44.entities["commerce.ProductTag"].create({ name: label,
|
|
198
|
+
const created = await base44.entities["commerce.ProductTag"].create({ name: label, count: 0 });
|
|
199
199
|
toast.success("Tag created");
|
|
200
200
|
setNewTag("");
|
|
201
201
|
await refresh?.();
|
|
@@ -3,7 +3,6 @@ import { Label } from "@/components/ui/label";
|
|
|
3
3
|
|
|
4
4
|
import { base44, call } from "../../../../lib/api";
|
|
5
5
|
import SearchSelect from "../../../../components/SearchSelect";
|
|
6
|
-
import { isGrouped } from "../../../../lib/product-utils";
|
|
7
6
|
|
|
8
7
|
/** Search products server-side for the pickers. */
|
|
9
8
|
const searchProducts = async (q) => {
|
|
@@ -60,22 +59,10 @@ function ProductIdsPicker({ ids, onChange, placeholder }) {
|
|
|
60
59
|
);
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
/** Upsells
|
|
62
|
+
/** Upsells and cross-sells. */
|
|
64
63
|
export default function LinkedTab({ product, up }) {
|
|
65
64
|
return (
|
|
66
65
|
<div className="max-w-md space-y-4">
|
|
67
|
-
{isGrouped(product) && (
|
|
68
|
-
<div className="space-y-1.5">
|
|
69
|
-
<Label>Grouped products</Label>
|
|
70
|
-
<ProductIdsPicker
|
|
71
|
-
ids={product.grouped_products}
|
|
72
|
-
onChange={(grouped_products) => up({ grouped_products })}
|
|
73
|
-
placeholder="Search for products to group…"
|
|
74
|
-
/>
|
|
75
|
-
<p className="text-xs text-muted-foreground">Products shown as part of this grouped product.</p>
|
|
76
|
-
</div>
|
|
77
|
-
)}
|
|
78
|
-
|
|
79
66
|
<div className="space-y-1.5">
|
|
80
67
|
<Label>Upsells</Label>
|
|
81
68
|
<ProductIdsPicker
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import MetaDataEditor from "../../../../components/MetaDataEditor";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Descriptive properties — Material, Care, GTIN. They are `meta_data`, never
|
|
7
|
+
* attributes: they don't create variants and never affect price or stock.
|
|
8
|
+
*/
|
|
9
|
+
export default function ModifiersTab({ product, up }) {
|
|
10
|
+
return (
|
|
11
|
+
<div className="max-w-xl space-y-2">
|
|
12
|
+
<p className="text-xs text-muted-foreground">
|
|
13
|
+
Shown as product details. They have no effect on price, stock or variants — what a product
|
|
14
|
+
varies by belongs in Attributes, under Price & Inventory.
|
|
15
|
+
</p>
|
|
16
|
+
<MetaDataEditor value={product.meta_data || []} onChange={(meta_data) => up({ meta_data })} />
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|