@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.
Files changed (86) hide show
  1. package/README.md +11 -11
  2. package/base44/agents/commerce/StoreAdmin.jsonc +7 -7
  3. package/base44/entities/commerce.Order.jsonc +1 -1
  4. package/base44/entities/commerce.PaymentGateway.jsonc +3 -3
  5. package/base44/entities/commerce.Product.jsonc +9 -45
  6. package/base44/entities/commerce.ProductAttribute.jsonc +7 -19
  7. package/base44/entities/commerce.ProductAttributeTerm.jsonc +4 -10
  8. package/base44/entities/commerce.ProductTag.jsonc +1 -8
  9. package/base44/entities/commerce.ProductVariation.jsonc +1 -1
  10. package/base44/entities/commerce.StoreSettings.jsonc +1 -1
  11. package/base44/functions/commerce/admin-products/entry.ts +73 -121
  12. package/base44/functions/commerce/admin-refunds/entry.ts +1 -1
  13. package/base44/functions/commerce/admin-reports/entry.ts +1 -1
  14. package/base44/functions/commerce/admin-tools/entry.ts +4 -3
  15. package/base44/functions/commerce/payments/entry.ts +0 -2
  16. package/base44/functions/commerce/seed-store/defaults.ts +13 -39
  17. package/base44/functions/commerce/seed-store/entry.ts +50 -166
  18. package/base44/functions/commerce/seed-store/sample-data.ts +28 -66
  19. package/base44/functions/commerce/seed-store/seed-catalog.ts +717 -0
  20. package/base44/functions/commerce/storefront-cart/entry.ts +0 -7
  21. package/base44/functions/commerce/storefront-catalog/entry.ts +12 -21
  22. package/base44/functions/commerce/storefront-checkout/entry.ts +5 -12
  23. package/base44/shared/commerce/catalog.ts +134 -0
  24. package/base44/shared/commerce/coupons.ts +4 -7
  25. package/base44/shared/commerce/email-templates.ts +15 -13
  26. package/base44/shared/commerce/emails.ts +4 -3
  27. package/base44/shared/commerce/payments.ts +8 -20
  28. package/base44/shared/commerce/products.ts +24 -0
  29. package/base44/shared/commerce/settings.ts +2 -3
  30. package/base44/shared/commerce/stock.ts +2 -4
  31. package/base44/shared/commerce/totals.ts +37 -42
  32. package/package.json +1 -1
  33. package/scripts/install.js +23 -7
  34. package/skills/commerce/SKILL.md +9 -7
  35. package/skills/commerce/docs/api-admin.md +20 -14
  36. package/skills/commerce/docs/api-storefront.md +39 -35
  37. package/skills/commerce/installation-guidelines.md +8 -7
  38. package/skills/commerce/post-installation.md +205 -84
  39. package/skills/commerce/references/admin-product-form.md +56 -0
  40. package/skills/commerce/references/emails.md +4 -3
  41. package/skills/commerce/references/guest-access-security.md +2 -2
  42. package/skills/commerce/references/limits-and-performance.md +1 -1
  43. package/skills/commerce/references/online-payments.md +8 -8
  44. package/skills/commerce/references/product-render.md +25 -23
  45. package/skills/commerce/references/reviews.md +20 -0
  46. package/skills/commerce/references/storefront-product-page.md +9 -9
  47. package/skills/commerce/references/webhooks.md +3 -1
  48. package/src/commerce/admin/README.md +4 -4
  49. package/src/commerce/admin/context/BasePathContext.jsx +5 -5
  50. package/src/commerce/admin/context/SettingsContext.jsx +4 -4
  51. package/src/commerce/admin/index.jsx +3 -3
  52. package/src/commerce/admin/layout/Sidebar.jsx +1 -9
  53. package/src/commerce/admin/lib/constants.js +0 -7
  54. package/src/commerce/admin/lib/paths.js +6 -6
  55. package/src/commerce/admin/lib/product-utils.js +18 -15
  56. package/src/commerce/admin/pages/orders/components/AddProductDialog.jsx +8 -8
  57. package/src/commerce/admin/pages/products/ProductEditor.jsx +10 -12
  58. package/src/commerce/admin/pages/products/ProductsList.jsx +3 -15
  59. package/src/commerce/admin/pages/products/components/AttributesSection.jsx +426 -0
  60. package/src/commerce/admin/pages/products/components/ProductDataPanel.jsx +33 -69
  61. package/src/commerce/admin/pages/products/components/TaxonomyPanel.jsx +1 -1
  62. package/src/commerce/admin/pages/products/components/tabs/LinkedTab.jsx +1 -14
  63. package/src/commerce/admin/pages/products/components/tabs/ModifiersTab.jsx +19 -0
  64. package/src/commerce/admin/pages/products/components/tabs/PriceInventoryTab.jsx +728 -0
  65. package/src/commerce/admin/pages/reports/Reports.jsx +3 -3
  66. package/src/commerce/admin/pages/settings/EmailsSettings.jsx +12 -14
  67. package/src/commerce/admin/pages/settings/GeneralSettings.jsx +6 -116
  68. package/src/commerce/admin/pages/settings/PaymentsSettings.jsx +101 -62
  69. package/src/commerce/admin/pages/settings/SettingsLayout.jsx +2 -6
  70. package/src/commerce/admin/pages/settings/TaxSettings.jsx +0 -1
  71. package/src/commerce/admin/pages/status/WebhookEditor.jsx +3 -3
  72. package/src/commerce/admin/pages/status/Webhooks.jsx +2 -2
  73. package/src/commerce/admin/routes.jsx +10 -19
  74. package/src/commerce/utils/index.js +2 -2
  75. package/src/commerce/utils/shipping-promos.js +9 -6
  76. package/src/commerce/utils/variants.js +21 -21
  77. package/src/commerce/admin/pages/products/AttributeTerms.jsx +0 -180
  78. package/src/commerce/admin/pages/products/Attributes.jsx +0 -183
  79. package/src/commerce/admin/pages/products/Tags.jsx +0 -150
  80. package/src/commerce/admin/pages/products/components/tabs/AdvancedTab.jsx +0 -48
  81. package/src/commerce/admin/pages/products/components/tabs/AttributesTab.jsx +0 -208
  82. package/src/commerce/admin/pages/products/components/tabs/ExternalTab.jsx +0 -41
  83. package/src/commerce/admin/pages/products/components/tabs/GeneralTab.jsx +0 -103
  84. package/src/commerce/admin/pages/products/components/tabs/InventoryTab.jsx +0 -93
  85. package/src/commerce/admin/pages/products/components/tabs/ShippingTab.jsx +0 -86
  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 { PRODUCT_TYPES } from "../../../lib/constants";
