@aglyn/plugins-commerce 1.0.0-beta.219 → 1.0.0-beta.221
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 +5 -0
- package/package.json +14 -14
- package/src/lib/components/console/catalog-organization-card.component.js +626 -446
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
- package/src/lib/components/console/payments-settings-card.component.js +1 -1
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +1127 -846
- package/src/lib/components/console/product-editor-dialog.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/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/constants/operator-alerts.js +5 -3
- package/src/lib/constants/operator-alerts.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 +18 -0
- package/src/lib/model/commerce-record-routes.js +1 -1
- package/src/lib/model/commerce-record-routes.js.map +1 -1
- package/src/lib/model/commerce-search-sources.js +4 -2
- package/src/lib/model/commerce-search-sources.js.map +1 -1
- 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/plugin.js +12 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +410 -208
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.js +1 -1
- package/src/lib/server/cart-checkout.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-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 +18 -10
- 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.js +5 -37
- package/src/lib/server/product-record-index.js.map +1 -1
- 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/revenue-source.js +3 -3
- package/src/lib/server/revenue-source.js.map +1 -1
- 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/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.js +54 -14
- package/src/lib/tenant-emails.js.map +1 -1
- package/src/lib/testing/stand-in-record-system.d.ts +11 -2
- package/src/lib/testing/stand-in-record-system.js +5 -3
- package/src/lib/testing/stand-in-record-system.js.map +1 -1
|
@@ -30,6 +30,7 @@ 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";
|
|
34
35
|
import { PRODUCT_EDITOR_ZONE } from "./product-zones.js";
|
|
35
36
|
import { MembersVideosField, PaidDownloadAddButton, PaidMediaProtection } from "./paid-media.js";
|
|
@@ -74,6 +75,9 @@ function comboLabel(options) {
|
|
|
74
75
|
return values.length ? values.join(' / ') : 'Default';
|
|
75
76
|
}
|
|
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 = [];
|
|
77
81
|
const FILL_ROW = {
|
|
78
82
|
flex: 1
|
|
79
83
|
};
|
|
@@ -116,6 +120,945 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
116
120
|
sx: props.fill ? FILL_ROW : undefined
|
|
117
121
|
});
|
|
118
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
|
+
});
|
|
119
1062
|
/**
|
|
120
1063
|
* Products hub editor (AGL-279): the full catalog editor — basics,
|
|
121
1064
|
* media, tags, options → variants matrix, per-variant pricing/stock, and
|
|
@@ -123,8 +1066,8 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
123
1066
|
* first variant so the legacy Product block + checkout API (AGL-90) keep
|
|
124
1067
|
* charging correctly without reading the variants array.
|
|
125
1068
|
*/ export function ProductEditorDialog(props) {
|
|
126
|
-
var _ref, _ref1, _current_description, _current_tags, _current_categoryIds, _current_options, _current_mediaUrls, _ref2, _ref3,
|
|
127
|
-
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;
|
|
128
1071
|
const { hostId, product, seedFromCache, seedUnreadable, open, onClose } = props;
|
|
129
1072
|
/**
|
|
130
1073
|
* Field-level entitlement gates (AGL-2080). Both of these were fully
|
|
@@ -204,27 +1147,34 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
204
1147
|
]);
|
|
205
1148
|
// Lazy-init per open; parent remounts via `key` on product change.
|
|
206
1149
|
const current = (_ref = draft != null ? draft : lifted) != null ? _ref : blankProduct();
|
|
207
|
-
const update = (patch)=>setDraft(_extends({}, current, patch));
|
|
208
1150
|
/*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
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.
|
|
211
1158
|
*/ const latest = useRef(current);
|
|
212
1159
|
latest.current = current;
|
|
213
|
-
const
|
|
214
|
-
const
|
|
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({
|
|
215
1165
|
tags: tags.map((tag)=>String(tag).trim()).filter(Boolean)
|
|
216
1166
|
}), [
|
|
217
|
-
|
|
1167
|
+
update
|
|
218
1168
|
]);
|
|
219
|
-
const setCategories = useCallback((picked)=>
|
|
1169
|
+
const setCategories = useCallback((picked)=>update({
|
|
220
1170
|
categoryIds: picked.map((category)=>category.$id)
|
|
221
1171
|
}), [
|
|
222
|
-
|
|
1172
|
+
update
|
|
223
1173
|
]);
|
|
224
|
-
const setRelatedProducts = useCallback((picked)=>
|
|
1174
|
+
const setRelatedProducts = useCallback((picked)=>update({
|
|
225
1175
|
relatedProductIds: picked.map((item)=>item.$id)
|
|
226
1176
|
}), [
|
|
227
|
-
|
|
1177
|
+
update
|
|
228
1178
|
]);
|
|
229
1179
|
const categoryIds = current.categoryIds;
|
|
230
1180
|
const pickedCategories = useMemo(()=>categories.rows.filter((category)=>(categoryIds != null ? categoryIds : []).includes(category.$id)), [
|
|
@@ -287,7 +1237,10 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
287
1237
|
}), [
|
|
288
1238
|
categories.rows
|
|
289
1239
|
]);
|
|
290
|
-
|
|
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({
|
|
291
1244
|
id: (_ref1 = product == null ? void 0 : product.$id) != null ? _ref1 : null,
|
|
292
1245
|
name: current.name,
|
|
293
1246
|
type: current.type,
|
|
@@ -301,7 +1254,17 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
301
1254
|
mediaUrls: (_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : [],
|
|
302
1255
|
seoTitle: (_ref2 = (_current_seo = current.seo) == null ? void 0 : _current_seo.title) != null ? _ref2 : '',
|
|
303
1256
|
seoDescription: (_ref3 = (_current_seo1 = current.seo) == null ? void 0 : _current_seo1.description) != null ? _ref3 : ''
|
|
304
|
-
};
|
|
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
|
+
});
|
|
305
1268
|
const error = current.name ? CommerceModel.validateProduct(current) : null;
|
|
306
1269
|
/**
|
|
307
1270
|
* Stock tracking is inert on a subscription-only product (AGL-1744) —
|
|
@@ -324,90 +1287,106 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
324
1287
|
* count this just cleared. Keys are DELETED rather than set undefined; the
|
|
325
1288
|
* save is a client-direct `setDoc`, which rejects undefined values.
|
|
326
1289
|
*/ const handleClearStockTracking = ()=>{
|
|
327
|
-
update({
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
+
}));
|
|
337
1300
|
};
|
|
338
|
-
const handleName = (
|
|
1301
|
+
const handleName = useCallback((event)=>{
|
|
1302
|
+
const name = event.target.value;
|
|
1303
|
+
update(_extends({
|
|
339
1304
|
name
|
|
340
1305
|
}, !product && !slugTouched ? {
|
|
341
1306
|
slug: CommerceModel.commerceSlug(name)
|
|
342
1307
|
} : {}));
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if (patch && ((_current_options1 = current.options) == null ? void 0 : _current_options1[index]) && Object.keys(patch).length === 1 && typeof patch.name === 'string') {
|
|
351
|
-
update(CommerceModel.renameProductOptions(current, current.options.map((option, at)=>at === index ? patch.name : option.name)));
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
const options = [
|
|
355
|
-
...(_current_options = current.options) != null ? _current_options : []
|
|
356
|
-
];
|
|
357
|
-
if (patch === null) options.splice(index, 1);
|
|
358
|
-
else options[index] = _extends({
|
|
359
|
-
name: '',
|
|
360
|
-
values: []
|
|
361
|
-
}, options[index], patch);
|
|
362
|
-
// Regenerate the matrix, carrying data over by option-combo key so
|
|
363
|
-
// edits to prices/SKUs survive option tweaks.
|
|
364
|
-
const previous = new Map(current.variants.map((variant)=>[
|
|
365
|
-
comboKey(variant.options),
|
|
366
|
-
variant
|
|
367
|
-
]));
|
|
368
|
-
const fallback = current.variants[0];
|
|
369
|
-
const variants = CommerceModel.expandVariantMatrix(options).map((combo, comboIndex)=>{
|
|
370
|
-
var _ref, _ref1;
|
|
371
|
-
const existing = previous.get(comboKey(combo));
|
|
372
|
-
return existing != null ? existing : {
|
|
373
|
-
id: `v${Date.now().toString(36)}${comboIndex}`,
|
|
374
|
-
options: combo,
|
|
375
|
-
priceUsd: (_ref = fallback == null ? void 0 : fallback.priceUsd) != null ? _ref : 0,
|
|
376
|
-
inventory: (_ref1 = fallback == null ? void 0 : fallback.inventory) != null ? _ref1 : null
|
|
377
|
-
};
|
|
378
|
-
});
|
|
1308
|
+
}, [
|
|
1309
|
+
product,
|
|
1310
|
+
slugTouched,
|
|
1311
|
+
update
|
|
1312
|
+
]);
|
|
1313
|
+
const handleSlug = useCallback((event)=>{
|
|
1314
|
+
setSlugTouched(true);
|
|
379
1315
|
update({
|
|
380
|
-
|
|
381
|
-
variants
|
|
1316
|
+
slug: CommerceModel.commerceSlug(event.target.value)
|
|
382
1317
|
});
|
|
383
1318
|
}, [
|
|
384
|
-
|
|
1319
|
+
update
|
|
385
1320
|
]);
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
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, {
|
|
389
1364
|
values: values.map((value)=>String(value).trim()).filter(Boolean)
|
|
390
|
-
}), [
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
+
]);
|
|
411
1390
|
const handleSave = useCallback(async ()=>{
|
|
412
1391
|
var _ref, _ref1, _ref2;
|
|
413
1392
|
var _current_mediaUrls;
|
|
@@ -594,129 +1573,17 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
594
1573
|
gap: 2
|
|
595
1574
|
},
|
|
596
1575
|
children: [
|
|
597
|
-
/*#__PURE__*/
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
label: "Name",
|
|
609
|
-
value: current.name,
|
|
610
|
-
onChange: (event)=>handleName(event.target.value),
|
|
611
|
-
size: "small",
|
|
612
|
-
autoFocus: true,
|
|
613
|
-
fullWidth: true
|
|
614
|
-
}),
|
|
615
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
616
|
-
label: "Slug",
|
|
617
|
-
value: current.slug,
|
|
618
|
-
onChange: (event)=>{
|
|
619
|
-
setSlugTouched(true);
|
|
620
|
-
update({
|
|
621
|
-
slug: CommerceModel.commerceSlug(event.target.value)
|
|
622
|
-
});
|
|
623
|
-
},
|
|
624
|
-
size: "small",
|
|
625
|
-
fullWidth: true,
|
|
626
|
-
helperText: current.slug ? `/products/${current.slug}` : undefined
|
|
627
|
-
})
|
|
628
|
-
]
|
|
629
|
-
}),
|
|
630
|
-
/*#__PURE__*/ _jsxs(Stack, {
|
|
631
|
-
direction: "row",
|
|
632
|
-
spacing: 2,
|
|
633
|
-
children: [
|
|
634
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
635
|
-
label: "Type",
|
|
636
|
-
value: current.type,
|
|
637
|
-
onChange: (event)=>update({
|
|
638
|
-
type: event.target.value
|
|
639
|
-
}),
|
|
640
|
-
size: "small",
|
|
641
|
-
select: true,
|
|
642
|
-
sx: {
|
|
643
|
-
minWidth: 140
|
|
644
|
-
},
|
|
645
|
-
children: [
|
|
646
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
647
|
-
value: "physical",
|
|
648
|
-
children: 'Physical'
|
|
649
|
-
}),
|
|
650
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
651
|
-
value: "digital",
|
|
652
|
-
children: 'Digital'
|
|
653
|
-
}),
|
|
654
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
655
|
-
value: "service",
|
|
656
|
-
children: 'Service'
|
|
657
|
-
})
|
|
658
|
-
]
|
|
659
|
-
}),
|
|
660
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
661
|
-
label: "Status",
|
|
662
|
-
value: current.status,
|
|
663
|
-
onChange: (event)=>update({
|
|
664
|
-
status: event.target.value
|
|
665
|
-
}),
|
|
666
|
-
size: "small",
|
|
667
|
-
select: true,
|
|
668
|
-
sx: {
|
|
669
|
-
minWidth: 140
|
|
670
|
-
},
|
|
671
|
-
children: [
|
|
672
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
673
|
-
value: "draft",
|
|
674
|
-
children: 'Draft'
|
|
675
|
-
}),
|
|
676
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
677
|
-
value: "active",
|
|
678
|
-
children: 'Active'
|
|
679
|
-
}),
|
|
680
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
681
|
-
value: "archived",
|
|
682
|
-
children: 'Archived'
|
|
683
|
-
})
|
|
684
|
-
]
|
|
685
|
-
}),
|
|
686
|
-
suppliers.rows.length > 0 ? /*#__PURE__*/ _jsxs(TextField, {
|
|
687
|
-
label: "Supplier",
|
|
688
|
-
value: (_current_supplierId = current.supplierId) != null ? _current_supplierId : '',
|
|
689
|
-
onChange: (event)=>update({
|
|
690
|
-
supplierId: event.target.value || undefined
|
|
691
|
-
}),
|
|
692
|
-
size: "small",
|
|
693
|
-
select: true,
|
|
694
|
-
sx: {
|
|
695
|
-
minWidth: 160
|
|
696
|
-
},
|
|
697
|
-
helperText: "Routes paid orders",
|
|
698
|
-
children: [
|
|
699
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
700
|
-
value: "",
|
|
701
|
-
children: 'None (self-fulfilled)'
|
|
702
|
-
}),
|
|
703
|
-
suppliers.rows.map((supplier)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
704
|
-
value: supplier.$id,
|
|
705
|
-
children: supplier.name
|
|
706
|
-
}, supplier.$id))
|
|
707
|
-
]
|
|
708
|
-
}) : null
|
|
709
|
-
]
|
|
710
|
-
}),
|
|
711
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
712
|
-
label: "Description",
|
|
713
|
-
value: (_current_description1 = current.description) != null ? _current_description1 : '',
|
|
714
|
-
onChange: (event)=>update({
|
|
715
|
-
description: event.target.value
|
|
716
|
-
}),
|
|
717
|
-
size: "small",
|
|
718
|
-
multiline: true,
|
|
719
|
-
minRows: 2
|
|
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
|
|
720
1587
|
}),
|
|
721
1588
|
/*#__PURE__*/ _jsx(ProductChipsField, {
|
|
722
1589
|
freeSolo: true,
|
|
@@ -734,7 +1601,8 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
734
1601
|
value: pickedCategories,
|
|
735
1602
|
onChange: setCategories
|
|
736
1603
|
}) : null,
|
|
737
|
-
WidgetSlot ? /*#__PURE__*/ _jsx(
|
|
1604
|
+
WidgetSlot ? /*#__PURE__*/ _jsx(HostedZone, {
|
|
1605
|
+
renderer: WidgetSlot,
|
|
738
1606
|
slot: PRODUCT_EDITOR_ZONE.id,
|
|
739
1607
|
hostId: hostId,
|
|
740
1608
|
orgId: undefined,
|
|
@@ -746,262 +1614,24 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
746
1614
|
textAlign: "left",
|
|
747
1615
|
children: 'Media'
|
|
748
1616
|
}),
|
|
749
|
-
/*#__PURE__*/
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
flexWrap: 'wrap'
|
|
754
|
-
},
|
|
755
|
-
children: [
|
|
756
|
-
((_current_mediaUrls1 = current.mediaUrls) != null ? _current_mediaUrls1 : []).map((url, index)=>/*#__PURE__*/ _jsxs(Box, {
|
|
757
|
-
sx: {
|
|
758
|
-
position: 'relative'
|
|
759
|
-
},
|
|
760
|
-
children: [
|
|
761
|
-
/*#__PURE__*/ _jsx(Box, {
|
|
762
|
-
component: "img",
|
|
763
|
-
src: url,
|
|
764
|
-
alt: "",
|
|
765
|
-
sx: {
|
|
766
|
-
width: 72,
|
|
767
|
-
height: 72,
|
|
768
|
-
objectFit: 'cover',
|
|
769
|
-
borderRadius: 1,
|
|
770
|
-
border: 1,
|
|
771
|
-
borderColor: 'divider'
|
|
772
|
-
}
|
|
773
|
-
}),
|
|
774
|
-
/*#__PURE__*/ _jsx(IconButton, {
|
|
775
|
-
size: "small",
|
|
776
|
-
"aria-label": "Remove image",
|
|
777
|
-
onClick: ()=>{
|
|
778
|
-
var _current_mediaUrls;
|
|
779
|
-
return update({
|
|
780
|
-
mediaUrls: ((_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
781
|
-
});
|
|
782
|
-
},
|
|
783
|
-
sx: {
|
|
784
|
-
position: 'absolute',
|
|
785
|
-
top: -8,
|
|
786
|
-
right: -8,
|
|
787
|
-
bgcolor: 'background.paper',
|
|
788
|
-
border: 1,
|
|
789
|
-
borderColor: 'divider',
|
|
790
|
-
p: 0.25
|
|
791
|
-
},
|
|
792
|
-
children: '✕'
|
|
793
|
-
})
|
|
794
|
-
]
|
|
795
|
-
}, `${url}-${index}`)),
|
|
796
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
797
|
-
size: "small",
|
|
798
|
-
onClick: ()=>void pick((media)=>{
|
|
799
|
-
var _current_mediaUrls;
|
|
800
|
-
return update({
|
|
801
|
-
mediaUrls: [
|
|
802
|
-
...(_current_mediaUrls = current.mediaUrls) != null ? _current_mediaUrls : [],
|
|
803
|
-
media.url
|
|
804
|
-
]
|
|
805
|
-
});
|
|
806
|
-
}),
|
|
807
|
-
children: 'Add image'
|
|
808
|
-
})
|
|
809
|
-
]
|
|
1617
|
+
/*#__PURE__*/ _jsx(ProductMediaFields, {
|
|
1618
|
+
mediaUrls: (_current_mediaUrls1 = current.mediaUrls) != null ? _current_mediaUrls1 : NO_ITEMS,
|
|
1619
|
+
update: update,
|
|
1620
|
+
pick: pick
|
|
810
1621
|
}),
|
|
811
1622
|
/*#__PURE__*/ _jsx(Divider, {
|
|
812
1623
|
textAlign: "left",
|
|
813
1624
|
children: 'Options & variants'
|
|
814
1625
|
}),
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
value: option.name,
|
|
825
|
-
onChange: (event)=>handleOptionsChange(index, {
|
|
826
|
-
name: event.target.value
|
|
827
|
-
}),
|
|
828
|
-
size: "small",
|
|
829
|
-
sx: {
|
|
830
|
-
width: 160
|
|
831
|
-
},
|
|
832
|
-
placeholder: "Size"
|
|
833
|
-
}),
|
|
834
|
-
/*#__PURE__*/ _jsx(ProductChipsField, {
|
|
835
|
-
freeSolo: true,
|
|
836
|
-
fill: true,
|
|
837
|
-
label: "Values",
|
|
838
|
-
placeholder: "S, M, L…",
|
|
839
|
-
options: NO_ITEMS,
|
|
840
|
-
value: option.values,
|
|
841
|
-
index: index,
|
|
842
|
-
onChange: setOptionValues
|
|
843
|
-
}),
|
|
844
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
845
|
-
size: "small",
|
|
846
|
-
color: "error",
|
|
847
|
-
onClick: ()=>handleOptionsChange(index, null),
|
|
848
|
-
sx: {
|
|
849
|
-
mt: 0.5
|
|
850
|
-
},
|
|
851
|
-
children: 'Remove'
|
|
852
|
-
})
|
|
853
|
-
]
|
|
854
|
-
}, index)),
|
|
855
|
-
((_ref4 = (_current_options2 = current.options) == null ? void 0 : _current_options2.length) != null ? _ref4 : 0) < CommerceModel.COMMERCE_MAX_OPTIONS ? /*#__PURE__*/ _jsx(Button, {
|
|
856
|
-
size: "small",
|
|
857
|
-
sx: {
|
|
858
|
-
alignSelf: 'flex-start'
|
|
859
|
-
},
|
|
860
|
-
onClick: ()=>{
|
|
861
|
-
var _ref;
|
|
862
|
-
var _current_options;
|
|
863
|
-
return handleOptionsChange((_ref = (_current_options = current.options) == null ? void 0 : _current_options.length) != null ? _ref : 0, {
|
|
864
|
-
name: '',
|
|
865
|
-
values: []
|
|
866
|
-
});
|
|
867
|
-
},
|
|
868
|
-
children: 'Add option'
|
|
869
|
-
}) : null,
|
|
870
|
-
/*#__PURE__*/ _jsx(Box, {
|
|
871
|
-
children: /*#__PURE__*/ _jsxs(ScrollTable, {
|
|
872
|
-
size: "small",
|
|
873
|
-
children: [
|
|
874
|
-
/*#__PURE__*/ _jsx(TableHead, {
|
|
875
|
-
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
876
|
-
children: [
|
|
877
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
878
|
-
children: 'Variant'
|
|
879
|
-
}),
|
|
880
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
881
|
-
children: 'Price ($)'
|
|
882
|
-
}),
|
|
883
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
884
|
-
children: 'Compare-at'
|
|
885
|
-
}),
|
|
886
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
887
|
-
children: 'SKU'
|
|
888
|
-
}),
|
|
889
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
890
|
-
children: 'Barcode'
|
|
891
|
-
}),
|
|
892
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
893
|
-
children: 'Stock'
|
|
894
|
-
}),
|
|
895
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
896
|
-
children: 'Weight (g)'
|
|
897
|
-
})
|
|
898
|
-
]
|
|
899
|
-
})
|
|
900
|
-
}),
|
|
901
|
-
/*#__PURE__*/ _jsx(TableBody, {
|
|
902
|
-
children: current.variants.map((variant, index)=>{
|
|
903
|
-
var _variant_priceUsd, _variant_compareAtPriceUsd, _variant_sku, _variant_barcode, _variant_inventory, _variant_weightGrams;
|
|
904
|
-
return /*#__PURE__*/ _jsxs(TableRow, {
|
|
905
|
-
children: [
|
|
906
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
907
|
-
sx: {
|
|
908
|
-
whiteSpace: 'nowrap'
|
|
909
|
-
},
|
|
910
|
-
children: comboLabel(variant.options)
|
|
911
|
-
}),
|
|
912
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
913
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
914
|
-
value: (_variant_priceUsd = variant.priceUsd) != null ? _variant_priceUsd : '',
|
|
915
|
-
onChange: (event)=>handleVariantField(index, 'priceUsd', event.target.value),
|
|
916
|
-
size: "small",
|
|
917
|
-
sx: {
|
|
918
|
-
width: 88
|
|
919
|
-
},
|
|
920
|
-
// An empty price is marked (AGL-2916): a proposed
|
|
921
|
-
// product arrives with none, and Save waits for one.
|
|
922
|
-
error: !CommerceModel.variantHasPrice(variant),
|
|
923
|
-
placeholder: "Set",
|
|
924
|
-
slotProps: {
|
|
925
|
-
htmlInput: {
|
|
926
|
-
inputMode: 'decimal'
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
})
|
|
930
|
-
}),
|
|
931
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
932
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
933
|
-
value: (_variant_compareAtPriceUsd = variant.compareAtPriceUsd) != null ? _variant_compareAtPriceUsd : '',
|
|
934
|
-
onChange: (event)=>handleVariantField(index, 'compareAtPriceUsd', event.target.value),
|
|
935
|
-
size: "small",
|
|
936
|
-
sx: {
|
|
937
|
-
width: 88
|
|
938
|
-
},
|
|
939
|
-
slotProps: {
|
|
940
|
-
htmlInput: {
|
|
941
|
-
inputMode: 'decimal'
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
})
|
|
945
|
-
}),
|
|
946
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
947
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
948
|
-
value: (_variant_sku = variant.sku) != null ? _variant_sku : '',
|
|
949
|
-
onChange: (event)=>handleVariantField(index, 'sku', event.target.value),
|
|
950
|
-
size: "small",
|
|
951
|
-
sx: {
|
|
952
|
-
width: 110
|
|
953
|
-
}
|
|
954
|
-
})
|
|
955
|
-
}),
|
|
956
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
957
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
958
|
-
value: (_variant_barcode = variant.barcode) != null ? _variant_barcode : '',
|
|
959
|
-
onChange: (event)=>handleVariantField(index, 'barcode', event.target.value),
|
|
960
|
-
size: "small",
|
|
961
|
-
sx: {
|
|
962
|
-
width: 110
|
|
963
|
-
}
|
|
964
|
-
})
|
|
965
|
-
}),
|
|
966
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
967
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
968
|
-
value: (_variant_inventory = variant.inventory) != null ? _variant_inventory : '',
|
|
969
|
-
placeholder: stockApplies ? '—' : 'n/a',
|
|
970
|
-
disabled: !stockApplies,
|
|
971
|
-
onChange: (event)=>handleVariantField(index, 'inventory', event.target.value),
|
|
972
|
-
size: "small",
|
|
973
|
-
sx: {
|
|
974
|
-
width: 72
|
|
975
|
-
},
|
|
976
|
-
slotProps: {
|
|
977
|
-
htmlInput: {
|
|
978
|
-
inputMode: 'numeric',
|
|
979
|
-
'aria-label': `Stock — ${comboLabel(variant.options)}`
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
})
|
|
983
|
-
}),
|
|
984
|
-
/*#__PURE__*/ _jsx(TableCell, {
|
|
985
|
-
children: /*#__PURE__*/ _jsx(TextField, {
|
|
986
|
-
value: (_variant_weightGrams = variant.weightGrams) != null ? _variant_weightGrams : '',
|
|
987
|
-
onChange: (event)=>handleVariantField(index, 'weightGrams', event.target.value),
|
|
988
|
-
size: "small",
|
|
989
|
-
sx: {
|
|
990
|
-
width: 88
|
|
991
|
-
},
|
|
992
|
-
slotProps: {
|
|
993
|
-
htmlInput: {
|
|
994
|
-
inputMode: 'numeric'
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
})
|
|
998
|
-
})
|
|
999
|
-
]
|
|
1000
|
-
}, variant.id);
|
|
1001
|
-
})
|
|
1002
|
-
})
|
|
1003
|
-
]
|
|
1004
|
-
})
|
|
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
|
|
1005
1635
|
}),
|
|
1006
1636
|
/*#__PURE__*/ _jsx(Typography, {
|
|
1007
1637
|
variant: "caption",
|
|
@@ -1022,329 +1652,31 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
1022
1652
|
upgradeHref: subsLocked ? subs.upgradeHref : gifts.upgradeHref,
|
|
1023
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.'
|
|
1024
1654
|
}) : null,
|
|
1025
|
-
/*#__PURE__*/
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
}),
|
|
1035
|
-
size: "small",
|
|
1036
|
-
select: true,
|
|
1037
|
-
sx: {
|
|
1038
|
-
minWidth: 200
|
|
1039
|
-
},
|
|
1040
|
-
children: [
|
|
1041
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1042
|
-
value: "deny",
|
|
1043
|
-
children: 'Stop selling (sold out)'
|
|
1044
|
-
}),
|
|
1045
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1046
|
-
value: "backorder",
|
|
1047
|
-
children: 'Keep selling (backorder)'
|
|
1048
|
-
})
|
|
1049
|
-
]
|
|
1050
|
-
}),
|
|
1051
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
1052
|
-
label: "Kind",
|
|
1053
|
-
value: current.giftCard ? 'gift' : 'standard',
|
|
1054
|
-
onChange: (event)=>update({
|
|
1055
|
-
giftCard: event.target.value === 'gift'
|
|
1056
|
-
}),
|
|
1057
|
-
size: "small",
|
|
1058
|
-
select: true,
|
|
1059
|
-
sx: {
|
|
1060
|
-
minWidth: 130
|
|
1061
|
-
},
|
|
1062
|
-
helperText: giftsLocked ? `Gift cards are on ${(_gifts_planLabel2 = gifts.planLabel) != null ? _gifts_planLabel2 : 'a higher plan'}` : 'Gift cards issue a code',
|
|
1063
|
-
children: [
|
|
1064
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1065
|
-
value: "standard",
|
|
1066
|
-
children: 'Standard'
|
|
1067
|
-
}),
|
|
1068
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1069
|
-
value: "gift",
|
|
1070
|
-
disabled: giftsLocked,
|
|
1071
|
-
children: giftsLocked ? `Gift card — ${(_gifts_planLabel3 = gifts.planLabel) != null ? _gifts_planLabel3 : 'upgrade'} plan` : 'Gift card'
|
|
1072
|
-
})
|
|
1073
|
-
]
|
|
1074
|
-
}),
|
|
1075
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
1076
|
-
label: "Tax",
|
|
1077
|
-
value: current.taxExempt ? 'exempt' : 'taxable',
|
|
1078
|
-
onChange: (event)=>update({
|
|
1079
|
-
taxExempt: event.target.value === 'exempt'
|
|
1080
|
-
}),
|
|
1081
|
-
size: "small",
|
|
1082
|
-
select: true,
|
|
1083
|
-
sx: {
|
|
1084
|
-
minWidth: 120
|
|
1085
|
-
},
|
|
1086
|
-
children: [
|
|
1087
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1088
|
-
value: "taxable",
|
|
1089
|
-
children: 'Taxable'
|
|
1090
|
-
}),
|
|
1091
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1092
|
-
value: "exempt",
|
|
1093
|
-
children: 'Tax exempt'
|
|
1094
|
-
})
|
|
1095
|
-
]
|
|
1096
|
-
}),
|
|
1097
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1098
|
-
label: "Low-stock alert at",
|
|
1099
|
-
value: (_current_lowStockThreshold = current.lowStockThreshold) != null ? _current_lowStockThreshold : '',
|
|
1100
|
-
placeholder: "Off",
|
|
1101
|
-
disabled: !stockApplies,
|
|
1102
|
-
onChange: (event)=>{
|
|
1103
|
-
const raw = event.target.value.trim();
|
|
1104
|
-
update({
|
|
1105
|
-
lowStockThreshold: raw === '' ? undefined : Math.max(0, Math.round(Number(raw)))
|
|
1106
|
-
});
|
|
1107
|
-
},
|
|
1108
|
-
size: "small",
|
|
1109
|
-
sx: {
|
|
1110
|
-
width: 140
|
|
1111
|
-
},
|
|
1112
|
-
slotProps: {
|
|
1113
|
-
htmlInput: {
|
|
1114
|
-
inputMode: 'numeric'
|
|
1115
|
-
}
|
|
1116
|
-
},
|
|
1117
|
-
helperText: "Notifies managers"
|
|
1118
|
-
})
|
|
1119
|
-
]
|
|
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
|
|
1120
1664
|
}),
|
|
1121
|
-
/*#__PURE__*/
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
onChange: (event)=>{
|
|
1129
|
-
const value = event.target.value;
|
|
1130
|
-
// "Both" (AGL-545): the PDP offers one-time OR subscribe at
|
|
1131
|
-
// the same price; the interval field beside picks the cadence.
|
|
1132
|
-
// Cleared keys are deleted (not set undefined) so the
|
|
1133
|
-
// client-direct setDoc on save never sees undefined values.
|
|
1134
|
-
const next = _extends({}, current);
|
|
1135
|
-
if (value === 'once') {
|
|
1136
|
-
delete next.subscription;
|
|
1137
|
-
} else {
|
|
1138
|
-
var _current_subscription, _ref;
|
|
1139
|
-
var _current_subscription1;
|
|
1140
|
-
next.subscription = _extends({}, (_current_subscription = current.subscription) != null ? _current_subscription : {}, {
|
|
1141
|
-
interval: value === 'both' ? (_ref = (_current_subscription1 = current.subscription) == null ? void 0 : _current_subscription1.interval) != null ? _ref : 'month' : value
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
if (value === 'both') next.subscriptionOptional = true;
|
|
1145
|
-
else delete next.subscriptionOptional;
|
|
1146
|
-
// setDraft directly: update() spreads the patch over
|
|
1147
|
-
// `current`, which would resurrect the deleted keys.
|
|
1148
|
-
setDraft(next);
|
|
1149
|
-
},
|
|
1150
|
-
size: "small",
|
|
1151
|
-
select: true,
|
|
1152
|
-
sx: {
|
|
1153
|
-
minWidth: 180
|
|
1154
|
-
},
|
|
1155
|
-
helperText: subsLocked ? `Subscriptions are on ${(_subs_planLabel2 = subs.planLabel) != null ? _subs_planLabel2 : 'a higher plan'}` : 'Subscriptions bill until canceled',
|
|
1156
|
-
children: [
|
|
1157
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1158
|
-
value: "once",
|
|
1159
|
-
children: 'One-time purchase'
|
|
1160
|
-
}),
|
|
1161
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1162
|
-
value: "month",
|
|
1163
|
-
disabled: subsLocked,
|
|
1164
|
-
children: 'Monthly subscription'
|
|
1165
|
-
}),
|
|
1166
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1167
|
-
value: "year",
|
|
1168
|
-
disabled: subsLocked,
|
|
1169
|
-
children: 'Yearly subscription'
|
|
1170
|
-
}),
|
|
1171
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1172
|
-
value: "both",
|
|
1173
|
-
disabled: subsLocked,
|
|
1174
|
-
children: 'Both — buyer chooses'
|
|
1175
|
-
})
|
|
1176
|
-
]
|
|
1177
|
-
}),
|
|
1178
|
-
current.subscription && current.subscriptionOptional ? /*#__PURE__*/ _jsxs(TextField, {
|
|
1179
|
-
label: "Interval",
|
|
1180
|
-
value: current.subscription.interval,
|
|
1181
|
-
onChange: (event)=>update({
|
|
1182
|
-
subscription: _extends({}, current.subscription, {
|
|
1183
|
-
interval: event.target.value
|
|
1184
|
-
})
|
|
1185
|
-
}),
|
|
1186
|
-
size: "small",
|
|
1187
|
-
select: true,
|
|
1188
|
-
sx: {
|
|
1189
|
-
minWidth: 120
|
|
1190
|
-
},
|
|
1191
|
-
children: [
|
|
1192
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1193
|
-
value: "month",
|
|
1194
|
-
children: 'Monthly'
|
|
1195
|
-
}),
|
|
1196
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1197
|
-
value: "year",
|
|
1198
|
-
children: 'Yearly'
|
|
1199
|
-
})
|
|
1200
|
-
]
|
|
1201
|
-
}) : null,
|
|
1202
|
-
current.subscription ? /*#__PURE__*/ _jsx(TextField, {
|
|
1203
|
-
label: "Free trial (days)",
|
|
1204
|
-
placeholder: "None",
|
|
1205
|
-
value: (_current_subscription_trialDays = current.subscription.trialDays) != null ? _current_subscription_trialDays : '',
|
|
1206
|
-
onChange: (event)=>{
|
|
1207
|
-
const raw = event.target.value.trim();
|
|
1208
|
-
update({
|
|
1209
|
-
subscription: _extends({}, current.subscription, raw === '' ? {
|
|
1210
|
-
trialDays: undefined
|
|
1211
|
-
} : {
|
|
1212
|
-
trialDays: Math.max(1, Math.round(Number(raw)))
|
|
1213
|
-
})
|
|
1214
|
-
});
|
|
1215
|
-
},
|
|
1216
|
-
size: "small",
|
|
1217
|
-
sx: {
|
|
1218
|
-
width: 140
|
|
1219
|
-
},
|
|
1220
|
-
slotProps: {
|
|
1221
|
-
htmlInput: {
|
|
1222
|
-
inputMode: 'numeric'
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
}) : null
|
|
1226
|
-
]
|
|
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
|
|
1227
1672
|
}),
|
|
1228
|
-
current.type === 'digital' ? /*#__PURE__*/
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
var _file_version;
|
|
1236
|
-
return /*#__PURE__*/ _jsxs(Stack, {
|
|
1237
|
-
direction: "row",
|
|
1238
|
-
spacing: 1,
|
|
1239
|
-
sx: {
|
|
1240
|
-
alignItems: 'center'
|
|
1241
|
-
},
|
|
1242
|
-
children: [
|
|
1243
|
-
/*#__PURE__*/ _jsxs(Typography, {
|
|
1244
|
-
variant: "body2",
|
|
1245
|
-
sx: {
|
|
1246
|
-
flex: 1
|
|
1247
|
-
},
|
|
1248
|
-
noWrap: true,
|
|
1249
|
-
children: [
|
|
1250
|
-
file.fileName,
|
|
1251
|
-
file.version ? ` · v${file.version}` : ''
|
|
1252
|
-
]
|
|
1253
|
-
}),
|
|
1254
|
-
/*#__PURE__*/ _jsx(PaidMediaProtection, {
|
|
1255
|
-
url: file.url,
|
|
1256
|
-
hostId: hostId,
|
|
1257
|
-
productId: product == null ? void 0 : product.$id,
|
|
1258
|
-
kind: "download"
|
|
1259
|
-
}),
|
|
1260
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1261
|
-
label: "Version",
|
|
1262
|
-
value: (_file_version = file.version) != null ? _file_version : '',
|
|
1263
|
-
onChange: (event)=>{
|
|
1264
|
-
var _current_digitalFiles;
|
|
1265
|
-
const digitalFiles = [
|
|
1266
|
-
...(_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []
|
|
1267
|
-
];
|
|
1268
|
-
digitalFiles[index] = _extends({}, file, {
|
|
1269
|
-
version: event.target.value.slice(0, 20)
|
|
1270
|
-
});
|
|
1271
|
-
update({
|
|
1272
|
-
digitalFiles
|
|
1273
|
-
});
|
|
1274
|
-
},
|
|
1275
|
-
size: "small",
|
|
1276
|
-
sx: {
|
|
1277
|
-
width: 100
|
|
1278
|
-
}
|
|
1279
|
-
}),
|
|
1280
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1281
|
-
size: "small",
|
|
1282
|
-
color: "error",
|
|
1283
|
-
onClick: ()=>{
|
|
1284
|
-
var _current_digitalFiles;
|
|
1285
|
-
return update({
|
|
1286
|
-
digitalFiles: ((_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : []).filter((_item, itemIndex)=>itemIndex !== index)
|
|
1287
|
-
});
|
|
1288
|
-
},
|
|
1289
|
-
children: '✕'
|
|
1290
|
-
})
|
|
1291
|
-
]
|
|
1292
|
-
}, index);
|
|
1293
|
-
}),
|
|
1294
|
-
/*#__PURE__*/ _jsxs(Stack, {
|
|
1295
|
-
direction: "row",
|
|
1296
|
-
spacing: 2,
|
|
1297
|
-
children: [
|
|
1298
|
-
/*#__PURE__*/ _jsx(PaidDownloadAddButton, {
|
|
1299
|
-
hostId: hostId,
|
|
1300
|
-
productId: product == null ? void 0 : product.$id,
|
|
1301
|
-
onAdd: (file)=>{
|
|
1302
|
-
var _current_digitalFiles;
|
|
1303
|
-
return update({
|
|
1304
|
-
digitalFiles: [
|
|
1305
|
-
...(_current_digitalFiles = current.digitalFiles) != null ? _current_digitalFiles : [],
|
|
1306
|
-
file
|
|
1307
|
-
]
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1310
|
-
}),
|
|
1311
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1312
|
-
label: "Download limit",
|
|
1313
|
-
placeholder: "Unlimited",
|
|
1314
|
-
value: (_current_downloadLimit = current.downloadLimit) != null ? _current_downloadLimit : '',
|
|
1315
|
-
onChange: (event)=>{
|
|
1316
|
-
const raw = event.target.value.trim();
|
|
1317
|
-
update({
|
|
1318
|
-
downloadLimit: raw === '' ? undefined : Math.max(1, Math.round(Number(raw)))
|
|
1319
|
-
});
|
|
1320
|
-
},
|
|
1321
|
-
size: "small",
|
|
1322
|
-
sx: {
|
|
1323
|
-
width: 140
|
|
1324
|
-
},
|
|
1325
|
-
slotProps: {
|
|
1326
|
-
htmlInput: {
|
|
1327
|
-
inputMode: 'numeric'
|
|
1328
|
-
}
|
|
1329
|
-
},
|
|
1330
|
-
helperText: "Attempts per order"
|
|
1331
|
-
})
|
|
1332
|
-
]
|
|
1333
|
-
}),
|
|
1334
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
1335
|
-
variant: "caption",
|
|
1336
|
-
color: "text.secondary",
|
|
1337
|
-
children: 'Buyers always download the current files — uploading a new ' + 'version re-delivers to everyone.'
|
|
1338
|
-
}),
|
|
1339
|
-
/*#__PURE__*/ _jsx(MembersVideosField, {
|
|
1340
|
-
hostId: hostId,
|
|
1341
|
-
productId: product == null ? void 0 : product.$id,
|
|
1342
|
-
videos: (_current_gatedVideos = current.gatedVideos) != null ? _current_gatedVideos : [],
|
|
1343
|
-
onChange: (gatedVideos)=>update({
|
|
1344
|
-
gatedVideos
|
|
1345
|
-
})
|
|
1346
|
-
})
|
|
1347
|
-
]
|
|
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
|
|
1348
1680
|
}) : null,
|
|
1349
1681
|
/*#__PURE__*/ _jsx(ProductChipsField, {
|
|
1350
1682
|
label: "Related products (upsells)",
|
|
@@ -1355,74 +1687,23 @@ const sameRecord = (option, value)=>option.$id === value.$id;
|
|
|
1355
1687
|
value: pickedRelated,
|
|
1356
1688
|
onChange: setRelatedProducts
|
|
1357
1689
|
}),
|
|
1358
|
-
/*#__PURE__*/ _jsx(
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
xs: 'column',
|
|
1365
|
-
sm: 'row'
|
|
1366
|
-
},
|
|
1367
|
-
spacing: 2,
|
|
1368
|
-
children: [
|
|
1369
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1370
|
-
label: "SEO title",
|
|
1371
|
-
value: (_ref5 = (_current_seo2 = current.seo) == null ? void 0 : _current_seo2.title) != null ? _ref5 : '',
|
|
1372
|
-
onChange: (event)=>update({
|
|
1373
|
-
seo: _extends({}, current.seo, {
|
|
1374
|
-
title: event.target.value
|
|
1375
|
-
})
|
|
1376
|
-
}),
|
|
1377
|
-
// The counts every search listing editor prints (AGL-2910): what a
|
|
1378
|
-
// search result shows before it truncates.
|
|
1379
|
-
helperText: seoListingFieldCount('title', (_current_seo3 = current.seo) == null ? void 0 : _current_seo3.title),
|
|
1380
|
-
error: seoListingFieldTooLong('title', (_current_seo4 = current.seo) == null ? void 0 : _current_seo4.title),
|
|
1381
|
-
size: "small",
|
|
1382
|
-
fullWidth: true
|
|
1383
|
-
}),
|
|
1384
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1385
|
-
size: "small",
|
|
1386
|
-
onClick: ()=>void pick((media)=>update({
|
|
1387
|
-
seo: _extends({}, current.seo, {
|
|
1388
|
-
imageUrl: media.url
|
|
1389
|
-
})
|
|
1390
|
-
})),
|
|
1391
|
-
children: ((_current_seo5 = current.seo) == null ? void 0 : _current_seo5.imageUrl) ? 'Change OG image' : 'OG image'
|
|
1392
|
-
})
|
|
1393
|
-
]
|
|
1394
|
-
}),
|
|
1395
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1396
|
-
label: "SEO description",
|
|
1397
|
-
value: (_ref6 = (_current_seo6 = current.seo) == null ? void 0 : _current_seo6.description) != null ? _ref6 : '',
|
|
1398
|
-
onChange: (event)=>update({
|
|
1399
|
-
seo: _extends({}, current.seo, {
|
|
1400
|
-
description: event.target.value
|
|
1401
|
-
})
|
|
1402
|
-
}),
|
|
1403
|
-
helperText: seoListingFieldCount('description', (_current_seo7 = current.seo) == null ? void 0 : _current_seo7.description),
|
|
1404
|
-
error: seoListingFieldTooLong('description', (_current_seo8 = current.seo) == null ? void 0 : _current_seo8.description),
|
|
1405
|
-
size: "small",
|
|
1406
|
-
multiline: true,
|
|
1407
|
-
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
|
|
1408
1696
|
}),
|
|
1409
|
-
WidgetSlot ? /*#__PURE__*/ _jsx(
|
|
1697
|
+
WidgetSlot ? /*#__PURE__*/ _jsx(HostedZone, {
|
|
1698
|
+
renderer: WidgetSlot,
|
|
1410
1699
|
slot: "seoFields",
|
|
1411
1700
|
hostId: hostId,
|
|
1412
1701
|
orgId: undefined,
|
|
1413
1702
|
orgSlug: "",
|
|
1414
|
-
subject:
|
|
1415
|
-
kind: 'product',
|
|
1416
|
-
id: (_ref7 = product == null ? void 0 : product.$id) != null ? _ref7 : null,
|
|
1417
|
-
name: current.name,
|
|
1418
|
-
description: String((_current_description2 = current.description) != null ? _current_description2 : '')
|
|
1419
|
-
},
|
|
1703
|
+
subject: seoSubject,
|
|
1420
1704
|
fields: PRODUCT_SEO_LISTING_FIELDS,
|
|
1421
|
-
values:
|
|
1422
|
-
|
|
1423
|
-
description: (_ref9 = (_current_seo10 = current.seo) == null ? void 0 : _current_seo10.description) != null ? _ref9 : ''
|
|
1424
|
-
},
|
|
1425
|
-
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),
|
|
1426
1707
|
proposeValues: proposeSeoValues
|
|
1427
1708
|
}) : null,
|
|
1428
1709
|
error ? /*#__PURE__*/ _jsx(Alert, {
|