@aglyn/plugins-marketplace 1.0.0-beta.291 → 1.0.0-beta.293
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/package.json +14 -14
- package/src/lib/components/listing-detail-editor.component.js +32 -10
- package/src/lib/components/listing-detail-editor.component.js.map +1 -1
- package/src/lib/components/listing-verification-request.component.js +32 -11
- package/src/lib/components/listing-verification-request.component.js.map +1 -1
- package/src/lib/components/org-seller-panel.component.js +121 -143
- package/src/lib/components/org-seller-panel.component.js.map +1 -1
- package/src/lib/components/publish-artifact-dialog.component.js +115 -115
- package/src/lib/components/publish-artifact-dialog.component.js.map +1 -1
- package/src/lib/components/publish-plugin-form.component.js +32 -36
- package/src/lib/components/publish-plugin-form.component.js.map +1 -1
- package/src/lib/components/publisher-agreement-checkbox.component.d.ts +56 -0
- package/src/lib/components/publisher-agreement-checkbox.component.js +121 -0
- package/src/lib/components/publisher-agreement-checkbox.component.js.map +1 -0
- package/src/lib/components/publisher-agreement-confirm-dialog.component.d.ts +45 -0
- package/src/lib/components/publisher-agreement-confirm-dialog.component.js +109 -0
- package/src/lib/components/publisher-agreement-confirm-dialog.component.js.map +1 -0
- package/src/lib/components/publisher-agreement-summary.component.d.ts +4 -3
- package/src/lib/components/publisher-agreement-summary.component.js +4 -3
- package/src/lib/components/publisher-agreement-summary.component.js.map +1 -1
- package/src/lib/components/starter-picker-shelf.component.d.ts +29 -0
- package/src/lib/components/starter-picker-shelf.component.js +317 -0
- package/src/lib/components/starter-picker-shelf.component.js.map +1 -0
- package/src/lib/declarations.server.js +2 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-starter-purchase.d.ts +31 -0
- package/src/lib/hooks/use-starter-purchase.js +101 -0
- package/src/lib/hooks/use-starter-purchase.js.map +1 -0
- package/src/lib/hooks/use-starter-search.d.ts +42 -0
- package/src/lib/hooks/use-starter-search.js +137 -0
- package/src/lib/hooks/use-starter-search.js.map +1 -0
- package/src/lib/model/listing-visibility.d.ts +17 -9
- package/src/lib/model/listing-visibility.js +18 -32
- package/src/lib/model/listing-visibility.js.map +1 -1
- package/src/lib/model/publisher-agreement.d.ts +105 -8
- package/src/lib/model/publisher-agreement.js +131 -24
- package/src/lib/model/publisher-agreement.js.map +1 -1
- package/src/lib/model/site-starter-listing.js +4 -1
- package/src/lib/model/site-starter-listing.js.map +1 -1
- package/src/lib/model/starter-query.d.ts +159 -0
- package/src/lib/model/starter-query.js +267 -0
- package/src/lib/model/starter-query.js.map +1 -0
- package/src/lib/plugin.js +12 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/checkout.js +45 -12
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/preview-image.js +38 -8
- package/src/lib/server/preview-image.js.map +1 -1
- package/src/lib/server/publish-dataset-schema.js +27 -2
- package/src/lib/server/publish-dataset-schema.js.map +1 -1
- package/src/lib/server/publish-email-starter.js +27 -2
- package/src/lib/server/publish-email-starter.js.map +1 -1
- package/src/lib/server/publish-email-template.js +27 -2
- package/src/lib/server/publish-email-template.js.map +1 -1
- package/src/lib/server/publish-layout.js +27 -2
- package/src/lib/server/publish-layout.js.map +1 -1
- package/src/lib/server/publish-plugin.js +120 -14
- package/src/lib/server/publish-plugin.js.map +1 -1
- package/src/lib/server/publish-preconditions.d.ts +13 -9
- package/src/lib/server/publish-preconditions.js +19 -45
- package/src/lib/server/publish-preconditions.js.map +1 -1
- package/src/lib/server/publish-starter.js +27 -2
- package/src/lib/server/publish-starter.js.map +1 -1
- package/src/lib/server/publish-template.js +27 -2
- package/src/lib/server/publish-template.js.map +1 -1
- package/src/lib/server/publish-theme.js +27 -2
- package/src/lib/server/publish-theme.js.map +1 -1
- package/src/lib/server/publish.js +27 -2
- package/src/lib/server/publish.js.map +1 -1
- package/src/lib/server/publisher-agreement-acceptance.d.ts +49 -0
- package/src/lib/server/publisher-agreement-acceptance.js +97 -0
- package/src/lib/server/publisher-agreement-acceptance.js.map +1 -0
- package/src/lib/server/publisher-profile-save.js +46 -97
- package/src/lib/server/publisher-profile-save.js.map +1 -1
- package/src/lib/server/site-starter-source.js +97 -25
- package/src/lib/server/site-starter-source.js.map +1 -1
- package/src/lib/server/starters.d.ts +31 -0
- package/src/lib/server/starters.js +170 -0
- package/src/lib/server/starters.js.map +1 -0
- package/src/lib/server/verification-request.js +33 -8
- package/src/lib/server/verification-request.js.map +1 -1
- package/src/lib/server.js +14 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/components/publisher-agreement-client.d.ts +0 -48
- package/src/lib/components/publisher-agreement-client.js +0 -93
- package/src/lib/components/publisher-agreement-client.js.map +0 -1
- package/src/lib/components/publisher-agreement-dialog.component.d.ts +0 -47
- package/src/lib/components/publisher-agreement-dialog.component.js +0 -222
- package/src/lib/components/publisher-agreement-dialog.component.js.map +0 -1
- package/src/lib/components/use-publisher-agreement-gate.d.ts +0 -58
- package/src/lib/components/use-publisher-agreement-gate.js +0 -166
- package/src/lib/components/use-publisher-agreement-gate.js.map +0 -1
- package/src/lib/model/publisher-agreement-refusal.d.ts +0 -46
- package/src/lib/model/publisher-agreement-refusal.js +0 -41
- package/src/lib/model/publisher-agreement-refusal.js.map +0 -1
|
@@ -22,7 +22,7 @@ import { useUser } from "@aglyn/tenant-feature-instance";
|
|
|
22
22
|
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
23
23
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack, TextField, Typography } from "@mui/material";
|
|
24
24
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
25
|
-
import
|
|
25
|
+
import { PublisherAgreementCheckbox, usePublisherAgreementConsent } from "./publisher-agreement-checkbox.component.js";
|
|
26
26
|
/**
|
|
27
27
|
* WHERE EACH KIND GOES, which is the knowledge that used to sit in the app
|
|
28
28
|
* (AGL-3080).
|
|
@@ -133,7 +133,7 @@ import usePublisherAgreementGate from "./use-publisher-agreement-gate.js";
|
|
|
133
133
|
* with no widget on that zone leaves the offer out entirely, which is why
|
|
134
134
|
* this may safely draw nothing for a kind it does not sell.
|
|
135
135
|
*/ export function PublishArtifactDialog({ artifact, onClose }) {
|
|
136
|
-
var _ref, _ref1, _ref2,
|
|
136
|
+
var _ref, _ref1, _ref2, _marketplacePriceCostNote;
|
|
137
137
|
// Memoized because it is a dependency of the publish callback: rebuilt
|
|
138
138
|
// every render, it would rebuild that callback every render too.
|
|
139
139
|
const target = useMemo(()=>artifact ? publishRequestFor(artifact) : null, [
|
|
@@ -146,13 +146,10 @@ import usePublisherAgreementGate from "./use-publisher-agreement-gate.js";
|
|
|
146
146
|
const [category, setCategory] = useState('');
|
|
147
147
|
const [price, setPrice] = useState('');
|
|
148
148
|
const [busy, setBusy] = useState(false);
|
|
149
|
-
// The publisher agreement (AGL-
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
const {
|
|
153
|
-
orgId: (_ref = artifact == null ? void 0 : artifact.orgId) != null ? _ref : null,
|
|
154
|
-
offer: Boolean(target)
|
|
155
|
-
});
|
|
149
|
+
// The publisher agreement, agreed to on this publish (AGL-4105): the box
|
|
150
|
+
// above the button, unticked for every artifact the dialog opens on.
|
|
151
|
+
const agreement = usePublisherAgreementConsent();
|
|
152
|
+
const { reset: resetAgreement } = agreement;
|
|
156
153
|
useEffect(()=>{
|
|
157
154
|
var _artifact_displayName, _artifact_description;
|
|
158
155
|
if (!artifact) return;
|
|
@@ -160,31 +157,29 @@ import usePublisherAgreementGate from "./use-publisher-agreement-gate.js";
|
|
|
160
157
|
setDescription((_artifact_description = artifact.description) != null ? _artifact_description : '');
|
|
161
158
|
setCategory('');
|
|
162
159
|
setPrice('');
|
|
160
|
+
resetAgreement();
|
|
163
161
|
}, [
|
|
164
|
-
artifact
|
|
162
|
+
artifact,
|
|
163
|
+
resetAgreement
|
|
165
164
|
]);
|
|
166
165
|
const handlePublish = useCallback(async ()=>{
|
|
167
|
-
if (!target || !name.trim() || busy) return;
|
|
166
|
+
if (!target || !name.trim() || busy || !agreement.consent) return;
|
|
168
167
|
setBusy(true);
|
|
169
168
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}));
|
|
185
|
-
// The agreement was shown and closed; it said why, and the form stays
|
|
186
|
-
// as it was for when they are ready.
|
|
187
|
-
if (declined) return;
|
|
169
|
+
const response = await authorizedFetch(user, `/api/${target.endpoint}`, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: {
|
|
172
|
+
'Content-Type': 'application/json'
|
|
173
|
+
},
|
|
174
|
+
body: JSON.stringify(_extends({}, target.payload, {
|
|
175
|
+
displayName: name.trim(),
|
|
176
|
+
description: description.trim(),
|
|
177
|
+
category: category.trim(),
|
|
178
|
+
priceUsd: Number(price) || 0,
|
|
179
|
+
agreement: agreement.consent
|
|
180
|
+
}))
|
|
181
|
+
});
|
|
182
|
+
const payload = await response.json().catch(()=>({}));
|
|
188
183
|
if (!response.ok) {
|
|
189
184
|
var _ref;
|
|
190
185
|
// 412 means a setup step is missing (publisher profile, payouts) —
|
|
@@ -198,6 +193,8 @@ import usePublisherAgreementGate from "./use-publisher-agreement-gate.js";
|
|
|
198
193
|
variant: 'success',
|
|
199
194
|
persist: false
|
|
200
195
|
});
|
|
196
|
+
// Each publish is its own agreement: the next one ticks the box again.
|
|
197
|
+
resetAgreement();
|
|
201
198
|
onClose();
|
|
202
199
|
} catch (error) {
|
|
203
200
|
console.error(error);
|
|
@@ -218,7 +215,8 @@ import usePublisherAgreementGate from "./use-publisher-agreement-gate.js";
|
|
|
218
215
|
user,
|
|
219
216
|
enqueueSnackbar,
|
|
220
217
|
onClose,
|
|
221
|
-
|
|
218
|
+
agreement.consent,
|
|
219
|
+
resetAgreement
|
|
222
220
|
]);
|
|
223
221
|
if (artifact && !target) {
|
|
224
222
|
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
@@ -247,99 +245,101 @@ import usePublisherAgreementGate from "./use-publisher-agreement-gate.js";
|
|
|
247
245
|
]
|
|
248
246
|
});
|
|
249
247
|
}
|
|
250
|
-
return /*#__PURE__*/
|
|
251
|
-
children:
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
/*#__PURE__*/
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
},
|
|
267
|
-
children: [
|
|
268
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
269
|
-
variant: "body2",
|
|
270
|
-
color: "text.secondary",
|
|
271
|
-
children: `Publishes the current published version of this ` + `${(_ref2 = target == null ? void 0 : target.noun) != null ? _ref2 : 'artifact'} so other organizations can ` + 'install it. Your site is unaffected.'
|
|
272
|
-
}),
|
|
273
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
274
|
-
autoFocus: true,
|
|
275
|
-
size: "small",
|
|
276
|
-
label: "Listing name",
|
|
277
|
-
value: name,
|
|
278
|
-
onChange: (event)=>setName(event.target.value),
|
|
279
|
-
disabled: busy,
|
|
280
|
-
fullWidth: true
|
|
281
|
-
}),
|
|
282
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
283
|
-
size: "small",
|
|
284
|
-
label: "Description",
|
|
285
|
-
value: description,
|
|
286
|
-
onChange: (event)=>setDescription(event.target.value),
|
|
287
|
-
disabled: busy,
|
|
288
|
-
multiline: true,
|
|
289
|
-
minRows: 2,
|
|
290
|
-
fullWidth: true
|
|
291
|
-
}),
|
|
292
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
293
|
-
size: "small",
|
|
294
|
-
label: "Category",
|
|
295
|
-
placeholder: (_ref3 = target == null ? void 0 : target.categoryPlaceholder) != null ? _ref3 : 'e.g. Marketing, Docs',
|
|
296
|
-
value: category,
|
|
297
|
-
onChange: (event)=>setCategory(event.target.value),
|
|
298
|
-
disabled: busy,
|
|
299
|
-
fullWidth: true
|
|
300
|
-
}),
|
|
301
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
302
|
-
size: "small",
|
|
303
|
-
label: "Price (USD)",
|
|
304
|
-
placeholder: "0 = free",
|
|
305
|
-
// The minimum price (AGL-2343). Marketplace checkout is a
|
|
306
|
-
// destination charge, so Stripe's fee comes out of the PLATFORM's
|
|
307
|
-
// balance while the seller is transferred a fixed share — at $1 the
|
|
308
|
-
// fee is larger than the whole platform cut. The publish route
|
|
309
|
-
// refuses anything under the floor, so the field says so before the
|
|
310
|
-
// publisher gets there and the button holds.
|
|
311
|
-
error: isBelowMarketplacePriceFloor(price),
|
|
312
|
-
helperText: (_marketplacePriceCostNote = marketplacePriceCostNote(price)) != null ? _marketplacePriceCostNote : marketplacePriceFloorHint('Paid listings need payouts set up on your marketplace profile.'),
|
|
313
|
-
value: price,
|
|
314
|
-
onChange: (event)=>setPrice(event.target.value.replace(/[^0-9]/g, '')),
|
|
315
|
-
disabled: busy,
|
|
316
|
-
fullWidth: true
|
|
317
|
-
})
|
|
318
|
-
]
|
|
319
|
-
})
|
|
320
|
-
}),
|
|
321
|
-
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
248
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
249
|
+
children: /*#__PURE__*/ _jsxs(Dialog, {
|
|
250
|
+
open: !!target,
|
|
251
|
+
onClose: busy ? undefined : onClose,
|
|
252
|
+
maxWidth: "xs",
|
|
253
|
+
fullWidth: true,
|
|
254
|
+
children: [
|
|
255
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
256
|
+
children: `Publish ${(_ref = target == null ? void 0 : target.noun) != null ? _ref : 'artifact'}`
|
|
257
|
+
}),
|
|
258
|
+
/*#__PURE__*/ _jsx(DialogContent, {
|
|
259
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
260
|
+
spacing: 2,
|
|
261
|
+
sx: {
|
|
262
|
+
pt: 1
|
|
263
|
+
},
|
|
322
264
|
children: [
|
|
323
|
-
/*#__PURE__*/ _jsx(
|
|
265
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
266
|
+
variant: "body2",
|
|
267
|
+
color: "text.secondary",
|
|
268
|
+
children: `Publishes the current published version of this ` + `${(_ref1 = target == null ? void 0 : target.noun) != null ? _ref1 : 'artifact'} so other organizations can ` + 'install it. Your site is unaffected.'
|
|
269
|
+
}),
|
|
270
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
271
|
+
autoFocus: true,
|
|
324
272
|
size: "small",
|
|
325
|
-
|
|
273
|
+
label: "Listing name",
|
|
274
|
+
value: name,
|
|
275
|
+
onChange: (event)=>setName(event.target.value),
|
|
326
276
|
disabled: busy,
|
|
327
|
-
|
|
277
|
+
fullWidth: true
|
|
328
278
|
}),
|
|
329
|
-
/*#__PURE__*/ _jsx(
|
|
279
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
330
280
|
size: "small",
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
281
|
+
label: "Description",
|
|
282
|
+
value: description,
|
|
283
|
+
onChange: (event)=>setDescription(event.target.value),
|
|
284
|
+
disabled: busy,
|
|
285
|
+
multiline: true,
|
|
286
|
+
minRows: 2,
|
|
287
|
+
fullWidth: true
|
|
288
|
+
}),
|
|
289
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
290
|
+
size: "small",
|
|
291
|
+
label: "Category",
|
|
292
|
+
placeholder: (_ref2 = target == null ? void 0 : target.categoryPlaceholder) != null ? _ref2 : 'e.g. Marketing, Docs',
|
|
293
|
+
value: category,
|
|
294
|
+
onChange: (event)=>setCategory(event.target.value),
|
|
295
|
+
disabled: busy,
|
|
296
|
+
fullWidth: true
|
|
297
|
+
}),
|
|
298
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
299
|
+
size: "small",
|
|
300
|
+
label: "Price (USD)",
|
|
301
|
+
placeholder: "0 = free",
|
|
302
|
+
// The minimum price (AGL-2343). Marketplace checkout is a
|
|
303
|
+
// destination charge, so Stripe's fee comes out of the PLATFORM's
|
|
304
|
+
// balance while the seller is transferred a fixed share — at $1 the
|
|
305
|
+
// fee is larger than the whole platform cut. The publish route
|
|
306
|
+
// refuses anything under the floor, so the field says so before the
|
|
307
|
+
// publisher gets there and the button holds.
|
|
308
|
+
error: isBelowMarketplacePriceFloor(price),
|
|
309
|
+
helperText: (_marketplacePriceCostNote = marketplacePriceCostNote(price)) != null ? _marketplacePriceCostNote : marketplacePriceFloorHint('Paid listings need payouts set up on your marketplace profile.'),
|
|
310
|
+
value: price,
|
|
311
|
+
onChange: (event)=>setPrice(event.target.value.replace(/[^0-9]/g, '')),
|
|
312
|
+
disabled: busy,
|
|
313
|
+
fullWidth: true
|
|
314
|
+
}),
|
|
315
|
+
/*#__PURE__*/ _jsx(PublisherAgreementCheckbox, {
|
|
316
|
+
checked: agreement.agreed,
|
|
317
|
+
onChange: agreement.setAgreed,
|
|
318
|
+
disabled: busy
|
|
336
319
|
})
|
|
337
320
|
]
|
|
338
321
|
})
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
322
|
+
}),
|
|
323
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
324
|
+
children: [
|
|
325
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
326
|
+
size: "small",
|
|
327
|
+
onClick: onClose,
|
|
328
|
+
disabled: busy,
|
|
329
|
+
children: 'Cancel'
|
|
330
|
+
}),
|
|
331
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
332
|
+
size: "small",
|
|
333
|
+
variant: "contained",
|
|
334
|
+
color: "primary",
|
|
335
|
+
disabled: busy || !name.trim() || isBelowMarketplacePriceFloor(price) || !agreement.agreed,
|
|
336
|
+
onClick: ()=>void handlePublish(),
|
|
337
|
+
children: busy ? 'Publishing…' : 'Publish'
|
|
338
|
+
})
|
|
339
|
+
]
|
|
340
|
+
})
|
|
341
|
+
]
|
|
342
|
+
})
|
|
343
343
|
});
|
|
344
344
|
}
|
|
345
345
|
PublishArtifactDialog.displayName = 'PublishArtifactDialog';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/publish-artifact-dialog.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n isBelowMarketplacePriceFloor,\n marketplacePriceCostNote,\n marketplacePriceFloorHint,\n} from '../model/listing-price-floor'\nimport type {\n ConsoleArtifactPublishZoneProps,\n ConsolePublishableArtifact,\n} from '@aglyn/aglyn'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport usePublisherAgreementGate from './use-publisher-agreement-gate'\n\n/** One kind's publish route, and the words a person reads about it. */\ninterface PublishRequest {\n /** Plugin API path, e.g. `marketplace/publish-layout`. */\n endpoint: string\n /** Extra body fields identifying what is being published. */\n payload: Record<string, unknown>\n /** Noun used in copy: \"layout\", \"component\", … */\n noun: string\n categoryPlaceholder?: string\n}\n\n/**\n * WHERE EACH KIND GOES, which is the knowledge that used to sit in the app\n * (AGL-3080).\n *\n * A console page hands over what it has — a kind, the scope holding it, the\n * document — and this is the only place that turns it into a request. The\n * pages that offer publishing named the endpoint, the payload key and the\n * noun themselves, which made them files that could not compile without a\n * marketplace and could not be right without being kept in step with one.\n *\n * ⚠️ A KIND THIS DOES NOT KNOW IS SAID OUT LOUD, not drawn as nothing. It\n * means a console offering to publish something this marketplace does not\n * sell — the two lists have gone out of step — and the person has already\n * clicked. Drawing nothing would make the control look broken with no way to\n * tell what happened, and guessing an endpoint from the kind would post to a\n * route that does not exist and report the 404 to the publisher.\n *\n * The control itself is a separate matter: a page only offers the publish\n * when this zone has a widget at all, so a workspace with no marketplace\n * never gets here.\n */\nfunction publishRequestFor(\n artifact: ConsolePublishableArtifact,\n): PublishRequest | null {\n const hostId = artifact.hostId ?? ''\n const orgId = artifact.orgId ?? ''\n const artifactId = artifact.artifactId ?? ''\n switch (artifact.kind) {\n case 'layout':\n return {\n endpoint: 'marketplace/publish-layout',\n payload: { hostId, layoutId: artifactId },\n noun: 'layout',\n categoryPlaceholder: 'e.g. Marketing, Docs, Storefront',\n }\n case 'component':\n return {\n endpoint: 'marketplace/publish',\n payload: { hostId, componentId: artifactId },\n noun: 'component',\n categoryPlaceholder: 'e.g. Hero, Footer, Pricing',\n }\n case 'site':\n return {\n endpoint: 'marketplace/publish-template',\n payload: { hostId },\n noun: 'site template',\n categoryPlaceholder: 'e.g. Portfolio, Restaurant',\n }\n case 'theme':\n return {\n endpoint: 'marketplace/publish-theme',\n payload: { hostId },\n noun: 'theme',\n }\n // Datasets are org-scoped, so this route takes orgId rather than hostId.\n case 'datasetSchema':\n return {\n endpoint: 'marketplace/publish-dataset-schema',\n payload: { orgId, datasetId: artifactId },\n noun: 'dataset schema',\n }\n case 'emailTemplate':\n return {\n endpoint: 'marketplace/publish-email-template',\n payload: { hostId, templateKey: artifactId },\n noun: 'email template',\n }\n case 'emailStarter':\n return {\n endpoint: 'marketplace/publish-email-starter',\n payload: { hostId, screenId: artifactId },\n noun: 'email starter',\n }\n default:\n return null\n }\n}\n\n/**\n * Publish an artifact to the marketplace (AGL-672, moved out of the console\n * app by AGL-3080).\n *\n * The publish form is identical across artifact types — name, description,\n * category, price — and only the endpoint and identifying fields differ, so\n * this takes both rather than being copied per type. Every gate that\n * matters (plan, publisher profile, payouts, host role) lives on the server;\n * this surfaces the server's message rather than trying to predict it.\n *\n * Drawn through the `hostArtifactPublish` zone, so the page that offers the\n * publish keeps the control that opens it and never imports this. A page\n * with no widget on that zone leaves the offer out entirely, which is why\n * this may safely draw nothing for a kind it does not sell.\n */\nexport function PublishArtifactDialog({\n artifact,\n onClose,\n}: ConsoleArtifactPublishZoneProps) {\n // Memoized because it is a dependency of the publish callback: rebuilt\n // every render, it would rebuild that callback every render too.\n const target = useMemo(\n () => (artifact ? publishRequestFor(artifact) : null),\n [artifact],\n )\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [category, setCategory] = useState('')\n const [price, setPrice] = useState('')\n const [busy, setBusy] = useState(false)\n // The publisher agreement (AGL-3407): offered as the dialog opens when the\n // org's acceptance is missing or stale, and presented again over the form\n // if the publish is refused for it — accepting sends the same publish.\n const { send: sendGated, dialog: agreementDialog } =\n usePublisherAgreementGate({\n orgId: artifact?.orgId ?? null,\n offer: Boolean(target),\n })\n\n useEffect(() => {\n if (!artifact) return\n setName(artifact.displayName ?? '')\n setDescription(artifact.description ?? '')\n setCategory('')\n setPrice('')\n }, [artifact])\n\n const handlePublish = useCallback(async () => {\n if (!target || !name.trim() || busy) return\n setBusy(true)\n try {\n // Serialized once, so a retry after accepting the agreement sends the\n // very bytes the first attempt did.\n const body = JSON.stringify({\n ...target.payload,\n displayName: name.trim(),\n description: description.trim(),\n category: category.trim(),\n priceUsd: Number(price) || 0,\n })\n const { response, payload, declined } = await sendGated(() =>\n authorizedFetch(user, `/api/${target.endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n }),\n )\n // The agreement was shown and closed; it said why, and the form stays\n // as it was for when they are ready.\n if (declined) return\n if (!response.ok) {\n // 412 means a setup step is missing (publisher profile, payouts) —\n // actionable, so it reads as a warning rather than an error.\n return void enqueueSnackbar(payload?.error ?? 'Publish failed', {\n variant: response.status === 412 ? 'warning' : 'error',\n allowDuplicate: true,\n })\n }\n enqueueSnackbar(`Published v${payload.version} to the marketplace`, {\n variant: 'success',\n persist: false,\n })\n onClose()\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n target,\n name,\n description,\n category,\n price,\n busy,\n user,\n enqueueSnackbar,\n onClose,\n sendGated,\n ])\n\n if (artifact && !target) {\n return (\n <Dialog open onClose={onClose} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Nothing publishes this'}</DialogTitle>\n <DialogContent>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This marketplace does not publish a ${artifact.kind}, so there ` +\n 'is nowhere to send it. Nothing was changed.'}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button size=\"small\" onClick={onClose}>\n {'Close'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n }\n\n return (\n <>\n <Dialog\n open={!!target}\n onClose={busy ? undefined : onClose}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{`Publish ${target?.noun ?? 'artifact'}`}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Publishes the current published version of this ` +\n `${target?.noun ?? 'artifact'} so other organizations can ` +\n 'install it. Your site is unaffected.'}\n </Typography>\n <TextField\n autoFocus\n size=\"small\"\n label=\"Listing name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n disabled={busy}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Description\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n disabled={busy}\n multiline\n minRows={2}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Category\"\n placeholder={\n target?.categoryPlaceholder ?? 'e.g. Marketing, Docs'\n }\n value={category}\n onChange={(event) => setCategory(event.target.value)}\n disabled={busy}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Price (USD)\"\n placeholder=\"0 = free\"\n // The minimum price (AGL-2343). Marketplace checkout is a\n // destination charge, so Stripe's fee comes out of the PLATFORM's\n // balance while the seller is transferred a fixed share — at $1 the\n // fee is larger than the whole platform cut. The publish route\n // refuses anything under the floor, so the field says so before the\n // publisher gets there and the button holds.\n error={isBelowMarketplacePriceFloor(price)}\n helperText={\n marketplacePriceCostNote(price) ??\n marketplacePriceFloorHint(\n 'Paid listings need payouts set up on your marketplace profile.',\n )\n }\n value={price}\n onChange={(event) =>\n setPrice(event.target.value.replace(/[^0-9]/g, ''))\n }\n disabled={busy}\n fullWidth\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button size=\"small\" onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n disabled={\n busy || !name.trim() || isBelowMarketplacePriceFloor(price)\n }\n onClick={() => void handlePublish()}\n >\n {busy ? 'Publishing…' : 'Publish'}\n </Button>\n </DialogActions>\n </Dialog>\n {agreementDialog}\n </>\n )\n}\n\nPublishArtifactDialog.displayName = 'PublishArtifactDialog'\n\nexport default PublishArtifactDialog\n"],"names":["isBelowMarketplacePriceFloor","marketplacePriceCostNote","marketplacePriceFloorHint","useSnackbar","useUser","authorizedFetch","Button","Dialog","DialogActions","DialogContent","DialogTitle","Stack","TextField","Typography","useCallback","useEffect","useMemo","useState","usePublisherAgreementGate","publishRequestFor","artifact","hostId","orgId","artifactId","kind","endpoint","payload","layoutId","noun","categoryPlaceholder","componentId","datasetId","templateKey","screenId","PublishArtifactDialog","onClose","target","data","user","enqueueSnackbar","name","setName","description","setDescription","category","setCategory","price","setPrice","busy","setBusy","send","sendGated","dialog","agreementDialog","offer","Boolean","displayName","handlePublish","trim","body","JSON","stringify","priceUsd","Number","response","declined","method","headers","ok","error","variant","status","allowDuplicate","version","persist","console","open","maxWidth","fullWidth","color","size","onClick","undefined","spacing","sx","pt","autoFocus","label","value","onChange","event","disabled","multiline","minRows","placeholder","helperText","replace"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/components/publish-artifact-dialog.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n isBelowMarketplacePriceFloor,\n marketplacePriceCostNote,\n marketplacePriceFloorHint,\n} from '../model/listing-price-floor'\nimport type {\n ConsoleArtifactPublishZoneProps,\n ConsolePublishableArtifact,\n} from '@aglyn/aglyn'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport {\n PublisherAgreementCheckbox,\n usePublisherAgreementConsent,\n} from './publisher-agreement-checkbox.component'\n\n/** One kind's publish route, and the words a person reads about it. */\ninterface PublishRequest {\n /** Plugin API path, e.g. `marketplace/publish-layout`. */\n endpoint: string\n /** Extra body fields identifying what is being published. */\n payload: Record<string, unknown>\n /** Noun used in copy: \"layout\", \"component\", … */\n noun: string\n categoryPlaceholder?: string\n}\n\n/**\n * WHERE EACH KIND GOES, which is the knowledge that used to sit in the app\n * (AGL-3080).\n *\n * A console page hands over what it has — a kind, the scope holding it, the\n * document — and this is the only place that turns it into a request. The\n * pages that offer publishing named the endpoint, the payload key and the\n * noun themselves, which made them files that could not compile without a\n * marketplace and could not be right without being kept in step with one.\n *\n * ⚠️ A KIND THIS DOES NOT KNOW IS SAID OUT LOUD, not drawn as nothing. It\n * means a console offering to publish something this marketplace does not\n * sell — the two lists have gone out of step — and the person has already\n * clicked. Drawing nothing would make the control look broken with no way to\n * tell what happened, and guessing an endpoint from the kind would post to a\n * route that does not exist and report the 404 to the publisher.\n *\n * The control itself is a separate matter: a page only offers the publish\n * when this zone has a widget at all, so a workspace with no marketplace\n * never gets here.\n */\nfunction publishRequestFor(\n artifact: ConsolePublishableArtifact,\n): PublishRequest | null {\n const hostId = artifact.hostId ?? ''\n const orgId = artifact.orgId ?? ''\n const artifactId = artifact.artifactId ?? ''\n switch (artifact.kind) {\n case 'layout':\n return {\n endpoint: 'marketplace/publish-layout',\n payload: { hostId, layoutId: artifactId },\n noun: 'layout',\n categoryPlaceholder: 'e.g. Marketing, Docs, Storefront',\n }\n case 'component':\n return {\n endpoint: 'marketplace/publish',\n payload: { hostId, componentId: artifactId },\n noun: 'component',\n categoryPlaceholder: 'e.g. Hero, Footer, Pricing',\n }\n case 'site':\n return {\n endpoint: 'marketplace/publish-template',\n payload: { hostId },\n noun: 'site template',\n categoryPlaceholder: 'e.g. Portfolio, Restaurant',\n }\n case 'theme':\n return {\n endpoint: 'marketplace/publish-theme',\n payload: { hostId },\n noun: 'theme',\n }\n // Datasets are org-scoped, so this route takes orgId rather than hostId.\n case 'datasetSchema':\n return {\n endpoint: 'marketplace/publish-dataset-schema',\n payload: { orgId, datasetId: artifactId },\n noun: 'dataset schema',\n }\n case 'emailTemplate':\n return {\n endpoint: 'marketplace/publish-email-template',\n payload: { hostId, templateKey: artifactId },\n noun: 'email template',\n }\n case 'emailStarter':\n return {\n endpoint: 'marketplace/publish-email-starter',\n payload: { hostId, screenId: artifactId },\n noun: 'email starter',\n }\n default:\n return null\n }\n}\n\n/**\n * Publish an artifact to the marketplace (AGL-672, moved out of the console\n * app by AGL-3080).\n *\n * The publish form is identical across artifact types — name, description,\n * category, price — and only the endpoint and identifying fields differ, so\n * this takes both rather than being copied per type. Every gate that\n * matters (plan, publisher profile, payouts, host role) lives on the server;\n * this surfaces the server's message rather than trying to predict it.\n *\n * Drawn through the `hostArtifactPublish` zone, so the page that offers the\n * publish keeps the control that opens it and never imports this. A page\n * with no widget on that zone leaves the offer out entirely, which is why\n * this may safely draw nothing for a kind it does not sell.\n */\nexport function PublishArtifactDialog({\n artifact,\n onClose,\n}: ConsoleArtifactPublishZoneProps) {\n // Memoized because it is a dependency of the publish callback: rebuilt\n // every render, it would rebuild that callback every render too.\n const target = useMemo(\n () => (artifact ? publishRequestFor(artifact) : null),\n [artifact],\n )\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [category, setCategory] = useState('')\n const [price, setPrice] = useState('')\n const [busy, setBusy] = useState(false)\n // The publisher agreement, agreed to on this publish (AGL-4105): the box\n // above the button, unticked for every artifact the dialog opens on.\n const agreement = usePublisherAgreementConsent()\n const { reset: resetAgreement } = agreement\n\n useEffect(() => {\n if (!artifact) return\n setName(artifact.displayName ?? '')\n setDescription(artifact.description ?? '')\n setCategory('')\n setPrice('')\n resetAgreement()\n }, [artifact, resetAgreement])\n\n const handlePublish = useCallback(async () => {\n if (!target || !name.trim() || busy || !agreement.consent) return\n setBusy(true)\n try {\n const response = await authorizedFetch(user, `/api/${target.endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...target.payload,\n displayName: name.trim(),\n description: description.trim(),\n category: category.trim(),\n priceUsd: Number(price) || 0,\n agreement: agreement.consent,\n }),\n })\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n // 412 means a setup step is missing (publisher profile, payouts) —\n // actionable, so it reads as a warning rather than an error.\n return void enqueueSnackbar(payload?.error ?? 'Publish failed', {\n variant: response.status === 412 ? 'warning' : 'error',\n allowDuplicate: true,\n })\n }\n enqueueSnackbar(`Published v${payload.version} to the marketplace`, {\n variant: 'success',\n persist: false,\n })\n // Each publish is its own agreement: the next one ticks the box again.\n resetAgreement()\n onClose()\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n target,\n name,\n description,\n category,\n price,\n busy,\n user,\n enqueueSnackbar,\n onClose,\n agreement.consent,\n resetAgreement,\n ])\n\n if (artifact && !target) {\n return (\n <Dialog open onClose={onClose} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Nothing publishes this'}</DialogTitle>\n <DialogContent>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This marketplace does not publish a ${artifact.kind}, so there ` +\n 'is nowhere to send it. Nothing was changed.'}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button size=\"small\" onClick={onClose}>\n {'Close'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n }\n\n return (\n <>\n <Dialog\n open={!!target}\n onClose={busy ? undefined : onClose}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{`Publish ${target?.noun ?? 'artifact'}`}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Publishes the current published version of this ` +\n `${target?.noun ?? 'artifact'} so other organizations can ` +\n 'install it. Your site is unaffected.'}\n </Typography>\n <TextField\n autoFocus\n size=\"small\"\n label=\"Listing name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n disabled={busy}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Description\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n disabled={busy}\n multiline\n minRows={2}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Category\"\n placeholder={\n target?.categoryPlaceholder ?? 'e.g. Marketing, Docs'\n }\n value={category}\n onChange={(event) => setCategory(event.target.value)}\n disabled={busy}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Price (USD)\"\n placeholder=\"0 = free\"\n // The minimum price (AGL-2343). Marketplace checkout is a\n // destination charge, so Stripe's fee comes out of the PLATFORM's\n // balance while the seller is transferred a fixed share — at $1 the\n // fee is larger than the whole platform cut. The publish route\n // refuses anything under the floor, so the field says so before the\n // publisher gets there and the button holds.\n error={isBelowMarketplacePriceFloor(price)}\n helperText={\n marketplacePriceCostNote(price) ??\n marketplacePriceFloorHint(\n 'Paid listings need payouts set up on your marketplace profile.',\n )\n }\n value={price}\n onChange={(event) =>\n setPrice(event.target.value.replace(/[^0-9]/g, ''))\n }\n disabled={busy}\n fullWidth\n />\n {/* Directly above Publish (AGL-4105), which waits for it. */}\n <PublisherAgreementCheckbox\n checked={agreement.agreed}\n onChange={agreement.setAgreed}\n disabled={busy}\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button size=\"small\" onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n disabled={\n busy ||\n !name.trim() ||\n isBelowMarketplacePriceFloor(price) ||\n !agreement.agreed\n }\n onClick={() => void handlePublish()}\n >\n {busy ? 'Publishing…' : 'Publish'}\n </Button>\n </DialogActions>\n </Dialog>\n </>\n )\n}\n\nPublishArtifactDialog.displayName = 'PublishArtifactDialog'\n\nexport default PublishArtifactDialog\n"],"names":["isBelowMarketplacePriceFloor","marketplacePriceCostNote","marketplacePriceFloorHint","useSnackbar","useUser","authorizedFetch","Button","Dialog","DialogActions","DialogContent","DialogTitle","Stack","TextField","Typography","useCallback","useEffect","useMemo","useState","PublisherAgreementCheckbox","usePublisherAgreementConsent","publishRequestFor","artifact","hostId","orgId","artifactId","kind","endpoint","payload","layoutId","noun","categoryPlaceholder","componentId","datasetId","templateKey","screenId","PublishArtifactDialog","onClose","target","data","user","enqueueSnackbar","name","setName","description","setDescription","category","setCategory","price","setPrice","busy","setBusy","agreement","reset","resetAgreement","displayName","handlePublish","trim","consent","response","method","headers","body","JSON","stringify","priceUsd","Number","json","catch","ok","error","variant","status","allowDuplicate","version","persist","console","open","maxWidth","fullWidth","color","size","onClick","undefined","spacing","sx","pt","autoFocus","label","value","onChange","event","disabled","multiline","minRows","placeholder","helperText","replace","checked","agreed","setAgreed"],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
|
30
30
|
import { inheritedMediaAlt } from "@aglyn/aglyn/app-utils/media-metadata";
|
|
31
31
|
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
32
32
|
import { listingPath } from "../model/marketplace-paths.js";
|
|
33
|
-
import
|
|
33
|
+
import { PublisherAgreementCheckbox, usePublisherAgreementConsent } from "./publisher-agreement-checkbox.component.js";
|
|
34
34
|
// Mirrors the server taxonomy; the server re-validates (the console cannot
|
|
35
35
|
// import the marketplace plugin's model — scope:app may not reach aglyn:addons).
|
|
36
36
|
const LISTING_CATEGORIES = [
|
|
@@ -230,15 +230,11 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
230
230
|
// Normalized on arrival so a plain string from anywhere else still reads.
|
|
231
231
|
const [problems, setProblems] = useState([]);
|
|
232
232
|
const [missingAttestations, setMissingAttestations] = useState([]);
|
|
233
|
+
// The publisher agreement, agreed to on this publish (AGL-4105): the box
|
|
234
|
+
// above the button. Never part of the draft — a draft restored after a
|
|
235
|
+
// reload asks again, as every publish does.
|
|
236
|
+
const agreement = usePublisherAgreementConsent();
|
|
233
237
|
const [agreementProblem, setAgreementProblem] = useState('');
|
|
234
|
-
// The publisher agreement (AGL-3407), asked for HERE rather than on the
|
|
235
|
-
// Publisher Profile tab: offered as the form opens when the org's
|
|
236
|
-
// acceptance is missing or stale, and presented again if the publish is
|
|
237
|
-
// refused for it — accepting sends the same bundle and fields again.
|
|
238
|
-
const agreement = usePublisherAgreementGate({
|
|
239
|
-
orgId,
|
|
240
|
-
offer: true
|
|
241
|
-
});
|
|
242
238
|
const [fieldErrors, setFieldErrors] = useState({});
|
|
243
239
|
const set = (key)=>(value)=>setDraft((current)=>_extends({}, current, {
|
|
244
240
|
[key]: value
|
|
@@ -339,6 +335,7 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
339
335
|
setMissingAttestations([]);
|
|
340
336
|
setAgreementProblem('');
|
|
341
337
|
setFieldErrors({});
|
|
338
|
+
if (!agreement.consent) return;
|
|
342
339
|
if (!bundleFile) {
|
|
343
340
|
setFieldErrors({
|
|
344
341
|
bundle: 'Choose a plugin bundle (.js) to upload.'
|
|
@@ -356,8 +353,6 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
356
353
|
try {
|
|
357
354
|
var _manifest_name, _ref, _ref1;
|
|
358
355
|
const bundle = await fileToBase64(bundleFile);
|
|
359
|
-
// Serialized once: a retry after the agreement is accepted sends the
|
|
360
|
-
// bytes this attempt did, not whatever the form holds by then.
|
|
361
356
|
const body = JSON.stringify(_extends({
|
|
362
357
|
orgId,
|
|
363
358
|
bundle,
|
|
@@ -378,14 +373,17 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
378
373
|
license: draft.license.trim()
|
|
379
374
|
} : {}, draft.repositoryUrl.trim() ? {
|
|
380
375
|
repositoryUrl: draft.repositoryUrl.trim()
|
|
381
|
-
} : {}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
376
|
+
} : {}, {
|
|
377
|
+
agreement: agreement.consent
|
|
378
|
+
}));
|
|
379
|
+
const response = await authorizedFetch(user, '/api/marketplace/publish-plugin', {
|
|
380
|
+
method: 'POST',
|
|
381
|
+
headers: {
|
|
382
|
+
'Content-Type': 'application/json'
|
|
383
|
+
},
|
|
384
|
+
body
|
|
385
|
+
});
|
|
386
|
+
const payload = await response.json().catch(()=>({}));
|
|
389
387
|
if (!response.ok) {
|
|
390
388
|
var _ref2;
|
|
391
389
|
if (Array.isArray(payload == null ? void 0 : payload.problems)) {
|
|
@@ -403,10 +401,9 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
403
401
|
if (Array.isArray(payload == null ? void 0 : payload.missingAttestations)) {
|
|
404
402
|
setMissingAttestations(payload.missingAttestations);
|
|
405
403
|
}
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
|
|
409
|
-
if (declined) {
|
|
404
|
+
// Refused for the agreement (AGL-4105): said under the box it is
|
|
405
|
+
// about, not in a toast, and the form keeps everything.
|
|
406
|
+
if (payload == null ? void 0 : payload.agreement) {
|
|
410
407
|
var _payload_error;
|
|
411
408
|
return void setAgreementProblem(String((_payload_error = payload.error) != null ? _payload_error : ''));
|
|
412
409
|
}
|
|
@@ -430,6 +427,7 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
430
427
|
// opened from, which said nothing about what had just happened; the
|
|
431
428
|
// listing shows the version now queued for review.
|
|
432
429
|
clearDraft();
|
|
430
|
+
agreement.reset();
|
|
433
431
|
enqueueSnackbar(`Published v${(_ref = payload == null ? void 0 : payload.version) != null ? _ref : '1'} — it is queued for review`, {
|
|
434
432
|
variant: 'success'
|
|
435
433
|
});
|
|
@@ -449,7 +447,7 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
449
447
|
// minimum off a 400. A private plugin has no price at all — its field is
|
|
450
448
|
// disabled and sends 0 — so it can never be blocked by this.
|
|
451
449
|
const priceBelowFloor = draft.visibility !== 'private' && isBelowMarketplacePriceFloor(draft.priceUsd);
|
|
452
|
-
const blocked = busy || !bundleFile || unattested.length > 0 || unfilledSubjects.length > 0 || repositoryInvalid || manifestIdMismatch || priceBelowFloor;
|
|
450
|
+
const blocked = busy || !bundleFile || unattested.length > 0 || unfilledSubjects.length > 0 || repositoryInvalid || manifestIdMismatch || priceBelowFloor || !agreement.agreed;
|
|
453
451
|
return /*#__PURE__*/ _jsxs(Stack, {
|
|
454
452
|
spacing: 2,
|
|
455
453
|
children: [
|
|
@@ -483,17 +481,6 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
483
481
|
onClose: ()=>setDraftRestored(false),
|
|
484
482
|
children: 'Picked up where you left off. Your bundle and manifest file are ' + 'not saved — choose them again before publishing.'
|
|
485
483
|
}) : null,
|
|
486
|
-
agreementProblem ? /*#__PURE__*/ _jsx(Alert, {
|
|
487
|
-
severity: "warning",
|
|
488
|
-
action: /*#__PURE__*/ _jsx(Button, {
|
|
489
|
-
color: "inherit",
|
|
490
|
-
size: "small",
|
|
491
|
-
onClick: agreement.review,
|
|
492
|
-
children: 'Review the agreement'
|
|
493
|
-
}),
|
|
494
|
-
children: agreementProblem
|
|
495
|
-
}) : null,
|
|
496
|
-
agreement.dialog,
|
|
497
484
|
/*#__PURE__*/ _jsx(CardDisplay, {
|
|
498
485
|
header: isUpdate ? 'The new bundle and manifest' : 'Bundle and manifest',
|
|
499
486
|
help: pluginDocsHelp('publisherHandbook', {
|
|
@@ -841,6 +828,15 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
841
828
|
]
|
|
842
829
|
})
|
|
843
830
|
}),
|
|
831
|
+
/*#__PURE__*/ _jsx(PublisherAgreementCheckbox, {
|
|
832
|
+
checked: agreement.agreed,
|
|
833
|
+
onChange: (checked)=>{
|
|
834
|
+
agreement.setAgreed(checked);
|
|
835
|
+
setAgreementProblem('');
|
|
836
|
+
},
|
|
837
|
+
disabled: busy,
|
|
838
|
+
error: agreementProblem || null
|
|
839
|
+
}),
|
|
844
840
|
/*#__PURE__*/ _jsxs(Stack, {
|
|
845
841
|
direction: "row",
|
|
846
842
|
spacing: 1,
|
|
@@ -853,7 +849,7 @@ const draftKey = (orgId, listingId)=>`aglyn.publish-plugin.draft.${orgId}${listi
|
|
|
853
849
|
color: "primary",
|
|
854
850
|
onClick: ()=>void submit(),
|
|
855
851
|
disabled: blocked,
|
|
856
|
-
children: busy ? 'Publishing…' : !bundleFile ? 'Choose a bundle' : unattested.length ? `Confirm ${unattested.length} more` : unfilledSubjects.length || repositoryInvalid ? 'Add a repository URL' : isUpdate ? 'Publish new version' : draft.visibility === 'private' ? 'Publish privately' : 'Publish plugin'
|
|
852
|
+
children: busy ? 'Publishing…' : !bundleFile ? 'Choose a bundle' : unattested.length ? `Confirm ${unattested.length} more` : unfilledSubjects.length || repositoryInvalid ? 'Add a repository URL' : !agreement.agreed ? 'Agree to publish' : isUpdate ? 'Publish new version' : draft.visibility === 'private' ? 'Publish privately' : 'Publish plugin'
|
|
857
853
|
}),
|
|
858
854
|
/*#__PURE__*/ _jsx(Button, {
|
|
859
855
|
disabled: busy,
|