@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
|
@@ -24,7 +24,7 @@ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
|
24
24
|
import { Timestamp } from "@aglyn/shared-util-timestamp";
|
|
25
25
|
import { Alert, Autocomplete, Button, Chip, Dialog, DialogActions, DialogContent, DialogTitle, Divider, MenuItem, Stack, Switch, TextField, Typography } from "@mui/material";
|
|
26
26
|
import { collection, deleteDoc, doc, setDoc } from "firebase/firestore";
|
|
27
|
-
import { useCallback, useMemo, useState } from "react";
|
|
27
|
+
import { memo, useCallback, useMemo, useRef, useState } from "react";
|
|
28
28
|
import { useFirestore, useUser } from "@aglyn/tenant-feature-instance";
|
|
29
29
|
import { ceilingedWindow, collectionCeiling, useFirestoreCollection, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
|
|
30
30
|
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
@@ -89,13 +89,601 @@ const RULE_OPS = [
|
|
|
89
89
|
label: 'contains'
|
|
90
90
|
}
|
|
91
91
|
];
|
|
92
|
+
const productLabel = (product)=>product.name;
|
|
93
|
+
const sameProduct = (option, value)=>option.$id === value.$id;
|
|
94
|
+
/**
|
|
95
|
+
* A manual collection's products, as chips — MEMOIZED, and every prop it
|
|
96
|
+
* takes is stable while the picked products are (AGL-3423).
|
|
97
|
+
*
|
|
98
|
+
* A multiple Autocomplete hands its input a new chip array as
|
|
99
|
+
* `startAdornment` on every render, and MUI's `InputBase` copies that into
|
|
100
|
+
* its `FormControl` from a passive effect: a state update left pending after
|
|
101
|
+
* every commit the field takes part in. React 19 counts each such commit as a
|
|
102
|
+
* nested update, and keystrokes delivered back to back commit one after
|
|
103
|
+
* another with nothing to clear the count, so the fifty-first throws
|
|
104
|
+
* "Maximum update depth exceeded" (#185). The collection's name, slug and
|
|
105
|
+
* rules share one draft with this list, so each keystroke in them
|
|
106
|
+
* re-rendered it; kept out of those renders, it commits only when it changes.
|
|
107
|
+
*/ const CollectionProductsField = /*#__PURE__*/ memo(function CollectionProductsField(props) {
|
|
108
|
+
const { onChange } = props;
|
|
109
|
+
return /*#__PURE__*/ _jsx(Autocomplete, {
|
|
110
|
+
multiple: true,
|
|
111
|
+
options: props.products,
|
|
112
|
+
getOptionLabel: productLabel,
|
|
113
|
+
isOptionEqualToValue: sameProduct,
|
|
114
|
+
value: props.value,
|
|
115
|
+
onChange: (_event, picked)=>onChange(picked),
|
|
116
|
+
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
117
|
+
label: "Products",
|
|
118
|
+
size: "small"
|
|
119
|
+
}))
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* A text field that redraws only when what it shows changes (AGL-3423).
|
|
124
|
+
*
|
|
125
|
+
* Both editors keep their draft in this card, so a keystroke in either one
|
|
126
|
+
* re-renders the card, and drawn whole that is both lists with a match count
|
|
127
|
+
* per collection, their pagers, and every field of the dialog typed into.
|
|
128
|
+
* When a keystroke costs that much, typed input queues and is processed back
|
|
129
|
+
* to back, which is what lets a chip list's pending update climb to #185 (see
|
|
130
|
+
* `CollectionProductsField`). The lists and each part of the dialogs are
|
|
131
|
+
* memoized on what they show, and each field is this, handed a handler and
|
|
132
|
+
* styles that keep their identity, so the keystroke redraws the field it
|
|
133
|
+
* lands in.
|
|
134
|
+
*/ const MemoTextField = /*#__PURE__*/ memo(TextField);
|
|
135
|
+
const FIRST_FIELD = {
|
|
136
|
+
mt: 1
|
|
137
|
+
};
|
|
138
|
+
const RULE_FIELD = {
|
|
139
|
+
width: 130
|
|
140
|
+
};
|
|
141
|
+
const RULE_OP = {
|
|
142
|
+
width: 110
|
|
143
|
+
};
|
|
144
|
+
const RULE_VALUE = {
|
|
145
|
+
flex: 1
|
|
146
|
+
};
|
|
147
|
+
const MODE_MENU = [
|
|
148
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
149
|
+
value: "manual",
|
|
150
|
+
children: 'Manual — pick products'
|
|
151
|
+
}, "manual"),
|
|
152
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
153
|
+
value: "smart",
|
|
154
|
+
children: 'Smart — rule based'
|
|
155
|
+
}, "smart")
|
|
156
|
+
];
|
|
157
|
+
const RULE_FIELD_MENU = RULE_FIELDS.map((field)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
158
|
+
value: field.value,
|
|
159
|
+
children: field.label
|
|
160
|
+
}, field.value));
|
|
161
|
+
const RULE_OP_MENU = RULE_OPS.map((op)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
162
|
+
value: op.value,
|
|
163
|
+
children: op.label
|
|
164
|
+
}, op.value));
|
|
165
|
+
/** The category tree, a page at a time, and the button that adds one. */ const CategoriesSection = /*#__PURE__*/ memo(function CategoriesSection(props) {
|
|
166
|
+
const { categories, visible, onEdit, onDelete } = props;
|
|
167
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
168
|
+
children: [
|
|
169
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
170
|
+
variant: "subtitle2",
|
|
171
|
+
children: 'Categories'
|
|
172
|
+
}),
|
|
173
|
+
categories.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
|
|
174
|
+
variant: "body2",
|
|
175
|
+
color: "text.secondary",
|
|
176
|
+
children: 'Group products into a browsable tree (e.g. Brakes → Pads).'
|
|
177
|
+
}) : visible.map((category)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
178
|
+
direction: "row",
|
|
179
|
+
spacing: 1,
|
|
180
|
+
sx: {
|
|
181
|
+
alignItems: 'center',
|
|
182
|
+
pl: category.depth * 2
|
|
183
|
+
},
|
|
184
|
+
children: [
|
|
185
|
+
/*#__PURE__*/ _jsxs(Typography, {
|
|
186
|
+
variant: "body2",
|
|
187
|
+
sx: {
|
|
188
|
+
flex: 1
|
|
189
|
+
},
|
|
190
|
+
noWrap: true,
|
|
191
|
+
children: [
|
|
192
|
+
category.name,
|
|
193
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
194
|
+
component: "span",
|
|
195
|
+
variant: "caption",
|
|
196
|
+
color: "text.secondary",
|
|
197
|
+
children: ` /${category.slug}`
|
|
198
|
+
})
|
|
199
|
+
]
|
|
200
|
+
}),
|
|
201
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
202
|
+
size: "small",
|
|
203
|
+
onClick: ()=>{
|
|
204
|
+
var _category_parentId;
|
|
205
|
+
return onEdit({
|
|
206
|
+
id: category.$id,
|
|
207
|
+
name: category.name,
|
|
208
|
+
parentId: (_category_parentId = category.parentId) != null ? _category_parentId : ''
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
children: 'Edit'
|
|
212
|
+
}),
|
|
213
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
214
|
+
size: "small",
|
|
215
|
+
color: "error",
|
|
216
|
+
onClick: onDelete(category),
|
|
217
|
+
children: 'Delete'
|
|
218
|
+
})
|
|
219
|
+
]
|
|
220
|
+
}, category.$id)),
|
|
221
|
+
categories.length === 0 ? null : /*#__PURE__*/ _jsx(ListPagination, {
|
|
222
|
+
page: props.page,
|
|
223
|
+
pageSize: props.pageSize,
|
|
224
|
+
rowCount: visible.length,
|
|
225
|
+
// The categories the card HOLDS — a client slice of rows already
|
|
226
|
+
// read, so the total is known exactly.
|
|
227
|
+
count: categories.length,
|
|
228
|
+
onPageChange: props.onPageChange,
|
|
229
|
+
onPageSizeChange: props.onPageSizeChange
|
|
230
|
+
}),
|
|
231
|
+
props.truncated ? /*#__PURE__*/ _jsx(Alert, {
|
|
232
|
+
severity: "info",
|
|
233
|
+
children: `Showing ${CATEGORY_CEILING} categories, ordered by id. This ` + 'catalog has more — a category whose parent is past that ' + 'boundary is drawn at the top level here rather than under it.'
|
|
234
|
+
}) : null,
|
|
235
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
236
|
+
size: "small",
|
|
237
|
+
sx: {
|
|
238
|
+
alignSelf: 'flex-start'
|
|
239
|
+
},
|
|
240
|
+
onClick: ()=>onEdit({
|
|
241
|
+
id: null,
|
|
242
|
+
name: '',
|
|
243
|
+
parentId: ''
|
|
244
|
+
}),
|
|
245
|
+
children: 'Add category'
|
|
246
|
+
})
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
/** The catalog collections, a page at a time, and the button that adds one. */ const CollectionsSection = /*#__PURE__*/ memo(function CollectionsSection(props) {
|
|
251
|
+
const { collections, visible, products, countPrefix, onEdit, onDelete } = props;
|
|
252
|
+
/**
|
|
253
|
+
* How many products a collection holds — over the CATALOG WINDOW.
|
|
254
|
+
*
|
|
255
|
+
* Rendered with "at least" when the probe found a product past the ceiling,
|
|
256
|
+
* because past that point this is a lower bound and printing it as a total
|
|
257
|
+
* is the count-that-is-a-window-length defect. The number itself is honest
|
|
258
|
+
* either way; only the claim around it changes.
|
|
259
|
+
*/ const collectionCount = (row)=>products.filter((product)=>CommerceModel.matchesCollection(product, row, product.$id)).length;
|
|
260
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
261
|
+
children: [
|
|
262
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
263
|
+
variant: "subtitle2",
|
|
264
|
+
children: 'Collections'
|
|
265
|
+
}),
|
|
266
|
+
visible.map((row)=>{
|
|
267
|
+
var _row_mode;
|
|
268
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
269
|
+
direction: "row",
|
|
270
|
+
spacing: 1,
|
|
271
|
+
sx: {
|
|
272
|
+
alignItems: 'center'
|
|
273
|
+
},
|
|
274
|
+
children: [
|
|
275
|
+
/*#__PURE__*/ _jsxs(Typography, {
|
|
276
|
+
variant: "body2",
|
|
277
|
+
sx: {
|
|
278
|
+
flex: 1
|
|
279
|
+
},
|
|
280
|
+
noWrap: true,
|
|
281
|
+
children: [
|
|
282
|
+
row.name,
|
|
283
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
284
|
+
component: "span",
|
|
285
|
+
variant: "caption",
|
|
286
|
+
color: "text.secondary",
|
|
287
|
+
children: ` · ${(_row_mode = row.mode) != null ? _row_mode : 'manual'} · ${countPrefix}${collectionCount(row)} products`
|
|
288
|
+
})
|
|
289
|
+
]
|
|
290
|
+
}),
|
|
291
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
292
|
+
size: "small",
|
|
293
|
+
onClick: ()=>{
|
|
294
|
+
var _row_slug, _row_mode, _row_productIds, _row_rules;
|
|
295
|
+
return onEdit({
|
|
296
|
+
id: row.$id,
|
|
297
|
+
name: row.name,
|
|
298
|
+
slug: (_row_slug = row.slug) != null ? _row_slug : '',
|
|
299
|
+
mode: (_row_mode = row.mode) != null ? _row_mode : 'manual',
|
|
300
|
+
productIds: (_row_productIds = row.productIds) != null ? _row_productIds : [],
|
|
301
|
+
rules: (_row_rules = row.rules) != null ? _row_rules : [],
|
|
302
|
+
matchAll: row.matchAll !== false
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
children: 'Edit'
|
|
306
|
+
}),
|
|
307
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
308
|
+
size: "small",
|
|
309
|
+
color: "error",
|
|
310
|
+
onClick: onDelete(row),
|
|
311
|
+
children: 'Delete'
|
|
312
|
+
})
|
|
313
|
+
]
|
|
314
|
+
}, row.$id);
|
|
315
|
+
}),
|
|
316
|
+
collections.length === 0 ? null : /*#__PURE__*/ _jsx(ListPagination, {
|
|
317
|
+
page: props.page,
|
|
318
|
+
pageSize: props.pageSize,
|
|
319
|
+
rowCount: visible.length,
|
|
320
|
+
// The CATALOG collections, which is what this list is. Not the
|
|
321
|
+
// window's length: content collections share the subcollection
|
|
322
|
+
// and are classified out before this count is taken.
|
|
323
|
+
count: collections.length,
|
|
324
|
+
onPageChange: props.onPageChange,
|
|
325
|
+
onPageSizeChange: props.onPageSizeChange
|
|
326
|
+
}),
|
|
327
|
+
props.truncated ? /*#__PURE__*/ _jsx(Alert, {
|
|
328
|
+
severity: "info",
|
|
329
|
+
children: `Showing ${COLLECTION_CEILING} collections, ordered by id. This ` + 'site has more — the slug check below only covers the ones ' + 'listed here, so an address may already be taken by one that ' + 'is not.'
|
|
330
|
+
}) : null,
|
|
331
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
332
|
+
size: "small",
|
|
333
|
+
sx: {
|
|
334
|
+
alignSelf: 'flex-start'
|
|
335
|
+
},
|
|
336
|
+
onClick: ()=>onEdit({
|
|
337
|
+
id: null,
|
|
338
|
+
name: '',
|
|
339
|
+
slug: '',
|
|
340
|
+
mode: 'manual',
|
|
341
|
+
productIds: [],
|
|
342
|
+
rules: [],
|
|
343
|
+
matchAll: true
|
|
344
|
+
}),
|
|
345
|
+
children: 'Add collection'
|
|
346
|
+
})
|
|
347
|
+
]
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
/** The category editor: a name and a parent. */ const CategoryDialog = /*#__PURE__*/ memo(function CategoryDialog(props) {
|
|
351
|
+
var _ref, _ref1;
|
|
352
|
+
const { draft, categories, setDraft } = props;
|
|
353
|
+
const draftId = draft == null ? void 0 : draft.id;
|
|
354
|
+
const close = useCallback(()=>setDraft(null), [
|
|
355
|
+
setDraft
|
|
356
|
+
]);
|
|
357
|
+
const setName = useCallback((event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
358
|
+
name: event.target.value
|
|
359
|
+
}) : prev), [
|
|
360
|
+
setDraft
|
|
361
|
+
]);
|
|
362
|
+
const setParent = useCallback((event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
363
|
+
parentId: event.target.value
|
|
364
|
+
}) : prev), [
|
|
365
|
+
setDraft
|
|
366
|
+
]);
|
|
367
|
+
const parentMenu = useMemo(()=>[
|
|
368
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
369
|
+
value: "",
|
|
370
|
+
children: 'None (top level)'
|
|
371
|
+
}, ""),
|
|
372
|
+
// The whole set, not `visibleCategories` — a parent picker that
|
|
373
|
+
// offered only the current page could not reparent a category under
|
|
374
|
+
// one two pages away.
|
|
375
|
+
...categories.filter((category)=>category.$id !== draftId).map((category)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
376
|
+
value: category.$id,
|
|
377
|
+
children: `${'— '.repeat(category.depth)}${category.name}`
|
|
378
|
+
}, category.$id))
|
|
379
|
+
], [
|
|
380
|
+
categories,
|
|
381
|
+
draftId
|
|
382
|
+
]);
|
|
383
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
384
|
+
open: Boolean(draft),
|
|
385
|
+
onClose: close,
|
|
386
|
+
maxWidth: "xs",
|
|
387
|
+
fullWidth: true,
|
|
388
|
+
children: [
|
|
389
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
390
|
+
children: (draft == null ? void 0 : draft.id) ? 'Edit category' : 'New category'
|
|
391
|
+
}),
|
|
392
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
393
|
+
sx: {
|
|
394
|
+
display: 'flex',
|
|
395
|
+
flexDirection: 'column',
|
|
396
|
+
gap: 2
|
|
397
|
+
},
|
|
398
|
+
children: [
|
|
399
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
400
|
+
label: "Name",
|
|
401
|
+
value: (_ref = draft == null ? void 0 : draft.name) != null ? _ref : '',
|
|
402
|
+
onChange: setName,
|
|
403
|
+
size: "small",
|
|
404
|
+
autoFocus: true,
|
|
405
|
+
sx: FIRST_FIELD
|
|
406
|
+
}),
|
|
407
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
408
|
+
label: "Parent category",
|
|
409
|
+
value: (_ref1 = draft == null ? void 0 : draft.parentId) != null ? _ref1 : '',
|
|
410
|
+
onChange: setParent,
|
|
411
|
+
size: "small",
|
|
412
|
+
select: true,
|
|
413
|
+
children: parentMenu
|
|
414
|
+
})
|
|
415
|
+
]
|
|
416
|
+
}),
|
|
417
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
418
|
+
children: [
|
|
419
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
420
|
+
onClick: close,
|
|
421
|
+
children: 'Cancel'
|
|
422
|
+
}),
|
|
423
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
424
|
+
variant: "contained",
|
|
425
|
+
color: "primary",
|
|
426
|
+
disabled: !(draft == null ? void 0 : draft.name.trim()),
|
|
427
|
+
onClick: props.onSave,
|
|
428
|
+
children: 'Save'
|
|
429
|
+
})
|
|
430
|
+
]
|
|
431
|
+
})
|
|
432
|
+
]
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
const CollectionRuleRow = /*#__PURE__*/ memo(function CollectionRuleRow(props) {
|
|
436
|
+
const { index, rule, onChange } = props;
|
|
437
|
+
const setField = useCallback((event)=>onChange(index, {
|
|
438
|
+
field: event.target.value
|
|
439
|
+
}), [
|
|
440
|
+
index,
|
|
441
|
+
onChange
|
|
442
|
+
]);
|
|
443
|
+
const setOp = useCallback((event)=>onChange(index, {
|
|
444
|
+
op: event.target.value
|
|
445
|
+
}), [
|
|
446
|
+
index,
|
|
447
|
+
onChange
|
|
448
|
+
]);
|
|
449
|
+
const setCategory = useCallback((event)=>onChange(index, {
|
|
450
|
+
value: event.target.value
|
|
451
|
+
}), [
|
|
452
|
+
index,
|
|
453
|
+
onChange
|
|
454
|
+
]);
|
|
455
|
+
const ruleField = rule.field;
|
|
456
|
+
const setValue = useCallback((event)=>onChange(index, {
|
|
457
|
+
value: ruleField === 'priceUsd' ? Number(event.target.value) : event.target.value
|
|
458
|
+
}), [
|
|
459
|
+
index,
|
|
460
|
+
onChange,
|
|
461
|
+
ruleField
|
|
462
|
+
]);
|
|
463
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
464
|
+
direction: "row",
|
|
465
|
+
spacing: 1,
|
|
466
|
+
children: [
|
|
467
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
468
|
+
value: rule.field,
|
|
469
|
+
onChange: setField,
|
|
470
|
+
size: "small",
|
|
471
|
+
select: true,
|
|
472
|
+
sx: RULE_FIELD,
|
|
473
|
+
children: RULE_FIELD_MENU
|
|
474
|
+
}),
|
|
475
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
476
|
+
value: rule.op,
|
|
477
|
+
onChange: setOp,
|
|
478
|
+
size: "small",
|
|
479
|
+
select: true,
|
|
480
|
+
sx: RULE_OP,
|
|
481
|
+
children: RULE_OP_MENU
|
|
482
|
+
}),
|
|
483
|
+
rule.field === 'categoryId' ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
484
|
+
value: rule.value,
|
|
485
|
+
onChange: setCategory,
|
|
486
|
+
size: "small",
|
|
487
|
+
select: true,
|
|
488
|
+
sx: RULE_VALUE,
|
|
489
|
+
children: props.categoryMenu
|
|
490
|
+
}) : /*#__PURE__*/ _jsx(MemoTextField, {
|
|
491
|
+
value: rule.value,
|
|
492
|
+
onChange: setValue,
|
|
493
|
+
size: "small",
|
|
494
|
+
sx: RULE_VALUE,
|
|
495
|
+
placeholder: rule.field === 'type' ? 'physical' : 'Value'
|
|
496
|
+
}),
|
|
497
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
498
|
+
size: "small",
|
|
499
|
+
color: "error",
|
|
500
|
+
onClick: ()=>onChange(index, null),
|
|
501
|
+
children: '✕'
|
|
502
|
+
})
|
|
503
|
+
]
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
/** Whether every rule must hold, or any one. */ const CollectionMatchSwitch = /*#__PURE__*/ memo(function CollectionMatchSwitch(props) {
|
|
507
|
+
const { matchAll, setDraft } = props;
|
|
508
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
509
|
+
direction: "row",
|
|
510
|
+
spacing: 1,
|
|
511
|
+
sx: {
|
|
512
|
+
alignItems: 'center'
|
|
513
|
+
},
|
|
514
|
+
children: [
|
|
515
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
516
|
+
variant: "body2",
|
|
517
|
+
children: 'Match'
|
|
518
|
+
}),
|
|
519
|
+
/*#__PURE__*/ _jsx(Switch, {
|
|
520
|
+
size: "small",
|
|
521
|
+
checked: matchAll,
|
|
522
|
+
onChange: (event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
523
|
+
matchAll: event.target.checked
|
|
524
|
+
}) : prev)
|
|
525
|
+
}),
|
|
526
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
527
|
+
variant: "body2",
|
|
528
|
+
children: matchAll ? 'all rules' : 'any rule'
|
|
529
|
+
})
|
|
530
|
+
]
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
/** A smart collection's rules, whether all or any must hold, and the button that adds one. */ const CollectionRulesFields = /*#__PURE__*/ memo(function CollectionRulesFields(props) {
|
|
534
|
+
const { rules, matchAll, categories, setDraft, onRule } = props;
|
|
535
|
+
const categoryMenu = useMemo(()=>categories.map((category)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
536
|
+
value: category.$id,
|
|
537
|
+
children: category.name
|
|
538
|
+
}, category.$id)), [
|
|
539
|
+
categories
|
|
540
|
+
]);
|
|
541
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
542
|
+
children: [
|
|
543
|
+
/*#__PURE__*/ _jsx(CollectionMatchSwitch, {
|
|
544
|
+
matchAll: matchAll,
|
|
545
|
+
setDraft: setDraft
|
|
546
|
+
}),
|
|
547
|
+
rules.map((rule, index)=>/*#__PURE__*/ _jsx(CollectionRuleRow, {
|
|
548
|
+
index: index,
|
|
549
|
+
rule: rule,
|
|
550
|
+
categoryMenu: categoryMenu,
|
|
551
|
+
onChange: onRule
|
|
552
|
+
}, index)),
|
|
553
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
554
|
+
size: "small",
|
|
555
|
+
sx: {
|
|
556
|
+
alignSelf: 'flex-start'
|
|
557
|
+
},
|
|
558
|
+
onClick: ()=>onRule(rules.length, {}),
|
|
559
|
+
children: 'Add rule'
|
|
560
|
+
})
|
|
561
|
+
]
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
/** The products a draft collection holds, the first few by name. */ const CollectionPreview = /*#__PURE__*/ memo(function CollectionPreview(props) {
|
|
565
|
+
const { matches, countPrefix } = props;
|
|
566
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
567
|
+
direction: "row",
|
|
568
|
+
spacing: 0.5,
|
|
569
|
+
sx: {
|
|
570
|
+
flexWrap: 'wrap'
|
|
571
|
+
},
|
|
572
|
+
children: [
|
|
573
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
574
|
+
variant: "caption",
|
|
575
|
+
color: "text.secondary",
|
|
576
|
+
children: `Matches ${countPrefix}${matches.length} products: `
|
|
577
|
+
}),
|
|
578
|
+
matches.slice(0, 6).map((product)=>/*#__PURE__*/ _jsx(Chip, {
|
|
579
|
+
label: product.name,
|
|
580
|
+
size: "small"
|
|
581
|
+
}, product.$id)),
|
|
582
|
+
matches.length > 6 ? /*#__PURE__*/ _jsx(Typography, {
|
|
583
|
+
variant: "caption",
|
|
584
|
+
color: "text.secondary",
|
|
585
|
+
children: `+${matches.length - 6} more`
|
|
586
|
+
}) : null
|
|
587
|
+
]
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
/** The collection editor: a name, a mode, and the products or rules it holds. */ const CollectionDialog = /*#__PURE__*/ memo(function CollectionDialog(props) {
|
|
591
|
+
var _ref, _ref1, _ref2;
|
|
592
|
+
const { draft, error, setDraft } = props;
|
|
593
|
+
const close = useCallback(()=>setDraft(null), [
|
|
594
|
+
setDraft
|
|
595
|
+
]);
|
|
596
|
+
const setName = useCallback((event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
597
|
+
name: event.target.value
|
|
598
|
+
}) : prev), [
|
|
599
|
+
setDraft
|
|
600
|
+
]);
|
|
601
|
+
const setMode = useCallback((event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
602
|
+
mode: event.target.value
|
|
603
|
+
}) : prev), [
|
|
604
|
+
setDraft
|
|
605
|
+
]);
|
|
606
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
607
|
+
open: Boolean(draft),
|
|
608
|
+
onClose: close,
|
|
609
|
+
maxWidth: "sm",
|
|
610
|
+
fullWidth: true,
|
|
611
|
+
children: [
|
|
612
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
613
|
+
children: (draft == null ? void 0 : draft.id) ? 'Edit collection' : 'New collection'
|
|
614
|
+
}),
|
|
615
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
616
|
+
sx: {
|
|
617
|
+
display: 'flex',
|
|
618
|
+
flexDirection: 'column',
|
|
619
|
+
gap: 2
|
|
620
|
+
},
|
|
621
|
+
children: [
|
|
622
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
623
|
+
label: "Name",
|
|
624
|
+
value: (_ref = draft == null ? void 0 : draft.name) != null ? _ref : '',
|
|
625
|
+
onChange: setName,
|
|
626
|
+
size: "small",
|
|
627
|
+
autoFocus: true,
|
|
628
|
+
sx: FIRST_FIELD,
|
|
629
|
+
error: props.slugTaken,
|
|
630
|
+
helperText: (draft == null ? void 0 : draft.name) ? `/collections/${props.slug}` : undefined
|
|
631
|
+
}),
|
|
632
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
633
|
+
label: "Mode",
|
|
634
|
+
value: (_ref1 = draft == null ? void 0 : draft.mode) != null ? _ref1 : 'manual',
|
|
635
|
+
onChange: setMode,
|
|
636
|
+
size: "small",
|
|
637
|
+
select: true,
|
|
638
|
+
children: MODE_MENU
|
|
639
|
+
}),
|
|
640
|
+
(draft == null ? void 0 : draft.mode) === 'manual' ? /*#__PURE__*/ _jsx(CollectionProductsField, {
|
|
641
|
+
products: props.products,
|
|
642
|
+
value: props.picked,
|
|
643
|
+
onChange: props.onProducts
|
|
644
|
+
}) : /*#__PURE__*/ _jsx(CollectionRulesFields, {
|
|
645
|
+
rules: (_ref2 = draft == null ? void 0 : draft.rules) != null ? _ref2 : NO_RULES,
|
|
646
|
+
matchAll: (draft == null ? void 0 : draft.matchAll) !== false,
|
|
647
|
+
categories: props.categories,
|
|
648
|
+
setDraft: setDraft,
|
|
649
|
+
onRule: props.onRule
|
|
650
|
+
}),
|
|
651
|
+
error ? /*#__PURE__*/ _jsx(Alert, {
|
|
652
|
+
severity: "warning",
|
|
653
|
+
children: error
|
|
654
|
+
}) : null,
|
|
655
|
+
draft ? /*#__PURE__*/ _jsx(CollectionPreview, {
|
|
656
|
+
matches: props.matches,
|
|
657
|
+
countPrefix: props.countPrefix
|
|
658
|
+
}) : null
|
|
659
|
+
]
|
|
660
|
+
}),
|
|
661
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
662
|
+
children: [
|
|
663
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
664
|
+
onClick: close,
|
|
665
|
+
children: 'Cancel'
|
|
666
|
+
}),
|
|
667
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
668
|
+
variant: "contained",
|
|
669
|
+
color: "primary",
|
|
670
|
+
disabled: !(draft == null ? void 0 : draft.name.trim()) || Boolean(error),
|
|
671
|
+
onClick: props.onSave,
|
|
672
|
+
children: 'Save'
|
|
673
|
+
})
|
|
674
|
+
]
|
|
675
|
+
})
|
|
676
|
+
]
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
/** A collection with no rules yet, the same list on every render. */ const NO_RULES = [];
|
|
92
680
|
/**
|
|
93
681
|
* Categories & collections manager (AGL-280): category tree (parentId)
|
|
94
682
|
* at `hosts/{hostId}/productCategories`, manual + smart collections at
|
|
95
683
|
* `hosts/{hostId}/collections` with a live matched-product preview from
|
|
96
684
|
* the same `matchesCollection` matcher the storefront uses.
|
|
97
685
|
*/ export function CatalogOrganizationCard(props) {
|
|
98
|
-
var _CommerceModel_validateCollection
|
|
686
|
+
var _CommerceModel_validateCollection;
|
|
99
687
|
const { hostId } = props;
|
|
100
688
|
const firestore = useFirestore();
|
|
101
689
|
const { enqueueSnackbar } = useSnackbar();
|
|
@@ -421,14 +1009,35 @@ const RULE_OPS = [
|
|
|
421
1009
|
const collectionError = collectionDraft ? collectionDraft.name ? (_CommerceModel_validateCollection = CommerceModel.validateCollection(_extends({}, collectionDraft, {
|
|
422
1010
|
slug: draftSlug
|
|
423
1011
|
}))) != null ? _CommerceModel_validateCollection : slugTaken ? `Another collection already serves /collections/${draftSlug}` : null : null : null;
|
|
1012
|
+
const collectionProductIds = collectionDraft == null ? void 0 : collectionDraft.productIds;
|
|
1013
|
+
const collectionProducts = useMemo(()=>products.filter((product)=>(collectionProductIds != null ? collectionProductIds : []).includes(product.$id)), [
|
|
1014
|
+
products,
|
|
1015
|
+
collectionProductIds
|
|
1016
|
+
]);
|
|
1017
|
+
const setCollectionProducts = useCallback((picked)=>setCollectionDraft((prev)=>prev ? _extends({}, prev, {
|
|
1018
|
+
productIds: picked.map((item)=>item.$id)
|
|
1019
|
+
}) : prev), []);
|
|
1020
|
+
/*
|
|
1021
|
+
* Recomputed when what decides membership changes — the mode, the picked
|
|
1022
|
+
* products, the rules and whether all must hold — and not on a keystroke in
|
|
1023
|
+
* the name, which no match reads (AGL-3423).
|
|
1024
|
+
*/ const draftMode = collectionDraft == null ? void 0 : collectionDraft.mode;
|
|
1025
|
+
const draftRules = collectionDraft == null ? void 0 : collectionDraft.rules;
|
|
1026
|
+
const draftMatchAll = collectionDraft == null ? void 0 : collectionDraft.matchAll;
|
|
424
1027
|
const previewMatches = useMemo(()=>{
|
|
425
|
-
if (!
|
|
426
|
-
const candidate =
|
|
427
|
-
|
|
428
|
-
|
|
1028
|
+
if (!draftMode) return [];
|
|
1029
|
+
const candidate = {
|
|
1030
|
+
mode: draftMode,
|
|
1031
|
+
productIds: collectionProductIds,
|
|
1032
|
+
rules: draftRules,
|
|
1033
|
+
matchAll: draftMatchAll
|
|
1034
|
+
};
|
|
429
1035
|
return products.filter((product)=>CommerceModel.matchesCollection(product, candidate, product.$id));
|
|
430
1036
|
}, [
|
|
431
|
-
|
|
1037
|
+
draftMode,
|
|
1038
|
+
collectionProductIds,
|
|
1039
|
+
draftRules,
|
|
1040
|
+
draftMatchAll,
|
|
432
1041
|
products
|
|
433
1042
|
]);
|
|
434
1043
|
/**
|
|
@@ -568,7 +1177,7 @@ const RULE_OPS = [
|
|
|
568
1177
|
// entries with it was the opposite of what happens, and the two
|
|
569
1178
|
// blockers are the whole point of the feature — say them before the
|
|
570
1179
|
// button is armed, not in a 409 afterwards.
|
|
571
|
-
description: `Storefront blocks pointing at "${row.name}" go empty. The delete ` + 'is refused while the collection still has entries, or while a ' + '
|
|
1180
|
+
description: `Storefront blocks pointing at "${row.name}" go empty. The delete ` + 'is refused while the collection still has entries, or while a ' + 'page uses it as a list or entry template — empty it and detach ' + 'those pages first. It also takes the site admin role.',
|
|
572
1181
|
confirmationText: 'Delete',
|
|
573
1182
|
confirmationButtonProps: {
|
|
574
1183
|
color: 'error'
|
|
@@ -622,14 +1231,6 @@ const RULE_OPS = [
|
|
|
622
1231
|
enqueueSnackbar,
|
|
623
1232
|
restampMembership
|
|
624
1233
|
]);
|
|
625
|
-
/**
|
|
626
|
-
* How many products a collection holds — over the CATALOG WINDOW.
|
|
627
|
-
*
|
|
628
|
-
* Rendered with "at least" when the probe found a product past the ceiling,
|
|
629
|
-
* because past that point this is a lower bound and printing it as a total
|
|
630
|
-
* is the count-that-is-a-window-length defect. The number itself is honest
|
|
631
|
-
* either way; only the claim around it changes.
|
|
632
|
-
*/ const collectionCount = (row)=>products.filter((product)=>CommerceModel.matchesCollection(product, row, product.$id)).length;
|
|
633
1234
|
/*
|
|
634
1235
|
* "at least", or nothing at all.
|
|
635
1236
|
*
|
|
@@ -642,11 +1243,18 @@ const RULE_OPS = [
|
|
|
642
1243
|
* because a catalog of exactly the ceiling is complete: nothing is missing,
|
|
643
1244
|
* and a comparison would put "at least" on a number that is exact.
|
|
644
1245
|
*/ const countPrefix = productsTruncated ? 'at least ' : '';
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
1246
|
+
/*
|
|
1247
|
+
* A rule's change, written over the collection draft as last rendered, from
|
|
1248
|
+
* a handler that keeps its identity so a rule row redraws only when its own
|
|
1249
|
+
* rule changes (AGL-3423).
|
|
1250
|
+
*/ const latestCollectionDraft = useRef(collectionDraft);
|
|
1251
|
+
latestCollectionDraft.current = collectionDraft;
|
|
1252
|
+
const updateRule = useCallback((index, patch)=>{
|
|
1253
|
+
var _draft_rules;
|
|
1254
|
+
const draft = latestCollectionDraft.current;
|
|
1255
|
+
if (!draft) return;
|
|
648
1256
|
const rules = [
|
|
649
|
-
...(
|
|
1257
|
+
...(_draft_rules = draft.rules) != null ? _draft_rules : []
|
|
650
1258
|
];
|
|
651
1259
|
if (patch === null) rules.splice(index, 1);
|
|
652
1260
|
else rules[index] = _extends({
|
|
@@ -654,10 +1262,10 @@ const RULE_OPS = [
|
|
|
654
1262
|
op: 'eq',
|
|
655
1263
|
value: ''
|
|
656
1264
|
}, rules[index], patch);
|
|
657
|
-
setCollectionDraft(_extends({},
|
|
1265
|
+
setCollectionDraft(_extends({}, draft, {
|
|
658
1266
|
rules
|
|
659
1267
|
}));
|
|
660
|
-
};
|
|
1268
|
+
}, []);
|
|
661
1269
|
return /*#__PURE__*/ _jsxs(CardDisplay, {
|
|
662
1270
|
header: 'Categories & collections',
|
|
663
1271
|
help: pluginDocsHelp('catalog', {
|
|
@@ -669,459 +1277,57 @@ const RULE_OPS = [
|
|
|
669
1277
|
/*#__PURE__*/ _jsxs(Stack, {
|
|
670
1278
|
spacing: 1,
|
|
671
1279
|
children: [
|
|
672
|
-
/*#__PURE__*/ _jsx(
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
}),
|
|
676
|
-
categories.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
|
|
677
|
-
variant: "body2",
|
|
678
|
-
color: "text.secondary",
|
|
679
|
-
children: 'Group products into a browsable tree (e.g. Brakes → Pads).'
|
|
680
|
-
}) : visibleCategories.map((category)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
681
|
-
direction: "row",
|
|
682
|
-
spacing: 1,
|
|
683
|
-
sx: {
|
|
684
|
-
alignItems: 'center',
|
|
685
|
-
pl: category.depth * 2
|
|
686
|
-
},
|
|
687
|
-
children: [
|
|
688
|
-
/*#__PURE__*/ _jsxs(Typography, {
|
|
689
|
-
variant: "body2",
|
|
690
|
-
sx: {
|
|
691
|
-
flex: 1
|
|
692
|
-
},
|
|
693
|
-
noWrap: true,
|
|
694
|
-
children: [
|
|
695
|
-
category.name,
|
|
696
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
697
|
-
component: "span",
|
|
698
|
-
variant: "caption",
|
|
699
|
-
color: "text.secondary",
|
|
700
|
-
children: ` /${category.slug}`
|
|
701
|
-
})
|
|
702
|
-
]
|
|
703
|
-
}),
|
|
704
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
705
|
-
size: "small",
|
|
706
|
-
onClick: ()=>{
|
|
707
|
-
var _category_parentId;
|
|
708
|
-
return setCategoryDraft({
|
|
709
|
-
id: category.$id,
|
|
710
|
-
name: category.name,
|
|
711
|
-
parentId: (_category_parentId = category.parentId) != null ? _category_parentId : ''
|
|
712
|
-
});
|
|
713
|
-
},
|
|
714
|
-
children: 'Edit'
|
|
715
|
-
}),
|
|
716
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
717
|
-
size: "small",
|
|
718
|
-
color: "error",
|
|
719
|
-
onClick: handleCategoryDelete(category),
|
|
720
|
-
children: 'Delete'
|
|
721
|
-
})
|
|
722
|
-
]
|
|
723
|
-
}, category.$id)),
|
|
724
|
-
categories.length === 0 ? null : /*#__PURE__*/ _jsx(ListPagination, {
|
|
1280
|
+
/*#__PURE__*/ _jsx(CategoriesSection, {
|
|
1281
|
+
categories: categories,
|
|
1282
|
+
visible: visibleCategories,
|
|
725
1283
|
page: categoryPage,
|
|
726
1284
|
pageSize: categoryPageSize,
|
|
727
|
-
|
|
728
|
-
// The categories the card HOLDS — a client slice of rows already
|
|
729
|
-
// read, so the total is known exactly.
|
|
730
|
-
count: categories.length,
|
|
1285
|
+
truncated: categoriesTruncated,
|
|
731
1286
|
onPageChange: setCategoryPage,
|
|
732
|
-
onPageSizeChange: setCategoryPageSize
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
severity: "info",
|
|
736
|
-
children: `Showing ${CATEGORY_CEILING} categories, ordered by id. This ` + 'catalog has more — a category whose parent is past that ' + 'boundary is drawn at the top level here rather than under it.'
|
|
737
|
-
}) : null,
|
|
738
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
739
|
-
size: "small",
|
|
740
|
-
sx: {
|
|
741
|
-
alignSelf: 'flex-start'
|
|
742
|
-
},
|
|
743
|
-
onClick: ()=>setCategoryDraft({
|
|
744
|
-
id: null,
|
|
745
|
-
name: '',
|
|
746
|
-
parentId: ''
|
|
747
|
-
}),
|
|
748
|
-
children: 'Add category'
|
|
1287
|
+
onPageSizeChange: setCategoryPageSize,
|
|
1288
|
+
onEdit: setCategoryDraft,
|
|
1289
|
+
onDelete: handleCategoryDelete
|
|
749
1290
|
}),
|
|
750
1291
|
/*#__PURE__*/ _jsx(Divider, {
|
|
751
1292
|
sx: {
|
|
752
1293
|
my: 1
|
|
753
1294
|
}
|
|
754
1295
|
}),
|
|
755
|
-
/*#__PURE__*/ _jsx(
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
var _row_mode;
|
|
761
|
-
return /*#__PURE__*/ _jsxs(Stack, {
|
|
762
|
-
direction: "row",
|
|
763
|
-
spacing: 1,
|
|
764
|
-
sx: {
|
|
765
|
-
alignItems: 'center'
|
|
766
|
-
},
|
|
767
|
-
children: [
|
|
768
|
-
/*#__PURE__*/ _jsxs(Typography, {
|
|
769
|
-
variant: "body2",
|
|
770
|
-
sx: {
|
|
771
|
-
flex: 1
|
|
772
|
-
},
|
|
773
|
-
noWrap: true,
|
|
774
|
-
children: [
|
|
775
|
-
row.name,
|
|
776
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
777
|
-
component: "span",
|
|
778
|
-
variant: "caption",
|
|
779
|
-
color: "text.secondary",
|
|
780
|
-
children: ` · ${(_row_mode = row.mode) != null ? _row_mode : 'manual'} · ${countPrefix}${collectionCount(row)} products`
|
|
781
|
-
})
|
|
782
|
-
]
|
|
783
|
-
}),
|
|
784
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
785
|
-
size: "small",
|
|
786
|
-
onClick: ()=>{
|
|
787
|
-
var _row_slug, _row_mode, _row_productIds, _row_rules;
|
|
788
|
-
return setCollectionDraft({
|
|
789
|
-
id: row.$id,
|
|
790
|
-
name: row.name,
|
|
791
|
-
slug: (_row_slug = row.slug) != null ? _row_slug : '',
|
|
792
|
-
mode: (_row_mode = row.mode) != null ? _row_mode : 'manual',
|
|
793
|
-
productIds: (_row_productIds = row.productIds) != null ? _row_productIds : [],
|
|
794
|
-
rules: (_row_rules = row.rules) != null ? _row_rules : [],
|
|
795
|
-
matchAll: row.matchAll !== false
|
|
796
|
-
});
|
|
797
|
-
},
|
|
798
|
-
children: 'Edit'
|
|
799
|
-
}),
|
|
800
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
801
|
-
size: "small",
|
|
802
|
-
color: "error",
|
|
803
|
-
onClick: handleCollectionDelete(row),
|
|
804
|
-
children: 'Delete'
|
|
805
|
-
})
|
|
806
|
-
]
|
|
807
|
-
}, row.$id);
|
|
808
|
-
}),
|
|
809
|
-
commerceCollections.length === 0 ? null : /*#__PURE__*/ _jsx(ListPagination, {
|
|
1296
|
+
/*#__PURE__*/ _jsx(CollectionsSection, {
|
|
1297
|
+
collections: commerceCollections,
|
|
1298
|
+
visible: visibleCollections,
|
|
1299
|
+
products: products,
|
|
1300
|
+
countPrefix: countPrefix,
|
|
810
1301
|
page: collectionPage,
|
|
811
1302
|
pageSize: collectionPageSize,
|
|
812
|
-
|
|
813
|
-
// The CATALOG collections, which is what this list is. Not the
|
|
814
|
-
// window's length: content collections share the subcollection
|
|
815
|
-
// and are classified out before this count is taken.
|
|
816
|
-
count: commerceCollections.length,
|
|
1303
|
+
truncated: collectionsTruncated,
|
|
817
1304
|
onPageChange: setCollectionPage,
|
|
818
|
-
onPageSizeChange: setCollectionPageSize
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
severity: "info",
|
|
822
|
-
children: `Showing ${COLLECTION_CEILING} collections, ordered by id. This ` + 'site has more — the slug check below only covers the ones ' + 'listed here, so an address may already be taken by one that ' + 'is not.'
|
|
823
|
-
}) : null,
|
|
824
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
825
|
-
size: "small",
|
|
826
|
-
sx: {
|
|
827
|
-
alignSelf: 'flex-start'
|
|
828
|
-
},
|
|
829
|
-
onClick: ()=>setCollectionDraft({
|
|
830
|
-
id: null,
|
|
831
|
-
name: '',
|
|
832
|
-
slug: '',
|
|
833
|
-
mode: 'manual',
|
|
834
|
-
productIds: [],
|
|
835
|
-
rules: [],
|
|
836
|
-
matchAll: true
|
|
837
|
-
}),
|
|
838
|
-
children: 'Add collection'
|
|
1305
|
+
onPageSizeChange: setCollectionPageSize,
|
|
1306
|
+
onEdit: setCollectionDraft,
|
|
1307
|
+
onDelete: handleCollectionDelete
|
|
839
1308
|
})
|
|
840
1309
|
]
|
|
841
1310
|
}),
|
|
842
|
-
/*#__PURE__*/
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
children: [
|
|
848
|
-
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
849
|
-
children: (categoryDraft == null ? void 0 : categoryDraft.id) ? 'Edit category' : 'New category'
|
|
850
|
-
}),
|
|
851
|
-
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
852
|
-
sx: {
|
|
853
|
-
display: 'flex',
|
|
854
|
-
flexDirection: 'column',
|
|
855
|
-
gap: 2
|
|
856
|
-
},
|
|
857
|
-
children: [
|
|
858
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
859
|
-
label: "Name",
|
|
860
|
-
value: (_ref = categoryDraft == null ? void 0 : categoryDraft.name) != null ? _ref : '',
|
|
861
|
-
onChange: (event)=>setCategoryDraft((prev)=>prev ? _extends({}, prev, {
|
|
862
|
-
name: event.target.value
|
|
863
|
-
}) : prev),
|
|
864
|
-
size: "small",
|
|
865
|
-
autoFocus: true,
|
|
866
|
-
sx: {
|
|
867
|
-
mt: 1
|
|
868
|
-
}
|
|
869
|
-
}),
|
|
870
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
871
|
-
label: "Parent category",
|
|
872
|
-
value: (_ref1 = categoryDraft == null ? void 0 : categoryDraft.parentId) != null ? _ref1 : '',
|
|
873
|
-
onChange: (event)=>setCategoryDraft((prev)=>prev ? _extends({}, prev, {
|
|
874
|
-
parentId: event.target.value
|
|
875
|
-
}) : prev),
|
|
876
|
-
size: "small",
|
|
877
|
-
select: true,
|
|
878
|
-
children: [
|
|
879
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
880
|
-
value: "",
|
|
881
|
-
children: 'None (top level)'
|
|
882
|
-
}),
|
|
883
|
-
categories.filter((category)=>category.$id !== (categoryDraft == null ? void 0 : categoryDraft.id)).map((category)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
884
|
-
value: category.$id,
|
|
885
|
-
children: `${'— '.repeat(category.depth)}${category.name}`
|
|
886
|
-
}, category.$id))
|
|
887
|
-
]
|
|
888
|
-
})
|
|
889
|
-
]
|
|
890
|
-
}),
|
|
891
|
-
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
892
|
-
children: [
|
|
893
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
894
|
-
onClick: ()=>setCategoryDraft(null),
|
|
895
|
-
children: 'Cancel'
|
|
896
|
-
}),
|
|
897
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
898
|
-
variant: "contained",
|
|
899
|
-
color: "primary",
|
|
900
|
-
disabled: !(categoryDraft == null ? void 0 : categoryDraft.name.trim()),
|
|
901
|
-
onClick: handleCategorySave,
|
|
902
|
-
children: 'Save'
|
|
903
|
-
})
|
|
904
|
-
]
|
|
905
|
-
})
|
|
906
|
-
]
|
|
1311
|
+
/*#__PURE__*/ _jsx(CategoryDialog, {
|
|
1312
|
+
draft: categoryDraft,
|
|
1313
|
+
categories: categories,
|
|
1314
|
+
setDraft: setCategoryDraft,
|
|
1315
|
+
onSave: handleCategorySave
|
|
907
1316
|
}),
|
|
908
|
-
/*#__PURE__*/
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
},
|
|
923
|
-
children: [
|
|
924
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
925
|
-
label: "Name",
|
|
926
|
-
value: (_ref2 = collectionDraft == null ? void 0 : collectionDraft.name) != null ? _ref2 : '',
|
|
927
|
-
onChange: (event)=>setCollectionDraft((prev)=>prev ? _extends({}, prev, {
|
|
928
|
-
name: event.target.value
|
|
929
|
-
}) : prev),
|
|
930
|
-
size: "small",
|
|
931
|
-
autoFocus: true,
|
|
932
|
-
sx: {
|
|
933
|
-
mt: 1
|
|
934
|
-
},
|
|
935
|
-
error: slugTaken,
|
|
936
|
-
helperText: (collectionDraft == null ? void 0 : collectionDraft.name) ? `/collections/${draftSlug}` : undefined
|
|
937
|
-
}),
|
|
938
|
-
/*#__PURE__*/ _jsxs(TextField, {
|
|
939
|
-
label: "Mode",
|
|
940
|
-
value: (_ref3 = collectionDraft == null ? void 0 : collectionDraft.mode) != null ? _ref3 : 'manual',
|
|
941
|
-
onChange: (event)=>setCollectionDraft((prev)=>prev ? _extends({}, prev, {
|
|
942
|
-
mode: event.target.value
|
|
943
|
-
}) : prev),
|
|
944
|
-
size: "small",
|
|
945
|
-
select: true,
|
|
946
|
-
children: [
|
|
947
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
948
|
-
value: "manual",
|
|
949
|
-
children: 'Manual — pick products'
|
|
950
|
-
}),
|
|
951
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
952
|
-
value: "smart",
|
|
953
|
-
children: 'Smart — rule based'
|
|
954
|
-
})
|
|
955
|
-
]
|
|
956
|
-
}),
|
|
957
|
-
(collectionDraft == null ? void 0 : collectionDraft.mode) === 'manual' ? /*#__PURE__*/ _jsx(Autocomplete, {
|
|
958
|
-
multiple: true,
|
|
959
|
-
options: products,
|
|
960
|
-
getOptionLabel: (product)=>product.name,
|
|
961
|
-
isOptionEqualToValue: (option, value)=>option.$id === value.$id,
|
|
962
|
-
value: products.filter((product)=>{
|
|
963
|
-
var _collectionDraft_productIds;
|
|
964
|
-
return ((_collectionDraft_productIds = collectionDraft.productIds) != null ? _collectionDraft_productIds : []).includes(product.$id);
|
|
965
|
-
}),
|
|
966
|
-
onChange: (_event, picked)=>setCollectionDraft((prev)=>prev ? _extends({}, prev, {
|
|
967
|
-
productIds: picked.map((item)=>item.$id)
|
|
968
|
-
}) : prev),
|
|
969
|
-
renderInput: (params)=>/*#__PURE__*/ _jsx(TextField, _extends({}, params, {
|
|
970
|
-
label: "Products",
|
|
971
|
-
size: "small"
|
|
972
|
-
}))
|
|
973
|
-
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
974
|
-
children: [
|
|
975
|
-
/*#__PURE__*/ _jsxs(Stack, {
|
|
976
|
-
direction: "row",
|
|
977
|
-
spacing: 1,
|
|
978
|
-
sx: {
|
|
979
|
-
alignItems: 'center'
|
|
980
|
-
},
|
|
981
|
-
children: [
|
|
982
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
983
|
-
variant: "body2",
|
|
984
|
-
children: 'Match'
|
|
985
|
-
}),
|
|
986
|
-
/*#__PURE__*/ _jsx(Switch, {
|
|
987
|
-
size: "small",
|
|
988
|
-
checked: (collectionDraft == null ? void 0 : collectionDraft.matchAll) !== false,
|
|
989
|
-
onChange: (event)=>setCollectionDraft((prev)=>prev ? _extends({}, prev, {
|
|
990
|
-
matchAll: event.target.checked
|
|
991
|
-
}) : prev)
|
|
992
|
-
}),
|
|
993
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
994
|
-
variant: "body2",
|
|
995
|
-
children: (collectionDraft == null ? void 0 : collectionDraft.matchAll) !== false ? 'all rules' : 'any rule'
|
|
996
|
-
})
|
|
997
|
-
]
|
|
998
|
-
}),
|
|
999
|
-
((_ref4 = collectionDraft == null ? void 0 : collectionDraft.rules) != null ? _ref4 : []).map((rule, index)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
1000
|
-
direction: "row",
|
|
1001
|
-
spacing: 1,
|
|
1002
|
-
children: [
|
|
1003
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1004
|
-
value: rule.field,
|
|
1005
|
-
onChange: (event)=>updateRule(index, {
|
|
1006
|
-
field: event.target.value
|
|
1007
|
-
}),
|
|
1008
|
-
size: "small",
|
|
1009
|
-
select: true,
|
|
1010
|
-
sx: {
|
|
1011
|
-
width: 130
|
|
1012
|
-
},
|
|
1013
|
-
children: RULE_FIELDS.map((field)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1014
|
-
value: field.value,
|
|
1015
|
-
children: field.label
|
|
1016
|
-
}, field.value))
|
|
1017
|
-
}),
|
|
1018
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1019
|
-
value: rule.op,
|
|
1020
|
-
onChange: (event)=>updateRule(index, {
|
|
1021
|
-
op: event.target.value
|
|
1022
|
-
}),
|
|
1023
|
-
size: "small",
|
|
1024
|
-
select: true,
|
|
1025
|
-
sx: {
|
|
1026
|
-
width: 110
|
|
1027
|
-
},
|
|
1028
|
-
children: RULE_OPS.map((op)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1029
|
-
value: op.value,
|
|
1030
|
-
children: op.label
|
|
1031
|
-
}, op.value))
|
|
1032
|
-
}),
|
|
1033
|
-
rule.field === 'categoryId' ? /*#__PURE__*/ _jsx(TextField, {
|
|
1034
|
-
value: rule.value,
|
|
1035
|
-
onChange: (event)=>updateRule(index, {
|
|
1036
|
-
value: event.target.value
|
|
1037
|
-
}),
|
|
1038
|
-
size: "small",
|
|
1039
|
-
select: true,
|
|
1040
|
-
sx: {
|
|
1041
|
-
flex: 1
|
|
1042
|
-
},
|
|
1043
|
-
children: categories.map((category)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1044
|
-
value: category.$id,
|
|
1045
|
-
children: category.name
|
|
1046
|
-
}, category.$id))
|
|
1047
|
-
}) : /*#__PURE__*/ _jsx(TextField, {
|
|
1048
|
-
value: rule.value,
|
|
1049
|
-
onChange: (event)=>updateRule(index, {
|
|
1050
|
-
value: rule.field === 'priceUsd' ? Number(event.target.value) : event.target.value
|
|
1051
|
-
}),
|
|
1052
|
-
size: "small",
|
|
1053
|
-
sx: {
|
|
1054
|
-
flex: 1
|
|
1055
|
-
},
|
|
1056
|
-
placeholder: rule.field === 'type' ? 'physical' : 'Value'
|
|
1057
|
-
}),
|
|
1058
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1059
|
-
size: "small",
|
|
1060
|
-
color: "error",
|
|
1061
|
-
onClick: ()=>updateRule(index, null),
|
|
1062
|
-
children: '✕'
|
|
1063
|
-
})
|
|
1064
|
-
]
|
|
1065
|
-
}, index)),
|
|
1066
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1067
|
-
size: "small",
|
|
1068
|
-
sx: {
|
|
1069
|
-
alignSelf: 'flex-start'
|
|
1070
|
-
},
|
|
1071
|
-
onClick: ()=>{
|
|
1072
|
-
var _ref;
|
|
1073
|
-
var _collectionDraft_rules;
|
|
1074
|
-
return updateRule((_ref = collectionDraft == null ? void 0 : (_collectionDraft_rules = collectionDraft.rules) == null ? void 0 : _collectionDraft_rules.length) != null ? _ref : 0, {});
|
|
1075
|
-
},
|
|
1076
|
-
children: 'Add rule'
|
|
1077
|
-
})
|
|
1078
|
-
]
|
|
1079
|
-
}),
|
|
1080
|
-
collectionError ? /*#__PURE__*/ _jsx(Alert, {
|
|
1081
|
-
severity: "warning",
|
|
1082
|
-
children: collectionError
|
|
1083
|
-
}) : null,
|
|
1084
|
-
collectionDraft ? /*#__PURE__*/ _jsxs(Stack, {
|
|
1085
|
-
direction: "row",
|
|
1086
|
-
spacing: 0.5,
|
|
1087
|
-
sx: {
|
|
1088
|
-
flexWrap: 'wrap'
|
|
1089
|
-
},
|
|
1090
|
-
children: [
|
|
1091
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
1092
|
-
variant: "caption",
|
|
1093
|
-
color: "text.secondary",
|
|
1094
|
-
children: `Matches ${countPrefix}${previewMatches.length} products: `
|
|
1095
|
-
}),
|
|
1096
|
-
previewMatches.slice(0, 6).map((product)=>/*#__PURE__*/ _jsx(Chip, {
|
|
1097
|
-
label: product.name,
|
|
1098
|
-
size: "small"
|
|
1099
|
-
}, product.$id)),
|
|
1100
|
-
previewMatches.length > 6 ? /*#__PURE__*/ _jsx(Typography, {
|
|
1101
|
-
variant: "caption",
|
|
1102
|
-
color: "text.secondary",
|
|
1103
|
-
children: `+${previewMatches.length - 6} more`
|
|
1104
|
-
}) : null
|
|
1105
|
-
]
|
|
1106
|
-
}) : null
|
|
1107
|
-
]
|
|
1108
|
-
}),
|
|
1109
|
-
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
1110
|
-
children: [
|
|
1111
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1112
|
-
onClick: ()=>setCollectionDraft(null),
|
|
1113
|
-
children: 'Cancel'
|
|
1114
|
-
}),
|
|
1115
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1116
|
-
variant: "contained",
|
|
1117
|
-
color: "primary",
|
|
1118
|
-
disabled: !(collectionDraft == null ? void 0 : collectionDraft.name.trim()) || Boolean(collectionError),
|
|
1119
|
-
onClick: handleCollectionSave,
|
|
1120
|
-
children: 'Save'
|
|
1121
|
-
})
|
|
1122
|
-
]
|
|
1123
|
-
})
|
|
1124
|
-
]
|
|
1317
|
+
/*#__PURE__*/ _jsx(CollectionDialog, {
|
|
1318
|
+
draft: collectionDraft,
|
|
1319
|
+
slug: draftSlug,
|
|
1320
|
+
slugTaken: slugTaken,
|
|
1321
|
+
error: collectionError,
|
|
1322
|
+
products: products,
|
|
1323
|
+
picked: collectionProducts,
|
|
1324
|
+
categories: categories,
|
|
1325
|
+
matches: previewMatches,
|
|
1326
|
+
countPrefix: countPrefix,
|
|
1327
|
+
setDraft: setCollectionDraft,
|
|
1328
|
+
onProducts: setCollectionProducts,
|
|
1329
|
+
onRule: updateRule,
|
|
1330
|
+
onSave: handleCollectionSave
|
|
1125
1331
|
})
|
|
1126
1332
|
]
|
|
1127
1333
|
});
|