@aglyn/plugins-commerce 1.0.0-beta.218 → 1.0.0-beta.220
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 +6 -0
- package/package.json +14 -14
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -19
- package/src/index.js.map +1 -1
- package/src/lib/components/cart.js +2 -1
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/console/catalog-organization-card.component.js +665 -459
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +2 -1
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/member-posts-card.component.js +1 -1
- package/src/lib/components/console/member-posts-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +8 -7
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/payments-settings-card.component.js +2 -2
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +1221 -889
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-zones.d.ts +184 -0
- package/src/lib/components/console/product-zones.js +54 -0
- package/src/lib/components/console/product-zones.js.map +1 -0
- package/src/lib/components/console/products-hub-card.component.js +3 -2
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/products-hub-zone.component.d.ts +1 -1
- package/src/lib/components/console/products-hub-zone.component.js +2 -1
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
- package/src/lib/components/console/site-member-purchases.component.d.ts +24 -0
- package/src/lib/components/console/site-member-purchases.component.js +339 -0
- package/src/lib/components/console/site-member-purchases.component.js.map +1 -0
- package/src/lib/components/console/store-settings-card.component.js +2 -2
- package/src/lib/components/console/store-settings-card.component.js.map +1 -1
- package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -1
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
- package/src/lib/components/member-signup.js +2 -2
- package/src/lib/components/member-signup.js.map +1 -1
- package/src/lib/components/newsletter-signup.js +2 -2
- package/src/lib/components/newsletter-signup.js.map +1 -1
- package/src/lib/components/product-detail.js +2 -1
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-grid.js +1 -1
- package/src/lib/components/product-grid.js.map +1 -1
- package/src/lib/constants/operator-alerts.js +5 -3
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/constants/storefront-payments.d.ts +33 -0
- package/src/lib/constants/storefront-payments.js +35 -0
- package/src/lib/constants/storefront-payments.js.map +1 -0
- package/src/lib/declarations.server.d.ts +3 -1
- package/src/lib/declarations.server.js +19 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/commerce-io.js +1 -1
- package/src/lib/model/commerce-io.js.map +1 -1
- package/src/lib/model/commerce-record-lists.d.ts +31 -0
- package/src/lib/model/commerce-record-lists.js +45 -0
- package/src/lib/model/commerce-record-lists.js.map +1 -0
- package/src/lib/model/commerce-record-routes.d.ts +45 -0
- package/src/lib/model/commerce-record-routes.js +72 -0
- package/src/lib/model/commerce-record-routes.js.map +1 -0
- package/src/lib/model/commerce-search-sources.d.ts +21 -0
- package/src/lib/model/commerce-search-sources.js +42 -0
- package/src/lib/model/commerce-search-sources.js.map +1 -0
- package/src/lib/model/commerce-topics.d.ts +20 -0
- package/src/lib/model/commerce-topics.js +33 -0
- package/src/lib/model/commerce-topics.js.map +1 -0
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/product-record.d.ts +32 -0
- package/src/lib/model/product-record.js +82 -0
- package/src/lib/model/product-record.js.map +1 -0
- package/src/lib/model/site-member-purchases.d.ts +48 -0
- package/src/lib/model/site-member-purchases.js +50 -0
- package/src/lib/model/site-member-purchases.js.map +1 -0
- package/src/lib/model/storefront-tax-summary.d.ts +121 -0
- package/src/lib/model/storefront-tax-summary.js +148 -0
- package/src/lib/model/storefront-tax-summary.js.map +1 -0
- package/src/lib/plan-entitlements.d.ts +35 -0
- package/src/lib/plan-entitlements.js +54 -0
- package/src/lib/plan-entitlements.js.map +1 -0
- package/src/lib/plugin.js +21 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +387 -248
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.js +3 -3
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/checkout.js +2 -2
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/connect.js +5 -5
- package/src/lib/server/connect.js.map +1 -1
- package/src/lib/server/draft-order.js +2 -2
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/gift-cards.js +7 -3
- package/src/lib/server/gift-cards.js.map +1 -1
- package/src/lib/server/low-stock.js +3 -1
- package/src/lib/server/low-stock.js.map +1 -1
- package/src/lib/server/member-post.js +2 -2
- package/src/lib/server/member-post.js.map +1 -1
- package/src/lib/server/membership-admin-password.js +4 -1
- package/src/lib/server/membership-admin-password.js.map +1 -1
- package/src/lib/server/membership-content.js +1 -1
- package/src/lib/server/membership-content.js.map +1 -1
- package/src/lib/server/membership-register.js +13 -2
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/newsletter.js +32 -19
- package/src/lib/server/newsletter.js.map +1 -1
- package/src/lib/server/pos-order.js +3 -3
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/process-abandoned.js +4 -2
- package/src/lib/server/process-abandoned.js.map +1 -1
- package/src/lib/server/process-restock.js +7 -5
- package/src/lib/server/process-restock.js.map +1 -1
- package/src/lib/server/product-record-index.d.ts +19 -0
- package/src/lib/server/product-record-index.js +83 -0
- package/src/lib/server/product-record-index.js.map +1 -0
- package/src/lib/server/reconcile-stock.js +1 -1
- package/src/lib/server/reconcile-stock.js.map +1 -1
- package/src/lib/server/reserve-stock.js +6 -1
- package/src/lib/server/reserve-stock.js.map +1 -1
- package/src/lib/server/reserve.js +2 -2
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/revenue-source.d.ts +130 -0
- package/src/lib/server/revenue-source.js +286 -0
- package/src/lib/server/revenue-source.js.map +1 -0
- package/src/lib/server/supplier-outbox.js +16 -1
- package/src/lib/server/supplier-outbox.js.map +1 -1
- package/src/lib/server/supplier-update.js +19 -9
- package/src/lib/server/supplier-update.js.map +1 -1
- package/src/lib/server/tax-profile.d.ts +8 -5
- package/src/lib/server/tax-profile.js +22 -5
- package/src/lib/server/tax-profile.js.map +1 -1
- package/src/lib/server/tax-return-source.d.ts +125 -0
- package/src/lib/server/tax-return-source.js +524 -0
- package/src/lib/server/tax-return-source.js.map +1 -0
- package/src/lib/server/tax-summary.d.ts +92 -0
- package/src/lib/server/tax-summary.js +258 -0
- package/src/lib/server/tax-summary.js.map +1 -0
- package/src/lib/server.d.ts +1 -0
- package/src/lib/server.js +23 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/starter-templates.d.ts +19 -0
- package/src/lib/starter-templates.js +157 -0
- package/src/lib/starter-templates.js.map +1 -0
- package/src/lib/tenant-emails.d.ts +33 -0
- package/src/lib/tenant-emails.js +551 -0
- package/src/lib/tenant-emails.js.map +1 -0
- package/src/lib/testing/stand-in-crm-record-routes.d.ts +25 -0
- package/src/lib/testing/stand-in-crm-record-routes.js +46 -0
- package/src/lib/testing/stand-in-crm-record-routes.js.map +1 -0
|
@@ -23,14 +23,16 @@ import { Timestamp } from "@aglyn/shared-util-timestamp";
|
|
|
23
23
|
import { Alert, Autocomplete, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider, IconButton, MenuItem, Stack, TableBody, TableCell, TableHead, TableRow, TextField, Typography } from "@mui/material";
|
|
24
24
|
import { collection, doc, getDoc } from "firebase/firestore";
|
|
25
25
|
import { productCollectionFields } from "./smart-collections.js";
|
|
26
|
-
import { useCallback, useMemo, useState } from "react";
|
|
26
|
+
import { memo, useCallback, useMemo, useRef, useState } from "react";
|
|
27
27
|
import { ceilingedWindow, collectionCeiling, useFirestore, useFirestoreCollection, useHostResourceApi, writeGuardedBySeed, useUser } from "@aglyn/tenant-feature-instance";
|
|
28
28
|
import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
|
|
29
29
|
import { useMediaPicker } from "@aglyn/aglyn";
|
|
30
30
|
import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
|
|
31
31
|
import { seoListingFieldCount, seoListingFieldTooLong } from "@aglyn/aglyn/app-utils/seo-listing-fields";
|
|
32
32
|
import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
|
|
33
|
+
import { useContentStable } from "@aglyn/shared-ui-jsx/hooks/use-content-stable";
|
|
33
34
|
import { EntitlementUpsell, useCommerceEntitlement } from "./entitlement-gate.component.js";
|
|
35
|
+
import { PRODUCT_EDITOR_ZONE } from "./product-zones.js";
|
|
34
36
|
import { MembersVideosField, PaidDownloadAddButton, PaidMediaProtection } from "./paid-media.js";
|
|
35
37
|
/**
|
|
36
38
|
* What each picker in this dialog will offer.
|
|
@@ -72,6 +74,991 @@ function comboLabel(options) {
|
|
|
72
74
|
const values = Object.values(options != null ? options : {});
|
|
73
75
|
return values.length ? values.join(' / ') : 'Default';
|
|
74
76
|
}
|
|
77
|
+
/** Stand-in for a list the product does not hold yet, the same one each render. */ const NO_ITEMS = [];
|
|
78
|
+
const NO_OPTIONS = [];
|
|
79
|
+
const NO_FILES = [];
|
|
80
|
+
const NO_VIDEOS = [];
|
|
81
|
+
const FILL_ROW = {
|
|
82
|
+
flex: 1
|
|
83
|
+
};
|
|
84
|
+
const categoryLabel = (category)=>category.name;
|
|
85
|
+
const recordLabel = (item)=>{
|
|
86
|
+
var _item_name;
|
|
87
|
+
return (_item_name = item.name) != null ? _item_name : item.$id;
|
|
88
|
+
};
|
|
89
|
+
const sameRecord = (option, value)=>option.$id === value.$id;
|
|
90
|
+
/**
|
|
91
|
+
* One of the editor's chip lists — tags, categories, an option's values,
|
|
92
|
+
* related products — MEMOIZED, and every prop it takes is stable while its
|
|
93
|
+
* own list is (AGL-3423).
|
|
94
|
+
*
|
|
95
|
+
* A multiple Autocomplete hands its input a new chip array as
|
|
96
|
+
* `startAdornment` on every render, and MUI's `InputBase` copies that into
|
|
97
|
+
* its `FormControl` from a passive effect: a state update left pending after
|
|
98
|
+
* every commit the field takes part in. React 19 counts each such commit as a
|
|
99
|
+
* nested update, and keystrokes delivered back to back commit one after
|
|
100
|
+
* another with nothing to clear the count, so the fifty-first throws
|
|
101
|
+
* "Maximum update depth exceeded" (#185). Every field in this editor writes
|
|
102
|
+
* one draft, so every keystroke in any of them re-rendered all four lists;
|
|
103
|
+
* kept out of those renders, a list commits only when it changes.
|
|
104
|
+
*/ const ProductChipsField = /*#__PURE__*/ memo(function ProductChipsField(props) {
|
|
105
|
+
const { index = 0, onChange } = props;
|
|
106
|
+
return /*#__PURE__*/ _jsx(Autocomplete, {
|
|
107
|
+
multiple: true,
|
|
108
|
+
freeSolo: props.freeSolo,
|
|
109
|
+
options: props.options,
|
|
110
|
+
value: props.value,
|
|
111
|
+
getOptionLabel: props.getOptionLabel,
|
|
112
|
+
isOptionEqualToValue: props.isOptionEqualToValue,
|
|
113
|
+
onChange: (_event, next)=>onChange(next, index),
|
|
114
|
+
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
115
|
+
label: props.label,
|
|
116
|
+
size: "small",
|
|
117
|
+
placeholder: props.placeholder,
|
|
118
|
+
helperText: props.helperText
|
|
119
|
+
})),
|
|
120
|
+
sx: props.fill ? FILL_ROW : undefined
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
/**
|
|
124
|
+
* A text field that redraws only when what it shows changes (AGL-3423).
|
|
125
|
+
*
|
|
126
|
+
* Every field in this editor writes one draft, so a keystroke in any of them
|
|
127
|
+
* re-renders the dialog, and drawn whole that is some forty inputs and twelve
|
|
128
|
+
* hundred components for one letter in a product with four variants. When a
|
|
129
|
+
* keystroke costs that much, typed input queues and is processed back to
|
|
130
|
+
* back, which is what lets a chip list's pending update climb to #185 (see
|
|
131
|
+
* `ProductChipsField`). The sections below are memoized on the slice of the
|
|
132
|
+
* draft they show, and each field in them is this, handed a handler and
|
|
133
|
+
* styles that keep their identity, so the keystroke redraws the field it
|
|
134
|
+
* lands in.
|
|
135
|
+
*/ const MemoTextField = /*#__PURE__*/ memo(TextField);
|
|
136
|
+
const FIRST_ROW = {
|
|
137
|
+
mt: 1
|
|
138
|
+
};
|
|
139
|
+
const WIDE_ROW = {
|
|
140
|
+
xs: 'column',
|
|
141
|
+
sm: 'row'
|
|
142
|
+
};
|
|
143
|
+
const NARROW_SELECT = {
|
|
144
|
+
minWidth: 140
|
|
145
|
+
};
|
|
146
|
+
const SUPPLIER_SELECT = {
|
|
147
|
+
minWidth: 160
|
|
148
|
+
};
|
|
149
|
+
const OVERSELL_SELECT = {
|
|
150
|
+
minWidth: 200
|
|
151
|
+
};
|
|
152
|
+
const KIND_SELECT = {
|
|
153
|
+
minWidth: 130
|
|
154
|
+
};
|
|
155
|
+
const SHORT_SELECT = {
|
|
156
|
+
minWidth: 120
|
|
157
|
+
};
|
|
158
|
+
const BILLING_SELECT = {
|
|
159
|
+
minWidth: 180
|
|
160
|
+
};
|
|
161
|
+
const COUNT_FIELD = {
|
|
162
|
+
width: 140
|
|
163
|
+
};
|
|
164
|
+
const VERSION_FIELD = {
|
|
165
|
+
width: 100
|
|
166
|
+
};
|
|
167
|
+
const OPTION_FIELD = {
|
|
168
|
+
width: 160
|
|
169
|
+
};
|
|
170
|
+
const PRICE_CELL = {
|
|
171
|
+
width: 88
|
|
172
|
+
};
|
|
173
|
+
const CODE_CELL = {
|
|
174
|
+
width: 110
|
|
175
|
+
};
|
|
176
|
+
const STOCK_CELL = {
|
|
177
|
+
width: 72
|
|
178
|
+
};
|
|
179
|
+
const DECIMAL_INPUT = {
|
|
180
|
+
htmlInput: {
|
|
181
|
+
inputMode: 'decimal'
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const NUMERIC_INPUT = {
|
|
185
|
+
htmlInput: {
|
|
186
|
+
inputMode: 'numeric'
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const TYPE_MENU = [
|
|
190
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
191
|
+
value: "physical",
|
|
192
|
+
children: 'Physical'
|
|
193
|
+
}, "physical"),
|
|
194
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
195
|
+
value: "digital",
|
|
196
|
+
children: 'Digital'
|
|
197
|
+
}, "digital"),
|
|
198
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
199
|
+
value: "service",
|
|
200
|
+
children: 'Service'
|
|
201
|
+
}, "service")
|
|
202
|
+
];
|
|
203
|
+
const STATUS_MENU = [
|
|
204
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
205
|
+
value: "draft",
|
|
206
|
+
children: 'Draft'
|
|
207
|
+
}, "draft"),
|
|
208
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
209
|
+
value: "active",
|
|
210
|
+
children: 'Active'
|
|
211
|
+
}, "active"),
|
|
212
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
213
|
+
value: "archived",
|
|
214
|
+
children: 'Archived'
|
|
215
|
+
}, "archived")
|
|
216
|
+
];
|
|
217
|
+
const OVERSELL_MENU = [
|
|
218
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
219
|
+
value: "deny",
|
|
220
|
+
children: 'Stop selling (sold out)'
|
|
221
|
+
}, "deny"),
|
|
222
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
223
|
+
value: "backorder",
|
|
224
|
+
children: 'Keep selling (backorder)'
|
|
225
|
+
}, "backorder")
|
|
226
|
+
];
|
|
227
|
+
const TAX_MENU = [
|
|
228
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
229
|
+
value: "taxable",
|
|
230
|
+
children: 'Taxable'
|
|
231
|
+
}, "taxable"),
|
|
232
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
233
|
+
value: "exempt",
|
|
234
|
+
children: 'Tax exempt'
|
|
235
|
+
}, "exempt")
|
|
236
|
+
];
|
|
237
|
+
const INTERVAL_MENU = [
|
|
238
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
239
|
+
value: "month",
|
|
240
|
+
children: 'Monthly'
|
|
241
|
+
}, "month"),
|
|
242
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
243
|
+
value: "year",
|
|
244
|
+
children: 'Yearly'
|
|
245
|
+
}, "year")
|
|
246
|
+
];
|
|
247
|
+
/**
|
|
248
|
+
* A zone hosted in the dialog, drawn again only when what it is handed
|
|
249
|
+
* changes (AGL-3423). The shell's renderer is not memoized: drawn straight
|
|
250
|
+
* into the dialog, every widget in the zone would redraw on each keystroke in
|
|
251
|
+
* any field.
|
|
252
|
+
*/ const HostedZone = /*#__PURE__*/ memo(function HostedZone(props) {
|
|
253
|
+
const { renderer: Renderer } = props, zone = _object_without_properties_loose(props, [
|
|
254
|
+
"renderer"
|
|
255
|
+
]);
|
|
256
|
+
return /*#__PURE__*/ _jsx(Renderer, _extends({}, zone));
|
|
257
|
+
});
|
|
258
|
+
/** The product's name and address, type, status, supplier and description. */ const ProductBasicsFields = /*#__PURE__*/ memo(function ProductBasicsFields(props) {
|
|
259
|
+
var _props_supplierId;
|
|
260
|
+
const { suppliers, update } = props;
|
|
261
|
+
const setType = useCallback((event)=>update({
|
|
262
|
+
type: event.target.value
|
|
263
|
+
}), [
|
|
264
|
+
update
|
|
265
|
+
]);
|
|
266
|
+
const setStatus = useCallback((event)=>update({
|
|
267
|
+
status: event.target.value
|
|
268
|
+
}), [
|
|
269
|
+
update
|
|
270
|
+
]);
|
|
271
|
+
const setSupplier = useCallback((event)=>update({
|
|
272
|
+
supplierId: event.target.value || undefined
|
|
273
|
+
}), [
|
|
274
|
+
update
|
|
275
|
+
]);
|
|
276
|
+
const setDescription = useCallback((event)=>update({
|
|
277
|
+
description: event.target.value
|
|
278
|
+
}), [
|
|
279
|
+
update
|
|
280
|
+
]);
|
|
281
|
+
const supplierMenu = useMemo(()=>[
|
|
282
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
283
|
+
value: "",
|
|
284
|
+
children: 'None (self-fulfilled)'
|
|
285
|
+
}, ""),
|
|
286
|
+
...suppliers.map((supplier)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
287
|
+
value: supplier.$id,
|
|
288
|
+
children: supplier.name
|
|
289
|
+
}, supplier.$id))
|
|
290
|
+
], [
|
|
291
|
+
suppliers
|
|
292
|
+
]);
|
|
293
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
294
|
+
children: [
|
|
295
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
296
|
+
direction: WIDE_ROW,
|
|
297
|
+
spacing: 2,
|
|
298
|
+
sx: FIRST_ROW,
|
|
299
|
+
children: [
|
|
300
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
301
|
+
label: "Name",
|
|
302
|
+
value: props.name,
|
|
303
|
+
onChange: props.onName,
|
|
304
|
+
size: "small",
|
|
305
|
+
autoFocus: true,
|
|
306
|
+
fullWidth: true
|
|
307
|
+
}),
|
|
308
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
309
|
+
label: "Slug",
|
|
310
|
+
value: props.slug,
|
|
311
|
+
onChange: props.onSlug,
|
|
312
|
+
size: "small",
|
|
313
|
+
fullWidth: true,
|
|
314
|
+
helperText: props.slug ? `/products/${props.slug}` : undefined
|
|
315
|
+
})
|
|
316
|
+
]
|
|
317
|
+
}),
|
|
318
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
319
|
+
direction: "row",
|
|
320
|
+
spacing: 2,
|
|
321
|
+
children: [
|
|
322
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
323
|
+
label: "Type",
|
|
324
|
+
value: props.type,
|
|
325
|
+
onChange: setType,
|
|
326
|
+
size: "small",
|
|
327
|
+
select: true,
|
|
328
|
+
sx: NARROW_SELECT,
|
|
329
|
+
children: TYPE_MENU
|
|
330
|
+
}),
|
|
331
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
332
|
+
label: "Status",
|
|
333
|
+
value: props.status,
|
|
334
|
+
onChange: setStatus,
|
|
335
|
+
size: "small",
|
|
336
|
+
select: true,
|
|
337
|
+
sx: NARROW_SELECT,
|
|
338
|
+
children: STATUS_MENU
|
|
339
|
+
}),
|
|
340
|
+
suppliers.length > 0 ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
341
|
+
label: "Supplier",
|
|
342
|
+
value: (_props_supplierId = props.supplierId) != null ? _props_supplierId : '',
|
|
343
|
+
onChange: setSupplier,
|
|
344
|
+
size: "small",
|
|
345
|
+
select: true,
|
|
346
|
+
sx: SUPPLIER_SELECT,
|
|
347
|
+
helperText: "Routes paid orders",
|
|
348
|
+
children: supplierMenu
|
|
349
|
+
}) : null
|
|
350
|
+
]
|
|
351
|
+
}),
|
|
352
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
353
|
+
label: "Description",
|
|
354
|
+
value: props.description,
|
|
355
|
+
onChange: setDescription,
|
|
356
|
+
size: "small",
|
|
357
|
+
multiline: true,
|
|
358
|
+
minRows: 2
|
|
359
|
+
})
|
|
360
|
+
]
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
/** The product's images, each removable, and the button that adds one. */ const ProductMediaFields = /*#__PURE__*/ memo(function ProductMediaFields(props) {
|
|
364
|
+
const { mediaUrls, update, pick } = props;
|
|
365
|
+
return /*#__PURE__*/ _jsxs(Box, {
|
|
366
|
+
sx: {
|
|
367
|
+
display: 'flex',
|
|
368
|
+
gap: 1,
|
|
369
|
+
flexWrap: 'wrap'
|
|
370
|
+
},
|
|
371
|
+
children: [
|
|
372
|
+
mediaUrls.map((url, index)=>/*#__PURE__*/ _jsxs(Box, {
|
|
373
|
+
sx: {
|
|
374
|
+
position: 'relative'
|
|
375
|
+
},
|
|
376
|
+
children: [
|
|
377
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
378
|
+
component: "img",
|
|
379
|
+
src: url,
|
|
380
|
+
alt: "",
|
|
381
|
+
sx: {
|
|
382
|
+
width: 72,
|
|
383
|
+
height: 72,
|
|
384
|
+
objectFit: 'cover',
|
|
385
|
+
borderRadius: 1,
|
|
386
|
+
border: 1,
|
|
387
|
+
borderColor: 'divider'
|
|
388
|
+
}
|
|
389
|
+
}),
|
|
390
|
+
/*#__PURE__*/ _jsx(IconButton, {
|
|
391
|
+
size: "small",
|
|
392
|
+
"aria-label": "Remove image",
|
|
393
|
+
onClick: ()=>update((product)=>{
|
|
394
|
+
var _product_mediaUrls;
|
|
395
|
+
return {
|
|
396
|
+
mediaUrls: ((_product_mediaUrls = product.mediaUrls) != null ? _product_mediaUrls : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
397
|
+
};
|
|
398
|
+
}),
|
|
399
|
+
sx: {
|
|
400
|
+
position: 'absolute',
|
|
401
|
+
top: -8,
|
|
402
|
+
right: -8,
|
|
403
|
+
bgcolor: 'background.paper',
|
|
404
|
+
border: 1,
|
|
405
|
+
borderColor: 'divider',
|
|
406
|
+
p: 0.25
|
|
407
|
+
},
|
|
408
|
+
children: '✕'
|
|
409
|
+
})
|
|
410
|
+
]
|
|
411
|
+
}, `${url}-${index}`)),
|
|
412
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
413
|
+
size: "small",
|
|
414
|
+
onClick: ()=>void pick((media)=>update((product)=>{
|
|
415
|
+
var _product_mediaUrls;
|
|
416
|
+
return {
|
|
417
|
+
mediaUrls: [
|
|
418
|
+
...(_product_mediaUrls = product.mediaUrls) != null ? _product_mediaUrls : [],
|
|
419
|
+
media.url
|
|
420
|
+
]
|
|
421
|
+
};
|
|
422
|
+
})),
|
|
423
|
+
children: 'Add image'
|
|
424
|
+
})
|
|
425
|
+
]
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
const ProductOptionRow = /*#__PURE__*/ memo(function ProductOptionRow(props) {
|
|
429
|
+
const { index, option, onChange, onValues } = props;
|
|
430
|
+
const setName = useCallback((event)=>onChange(index, {
|
|
431
|
+
name: event.target.value
|
|
432
|
+
}), [
|
|
433
|
+
index,
|
|
434
|
+
onChange
|
|
435
|
+
]);
|
|
436
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
437
|
+
direction: "row",
|
|
438
|
+
spacing: 1,
|
|
439
|
+
sx: {
|
|
440
|
+
alignItems: 'flex-start'
|
|
441
|
+
},
|
|
442
|
+
children: [
|
|
443
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
444
|
+
label: "Option",
|
|
445
|
+
value: option.name,
|
|
446
|
+
onChange: setName,
|
|
447
|
+
size: "small",
|
|
448
|
+
sx: OPTION_FIELD,
|
|
449
|
+
placeholder: "Size"
|
|
450
|
+
}),
|
|
451
|
+
/*#__PURE__*/ _jsx(ProductChipsField, {
|
|
452
|
+
freeSolo: true,
|
|
453
|
+
fill: true,
|
|
454
|
+
label: "Values",
|
|
455
|
+
placeholder: "S, M, L…",
|
|
456
|
+
options: NO_ITEMS,
|
|
457
|
+
value: option.values,
|
|
458
|
+
index: index,
|
|
459
|
+
onChange: onValues
|
|
460
|
+
}),
|
|
461
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
462
|
+
size: "small",
|
|
463
|
+
color: "error",
|
|
464
|
+
onClick: ()=>onChange(index, null),
|
|
465
|
+
sx: {
|
|
466
|
+
mt: 0.5
|
|
467
|
+
},
|
|
468
|
+
children: 'Remove'
|
|
469
|
+
})
|
|
470
|
+
]
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
/** The product's options, one row each, and the button that adds one. */ const ProductOptionsFields = /*#__PURE__*/ memo(function ProductOptionsFields(props) {
|
|
474
|
+
const { options, onChange, onValues } = props;
|
|
475
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
476
|
+
children: [
|
|
477
|
+
options.map((option, index)=>/*#__PURE__*/ _jsx(ProductOptionRow, {
|
|
478
|
+
index: index,
|
|
479
|
+
option: option,
|
|
480
|
+
onChange: onChange,
|
|
481
|
+
onValues: onValues
|
|
482
|
+
}, index)),
|
|
483
|
+
options.length < CommerceModel.COMMERCE_MAX_OPTIONS ? /*#__PURE__*/ _jsx(Button, {
|
|
484
|
+
size: "small",
|
|
485
|
+
sx: {
|
|
486
|
+
alignSelf: 'flex-start'
|
|
487
|
+
},
|
|
488
|
+
onClick: ()=>onChange(options.length, {
|
|
489
|
+
name: '',
|
|
490
|
+
values: []
|
|
491
|
+
}),
|
|
492
|
+
children: 'Add option'
|
|
493
|
+
}) : null
|
|
494
|
+
]
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
const ProductVariantRow = /*#__PURE__*/ memo(function ProductVariantRow(props) {
|
|
498
|
+
var _variant_priceUsd, _variant_compareAtPriceUsd, _variant_sku, _variant_barcode, _variant_inventory, _variant_weightGrams;
|
|
499
|
+
const { index, variant, stockApplies, onField } = props;
|
|
500
|
+
const label = comboLabel(variant.options);
|
|
501
|
+
// One handler per cell, each keeping its identity while the row's does.
|
|
502
|
+
const set = useMemo(()=>{
|
|
503
|
+
const cell = (field)=>(event)=>onField(index, field, event.target.value);
|
|
504
|
+
return {
|
|
505
|
+
priceUsd: cell('priceUsd'),
|
|
506
|
+
compareAtPriceUsd: cell('compareAtPriceUsd'),
|
|
507
|
+
sku: cell('sku'),
|
|
508
|
+
barcode: cell('barcode'),
|
|
509
|
+
inventory: cell('inventory'),
|
|
510
|
+
weightGrams: cell('weightGrams')
|
|
511
|
+
};
|
|
512
|
+
}, [
|
|
513
|
+
index,
|
|
514
|
+
onField
|
|
515
|
+
]);
|
|
516
|
+
const stockInput = useMemo(()=>({
|
|
517
|
+
htmlInput: {
|
|
518
|
+
inputMode: 'numeric',
|
|
519
|
+
'aria-label': `Stock — ${label}`
|
|
520
|
+
}
|
|
521
|
+
}), [
|
|
522
|
+
label
|
|
523
|
+
]);
|
|
524
|
+
return /*#__PURE__*/ _jsxs(TableRow, {
|
|
525
|
+
children: [
|
|
526
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
527
|
+
sx: {
|
|
528
|
+
whiteSpace: 'nowrap'
|
|
529
|
+
},
|
|
530
|
+
children: label
|
|
531
|
+
}),
|
|
532
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
533
|
+
children: /*#__PURE__*/ _jsx(MemoTextField, {
|
|
534
|
+
value: (_variant_priceUsd = variant.priceUsd) != null ? _variant_priceUsd : '',
|
|
535
|
+
onChange: set.priceUsd,
|
|
536
|
+
size: "small",
|
|
537
|
+
sx: PRICE_CELL,
|
|
538
|
+
// An empty price is marked (AGL-2916): a proposed
|
|
539
|
+
// product arrives with none, and Save waits for one.
|
|
540
|
+
error: !CommerceModel.variantHasPrice(variant),
|
|
541
|
+
placeholder: "Set",
|
|
542
|
+
slotProps: DECIMAL_INPUT
|
|
543
|
+
})
|
|
544
|
+
}),
|
|
545
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
546
|
+
children: /*#__PURE__*/ _jsx(MemoTextField, {
|
|
547
|
+
value: (_variant_compareAtPriceUsd = variant.compareAtPriceUsd) != null ? _variant_compareAtPriceUsd : '',
|
|
548
|
+
onChange: set.compareAtPriceUsd,
|
|
549
|
+
size: "small",
|
|
550
|
+
sx: PRICE_CELL,
|
|
551
|
+
slotProps: DECIMAL_INPUT
|
|
552
|
+
})
|
|
553
|
+
}),
|
|
554
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
555
|
+
children: /*#__PURE__*/ _jsx(MemoTextField, {
|
|
556
|
+
value: (_variant_sku = variant.sku) != null ? _variant_sku : '',
|
|
557
|
+
onChange: set.sku,
|
|
558
|
+
size: "small",
|
|
559
|
+
sx: CODE_CELL
|
|
560
|
+
})
|
|
561
|
+
}),
|
|
562
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
563
|
+
children: /*#__PURE__*/ _jsx(MemoTextField, {
|
|
564
|
+
value: (_variant_barcode = variant.barcode) != null ? _variant_barcode : '',
|
|
565
|
+
onChange: set.barcode,
|
|
566
|
+
size: "small",
|
|
567
|
+
sx: CODE_CELL
|
|
568
|
+
})
|
|
569
|
+
}),
|
|
570
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
571
|
+
children: /*#__PURE__*/ _jsx(MemoTextField, {
|
|
572
|
+
value: (_variant_inventory = variant.inventory) != null ? _variant_inventory : '',
|
|
573
|
+
placeholder: stockApplies ? '—' : 'n/a',
|
|
574
|
+
disabled: !stockApplies,
|
|
575
|
+
onChange: set.inventory,
|
|
576
|
+
size: "small",
|
|
577
|
+
sx: STOCK_CELL,
|
|
578
|
+
slotProps: stockInput
|
|
579
|
+
})
|
|
580
|
+
}),
|
|
581
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
582
|
+
children: /*#__PURE__*/ _jsx(MemoTextField, {
|
|
583
|
+
value: (_variant_weightGrams = variant.weightGrams) != null ? _variant_weightGrams : '',
|
|
584
|
+
onChange: set.weightGrams,
|
|
585
|
+
size: "small",
|
|
586
|
+
sx: PRICE_CELL,
|
|
587
|
+
slotProps: NUMERIC_INPUT
|
|
588
|
+
})
|
|
589
|
+
})
|
|
590
|
+
]
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
/** The matrix's column headings, one element for every render. */ const VARIANTS_HEAD = /*#__PURE__*/ _jsx(TableHead, {
|
|
594
|
+
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
595
|
+
children: [
|
|
596
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
597
|
+
children: 'Variant'
|
|
598
|
+
}),
|
|
599
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
600
|
+
children: 'Price ($)'
|
|
601
|
+
}),
|
|
602
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
603
|
+
children: 'Compare-at'
|
|
604
|
+
}),
|
|
605
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
606
|
+
children: 'SKU'
|
|
607
|
+
}),
|
|
608
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
609
|
+
children: 'Barcode'
|
|
610
|
+
}),
|
|
611
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
612
|
+
children: 'Stock'
|
|
613
|
+
}),
|
|
614
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
615
|
+
children: 'Weight (g)'
|
|
616
|
+
})
|
|
617
|
+
]
|
|
618
|
+
})
|
|
619
|
+
});
|
|
620
|
+
/**
|
|
621
|
+
* The variants matrix: one row per combination of the options above, each
|
|
622
|
+
* with its own price, SKU, barcode, stock and weight. A keystroke in one row
|
|
623
|
+
* leaves the others' props as they were.
|
|
624
|
+
*/ const ProductVariantsTable = /*#__PURE__*/ memo(function ProductVariantsTable(props) {
|
|
625
|
+
const { variants, stockApplies, onField } = props;
|
|
626
|
+
return /*#__PURE__*/ _jsx(Box, {
|
|
627
|
+
children: /*#__PURE__*/ _jsxs(ScrollTable, {
|
|
628
|
+
size: "small",
|
|
629
|
+
children: [
|
|
630
|
+
VARIANTS_HEAD,
|
|
631
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
632
|
+
children: variants.map((variant, index)=>/*#__PURE__*/ _jsx(ProductVariantRow, {
|
|
633
|
+
index: index,
|
|
634
|
+
variant: variant,
|
|
635
|
+
stockApplies: stockApplies,
|
|
636
|
+
onField: onField
|
|
637
|
+
}, variant.id))
|
|
638
|
+
})
|
|
639
|
+
]
|
|
640
|
+
})
|
|
641
|
+
});
|
|
642
|
+
});
|
|
643
|
+
/** What happens when stock runs out, the gift-card kind, tax, and the low-stock alert. */ const ProductSellingFields = /*#__PURE__*/ memo(function ProductSellingFields(props) {
|
|
644
|
+
var _props_lowStockThreshold;
|
|
645
|
+
const { giftsLocked, giftsPlanLabel, update } = props;
|
|
646
|
+
const setOversellPolicy = useCallback((event)=>update({
|
|
647
|
+
oversellPolicy: event.target.value
|
|
648
|
+
}), [
|
|
649
|
+
update
|
|
650
|
+
]);
|
|
651
|
+
const setKind = useCallback((event)=>update({
|
|
652
|
+
giftCard: event.target.value === 'gift'
|
|
653
|
+
}), [
|
|
654
|
+
update
|
|
655
|
+
]);
|
|
656
|
+
const setTax = useCallback((event)=>update({
|
|
657
|
+
taxExempt: event.target.value === 'exempt'
|
|
658
|
+
}), [
|
|
659
|
+
update
|
|
660
|
+
]);
|
|
661
|
+
const setLowStock = useCallback((event)=>{
|
|
662
|
+
const raw = event.target.value.trim();
|
|
663
|
+
update({
|
|
664
|
+
lowStockThreshold: raw === '' ? undefined : Math.max(0, Math.round(Number(raw)))
|
|
665
|
+
});
|
|
666
|
+
}, [
|
|
667
|
+
update
|
|
668
|
+
]);
|
|
669
|
+
const kindMenu = useMemo(()=>[
|
|
670
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
671
|
+
value: "standard",
|
|
672
|
+
children: 'Standard'
|
|
673
|
+
}, "standard"),
|
|
674
|
+
// Disabled, never removed (AGL-2080). A product saved as a gift
|
|
675
|
+
// card before the plan lapsed still has `giftCard: true`, and a
|
|
676
|
+
// MUI select whose value is absent from its options renders
|
|
677
|
+
// blank — the next edit would silently rewrite the product to
|
|
678
|
+
// Standard. Locking the option refuses NEW configuration
|
|
679
|
+
// without rewriting existing data.
|
|
680
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
681
|
+
value: "gift",
|
|
682
|
+
disabled: giftsLocked,
|
|
683
|
+
children: giftsLocked ? `Gift card — ${giftsPlanLabel != null ? giftsPlanLabel : 'upgrade'} plan` : 'Gift card'
|
|
684
|
+
}, "gift")
|
|
685
|
+
], [
|
|
686
|
+
giftsLocked,
|
|
687
|
+
giftsPlanLabel
|
|
688
|
+
]);
|
|
689
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
690
|
+
direction: "row",
|
|
691
|
+
spacing: 2,
|
|
692
|
+
children: [
|
|
693
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
694
|
+
label: "When out of stock",
|
|
695
|
+
value: props.oversellPolicy,
|
|
696
|
+
onChange: setOversellPolicy,
|
|
697
|
+
size: "small",
|
|
698
|
+
select: true,
|
|
699
|
+
sx: OVERSELL_SELECT,
|
|
700
|
+
children: OVERSELL_MENU
|
|
701
|
+
}),
|
|
702
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
703
|
+
label: "Kind",
|
|
704
|
+
value: props.giftCard ? 'gift' : 'standard',
|
|
705
|
+
onChange: setKind,
|
|
706
|
+
size: "small",
|
|
707
|
+
select: true,
|
|
708
|
+
sx: KIND_SELECT,
|
|
709
|
+
helperText: giftsLocked ? `Gift cards are on ${giftsPlanLabel != null ? giftsPlanLabel : 'a higher plan'}` : 'Gift cards issue a code',
|
|
710
|
+
children: kindMenu
|
|
711
|
+
}),
|
|
712
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
713
|
+
label: "Tax",
|
|
714
|
+
value: props.taxExempt ? 'exempt' : 'taxable',
|
|
715
|
+
onChange: setTax,
|
|
716
|
+
size: "small",
|
|
717
|
+
select: true,
|
|
718
|
+
sx: SHORT_SELECT,
|
|
719
|
+
children: TAX_MENU
|
|
720
|
+
}),
|
|
721
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
722
|
+
label: "Low-stock alert at",
|
|
723
|
+
value: (_props_lowStockThreshold = props.lowStockThreshold) != null ? _props_lowStockThreshold : '',
|
|
724
|
+
placeholder: "Off",
|
|
725
|
+
disabled: !props.stockApplies,
|
|
726
|
+
onChange: setLowStock,
|
|
727
|
+
size: "small",
|
|
728
|
+
sx: COUNT_FIELD,
|
|
729
|
+
slotProps: NUMERIC_INPUT,
|
|
730
|
+
helperText: "Notifies managers"
|
|
731
|
+
})
|
|
732
|
+
]
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
/** One-time or subscription billing, its interval, and a free trial. */ const ProductBillingFields = /*#__PURE__*/ memo(function ProductBillingFields(props) {
|
|
736
|
+
var _props_subsPlanLabel, _subscription_trialDays;
|
|
737
|
+
const { subscription, subscriptionOptional, subsLocked, update, replaceDraft } = props;
|
|
738
|
+
const setBilling = useCallback((event)=>{
|
|
739
|
+
const value = event.target.value;
|
|
740
|
+
// `replaceDraft`, not `update`: a patch is spread over the draft,
|
|
741
|
+
// which would resurrect the keys deleted below.
|
|
742
|
+
replaceDraft((product)=>{
|
|
743
|
+
// "Both" (AGL-545): the PDP offers one-time OR subscribe at
|
|
744
|
+
// the same price; the interval field beside picks the cadence.
|
|
745
|
+
// Cleared keys are deleted (not set undefined) so the
|
|
746
|
+
// client-direct setDoc on save never sees undefined values.
|
|
747
|
+
const next = _extends({}, product);
|
|
748
|
+
if (value === 'once') {
|
|
749
|
+
delete next.subscription;
|
|
750
|
+
} else {
|
|
751
|
+
var _product_subscription, _ref;
|
|
752
|
+
var _product_subscription1;
|
|
753
|
+
next.subscription = _extends({}, (_product_subscription = product.subscription) != null ? _product_subscription : {}, {
|
|
754
|
+
interval: value === 'both' ? (_ref = (_product_subscription1 = product.subscription) == null ? void 0 : _product_subscription1.interval) != null ? _ref : 'month' : value
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
if (value === 'both') next.subscriptionOptional = true;
|
|
758
|
+
else delete next.subscriptionOptional;
|
|
759
|
+
return next;
|
|
760
|
+
});
|
|
761
|
+
}, [
|
|
762
|
+
replaceDraft
|
|
763
|
+
]);
|
|
764
|
+
const setBillingInterval = useCallback((event)=>{
|
|
765
|
+
const interval = event.target.value;
|
|
766
|
+
update((product)=>({
|
|
767
|
+
subscription: _extends({}, product.subscription, {
|
|
768
|
+
interval
|
|
769
|
+
})
|
|
770
|
+
}));
|
|
771
|
+
}, [
|
|
772
|
+
update
|
|
773
|
+
]);
|
|
774
|
+
const setTrialDays = useCallback((event)=>{
|
|
775
|
+
const raw = event.target.value.trim();
|
|
776
|
+
update((product)=>({
|
|
777
|
+
subscription: _extends({}, product.subscription, raw === '' ? {
|
|
778
|
+
trialDays: undefined
|
|
779
|
+
} : {
|
|
780
|
+
trialDays: Math.max(1, Math.round(Number(raw)))
|
|
781
|
+
})
|
|
782
|
+
}));
|
|
783
|
+
}, [
|
|
784
|
+
update
|
|
785
|
+
]);
|
|
786
|
+
const billingMenu = useMemo(()=>[
|
|
787
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
788
|
+
value: "once",
|
|
789
|
+
children: 'One-time purchase'
|
|
790
|
+
}, "once"),
|
|
791
|
+
// Same rule as the gift-card option: disabled, not removed, so an
|
|
792
|
+
// existing subscription product keeps its interval instead of being
|
|
793
|
+
// silently reset to one-time.
|
|
794
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
795
|
+
value: "month",
|
|
796
|
+
disabled: subsLocked,
|
|
797
|
+
children: 'Monthly subscription'
|
|
798
|
+
}, "month"),
|
|
799
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
800
|
+
value: "year",
|
|
801
|
+
disabled: subsLocked,
|
|
802
|
+
children: 'Yearly subscription'
|
|
803
|
+
}, "year"),
|
|
804
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
805
|
+
value: "both",
|
|
806
|
+
disabled: subsLocked,
|
|
807
|
+
children: 'Both — buyer chooses'
|
|
808
|
+
}, "both")
|
|
809
|
+
], [
|
|
810
|
+
subsLocked
|
|
811
|
+
]);
|
|
812
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
813
|
+
direction: "row",
|
|
814
|
+
spacing: 2,
|
|
815
|
+
children: [
|
|
816
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
817
|
+
label: "Billing",
|
|
818
|
+
value: subscription ? subscriptionOptional ? 'both' : subscription.interval : 'once',
|
|
819
|
+
onChange: setBilling,
|
|
820
|
+
size: "small",
|
|
821
|
+
select: true,
|
|
822
|
+
sx: BILLING_SELECT,
|
|
823
|
+
helperText: subsLocked ? `Subscriptions are on ${(_props_subsPlanLabel = props.subsPlanLabel) != null ? _props_subsPlanLabel : 'a higher plan'}` : 'Subscriptions bill until canceled',
|
|
824
|
+
children: billingMenu
|
|
825
|
+
}),
|
|
826
|
+
subscription && subscriptionOptional ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
827
|
+
label: "Interval",
|
|
828
|
+
value: subscription.interval,
|
|
829
|
+
onChange: setBillingInterval,
|
|
830
|
+
size: "small",
|
|
831
|
+
select: true,
|
|
832
|
+
sx: SHORT_SELECT,
|
|
833
|
+
children: INTERVAL_MENU
|
|
834
|
+
}) : null,
|
|
835
|
+
subscription ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
836
|
+
label: "Free trial (days)",
|
|
837
|
+
placeholder: "None",
|
|
838
|
+
value: (_subscription_trialDays = subscription.trialDays) != null ? _subscription_trialDays : '',
|
|
839
|
+
onChange: setTrialDays,
|
|
840
|
+
size: "small",
|
|
841
|
+
sx: COUNT_FIELD,
|
|
842
|
+
slotProps: NUMERIC_INPUT
|
|
843
|
+
}) : null
|
|
844
|
+
]
|
|
845
|
+
});
|
|
846
|
+
});
|
|
847
|
+
const DigitalFileRow = /*#__PURE__*/ memo(function DigitalFileRow(props) {
|
|
848
|
+
var _file_version;
|
|
849
|
+
const { index, file, update } = props;
|
|
850
|
+
const setVersion = useCallback((event)=>{
|
|
851
|
+
const version = event.target.value.slice(0, 20);
|
|
852
|
+
update((product)=>{
|
|
853
|
+
var _product_digitalFiles;
|
|
854
|
+
const digitalFiles = [
|
|
855
|
+
...(_product_digitalFiles = product.digitalFiles) != null ? _product_digitalFiles : []
|
|
856
|
+
];
|
|
857
|
+
digitalFiles[index] = _extends({}, file, {
|
|
858
|
+
version
|
|
859
|
+
});
|
|
860
|
+
return {
|
|
861
|
+
digitalFiles
|
|
862
|
+
};
|
|
863
|
+
});
|
|
864
|
+
}, [
|
|
865
|
+
file,
|
|
866
|
+
index,
|
|
867
|
+
update
|
|
868
|
+
]);
|
|
869
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
870
|
+
direction: "row",
|
|
871
|
+
spacing: 1,
|
|
872
|
+
sx: {
|
|
873
|
+
alignItems: 'center'
|
|
874
|
+
},
|
|
875
|
+
children: [
|
|
876
|
+
/*#__PURE__*/ _jsxs(Typography, {
|
|
877
|
+
variant: "body2",
|
|
878
|
+
sx: {
|
|
879
|
+
flex: 1
|
|
880
|
+
},
|
|
881
|
+
noWrap: true,
|
|
882
|
+
children: [
|
|
883
|
+
file.fileName,
|
|
884
|
+
file.version ? ` · v${file.version}` : ''
|
|
885
|
+
]
|
|
886
|
+
}),
|
|
887
|
+
/*#__PURE__*/ _jsx(PaidMediaProtection, {
|
|
888
|
+
url: file.url,
|
|
889
|
+
hostId: props.hostId,
|
|
890
|
+
productId: props.productId,
|
|
891
|
+
kind: "download"
|
|
892
|
+
}),
|
|
893
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
894
|
+
label: "Version",
|
|
895
|
+
value: (_file_version = file.version) != null ? _file_version : '',
|
|
896
|
+
onChange: setVersion,
|
|
897
|
+
size: "small",
|
|
898
|
+
sx: VERSION_FIELD
|
|
899
|
+
}),
|
|
900
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
901
|
+
size: "small",
|
|
902
|
+
color: "error",
|
|
903
|
+
onClick: ()=>update((product)=>{
|
|
904
|
+
var _product_digitalFiles;
|
|
905
|
+
return {
|
|
906
|
+
digitalFiles: ((_product_digitalFiles = product.digitalFiles) != null ? _product_digitalFiles : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
907
|
+
};
|
|
908
|
+
}),
|
|
909
|
+
children: '✕'
|
|
910
|
+
})
|
|
911
|
+
]
|
|
912
|
+
});
|
|
913
|
+
});
|
|
914
|
+
/*
|
|
915
|
+
* The paid-media controls beside the digital fields, drawn again only when
|
|
916
|
+
* what they are handed changes: a keystroke in the download limit leaves the
|
|
917
|
+
* videos, and the protection check on each, as they were.
|
|
918
|
+
*/ const MemoMembersVideosField = /*#__PURE__*/ memo(MembersVideosField);
|
|
919
|
+
const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
|
|
920
|
+
/** A digital product's files, its download limit and its members videos. */ const ProductDigitalFields = /*#__PURE__*/ memo(function ProductDigitalFields(props) {
|
|
921
|
+
var _props_downloadLimit;
|
|
922
|
+
const { hostId, productId, update } = props;
|
|
923
|
+
const addFile = useCallback((file)=>update((product)=>{
|
|
924
|
+
var _product_digitalFiles;
|
|
925
|
+
return {
|
|
926
|
+
digitalFiles: [
|
|
927
|
+
...(_product_digitalFiles = product.digitalFiles) != null ? _product_digitalFiles : [],
|
|
928
|
+
file
|
|
929
|
+
]
|
|
930
|
+
};
|
|
931
|
+
}), [
|
|
932
|
+
update
|
|
933
|
+
]);
|
|
934
|
+
const setDownloadLimit = useCallback((event)=>{
|
|
935
|
+
const raw = event.target.value.trim();
|
|
936
|
+
update({
|
|
937
|
+
downloadLimit: raw === '' ? undefined : Math.max(1, Math.round(Number(raw)))
|
|
938
|
+
});
|
|
939
|
+
}, [
|
|
940
|
+
update
|
|
941
|
+
]);
|
|
942
|
+
const setVideos = useCallback((gatedVideos)=>update({
|
|
943
|
+
gatedVideos
|
|
944
|
+
}), [
|
|
945
|
+
update
|
|
946
|
+
]);
|
|
947
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
948
|
+
children: [
|
|
949
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
950
|
+
textAlign: "left",
|
|
951
|
+
children: 'Digital delivery'
|
|
952
|
+
}),
|
|
953
|
+
props.digitalFiles.map((file, index)=>/*#__PURE__*/ _jsx(DigitalFileRow, {
|
|
954
|
+
index: index,
|
|
955
|
+
file: file,
|
|
956
|
+
hostId: hostId,
|
|
957
|
+
productId: productId,
|
|
958
|
+
update: update
|
|
959
|
+
}, index)),
|
|
960
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
961
|
+
direction: "row",
|
|
962
|
+
spacing: 2,
|
|
963
|
+
children: [
|
|
964
|
+
/*#__PURE__*/ _jsx(MemoPaidDownloadAddButton, {
|
|
965
|
+
hostId: hostId,
|
|
966
|
+
productId: productId,
|
|
967
|
+
onAdd: addFile
|
|
968
|
+
}),
|
|
969
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
970
|
+
label: "Download limit",
|
|
971
|
+
placeholder: "Unlimited",
|
|
972
|
+
value: (_props_downloadLimit = props.downloadLimit) != null ? _props_downloadLimit : '',
|
|
973
|
+
onChange: setDownloadLimit,
|
|
974
|
+
size: "small",
|
|
975
|
+
sx: COUNT_FIELD,
|
|
976
|
+
slotProps: NUMERIC_INPUT,
|
|
977
|
+
helperText: "Attempts per order"
|
|
978
|
+
})
|
|
979
|
+
]
|
|
980
|
+
}),
|
|
981
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
982
|
+
variant: "caption",
|
|
983
|
+
color: "text.secondary",
|
|
984
|
+
children: 'Buyers always download the current files — uploading a new ' + 'version re-delivers to everyone.'
|
|
985
|
+
}),
|
|
986
|
+
/*#__PURE__*/ _jsx(MemoMembersVideosField, {
|
|
987
|
+
hostId: hostId,
|
|
988
|
+
productId: productId,
|
|
989
|
+
videos: props.gatedVideos,
|
|
990
|
+
onChange: setVideos
|
|
991
|
+
})
|
|
992
|
+
]
|
|
993
|
+
});
|
|
994
|
+
});
|
|
995
|
+
/** The product's search listing: its title, description and share image. */ const ProductSeoFields = /*#__PURE__*/ memo(function ProductSeoFields(props) {
|
|
996
|
+
const { title, description, update, pick } = props;
|
|
997
|
+
const setTitle = useCallback((event)=>{
|
|
998
|
+
const next = event.target.value;
|
|
999
|
+
update((product)=>({
|
|
1000
|
+
seo: _extends({}, product.seo, {
|
|
1001
|
+
title: next
|
|
1002
|
+
})
|
|
1003
|
+
}));
|
|
1004
|
+
}, [
|
|
1005
|
+
update
|
|
1006
|
+
]);
|
|
1007
|
+
const setDescription = useCallback((event)=>{
|
|
1008
|
+
const next = event.target.value;
|
|
1009
|
+
update((product)=>({
|
|
1010
|
+
seo: _extends({}, product.seo, {
|
|
1011
|
+
description: next
|
|
1012
|
+
})
|
|
1013
|
+
}));
|
|
1014
|
+
}, [
|
|
1015
|
+
update
|
|
1016
|
+
]);
|
|
1017
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
1018
|
+
children: [
|
|
1019
|
+
/*#__PURE__*/ _jsx(Divider, {
|
|
1020
|
+
textAlign: "left",
|
|
1021
|
+
children: 'Search engine listing'
|
|
1022
|
+
}),
|
|
1023
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
1024
|
+
direction: WIDE_ROW,
|
|
1025
|
+
spacing: 2,
|
|
1026
|
+
children: [
|
|
1027
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1028
|
+
label: "SEO title",
|
|
1029
|
+
value: title != null ? title : '',
|
|
1030
|
+
onChange: setTitle,
|
|
1031
|
+
// The counts every search listing editor prints (AGL-2910): what a
|
|
1032
|
+
// search result shows before it truncates.
|
|
1033
|
+
helperText: seoListingFieldCount('title', title),
|
|
1034
|
+
error: seoListingFieldTooLong('title', title),
|
|
1035
|
+
size: "small",
|
|
1036
|
+
fullWidth: true
|
|
1037
|
+
}),
|
|
1038
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
1039
|
+
size: "small",
|
|
1040
|
+
onClick: ()=>void pick((media)=>update((product)=>({
|
|
1041
|
+
seo: _extends({}, product.seo, {
|
|
1042
|
+
imageUrl: media.url
|
|
1043
|
+
})
|
|
1044
|
+
}))),
|
|
1045
|
+
children: props.hasImage ? 'Change OG image' : 'OG image'
|
|
1046
|
+
})
|
|
1047
|
+
]
|
|
1048
|
+
}),
|
|
1049
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1050
|
+
label: "SEO description",
|
|
1051
|
+
value: description != null ? description : '',
|
|
1052
|
+
onChange: setDescription,
|
|
1053
|
+
helperText: seoListingFieldCount('description', description),
|
|
1054
|
+
error: seoListingFieldTooLong('description', description),
|
|
1055
|
+
size: "small",
|
|
1056
|
+
multiline: true,
|
|
1057
|
+
minRows: 2
|
|
1058
|
+
})
|
|
1059
|
+
]
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
75
1062
|
/**
|
|
76
1063
|
* Products hub editor (AGL-279): the full catalog editor — basics,
|
|
77
1064
|
* media, tags, options → variants matrix, per-variant pricing/stock, and
|
|
@@ -79,8 +1066,8 @@ function comboLabel(options) {
|
|
|
79
1066
|
* first variant so the legacy Product block + checkout API (AGL-90) keep
|
|
80
1067
|
* charging correctly without reading the variants array.
|
|
81
1068
|
*/ export function ProductEditorDialog(props) {
|
|
82
|
-
var _ref, _ref1, _current_description, _current_tags, _current_categoryIds, _current_options, _current_mediaUrls, _ref2, _ref3,
|
|
83
|
-
var _current_seo, _current_seo1,
|
|
1069
|
+
var _ref, _ref1, _current_description, _current_tags, _current_categoryIds, _current_options, _current_mediaUrls, _ref2, _ref3, _ref4, _current_description1, _ref5, _ref6, _current_description2, _current_tags1, _current_mediaUrls1, _current_options1, _subs_planLabel, _gifts_planLabel, _subs_planLabel1, _gifts_planLabel1, _current_oversellPolicy, _current_digitalFiles, _current_gatedVideos;
|
|
1070
|
+
var _current_seo, _current_seo1, _current_seo2, _current_seo3, _current_seo4, _current_seo5, _current_seo6, _current_seo7;
|
|
84
1071
|
const { hostId, product, seedFromCache, seedUnreadable, open, onClose } = props;
|
|
85
1072
|
/**
|
|
86
1073
|
* Field-level entitlement gates (AGL-2080). Both of these were fully
|
|
@@ -160,7 +1147,50 @@ function comboLabel(options) {
|
|
|
160
1147
|
]);
|
|
161
1148
|
// Lazy-init per open; parent remounts via `key` on product change.
|
|
162
1149
|
const current = (_ref = draft != null ? draft : lifted) != null ? _ref : blankProduct();
|
|
163
|
-
|
|
1150
|
+
/*
|
|
1151
|
+
* The two writes every field goes through, each keeping its identity for
|
|
1152
|
+
* the life of the dialog so a memoized section redraws only when its own
|
|
1153
|
+
* slice of the draft does (AGL-3423). Both write from the draft as last
|
|
1154
|
+
* rendered, which `latest` holds: `update` spreads a patch over it, and a
|
|
1155
|
+
* patch that is a function is handed it, so no field holds a copy of the
|
|
1156
|
+
* product to spread. A write that lands after a picker closes lands on the
|
|
1157
|
+
* draft as it is then.
|
|
1158
|
+
*/ const latest = useRef(current);
|
|
1159
|
+
latest.current = current;
|
|
1160
|
+
const replaceDraft = useCallback((build)=>setDraft(build(latest.current)), []);
|
|
1161
|
+
const update = useCallback((patch)=>replaceDraft((at)=>_extends({}, at, typeof patch === 'function' ? patch(at) : patch)), [
|
|
1162
|
+
replaceDraft
|
|
1163
|
+
]);
|
|
1164
|
+
const setTags = useCallback((tags)=>update({
|
|
1165
|
+
tags: tags.map((tag)=>String(tag).trim()).filter(Boolean)
|
|
1166
|
+
}), [
|
|
1167
|
+
update
|
|
1168
|
+
]);
|
|
1169
|
+
const setCategories = useCallback((picked)=>update({
|
|
1170
|
+
categoryIds: picked.map((category)=>category.$id)
|
|
1171
|
+
}), [
|
|
1172
|
+
update
|
|
1173
|
+
]);
|
|
1174
|
+
const setRelatedProducts = useCallback((picked)=>update({
|
|
1175
|
+
relatedProductIds: picked.map((item)=>item.$id)
|
|
1176
|
+
}), [
|
|
1177
|
+
update
|
|
1178
|
+
]);
|
|
1179
|
+
const categoryIds = current.categoryIds;
|
|
1180
|
+
const pickedCategories = useMemo(()=>categories.rows.filter((category)=>(categoryIds != null ? categoryIds : []).includes(category.$id)), [
|
|
1181
|
+
categories.rows,
|
|
1182
|
+
categoryIds
|
|
1183
|
+
]);
|
|
1184
|
+
const relatedProductIds = current.relatedProductIds;
|
|
1185
|
+
const productId = product == null ? void 0 : product.$id;
|
|
1186
|
+
const relatedOptions = useMemo(()=>relatedProducts.rows.filter((item)=>!item.deletedAt && item.$id !== productId), [
|
|
1187
|
+
relatedProducts.rows,
|
|
1188
|
+
productId
|
|
1189
|
+
]);
|
|
1190
|
+
const pickedRelated = useMemo(()=>relatedProducts.rows.filter((item)=>(relatedProductIds != null ? relatedProductIds : []).includes(item.$id)), [
|
|
1191
|
+
relatedProducts.rows,
|
|
1192
|
+
relatedProductIds
|
|
1193
|
+
]);
|
|
164
1194
|
/** The shell's zone renderer (AGL-2910); `null` outside the console shell. */ const WidgetSlot = useConsoleWidgetSlot();
|
|
165
1195
|
/**
|
|
166
1196
|
* A listing zone widget's proposal, staged into the draft like typing.
|
|
@@ -207,7 +1237,10 @@ function comboLabel(options) {
|
|
|
207
1237
|
}), [
|
|
208
1238
|
categories.rows
|
|
209
1239
|
]);
|
|
210
|
-
|
|
1240
|
+
/*
|
|
1241
|
+
* What the two zones are handed, held by content: a keystroke in a field
|
|
1242
|
+
* neither zone reads (a SKU, a price) leaves both as they were.
|
|
1243
|
+
*/ const zoneProduct = useContentStable({
|
|
211
1244
|
id: (_ref1 = product == null ? void 0 : product.$id) != null ? _ref1 : null,
|
|
212
1245
|
name: current.name,
|
|
213
1246
|
type: current.type,
|
|
@@ -221,7 +1254,17 @@ function comboLabel(options) {
|
|
|
221
1254
|
mediaUrls: (_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : [],
|
|
222
1255
|
seoTitle: (_ref2 = (_current_seo = current.seo) == null ? void 0 : _current_seo.title) != null ? _ref2 : '',
|
|
223
1256
|
seoDescription: (_ref3 = (_current_seo1 = current.seo) == null ? void 0 : _current_seo1.description) != null ? _ref3 : ''
|
|
224
|
-
};
|
|
1257
|
+
});
|
|
1258
|
+
const seoSubject = useContentStable({
|
|
1259
|
+
kind: 'product',
|
|
1260
|
+
id: (_ref4 = product == null ? void 0 : product.$id) != null ? _ref4 : null,
|
|
1261
|
+
name: current.name,
|
|
1262
|
+
description: String((_current_description1 = current.description) != null ? _current_description1 : '')
|
|
1263
|
+
});
|
|
1264
|
+
const seoValues = useContentStable({
|
|
1265
|
+
title: (_ref5 = (_current_seo2 = current.seo) == null ? void 0 : _current_seo2.title) != null ? _ref5 : '',
|
|
1266
|
+
description: (_ref6 = (_current_seo3 = current.seo) == null ? void 0 : _current_seo3.description) != null ? _ref6 : ''
|
|
1267
|
+
});
|
|
225
1268
|
const error = current.name ? CommerceModel.validateProduct(current) : null;
|
|
226
1269
|
/**
|
|
227
1270
|
* Stock tracking is inert on a subscription-only product (AGL-1744) —
|
|
@@ -244,85 +1287,106 @@ function comboLabel(options) {
|
|
|
244
1287
|
* count this just cleared. Keys are DELETED rather than set undefined; the
|
|
245
1288
|
* save is a client-direct `setDoc`, which rejects undefined values.
|
|
246
1289
|
*/ const handleClearStockTracking = ()=>{
|
|
247
|
-
update({
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
1290
|
+
update((at)=>({
|
|
1291
|
+
variants: at.variants.map((variant)=>{
|
|
1292
|
+
const { inventoryByLocation: _perLocation } = variant, rest = _object_without_properties_loose(variant, [
|
|
1293
|
+
"inventoryByLocation"
|
|
1294
|
+
]);
|
|
1295
|
+
return _extends({}, rest, {
|
|
1296
|
+
inventory: null
|
|
1297
|
+
});
|
|
1298
|
+
})
|
|
1299
|
+
}));
|
|
257
1300
|
};
|
|
258
|
-
const handleName = (
|
|
1301
|
+
const handleName = useCallback((event)=>{
|
|
1302
|
+
const name = event.target.value;
|
|
1303
|
+
update(_extends({
|
|
259
1304
|
name
|
|
260
1305
|
}, !product && !slugTouched ? {
|
|
261
1306
|
slug: CommerceModel.commerceSlug(name)
|
|
262
1307
|
} : {}));
|
|
263
|
-
const handleOptionsChange = useCallback((index, patch)=>{
|
|
264
|
-
var _current_options;
|
|
265
|
-
var _current_options1;
|
|
266
|
-
// A RENAME moves each variant's selection to the new name (AGL-3066).
|
|
267
|
-
// Rebuilding the matrix matches variants by name and value, so under a
|
|
268
|
-
// new name it finds none and replaces every variant, its id, price, SKU
|
|
269
|
-
// and stock with them. Only a change of values rebuilds.
|
|
270
|
-
if (patch && ((_current_options1 = current.options) == null ? void 0 : _current_options1[index]) && Object.keys(patch).length === 1 && typeof patch.name === 'string') {
|
|
271
|
-
update(CommerceModel.renameProductOptions(current, current.options.map((option, at)=>at === index ? patch.name : option.name)));
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
const options = [
|
|
275
|
-
...(_current_options = current.options) != null ? _current_options : []
|
|
276
|
-
];
|
|
277
|
-
if (patch === null) options.splice(index, 1);
|
|
278
|
-
else options[index] = _extends({
|
|
279
|
-
name: '',
|
|
280
|
-
values: []
|
|
281
|
-
}, options[index], patch);
|
|
282
|
-
// Regenerate the matrix, carrying data over by option-combo key so
|
|
283
|
-
// edits to prices/SKUs survive option tweaks.
|
|
284
|
-
const previous = new Map(current.variants.map((variant)=>[
|
|
285
|
-
comboKey(variant.options),
|
|
286
|
-
variant
|
|
287
|
-
]));
|
|
288
|
-
const fallback = current.variants[0];
|
|
289
|
-
const variants = CommerceModel.expandVariantMatrix(options).map((combo, comboIndex)=>{
|
|
290
|
-
var _ref, _ref1;
|
|
291
|
-
const existing = previous.get(comboKey(combo));
|
|
292
|
-
return existing != null ? existing : {
|
|
293
|
-
id: `v${Date.now().toString(36)}${comboIndex}`,
|
|
294
|
-
options: combo,
|
|
295
|
-
priceUsd: (_ref = fallback == null ? void 0 : fallback.priceUsd) != null ? _ref : 0,
|
|
296
|
-
inventory: (_ref1 = fallback == null ? void 0 : fallback.inventory) != null ? _ref1 : null
|
|
297
|
-
};
|
|
298
|
-
});
|
|
299
|
-
update({
|
|
300
|
-
options,
|
|
301
|
-
variants
|
|
302
|
-
});
|
|
303
1308
|
}, [
|
|
304
|
-
|
|
1309
|
+
product,
|
|
1310
|
+
slugTouched,
|
|
1311
|
+
update
|
|
305
1312
|
]);
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
...current.variants
|
|
309
|
-
];
|
|
310
|
-
const numeric = [
|
|
311
|
-
'priceUsd',
|
|
312
|
-
'compareAtPriceUsd',
|
|
313
|
-
'weightGrams'
|
|
314
|
-
];
|
|
315
|
-
const value = field === 'inventory' ? raw.trim() === '' ? null : Math.max(0, Math.round(Number(raw))) : numeric.includes(field) ? raw.trim() === '' ? undefined : Number(raw) : raw;
|
|
316
|
-
variants[index] = _extends({}, variants[index], {
|
|
317
|
-
[field]: value
|
|
318
|
-
});
|
|
319
|
-
if (value === undefined && (field === 'compareAtPriceUsd' || field === 'weightGrams')) {
|
|
320
|
-
delete variants[index][field];
|
|
321
|
-
}
|
|
1313
|
+
const handleSlug = useCallback((event)=>{
|
|
1314
|
+
setSlugTouched(true);
|
|
322
1315
|
update({
|
|
323
|
-
|
|
1316
|
+
slug: CommerceModel.commerceSlug(event.target.value)
|
|
324
1317
|
});
|
|
325
|
-
}
|
|
1318
|
+
}, [
|
|
1319
|
+
update
|
|
1320
|
+
]);
|
|
1321
|
+
const handleOptionsChange = useCallback((index, patch)=>update((at)=>{
|
|
1322
|
+
var _at_options;
|
|
1323
|
+
var _at_options1;
|
|
1324
|
+
// A RENAME moves each variant's selection to the new name (AGL-3066).
|
|
1325
|
+
// Rebuilding the matrix matches variants by name and value, so under a
|
|
1326
|
+
// new name it finds none and replaces every variant, its id, price, SKU
|
|
1327
|
+
// and stock with them. Only a change of values rebuilds.
|
|
1328
|
+
if (patch && ((_at_options1 = at.options) == null ? void 0 : _at_options1[index]) && Object.keys(patch).length === 1 && typeof patch.name === 'string') {
|
|
1329
|
+
return CommerceModel.renameProductOptions(at, at.options.map((option, optionIndex)=>optionIndex === index ? patch.name : option.name));
|
|
1330
|
+
}
|
|
1331
|
+
const options = [
|
|
1332
|
+
...(_at_options = at.options) != null ? _at_options : []
|
|
1333
|
+
];
|
|
1334
|
+
if (patch === null) options.splice(index, 1);
|
|
1335
|
+
else options[index] = _extends({
|
|
1336
|
+
name: '',
|
|
1337
|
+
values: []
|
|
1338
|
+
}, options[index], patch);
|
|
1339
|
+
// Regenerate the matrix, carrying data over by option-combo key so
|
|
1340
|
+
// edits to prices/SKUs survive option tweaks.
|
|
1341
|
+
const previous = new Map(at.variants.map((variant)=>[
|
|
1342
|
+
comboKey(variant.options),
|
|
1343
|
+
variant
|
|
1344
|
+
]));
|
|
1345
|
+
const fallback = at.variants[0];
|
|
1346
|
+
const variants = CommerceModel.expandVariantMatrix(options).map((combo, comboIndex)=>{
|
|
1347
|
+
var _ref, _ref1;
|
|
1348
|
+
const existing = previous.get(comboKey(combo));
|
|
1349
|
+
return existing != null ? existing : {
|
|
1350
|
+
id: `v${Date.now().toString(36)}${comboIndex}`,
|
|
1351
|
+
options: combo,
|
|
1352
|
+
priceUsd: (_ref = fallback == null ? void 0 : fallback.priceUsd) != null ? _ref : 0,
|
|
1353
|
+
inventory: (_ref1 = fallback == null ? void 0 : fallback.inventory) != null ? _ref1 : null
|
|
1354
|
+
};
|
|
1355
|
+
});
|
|
1356
|
+
return {
|
|
1357
|
+
options,
|
|
1358
|
+
variants
|
|
1359
|
+
};
|
|
1360
|
+
}), [
|
|
1361
|
+
update
|
|
1362
|
+
]);
|
|
1363
|
+
const setOptionValues = useCallback((values, index)=>handleOptionsChange(index, {
|
|
1364
|
+
values: values.map((value)=>String(value).trim()).filter(Boolean)
|
|
1365
|
+
}), [
|
|
1366
|
+
handleOptionsChange
|
|
1367
|
+
]);
|
|
1368
|
+
const handleVariantField = useCallback((index, field, raw)=>update((at)=>{
|
|
1369
|
+
const variants = [
|
|
1370
|
+
...at.variants
|
|
1371
|
+
];
|
|
1372
|
+
const numeric = [
|
|
1373
|
+
'priceUsd',
|
|
1374
|
+
'compareAtPriceUsd',
|
|
1375
|
+
'weightGrams'
|
|
1376
|
+
];
|
|
1377
|
+
const value = field === 'inventory' ? raw.trim() === '' ? null : Math.max(0, Math.round(Number(raw))) : numeric.includes(field) ? raw.trim() === '' ? undefined : Number(raw) : raw;
|
|
1378
|
+
variants[index] = _extends({}, variants[index], {
|
|
1379
|
+
[field]: value
|
|
1380
|
+
});
|
|
1381
|
+
if (value === undefined && (field === 'compareAtPriceUsd' || field === 'weightGrams')) {
|
|
1382
|
+
delete variants[index][field];
|
|
1383
|
+
}
|
|
1384
|
+
return {
|
|
1385
|
+
variants
|
|
1386
|
+
};
|
|
1387
|
+
}), [
|
|
1388
|
+
update
|
|
1389
|
+
]);
|
|
326
1390
|
const handleSave = useCallback(async ()=>{
|
|
327
1391
|
var _ref, _ref1, _ref2;
|
|
328
1392
|
var _current_mediaUrls;
|
|
@@ -509,163 +1573,37 @@ function comboLabel(options) {
|
|
|
509
1573
|
gap: 2
|
|
510
1574
|
},
|
|
511
1575
|
children: [
|
|
512
|
-
/*#__PURE__*/
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
label: "Name",
|
|
524
|
-
value: current.name,
|
|
525
|
-
onChange: (event)=>handleName(event.target.value),
|
|
526
|
-
size: "small",
|
|
527
|
-
autoFocus: true,
|
|
528
|
-
fullWidth: true
|
|
529
|
-
}),
|
|
530
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
531
|
-
label: "Slug",
|
|
532
|
-
value: current.slug,
|
|
533
|
-
onChange: (event)=>{
|
|
534
|
-
setSlugTouched(true);
|
|
535
|
-
update({
|
|
536
|
-
slug: CommerceModel.commerceSlug(event.target.value)
|
|
537
|
-
});
|
|
538
|
-
},
|
|
539
|
-
size: "small",
|
|
540
|
-
fullWidth: true,
|
|
541
|
-
helperText: current.slug ? `/products/${current.slug}` : undefined
|
|
542
|
-
})
|
|
543
|
-
]
|
|
544
|
-
}),
|
|
545
|
-
/*#__PURE__*/ _jsxs(Stack, {
|
|
546
|
-
direction: "row",
|
|
547
|
-
spacing: 2,
|
|
548
|
-
children: [
|
|
549
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
550
|
-
label: "Type",
|
|
551
|
-
value: current.type,
|
|
552
|
-
onChange: (event)=>update({
|
|
553
|
-
type: event.target.value
|
|
554
|
-
}),
|
|
555
|
-
size: "small",
|
|
556
|
-
select: true,
|
|
557
|
-
sx: {
|
|
558
|
-
minWidth: 140
|
|
559
|
-
},
|
|
560
|
-
children: [
|
|
561
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
562
|
-
value: "physical",
|
|
563
|
-
children: 'Physical'
|
|
564
|
-
}),
|
|
565
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
566
|
-
value: "digital",
|
|
567
|
-
children: 'Digital'
|
|
568
|
-
}),
|
|
569
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
570
|
-
value: "service",
|
|
571
|
-
children: 'Service'
|
|
572
|
-
})
|
|
573
|
-
]
|
|
574
|
-
}),
|
|
575
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
576
|
-
label: "Status",
|
|
577
|
-
value: current.status,
|
|
578
|
-
onChange: (event)=>update({
|
|
579
|
-
status: event.target.value
|
|
580
|
-
}),
|
|
581
|
-
size: "small",
|
|
582
|
-
select: true,
|
|
583
|
-
sx: {
|
|
584
|
-
minWidth: 140
|
|
585
|
-
},
|
|
586
|
-
children: [
|
|
587
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
588
|
-
value: "draft",
|
|
589
|
-
children: 'Draft'
|
|
590
|
-
}),
|
|
591
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
592
|
-
value: "active",
|
|
593
|
-
children: 'Active'
|
|
594
|
-
}),
|
|
595
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
596
|
-
value: "archived",
|
|
597
|
-
children: 'Archived'
|
|
598
|
-
})
|
|
599
|
-
]
|
|
600
|
-
}),
|
|
601
|
-
suppliers.rows.length > 0 ? /*#__PURE__*/ _jsxs(TextField, {
|
|
602
|
-
label: "Supplier",
|
|
603
|
-
value: (_current_supplierId = current.supplierId) != null ? _current_supplierId : '',
|
|
604
|
-
onChange: (event)=>update({
|
|
605
|
-
supplierId: event.target.value || undefined
|
|
606
|
-
}),
|
|
607
|
-
size: "small",
|
|
608
|
-
select: true,
|
|
609
|
-
sx: {
|
|
610
|
-
minWidth: 160
|
|
611
|
-
},
|
|
612
|
-
helperText: "Routes paid orders",
|
|
613
|
-
children: [
|
|
614
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
615
|
-
value: "",
|
|
616
|
-
children: 'None (self-fulfilled)'
|
|
617
|
-
}),
|
|
618
|
-
suppliers.rows.map((supplier)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
619
|
-
value: supplier.$id,
|
|
620
|
-
children: supplier.name
|
|
621
|
-
}, supplier.$id))
|
|
622
|
-
]
|
|
623
|
-
}) : null
|
|
624
|
-
]
|
|
1576
|
+
/*#__PURE__*/ _jsx(ProductBasicsFields, {
|
|
1577
|
+
name: current.name,
|
|
1578
|
+
slug: current.slug,
|
|
1579
|
+
type: current.type,
|
|
1580
|
+
status: current.status,
|
|
1581
|
+
supplierId: current.supplierId,
|
|
1582
|
+
description: (_current_description2 = current.description) != null ? _current_description2 : '',
|
|
1583
|
+
suppliers: suppliers.rows,
|
|
1584
|
+
onName: handleName,
|
|
1585
|
+
onSlug: handleSlug,
|
|
1586
|
+
update: update
|
|
625
1587
|
}),
|
|
626
|
-
/*#__PURE__*/ _jsx(
|
|
627
|
-
label: "Description",
|
|
628
|
-
value: (_current_description1 = current.description) != null ? _current_description1 : '',
|
|
629
|
-
onChange: (event)=>update({
|
|
630
|
-
description: event.target.value
|
|
631
|
-
}),
|
|
632
|
-
size: "small",
|
|
633
|
-
multiline: true,
|
|
634
|
-
minRows: 2
|
|
635
|
-
}),
|
|
636
|
-
/*#__PURE__*/ _jsx(Autocomplete, {
|
|
637
|
-
multiple: true,
|
|
1588
|
+
/*#__PURE__*/ _jsx(ProductChipsField, {
|
|
638
1589
|
freeSolo: true,
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
645
|
-
label: "Tags",
|
|
646
|
-
size: "small",
|
|
647
|
-
placeholder: "Type and press Enter"
|
|
648
|
-
}))
|
|
1590
|
+
label: "Tags",
|
|
1591
|
+
placeholder: "Type and press Enter",
|
|
1592
|
+
options: NO_ITEMS,
|
|
1593
|
+
value: (_current_tags1 = current.tags) != null ? _current_tags1 : NO_ITEMS,
|
|
1594
|
+
onChange: setTags
|
|
649
1595
|
}),
|
|
650
|
-
categories.rows.length > 0 ? /*#__PURE__*/ _jsx(
|
|
651
|
-
|
|
1596
|
+
categories.rows.length > 0 ? /*#__PURE__*/ _jsx(ProductChipsField, {
|
|
1597
|
+
label: "Categories",
|
|
652
1598
|
options: categories.rows,
|
|
653
|
-
getOptionLabel:
|
|
654
|
-
isOptionEqualToValue:
|
|
655
|
-
value:
|
|
656
|
-
|
|
657
|
-
return ((_current_categoryIds = current.categoryIds) != null ? _current_categoryIds : []).includes(category.$id);
|
|
658
|
-
}),
|
|
659
|
-
onChange: (_event, picked)=>update({
|
|
660
|
-
categoryIds: picked.map((category)=>category.$id)
|
|
661
|
-
}),
|
|
662
|
-
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
663
|
-
label: "Categories",
|
|
664
|
-
size: "small"
|
|
665
|
-
}))
|
|
1599
|
+
getOptionLabel: categoryLabel,
|
|
1600
|
+
isOptionEqualToValue: sameRecord,
|
|
1601
|
+
value: pickedCategories,
|
|
1602
|
+
onChange: setCategories
|
|
666
1603
|
}) : null,
|
|
667
|
-
WidgetSlot ? /*#__PURE__*/ _jsx(
|
|
668
|
-
|
|
1604
|
+
WidgetSlot ? /*#__PURE__*/ _jsx(HostedZone, {
|
|
1605
|
+
renderer: WidgetSlot,
|
|
1606
|
+
slot: PRODUCT_EDITOR_ZONE.id,
|
|
669
1607
|
hostId: hostId,
|
|
670
1608
|
orgId: undefined,
|
|
671
1609
|
product: zoneProduct,
|
|
@@ -676,269 +1614,24 @@ function comboLabel(options) {
|
|
|
676
1614
|
textAlign: "left",
|
|
677
1615
|
children: 'Media'
|
|
678
1616
|
}),
|
|
679
|
-
/*#__PURE__*/
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
flexWrap: 'wrap'
|
|
684
|
-
},
|
|
685
|
-
children: [
|
|
686
|
-
((_current_mediaUrls1 = current.mediaUrls) != null ? _current_mediaUrls1 : []).map((url, index)=>/*#__PURE__*/ _jsxs(Box, {
|
|
687
|
-
sx: {
|
|
688
|
-
position: 'relative'
|
|
689
|
-
},
|
|
690
|
-
children: [
|
|
691
|
-
/*#__PURE__*/ _jsx(Box, {
|
|
692
|
-
component: "img",
|
|
693
|
-
src: url,
|
|
694
|
-
alt: "",
|
|
695
|
-
sx: {
|
|
696
|
-
width: 72,
|
|
697
|
-
height: 72,
|
|
698
|
-
objectFit: 'cover',
|
|
699
|
-
borderRadius: 1,
|
|
700
|
-
border: 1,
|
|
701
|
-
borderColor: 'divider'
|
|
702
|
-
}
|
|
703
|
-
}),
|
|
704
|
-
/*#__PURE__*/ _jsx(IconButton, {
|
|
705
|
-
size: "small",
|
|
706
|
-
"aria-label": "Remove image",
|
|
707
|
-
onClick: ()=>{
|
|
708
|
-
var _current_mediaUrls;
|
|
709
|
-
return update({
|
|
710
|
-
mediaUrls: ((_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
711
|
-
});
|
|
712
|
-
},
|
|
713
|
-
sx: {
|
|
714
|
-
position: 'absolute',
|
|
715
|
-
top: -8,
|
|
716
|
-
right: -8,
|
|
717
|
-
bgcolor: 'background.paper',
|
|
718
|
-
border: 1,
|
|
719
|
-
borderColor: 'divider',
|
|
720
|
-
p: 0.25
|
|
721
|
-
},
|
|
722
|
-
children: '✕'
|
|
723
|
-
})
|
|
724
|
-
]
|
|
725
|
-
}, `${url}-${index}`)),
|
|
726
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
727
|
-
size: "small",
|
|
728
|
-
onClick: ()=>void pick((media)=>{
|
|
729
|
-
var _current_mediaUrls;
|
|
730
|
-
return update({
|
|
731
|
-
mediaUrls: [
|
|
732
|
-
...(_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : [],
|
|
733
|
-
media.url
|
|
734
|
-
]
|
|
735
|
-
});
|
|
736
|
-
}),
|
|
737
|
-
children: 'Add image'
|
|
738
|
-
})
|
|
739
|
-
]
|
|
1617
|
+
/*#__PURE__*/ _jsx(ProductMediaFields, {
|
|
1618
|
+
mediaUrls: (_current_mediaUrls1 = current.mediaUrls) != null ? _current_mediaUrls1 : NO_ITEMS,
|
|
1619
|
+
update: update,
|
|
1620
|
+
pick: pick
|
|
740
1621
|
}),
|
|
741
1622
|
/*#__PURE__*/ _jsx(Divider, {
|
|
742
1623
|
textAlign: "left",
|
|
743
1624
|
children: 'Options & variants'
|
|
744
1625
|
}),
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
value: option.name,
|
|
755
|
-
onChange: (event)=>handleOptionsChange(index, {
|
|
756
|
-
name: event.target.value
|
|
757
|
-
}),
|
|
758
|
-
size: "small",
|
|
759
|
-
sx: {
|
|
760
|
-
width: 160
|
|
761
|
-
},
|
|
762
|
-
placeholder: "Size"
|
|
763
|
-
}),
|
|
764
|
-
/*#__PURE__*/ _jsx(Autocomplete, {
|
|
765
|
-
multiple: true,
|
|
766
|
-
freeSolo: true,
|
|
767
|
-
options: [],
|
|
768
|
-
value: option.values,
|
|
769
|
-
onChange: (_event, values)=>handleOptionsChange(index, {
|
|
770
|
-
values: values.map((value)=>String(value).trim()).filter(Boolean)
|
|
771
|
-
}),
|
|
772
|
-
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
773
|
-
label: "Values",
|
|
774
|
-
size: "small",
|
|
775
|
-
placeholder: "S, M, L…"
|
|
776
|
-
})),
|
|
777
|
-
sx: {
|
|
778
|
-
flex: 1
|
|
779
|
-
}
|
|
780
|
-
}),
|
|
781
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
782
|
-
size: "small",
|
|
783
|
-
color: "error",
|
|
784
|
-
onClick: ()=>handleOptionsChange(index, null),
|
|
785
|
-
sx: {
|
|
786
|
-
mt: 0.5
|
|
787
|
-
},
|
|
788
|
-
children: 'Remove'
|
|
789
|
-
})
|
|
790
|
-
]
|
|
791
|
-
}, index)),
|
|
792
|
-
((_ref4 = (_current_options2 = current.options) == null ? void 0 : _current_options2.length) != null ? _ref4 : 0) < CommerceModel.COMMERCE_MAX_OPTIONS ? /*#__PURE__*/ _jsx(Button, {
|
|
793
|
-
size: "small",
|
|
794
|
-
sx: {
|
|
795
|
-
alignSelf: 'flex-start'
|
|
796
|
-
},
|
|
797
|
-
onClick: ()=>{
|
|
798
|
-
var _ref;
|
|
799
|
-
var _current_options;
|
|
800
|
-
return handleOptionsChange((_ref = (_current_options = current.options) == null ? void 0 : _current_options.length) != null ? _ref : 0, {
|
|
801
|
-
name: '',
|
|
802
|
-
values: []
|
|
803
|
-
});
|
|
804
|
-
},
|
|
805
|
-
children: 'Add option'
|
|
806
|
-
}) : null,
|
|
807
|
-
/*#__PURE__*/ _jsx(Box, {
|
|
808
|
-
children: /*#__PURE__*/ _jsxs(ScrollTable, {
|
|
809
|
-
size: "small",
|
|
810
|
-
children: [
|
|
811
|
-
/*#__PURE__*/ _jsx(TableHead, {
|
|
812
|
-
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
813
|
-
children: [
|
|
814
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
815
|
-
children: 'Variant'
|
|
816
|
-
}),
|
|
817
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
818
|
-
children: 'Price ($)'
|
|
819
|
-
}),
|
|
820
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
821
|
-
children: 'Compare-at'
|
|
822
|
-
}),
|
|
823
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
824
|
-
children: 'SKU'
|
|
825
|
-
}),
|
|
826
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
827
|
-
children: 'Barcode'
|
|
828
|
-
}),
|
|
829
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
830
|
-
children: 'Stock'
|
|
831
|
-
}),
|
|
832
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
833
|
-
children: 'Weight (g)'
|
|
834
|
-
})
|
|
835
|
-
]
|
|
836
|
-
})
|
|
837
|
-
}),
|
|
838
|
-
/*#__PURE__*/ _jsx(TableBody, {
|
|
839
|
-
children: current.variants.map((variant, index)=>{
|
|
840
|
-
var _variant_priceUsd, _variant_compareAtPriceUsd, _variant_sku, _variant_barcode, _variant_inventory, _variant_weightGrams;
|
|
841
|
-
return /*#__PURE__*/ _jsxs(TableRow, {
|
|
842
|
-
children: [
|
|
843
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
844
|
-
sx: {
|
|
845
|
-
whiteSpace: 'nowrap'
|
|
846
|
-
},
|
|
847
|
-
children: comboLabel(variant.options)
|
|
848
|
-
}),
|
|
849
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
850
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
851
|
-
value: (_variant_priceUsd = variant.priceUsd) != null ? _variant_priceUsd : '',
|
|
852
|
-
onChange: (event)=>handleVariantField(index, 'priceUsd', event.target.value),
|
|
853
|
-
size: "small",
|
|
854
|
-
sx: {
|
|
855
|
-
width: 88
|
|
856
|
-
},
|
|
857
|
-
// An empty price is marked (AGL-2916): a proposed
|
|
858
|
-
// product arrives with none, and Save waits for one.
|
|
859
|
-
error: !CommerceModel.variantHasPrice(variant),
|
|
860
|
-
placeholder: "Set",
|
|
861
|
-
slotProps: {
|
|
862
|
-
htmlInput: {
|
|
863
|
-
inputMode: 'decimal'
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
})
|
|
867
|
-
}),
|
|
868
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
869
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
870
|
-
value: (_variant_compareAtPriceUsd = variant.compareAtPriceUsd) != null ? _variant_compareAtPriceUsd : '',
|
|
871
|
-
onChange: (event)=>handleVariantField(index, 'compareAtPriceUsd', event.target.value),
|
|
872
|
-
size: "small",
|
|
873
|
-
sx: {
|
|
874
|
-
width: 88
|
|
875
|
-
},
|
|
876
|
-
slotProps: {
|
|
877
|
-
htmlInput: {
|
|
878
|
-
inputMode: 'decimal'
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
})
|
|
882
|
-
}),
|
|
883
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
884
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
885
|
-
value: (_variant_sku = variant.sku) != null ? _variant_sku : '',
|
|
886
|
-
onChange: (event)=>handleVariantField(index, 'sku', event.target.value),
|
|
887
|
-
size: "small",
|
|
888
|
-
sx: {
|
|
889
|
-
width: 110
|
|
890
|
-
}
|
|
891
|
-
})
|
|
892
|
-
}),
|
|
893
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
894
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
895
|
-
value: (_variant_barcode = variant.barcode) != null ? _variant_barcode : '',
|
|
896
|
-
onChange: (event)=>handleVariantField(index, 'barcode', event.target.value),
|
|
897
|
-
size: "small",
|
|
898
|
-
sx: {
|
|
899
|
-
width: 110
|
|
900
|
-
}
|
|
901
|
-
})
|
|
902
|
-
}),
|
|
903
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
904
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
905
|
-
value: (_variant_inventory = variant.inventory) != null ? _variant_inventory : '',
|
|
906
|
-
placeholder: stockApplies ? '—' : 'n/a',
|
|
907
|
-
disabled: !stockApplies,
|
|
908
|
-
onChange: (event)=>handleVariantField(index, 'inventory', event.target.value),
|
|
909
|
-
size: "small",
|
|
910
|
-
sx: {
|
|
911
|
-
width: 72
|
|
912
|
-
},
|
|
913
|
-
slotProps: {
|
|
914
|
-
htmlInput: {
|
|
915
|
-
inputMode: 'numeric',
|
|
916
|
-
'aria-label': `Stock — ${comboLabel(variant.options)}`
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
})
|
|
920
|
-
}),
|
|
921
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
922
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
923
|
-
value: (_variant_weightGrams = variant.weightGrams) != null ? _variant_weightGrams : '',
|
|
924
|
-
onChange: (event)=>handleVariantField(index, 'weightGrams', event.target.value),
|
|
925
|
-
size: "small",
|
|
926
|
-
sx: {
|
|
927
|
-
width: 88
|
|
928
|
-
},
|
|
929
|
-
slotProps: {
|
|
930
|
-
htmlInput: {
|
|
931
|
-
inputMode: 'numeric'
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
})
|
|
935
|
-
})
|
|
936
|
-
]
|
|
937
|
-
}, variant.id);
|
|
938
|
-
})
|
|
939
|
-
})
|
|
940
|
-
]
|
|
941
|
-
})
|
|
1626
|
+
/*#__PURE__*/ _jsx(ProductOptionsFields, {
|
|
1627
|
+
options: (_current_options1 = current.options) != null ? _current_options1 : NO_OPTIONS,
|
|
1628
|
+
onChange: handleOptionsChange,
|
|
1629
|
+
onValues: setOptionValues
|
|
1630
|
+
}),
|
|
1631
|
+
/*#__PURE__*/ _jsx(ProductVariantsTable, {
|
|
1632
|
+
variants: current.variants,
|
|
1633
|
+
stockApplies: stockApplies,
|
|
1634
|
+
onField: handleVariantField
|
|
942
1635
|
}),
|
|
943
1636
|
/*#__PURE__*/ _jsx(Typography, {
|
|
944
1637
|
variant: "caption",
|
|
@@ -959,419 +1652,58 @@ function comboLabel(options) {
|
|
|
959
1652
|
upgradeHref: subsLocked ? subs.upgradeHref : gifts.upgradeHref,
|
|
960
1653
|
children: subsLocked && giftsLocked ? `Subscription products (${(_subs_planLabel = subs.planLabel) != null ? _subs_planLabel : 'higher plan'}) ` + `and gift cards (${(_gifts_planLabel = gifts.planLabel) != null ? _gifts_planLabel : 'higher plan'}) are ` + 'not on your plan. You can still save this product — those ' + 'two options stay locked until you upgrade.' : subsLocked ? `Subscription products are on ${(_subs_planLabel1 = subs.planLabel) != null ? _subs_planLabel1 : 'a higher plan'}. ` + 'A subscription saved without it is refused at checkout, ' + 'so the option stays locked here instead.' : `Gift cards are on ${(_gifts_planLabel1 = gifts.planLabel) != null ? _gifts_planLabel1 : 'a higher plan'}. ` + 'A gift-card product saved without it is refused at ' + 'checkout, so the option stays locked here instead.'
|
|
961
1654
|
}) : null,
|
|
962
|
-
/*#__PURE__*/
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}),
|
|
972
|
-
size: "small",
|
|
973
|
-
select: true,
|
|
974
|
-
sx: {
|
|
975
|
-
minWidth: 200
|
|
976
|
-
},
|
|
977
|
-
children: [
|
|
978
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
979
|
-
value: "deny",
|
|
980
|
-
children: 'Stop selling (sold out)'
|
|
981
|
-
}),
|
|
982
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
983
|
-
value: "backorder",
|
|
984
|
-
children: 'Keep selling (backorder)'
|
|
985
|
-
})
|
|
986
|
-
]
|
|
987
|
-
}),
|
|
988
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
989
|
-
label: "Kind",
|
|
990
|
-
value: current.giftCard ? 'gift' : 'standard',
|
|
991
|
-
onChange: (event)=>update({
|
|
992
|
-
giftCard: event.target.value === 'gift'
|
|
993
|
-
}),
|
|
994
|
-
size: "small",
|
|
995
|
-
select: true,
|
|
996
|
-
sx: {
|
|
997
|
-
minWidth: 130
|
|
998
|
-
},
|
|
999
|
-
helperText: giftsLocked ? `Gift cards are on ${(_gifts_planLabel2 = gifts.planLabel) != null ? _gifts_planLabel2 : 'a higher plan'}` : 'Gift cards issue a code',
|
|
1000
|
-
children: [
|
|
1001
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1002
|
-
value: "standard",
|
|
1003
|
-
children: 'Standard'
|
|
1004
|
-
}),
|
|
1005
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1006
|
-
value: "gift",
|
|
1007
|
-
disabled: giftsLocked,
|
|
1008
|
-
children: giftsLocked ? `Gift card — ${(_gifts_planLabel3 = gifts.planLabel) != null ? _gifts_planLabel3 : 'upgrade'} plan` : 'Gift card'
|
|
1009
|
-
})
|
|
1010
|
-
]
|
|
1011
|
-
}),
|
|
1012
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
1013
|
-
label: "Tax",
|
|
1014
|
-
value: current.taxExempt ? 'exempt' : 'taxable',
|
|
1015
|
-
onChange: (event)=>update({
|
|
1016
|
-
taxExempt: event.target.value === 'exempt'
|
|
1017
|
-
}),
|
|
1018
|
-
size: "small",
|
|
1019
|
-
select: true,
|
|
1020
|
-
sx: {
|
|
1021
|
-
minWidth: 120
|
|
1022
|
-
},
|
|
1023
|
-
children: [
|
|
1024
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1025
|
-
value: "taxable",
|
|
1026
|
-
children: 'Taxable'
|
|
1027
|
-
}),
|
|
1028
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1029
|
-
value: "exempt",
|
|
1030
|
-
children: 'Tax exempt'
|
|
1031
|
-
})
|
|
1032
|
-
]
|
|
1033
|
-
}),
|
|
1034
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1035
|
-
label: "Low-stock alert at",
|
|
1036
|
-
value: (_current_lowStockThreshold = current.lowStockThreshold) != null ? _current_lowStockThreshold : '',
|
|
1037
|
-
placeholder: "Off",
|
|
1038
|
-
disabled: !stockApplies,
|
|
1039
|
-
onChange: (event)=>{
|
|
1040
|
-
const raw = event.target.value.trim();
|
|
1041
|
-
update({
|
|
1042
|
-
lowStockThreshold: raw === '' ? undefined : Math.max(0, Math.round(Number(raw)))
|
|
1043
|
-
});
|
|
1044
|
-
},
|
|
1045
|
-
size: "small",
|
|
1046
|
-
sx: {
|
|
1047
|
-
width: 140
|
|
1048
|
-
},
|
|
1049
|
-
slotProps: {
|
|
1050
|
-
htmlInput: {
|
|
1051
|
-
inputMode: 'numeric'
|
|
1052
|
-
}
|
|
1053
|
-
},
|
|
1054
|
-
helperText: "Notifies managers"
|
|
1055
|
-
})
|
|
1056
|
-
]
|
|
1655
|
+
/*#__PURE__*/ _jsx(ProductSellingFields, {
|
|
1656
|
+
oversellPolicy: (_current_oversellPolicy = current.oversellPolicy) != null ? _current_oversellPolicy : 'deny',
|
|
1657
|
+
giftCard: Boolean(current.giftCard),
|
|
1658
|
+
taxExempt: Boolean(current.taxExempt),
|
|
1659
|
+
lowStockThreshold: current.lowStockThreshold,
|
|
1660
|
+
stockApplies: stockApplies,
|
|
1661
|
+
giftsLocked: giftsLocked,
|
|
1662
|
+
giftsPlanLabel: gifts.planLabel,
|
|
1663
|
+
update: update
|
|
1057
1664
|
}),
|
|
1058
|
-
/*#__PURE__*/
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
onChange: (event)=>{
|
|
1066
|
-
const value = event.target.value;
|
|
1067
|
-
// "Both" (AGL-545): the PDP offers one-time OR subscribe at
|
|
1068
|
-
// the same price; the interval field beside picks the cadence.
|
|
1069
|
-
// Cleared keys are deleted (not set undefined) so the
|
|
1070
|
-
// client-direct setDoc on save never sees undefined values.
|
|
1071
|
-
const next = _extends({}, current);
|
|
1072
|
-
if (value === 'once') {
|
|
1073
|
-
delete next.subscription;
|
|
1074
|
-
} else {
|
|
1075
|
-
var _current_subscription, _ref;
|
|
1076
|
-
var _current_subscription1;
|
|
1077
|
-
next.subscription = _extends({}, (_current_subscription = current.subscription) != null ? _current_subscription : {}, {
|
|
1078
|
-
interval: value === 'both' ? (_ref = (_current_subscription1 = current.subscription) == null ? void 0 : _current_subscription1.interval) != null ? _ref : 'month' : value
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
if (value === 'both') next.subscriptionOptional = true;
|
|
1082
|
-
else delete next.subscriptionOptional;
|
|
1083
|
-
// setDraft directly: update() spreads the patch over
|
|
1084
|
-
// `current`, which would resurrect the deleted keys.
|
|
1085
|
-
setDraft(next);
|
|
1086
|
-
},
|
|
1087
|
-
size: "small",
|
|
1088
|
-
select: true,
|
|
1089
|
-
sx: {
|
|
1090
|
-
minWidth: 180
|
|
1091
|
-
},
|
|
1092
|
-
helperText: subsLocked ? `Subscriptions are on ${(_subs_planLabel2 = subs.planLabel) != null ? _subs_planLabel2 : 'a higher plan'}` : 'Subscriptions bill until canceled',
|
|
1093
|
-
children: [
|
|
1094
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1095
|
-
value: "once",
|
|
1096
|
-
children: 'One-time purchase'
|
|
1097
|
-
}),
|
|
1098
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1099
|
-
value: "month",
|
|
1100
|
-
disabled: subsLocked,
|
|
1101
|
-
children: 'Monthly subscription'
|
|
1102
|
-
}),
|
|
1103
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1104
|
-
value: "year",
|
|
1105
|
-
disabled: subsLocked,
|
|
1106
|
-
children: 'Yearly subscription'
|
|
1107
|
-
}),
|
|
1108
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1109
|
-
value: "both",
|
|
1110
|
-
disabled: subsLocked,
|
|
1111
|
-
children: 'Both — buyer chooses'
|
|
1112
|
-
})
|
|
1113
|
-
]
|
|
1114
|
-
}),
|
|
1115
|
-
current.subscription && current.subscriptionOptional ? /*#__PURE__*/ _jsxs(TextField, {
|
|
1116
|
-
label: "Interval",
|
|
1117
|
-
value: current.subscription.interval,
|
|
1118
|
-
onChange: (event)=>update({
|
|
1119
|
-
subscription: _extends({}, current.subscription, {
|
|
1120
|
-
interval: event.target.value
|
|
1121
|
-
})
|
|
1122
|
-
}),
|
|
1123
|
-
size: "small",
|
|
1124
|
-
select: true,
|
|
1125
|
-
sx: {
|
|
1126
|
-
minWidth: 120
|
|
1127
|
-
},
|
|
1128
|
-
children: [
|
|
1129
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1130
|
-
value: "month",
|
|
1131
|
-
children: 'Monthly'
|
|
1132
|
-
}),
|
|
1133
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1134
|
-
value: "year",
|
|
1135
|
-
children: 'Yearly'
|
|
1136
|
-
})
|
|
1137
|
-
]
|
|
1138
|
-
}) : null,
|
|
1139
|
-
current.subscription ? /*#__PURE__*/ _jsx(TextField, {
|
|
1140
|
-
label: "Free trial (days)",
|
|
1141
|
-
placeholder: "None",
|
|
1142
|
-
value: (_current_subscription_trialDays = current.subscription.trialDays) != null ? _current_subscription_trialDays : '',
|
|
1143
|
-
onChange: (event)=>{
|
|
1144
|
-
const raw = event.target.value.trim();
|
|
1145
|
-
update({
|
|
1146
|
-
subscription: _extends({}, current.subscription, raw === '' ? {
|
|
1147
|
-
trialDays: undefined
|
|
1148
|
-
} : {
|
|
1149
|
-
trialDays: Math.max(1, Math.round(Number(raw)))
|
|
1150
|
-
})
|
|
1151
|
-
});
|
|
1152
|
-
},
|
|
1153
|
-
size: "small",
|
|
1154
|
-
sx: {
|
|
1155
|
-
width: 140
|
|
1156
|
-
},
|
|
1157
|
-
slotProps: {
|
|
1158
|
-
htmlInput: {
|
|
1159
|
-
inputMode: 'numeric'
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
}) : null
|
|
1163
|
-
]
|
|
1665
|
+
/*#__PURE__*/ _jsx(ProductBillingFields, {
|
|
1666
|
+
subscription: current.subscription,
|
|
1667
|
+
subscriptionOptional: current.subscriptionOptional,
|
|
1668
|
+
subsLocked: subsLocked,
|
|
1669
|
+
subsPlanLabel: subs.planLabel,
|
|
1670
|
+
update: update,
|
|
1671
|
+
replaceDraft: replaceDraft
|
|
1164
1672
|
}),
|
|
1165
|
-
current.type === 'digital' ? /*#__PURE__*/
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
var _file_version;
|
|
1173
|
-
return /*#__PURE__*/ _jsxs(Stack, {
|
|
1174
|
-
direction: "row",
|
|
1175
|
-
spacing: 1,
|
|
1176
|
-
sx: {
|
|
1177
|
-
alignItems: 'center'
|
|
1178
|
-
},
|
|
1179
|
-
children: [
|
|
1180
|
-
/*#__PURE__*/ _jsxs(Typography, {
|
|
1181
|
-
variant: "body2",
|
|
1182
|
-
sx: {
|
|
1183
|
-
flex: 1
|
|
1184
|
-
},
|
|
1185
|
-
noWrap: true,
|
|
1186
|
-
children: [
|
|
1187
|
-
file.fileName,
|
|
1188
|
-
file.version ? ` · v${file.version}` : ''
|
|
1189
|
-
]
|
|
1190
|
-
}),
|
|
1191
|
-
/*#__PURE__*/ _jsx(PaidMediaProtection, {
|
|
1192
|
-
url: file.url,
|
|
1193
|
-
hostId: hostId,
|
|
1194
|
-
productId: product == null ? void 0 : product.$id,
|
|
1195
|
-
kind: "download"
|
|
1196
|
-
}),
|
|
1197
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1198
|
-
label: "Version",
|
|
1199
|
-
value: (_file_version = file.version) != null ? _file_version : '',
|
|
1200
|
-
onChange: (event)=>{
|
|
1201
|
-
var _current_digitalFiles;
|
|
1202
|
-
const digitalFiles = [
|
|
1203
|
-
...(_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []
|
|
1204
|
-
];
|
|
1205
|
-
digitalFiles[index] = _extends({}, file, {
|
|
1206
|
-
version: event.target.value.slice(0, 20)
|
|
1207
|
-
});
|
|
1208
|
-
update({
|
|
1209
|
-
digitalFiles
|
|
1210
|
-
});
|
|
1211
|
-
},
|
|
1212
|
-
size: "small",
|
|
1213
|
-
sx: {
|
|
1214
|
-
width: 100
|
|
1215
|
-
}
|
|
1216
|
-
}),
|
|
1217
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1218
|
-
size: "small",
|
|
1219
|
-
color: "error",
|
|
1220
|
-
onClick: ()=>{
|
|
1221
|
-
var _current_digitalFiles;
|
|
1222
|
-
return update({
|
|
1223
|
-
digitalFiles: ((_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
1224
|
-
});
|
|
1225
|
-
},
|
|
1226
|
-
children: '✕'
|
|
1227
|
-
})
|
|
1228
|
-
]
|
|
1229
|
-
}, index);
|
|
1230
|
-
}),
|
|
1231
|
-
/*#__PURE__*/ _jsxs(Stack, {
|
|
1232
|
-
direction: "row",
|
|
1233
|
-
spacing: 2,
|
|
1234
|
-
children: [
|
|
1235
|
-
/*#__PURE__*/ _jsx(PaidDownloadAddButton, {
|
|
1236
|
-
hostId: hostId,
|
|
1237
|
-
productId: product == null ? void 0 : product.$id,
|
|
1238
|
-
onAdd: (file)=>{
|
|
1239
|
-
var _current_digitalFiles;
|
|
1240
|
-
return update({
|
|
1241
|
-
digitalFiles: [
|
|
1242
|
-
...(_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : [],
|
|
1243
|
-
file
|
|
1244
|
-
]
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
}),
|
|
1248
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1249
|
-
label: "Download limit",
|
|
1250
|
-
placeholder: "Unlimited",
|
|
1251
|
-
value: (_current_downloadLimit = current.downloadLimit) != null ? _current_downloadLimit : '',
|
|
1252
|
-
onChange: (event)=>{
|
|
1253
|
-
const raw = event.target.value.trim();
|
|
1254
|
-
update({
|
|
1255
|
-
downloadLimit: raw === '' ? undefined : Math.max(1, Math.round(Number(raw)))
|
|
1256
|
-
});
|
|
1257
|
-
},
|
|
1258
|
-
size: "small",
|
|
1259
|
-
sx: {
|
|
1260
|
-
width: 140
|
|
1261
|
-
},
|
|
1262
|
-
slotProps: {
|
|
1263
|
-
htmlInput: {
|
|
1264
|
-
inputMode: 'numeric'
|
|
1265
|
-
}
|
|
1266
|
-
},
|
|
1267
|
-
helperText: "Attempts per order"
|
|
1268
|
-
})
|
|
1269
|
-
]
|
|
1270
|
-
}),
|
|
1271
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
1272
|
-
variant: "caption",
|
|
1273
|
-
color: "text.secondary",
|
|
1274
|
-
children: 'Buyers always download the current files — uploading a new ' + 'version re-delivers to everyone.'
|
|
1275
|
-
}),
|
|
1276
|
-
/*#__PURE__*/ _jsx(MembersVideosField, {
|
|
1277
|
-
hostId: hostId,
|
|
1278
|
-
productId: product == null ? void 0 : product.$id,
|
|
1279
|
-
videos: (_current_gatedVideos = current.gatedVideos) != null ? _current_gatedVideos : [],
|
|
1280
|
-
onChange: (gatedVideos)=>update({
|
|
1281
|
-
gatedVideos
|
|
1282
|
-
})
|
|
1283
|
-
})
|
|
1284
|
-
]
|
|
1673
|
+
current.type === 'digital' ? /*#__PURE__*/ _jsx(ProductDigitalFields, {
|
|
1674
|
+
hostId: hostId,
|
|
1675
|
+
productId: product == null ? void 0 : product.$id,
|
|
1676
|
+
digitalFiles: (_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : NO_FILES,
|
|
1677
|
+
downloadLimit: current.downloadLimit,
|
|
1678
|
+
gatedVideos: (_current_gatedVideos = current.gatedVideos) != null ? _current_gatedVideos : NO_VIDEOS,
|
|
1679
|
+
update: update
|
|
1285
1680
|
}) : null,
|
|
1286
|
-
/*#__PURE__*/ _jsx(
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
value: relatedProducts.rows.filter((item)=>{
|
|
1295
|
-
var _current_relatedProductIds;
|
|
1296
|
-
return ((_current_relatedProductIds = current.relatedProductIds) != null ? _current_relatedProductIds : []).includes(item.$id);
|
|
1297
|
-
}),
|
|
1298
|
-
onChange: (_event, picked)=>update({
|
|
1299
|
-
relatedProductIds: picked.map((item)=>item.$id)
|
|
1300
|
-
}),
|
|
1301
|
-
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
1302
|
-
label: "Related products (upsells)",
|
|
1303
|
-
size: "small",
|
|
1304
|
-
helperText: "Shown by the Related products block; blank falls back to frequently-bought-together"
|
|
1305
|
-
}))
|
|
1306
|
-
}),
|
|
1307
|
-
/*#__PURE__*/ _jsx(Divider, {
|
|
1308
|
-
textAlign: "left",
|
|
1309
|
-
children: 'Search engine listing'
|
|
1681
|
+
/*#__PURE__*/ _jsx(ProductChipsField, {
|
|
1682
|
+
label: "Related products (upsells)",
|
|
1683
|
+
helperText: "Shown by the Related products block; blank falls back to frequently-bought-together",
|
|
1684
|
+
options: relatedOptions,
|
|
1685
|
+
getOptionLabel: recordLabel,
|
|
1686
|
+
isOptionEqualToValue: sameRecord,
|
|
1687
|
+
value: pickedRelated,
|
|
1688
|
+
onChange: setRelatedProducts
|
|
1310
1689
|
}),
|
|
1311
|
-
/*#__PURE__*/
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
children: [
|
|
1318
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1319
|
-
label: "SEO title",
|
|
1320
|
-
value: (_ref5 = (_current_seo2 = current.seo) == null ? void 0 : _current_seo2.title) != null ? _ref5 : '',
|
|
1321
|
-
onChange: (event)=>update({
|
|
1322
|
-
seo: _extends({}, current.seo, {
|
|
1323
|
-
title: event.target.value
|
|
1324
|
-
})
|
|
1325
|
-
}),
|
|
1326
|
-
// The counts every search listing editor prints (AGL-2910): what a
|
|
1327
|
-
// search result shows before it truncates.
|
|
1328
|
-
helperText: seoListingFieldCount('title', (_current_seo3 = current.seo) == null ? void 0 : _current_seo3.title),
|
|
1329
|
-
error: seoListingFieldTooLong('title', (_current_seo4 = current.seo) == null ? void 0 : _current_seo4.title),
|
|
1330
|
-
size: "small",
|
|
1331
|
-
fullWidth: true
|
|
1332
|
-
}),
|
|
1333
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1334
|
-
size: "small",
|
|
1335
|
-
onClick: ()=>void pick((media)=>update({
|
|
1336
|
-
seo: _extends({}, current.seo, {
|
|
1337
|
-
imageUrl: media.url
|
|
1338
|
-
})
|
|
1339
|
-
})),
|
|
1340
|
-
children: ((_current_seo5 = current.seo) == null ? void 0 : _current_seo5.imageUrl) ? 'Change OG image' : 'OG image'
|
|
1341
|
-
})
|
|
1342
|
-
]
|
|
1343
|
-
}),
|
|
1344
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1345
|
-
label: "SEO description",
|
|
1346
|
-
value: (_ref6 = (_current_seo6 = current.seo) == null ? void 0 : _current_seo6.description) != null ? _ref6 : '',
|
|
1347
|
-
onChange: (event)=>update({
|
|
1348
|
-
seo: _extends({}, current.seo, {
|
|
1349
|
-
description: event.target.value
|
|
1350
|
-
})
|
|
1351
|
-
}),
|
|
1352
|
-
helperText: seoListingFieldCount('description', (_current_seo7 = current.seo) == null ? void 0 : _current_seo7.description),
|
|
1353
|
-
error: seoListingFieldTooLong('description', (_current_seo8 = current.seo) == null ? void 0 : _current_seo8.description),
|
|
1354
|
-
size: "small",
|
|
1355
|
-
multiline: true,
|
|
1356
|
-
minRows: 2
|
|
1690
|
+
/*#__PURE__*/ _jsx(ProductSeoFields, {
|
|
1691
|
+
title: (_current_seo4 = current.seo) == null ? void 0 : _current_seo4.title,
|
|
1692
|
+
description: (_current_seo5 = current.seo) == null ? void 0 : _current_seo5.description,
|
|
1693
|
+
hasImage: Boolean((_current_seo6 = current.seo) == null ? void 0 : _current_seo6.imageUrl),
|
|
1694
|
+
update: update,
|
|
1695
|
+
pick: pick
|
|
1357
1696
|
}),
|
|
1358
|
-
WidgetSlot ? /*#__PURE__*/ _jsx(
|
|
1697
|
+
WidgetSlot ? /*#__PURE__*/ _jsx(HostedZone, {
|
|
1698
|
+
renderer: WidgetSlot,
|
|
1359
1699
|
slot: "seoFields",
|
|
1360
1700
|
hostId: hostId,
|
|
1361
1701
|
orgId: undefined,
|
|
1362
1702
|
orgSlug: "",
|
|
1363
|
-
subject:
|
|
1364
|
-
kind: 'product',
|
|
1365
|
-
id: (_ref7 = product == null ? void 0 : product.$id) != null ? _ref7 : null,
|
|
1366
|
-
name: current.name,
|
|
1367
|
-
description: String((_current_description2 = current.description) != null ? _current_description2 : '')
|
|
1368
|
-
},
|
|
1703
|
+
subject: seoSubject,
|
|
1369
1704
|
fields: PRODUCT_SEO_LISTING_FIELDS,
|
|
1370
|
-
values:
|
|
1371
|
-
|
|
1372
|
-
description: (_ref9 = (_current_seo10 = current.seo) == null ? void 0 : _current_seo10.description) != null ? _ref9 : ''
|
|
1373
|
-
},
|
|
1374
|
-
hasImage: Boolean((_current_seo11 = current.seo) == null ? void 0 : _current_seo11.imageUrl),
|
|
1705
|
+
values: seoValues,
|
|
1706
|
+
hasImage: Boolean((_current_seo7 = current.seo) == null ? void 0 : _current_seo7.imageUrl),
|
|
1375
1707
|
proposeValues: proposeSeoValues
|
|
1376
1708
|
}) : null,
|
|
1377
1709
|
error ? /*#__PURE__*/ _jsx(Alert, {
|