15
- import { isSimple, isGrouped, isExternal, isVariable } from "../../../lib/product-utils";
16
- import GeneralTab from "./tabs/GeneralTab";
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: type selector + vertical tabs.
28
- * Tab visibility follows the product type / virtual / downloadable flags.
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 (!isGrouped(product)) list.push({ id: "general", label: "General" });
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("general");
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
- <Select value={product.type} onValueChange={(type) => up({ type })}>
53
- <SelectTrigger className="h-8 w-52"><SelectValue /></SelectTrigger>
54
- <SelectContent>
55
- {PRODUCT_TYPES.map((t) => (
56
- <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>
57
- ))}
58
- </SelectContent>
59
- </Select>
60
- {isSimple(product) && (
61
- <div className="flex items-center gap-4 text-sm">
62
- <label className="flex items-center gap-1.5">
63
- <Checkbox
64
- checked={product.virtual}
65
- onCheckedChange={(v) => up({ virtual: Boolean(v) })}
66
- />
67
- Virtual
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 === "general" &&
101
- (isExternal(product) ? (
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 === "advanced" && <AdvancedTab product={product} up={up} />}
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
- Type: {PRODUCT_TYPES.find((t) => t.value === product.type)?.label}
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, slug: slugify(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, cross-sells and (for grouped products) child products. */
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 &amp; Inventory.
15
+ </p>
16
+ <MetaDataEditor value={product.meta_data || []} onChange={(meta_data) => up({ meta_data })} />
17
+ </div>
18
+ );
19
+ }