@blocklet/launcher-workflow 2.0.47 → 2.1.0

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/lib/checkout.js CHANGED
@@ -4,20 +4,22 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireWildcard(require("react"));
8
7
  var _Dialog = _interopRequireDefault(require("@arcblock/ux/lib/Dialog"));
8
+ var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
9
9
  var _util = require("@blocklet/launcher-util/lib/util");
10
10
  var _constant = require("@blocklet/launcher-util/lib/constant");
11
11
  var _button = _interopRequireDefault(require("@blocklet/launcher-ux/lib/button"));
12
12
  var _useMobile = _interopRequireDefault(require("@blocklet/launcher-ux/lib/use-mobile"));
13
- var _payment = _interopRequireDefault(require("@did-pay/react/lib/payment"));
13
+ var _payment = _interopRequireDefault(require("@blocklet/payment/lib/payment"));
14
14
  var _styled = _interopRequireDefault(require("@emotion/styled"));
15
15
  var _Grid = _interopRequireDefault(require("@mui/material/Grid"));
16
16
  var _Skeleton = _interopRequireDefault(require("@mui/material/Skeleton"));
17
17
  var _propTypes = _interopRequireDefault(require("prop-types"));
18
+ var _react = _interopRequireWildcard(require("react"));
18
19
  var _reactRouterDom = require("react-router-dom");
19
20
  var _useAsync = _interopRequireDefault(require("react-use/lib/useAsync"));
20
21
  var _useSetState = _interopRequireDefault(require("react-use/lib/useSetState"));
22
+ var _dsbridge = _interopRequireDefault(require("dsbridge"));
21
23
  var _urlJoin = _interopRequireDefault(require("url-join"));
22
24
  var _confirm = _interopRequireDefault(require("@arcblock/ux/lib/Dialog/confirm"));
23
25
  var _agreement = _interopRequireDefault(require("./components/agreement"));
@@ -30,13 +32,13 @@ var _locale = require("./contexts/locale");
30
32
  var _request = _interopRequireDefault(require("./contexts/request"));
31
33
  var _session = require("./contexts/session");
32
34
  var _workflow = require("./contexts/workflow");
33
- var _query = _interopRequireDefault(require("./hooks/query"));
34
35
  var _util2 = require("./util");
35
36
  var _jsxRuntime = require("react/jsx-runtime");
36
37
  var _templateObject;
37
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
38
+ /* eslint-disable react-hooks/exhaustive-deps */
38
39
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
39
40
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
41
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
40
42
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
41
43
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
42
44
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -88,22 +90,23 @@ function CheckoutPage(_ref) {
88
90
  const {
89
91
  session
90
92
  } = (0, _session.useSessionContext)();
91
- const [showAgreement, setShowAgreement] = (0, _react.useState)(false);
92
- const [showPayment, setShowPayment] = (0, _react.useState)(false);
93
- const [paying, setPaying] = (0, _react.useState)(false);
94
- const [agree, setAgree] = (0, _react.useState)(false);
95
- const [showAgreeHint, setShowAgreeHint] = (0, _react.useState)(false);
96
- const [showPaidDialog, setShowPaidDialog] = (0, _useSetState.default)({
97
- open: false,
98
- nftId: ''
93
+ const [state, setState] = (0, _useSetState.default)({
94
+ showAgreement: false,
95
+ showPayment: false,
96
+ showAgreeHint: false,
97
+ showPaidDialog: {
98
+ open: false,
99
+ nftId: ''
100
+ },
101
+ agreed: false,
102
+ paying: false,
103
+ paymentMethod: null
99
104
  });
100
105
  const navigate = (0, _reactRouterDom.useNavigate)();
101
106
  const {
102
107
  create
103
108
  } = (0, _request.default)();
104
- const [paymentMethod, setPaymentMethod] = (0, _react.useState)(null);
105
- const query = (0, _query.default)();
106
- const [searchParams] = (0, _reactRouterDom.useSearchParams)();
109
+ const [params] = (0, _reactRouterDom.useSearchParams)();
107
110
  const {
108
111
  mobileSize,
109
112
  isMobile
@@ -111,14 +114,21 @@ function CheckoutPage(_ref) {
111
114
  const {
112
115
  routerPrefix,
113
116
  didPayPrefix,
114
- embed
117
+ embed,
118
+ isPurchaseOnly
115
119
  } = (0, _workflow.useWorkflowContext)();
120
+ (0, _react.useEffect)(() => {
121
+ if (session.user && !isPurchaseOnly) {
122
+ _util2.launchSession.connect(api, routerPrefix, sessionId, session.user.did);
123
+ }
124
+ }, [session.user]);
116
125
  const api = create({
117
126
  baseURL: didPayPrefix
118
127
  });
119
128
  const enableBlockletAgreement = !!blocklet;
120
- const planId = query.get('planId');
121
- const state = (0, _useAsync.default)(async () => {
129
+ const planId = params.get('planId');
130
+ const sessionId = params.get('sessionId');
131
+ const context = (0, _useAsync.default)(async () => {
122
132
  try {
123
133
  const [{
124
134
  data: {
@@ -130,7 +140,9 @@ function CheckoutPage(_ref) {
130
140
  }
131
141
  }] = await Promise.all([api.get('/payment-methods'), api.get("/plans/".concat(planId))]);
132
142
  if (methods.length > 0) {
133
- setPaymentMethod(methods[0]);
143
+ setState({
144
+ paymentMethod: methods[0]
145
+ });
134
146
  }
135
147
  return {
136
148
  methods,
@@ -145,93 +157,95 @@ function CheckoutPage(_ref) {
145
157
  }
146
158
  });
147
159
  const switchPayment = method => {
148
- setPaymentMethod(method);
160
+ setState({
161
+ paymentMethod: method
162
+ });
149
163
  };
150
164
  const handleCancelPay = () => {
151
- setShowPayment(false);
152
- setPaying(false);
165
+ setState({
166
+ showPayment: false,
167
+ paying: false
168
+ });
153
169
  };
154
170
  const handlePay = async () => {
155
- if (enableBlockletAgreement && !agree) {
156
- setShowAgreeHint(true);
171
+ if (enableBlockletAgreement && !state.agreed) {
172
+ setState({
173
+ showAgreeHint: true
174
+ });
157
175
  setTimeout(() => {
158
- setShowAgreeHint(false);
176
+ setState({
177
+ showAgreeHint: false
178
+ });
159
179
  }, 2000);
160
180
  return;
161
181
  }
162
- if (session.user) {
163
- setShowPayment(true);
164
- setPaying(true);
165
- return;
166
- }
167
- setPaying(true);
168
- if ((paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.provider.name) === 'ocap') {
169
- const paymentTokenURL = "/did/purchase/token?productId=".concat(planId, "&paymentMethodId=").concat(paymentMethod._id);
170
- const {
171
- data
172
- } = await api.get(paymentTokenURL);
173
- session.login({
174
- onSuccess: (results, decrypt) => {
175
- const [, purchaseResult] = results;
176
- return handlePaid(purchaseResult, decrypt);
177
- },
178
- onCancel: () => handleCancelPay(),
179
- extraParams: {
180
- nw: data.url,
181
- forceConnected: false,
182
- saveConnect: false
183
- }
184
- });
182
+ setState({
183
+ showPayment: true,
184
+ paying: true
185
+ });
186
+ };
187
+ const handleConnected = result => {
188
+ if (isPurchaseOnly) {
189
+ session.refresh();
185
190
  return;
186
191
  }
187
- session.login({
188
- onSuccess: () => {
189
- setShowPayment(true);
190
- },
191
- onCancel: () => handleCancelPay(),
192
- extraParams: {
193
- forceConnected: false,
194
- saveConnect: false
195
- }
192
+ _util2.launchSession.connect(api, routerPrefix, sessionId, result.did, () => {
193
+ session.refresh();
196
194
  });
197
195
  };
198
196
  const handlePaid = async _ref2 => {
199
197
  let {
200
198
  nftId,
201
- nftState
199
+ nftState,
200
+ paymentId
202
201
  } = _ref2;
203
202
  if ((nftState.tags || []).includes(_constant.NFT_TYPE_SERVERLESS)) {
204
203
  if (!embed) {
205
- setShowPaidDialog({
206
- open: true,
207
- nftId
204
+ setState({
205
+ showPaidDialog: {
206
+ open: true,
207
+ nftId
208
+ }
208
209
  });
209
210
  handleCancelPay();
210
211
  return;
211
212
  }
212
- searchParams.set('launchType', 'serverless');
213
+ params.set('launchType', 'serverless');
214
+ }
215
+ if (isPurchaseOnly) {
216
+ handleCancelPay();
217
+ _dsbridge.default.call('arcClosePage');
218
+ return;
213
219
  }
214
- navigate({
215
- pathname: (0, _urlJoin.default)(routerPrefix, "/launch/".concat(nftId)),
216
- search: searchParams.toString()
220
+ _util2.launchSession.pay(api, routerPrefix, sessionId, nftId, 'purchase', paymentId, err => {
221
+ handleCancelPay();
222
+ if (err) {
223
+ _Toast.default.error(err.message);
224
+ } else {
225
+ navigate({
226
+ pathname: (0, _urlJoin.default)(routerPrefix, "/launch/".concat(nftId)),
227
+ search: params.toString()
228
+ });
229
+ }
217
230
  });
218
- handleCancelPay();
219
231
  };
220
232
  const handlePayFailed = () => {
221
233
  // TODO: Toast 错误
222
- handleCancelPay(false);
234
+ handleCancelPay();
223
235
  };
224
236
  const calculateTotalPayment = prices => {
225
- if (!paymentMethod) {
237
+ if (!state.paymentMethod) {
226
238
  return '';
227
239
  }
228
- return (0, _util2.getPrice)(prices, paymentMethod.provider.name);
240
+ return (0, _util2.getPrice)(prices, state.paymentMethod.provider.name);
229
241
  };
230
- const toggleAgreement = () => setAgree(!agree);
242
+ const toggleAgreement = () => setState({
243
+ agreed: !state.agreed
244
+ });
231
245
  const {
232
246
  methods,
233
247
  plan
234
- } = state.loading ? {} : state.value;
248
+ } = context.loading ? {} : context.value;
235
249
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(Container, {
236
250
  mobileSize: mobileSize,
237
251
  enableBlockletAgreement: enableBlockletAgreement,
@@ -242,7 +256,7 @@ function CheckoutPage(_ref) {
242
256
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
243
257
  className: "header",
244
258
  children: t('common.details')
245
- }), state.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
259
+ }), context.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
246
260
  className: "skeleton",
247
261
  sx: {
248
262
  width: '100%',
@@ -269,7 +283,7 @@ function CheckoutPage(_ref) {
269
283
  })]
270
284
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
271
285
  className: "divider"
272
- }), state.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
286
+ }), context.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
273
287
  className: "skeleton",
274
288
  sx: {
275
289
  width: '100%',
@@ -291,7 +305,7 @@ function CheckoutPage(_ref) {
291
305
  })]
292
306
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
293
307
  className: "payment-method space",
294
- children: state.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
308
+ children: context.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Skeleton.default, {
295
309
  className: "skeleton",
296
310
  sx: {
297
311
  width: '100%',
@@ -317,7 +331,7 @@ function CheckoutPage(_ref) {
317
331
  xl: 2,
318
332
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_checkbox.default, {
319
333
  label: method.name[locale],
320
- checked: paymentMethod._id === method._id,
334
+ checked: state.paymentMethod._id === method._id,
321
335
  onClick: () => switchPayment(method)
322
336
  })
323
337
  }, method._id))
@@ -330,8 +344,8 @@ function CheckoutPage(_ref) {
330
344
  children: [enableBlockletAgreement && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
331
345
  className: "agreement",
332
346
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_checkbox.default, {
333
- checked: agree,
334
- showHint: showAgreeHint,
347
+ checked: state.agreed,
348
+ showHint: state.showAgreeHint,
335
349
  onClick: () => toggleAgreement(),
336
350
  label: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
337
351
  style: {
@@ -342,7 +356,9 @@ function CheckoutPage(_ref) {
342
356
  className: "agreement-label",
343
357
  onClick: e => {
344
358
  e.stopPropagation();
345
- setShowAgreement(true);
359
+ setState({
360
+ showAgreement: true
361
+ });
346
362
  },
347
363
  children: t('checkout.agreement', {
348
364
  name: (0, _util.getBlockletDisplayName)(blocklet)
@@ -358,25 +374,26 @@ function CheckoutPage(_ref) {
358
374
  onClick: () => navigate(-1),
359
375
  children: t('common.previous')
360
376
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.default, {
361
- loading: paying,
377
+ loading: state.paying,
362
378
  className: "button-pay",
363
- disabled: paying || showPayment || !planId || !paymentMethod,
379
+ disabled: state.paying || state.showPayment || !planId || !state.paymentMethod,
364
380
  variant: "contained",
365
381
  onClick: handlePay,
366
382
  children: t('common.pay')
367
383
  })]
368
384
  })]
369
- }), showPayment && /*#__PURE__*/(0, _jsxRuntime.jsx)(_payment.default, {
385
+ }), state.showPayment && /*#__PURE__*/(0, _jsxRuntime.jsx)(_payment.default, {
370
386
  baseURL: didPayPrefix,
371
- method: paymentMethod,
387
+ method: state.paymentMethod,
372
388
  userDid: session === null || session === void 0 ? void 0 : (_session$user = session.user) === null || _session$user === void 0 ? void 0 : _session$user.did,
373
389
  productId: planId,
374
390
  useSocket: false,
391
+ onConnect: handleConnected,
375
392
  onComplete: handlePaid,
376
393
  onFailed: handlePayFailed,
377
394
  onCancel: handleCancelPay
378
395
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_confirm.default, {
379
- open: showPaidDialog.open,
396
+ open: state.showPaidDialog.open,
380
397
  disableEscapeKeyDown: true,
381
398
  title: t('purchase.serverlessDialog.title'),
382
399
  confirmButton: {
@@ -388,20 +405,27 @@ function CheckoutPage(_ref) {
388
405
  minWidth: isMobile ? undefined : 600
389
406
  }
390
407
  },
391
- onCancel: () => setShowPaidDialog(false),
408
+ onCancel: () => setState({
409
+ showPaidDialog: {
410
+ open: false,
411
+ nftId: ''
412
+ }
413
+ }),
392
414
  showCancelButton: false,
393
415
  onConfirm: () => {
394
416
  const url = new URL(_util2.BLOCKLET_STORE_URL);
395
- url.searchParams.set('launcher_nft_id', showPaidDialog.nftId);
417
+ url.searchParams.set('launcher_nft_id', state.showPaidDialog.nftId);
396
418
  window.location = url.href;
397
419
  },
398
420
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
399
421
  children: t('purchase.serverlessDialog.purchaseServerlessSuccess')
400
422
  })
401
423
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Dialog.default, {
402
- open: showAgreement,
424
+ open: state.showAgreement,
403
425
  title: t('common.agreement'),
404
- onClose: () => setShowAgreement(false),
426
+ onClose: () => setState({
427
+ showAgreement: false
428
+ }),
405
429
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_agreement.default, {})
406
430
  })]
407
431
  });
@@ -12,7 +12,7 @@ var _useInterval = _interopRequireDefault(require("react-use/lib/useInterval"));
12
12
  var _lodash2 = _interopRequireDefault(require("lodash.throttle"));
13
13
  var _styled = _interopRequireDefault(require("@emotion/styled"));
14
14
  var _Button = _interopRequireDefault(require("@arcblock/ux/lib/Button"));
15
- var _Spinner = _interopRequireDefault(require("@arcblock/ux/lib/Spinner"));
15
+ var _CircularProgress = _interopRequireDefault(require("@mui/material/CircularProgress"));
16
16
  var _AnimationWaiter = _interopRequireDefault(require("@arcblock/ux/lib/AnimationWaiter"));
17
17
  var _constant = require("@blocklet/launcher-util/lib/constant");
18
18
  var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
@@ -177,7 +177,7 @@ function LaunchDedicated(_ref) {
177
177
  disableBack: true
178
178
  }), launchState.status === STATUS.waiting && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
179
179
  className: "center",
180
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Spinner.default, {})
180
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {})
181
181
  }), launchState.status === STATUS.launching && /*#__PURE__*/(0, _jsxRuntime.jsx)(WaiterContainer, {
182
182
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_AnimationWaiter.default, {
183
183
  message: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
@@ -202,8 +202,8 @@ function LaunchDedicated(_ref) {
202
202
  footer: successful ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(LinkEle, {
203
203
  href: launchState.appUrl,
204
204
  rel: "noreferrer",
205
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Spinner.default, {
206
- size: [16, 10],
205
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {
206
+ size: 16,
207
207
  style: {
208
208
  marginRight: 14
209
209
  }
@@ -6,16 +6,15 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = LaunchServerless;
7
7
  var _styled = _interopRequireDefault(require("@emotion/styled"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
- var _react = require("react");
9
+ var _react = _interopRequireDefault(require("react"));
10
10
  var _reactRouterDom = require("react-router-dom");
11
11
  var _useAsync = _interopRequireDefault(require("react-use/lib/useAsync"));
12
- var _ServerLogoNotext = _interopRequireDefault(require("@arcblock/icons/lib/ServerLogoNotext"));
13
12
  var _pageHeader = _interopRequireDefault(require("@blocklet/launcher-layout/lib/page-header"));
13
+ var _formatError = _interopRequireDefault(require("@blocklet/launcher-util/lib/format-error"));
14
+ var _launchResultMessage = _interopRequireDefault(require("@blocklet/launcher-layout/lib/launch-result-message"));
14
15
  var _button = _interopRequireDefault(require("@blocklet/launcher-ux/lib/button"));
15
- var _CircularProgress = _interopRequireDefault(require("@mui/material/CircularProgress"));
16
16
  var _locale = require("../contexts/locale");
17
17
  var _request = _interopRequireDefault(require("../contexts/request"));
18
- var _query = _interopRequireDefault(require("../hooks/query"));
19
18
  var _util = require("../util");
20
19
  var _jsxRuntime = require("react/jsx-runtime");
21
20
  var _templateObject;
@@ -28,18 +27,18 @@ function LaunchServerless(_ref) {
28
27
  const {
29
28
  t,
30
29
  locale
31
- } = (0, _react.useContext)(_locale.LocaleContext);
30
+ } = (0, _locale.useLocaleContext)();
32
31
  const {
33
32
  api
34
33
  } = (0, _request.default)();
35
34
  const [searchParams] = (0, _reactRouterDom.useSearchParams)();
36
- const query = (0, _query.default)();
35
+ const sessionId = searchParams.get('sessionId');
37
36
  const state = (0, _useAsync.default)(async () => {
38
37
  const {
39
38
  data: {
40
39
  instance
41
40
  }
42
- } = await api.post("/serverless/".concat(nftId, "/allocate"));
41
+ } = await api.post("/serverless/".concat(nftId, "/allocate?sessionId=").concat(sessionId));
43
42
  setTimeout(() => {
44
43
  var _window$blocklet;
45
44
  window.location = (0, _util.getLaunchBlockletUrl)({
@@ -48,55 +47,48 @@ function LaunchServerless(_ref) {
48
47
  locale,
49
48
  launchType: 'serverless',
50
49
  nftId,
50
+ sessionId,
51
51
  chainHost: (_window$blocklet = window.blocklet) === null || _window$blocklet === void 0 ? void 0 : _window$blocklet.CHAIN_HOST,
52
- from: query.get('from')
52
+ from: searchParams.get('from')
53
53
  });
54
- }, 3000);
54
+ }, 1000);
55
+ return instance;
55
56
  });
56
57
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(Container, {
57
58
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_pageHeader.default, {
58
59
  title: t('launch.pageTitle')
59
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
60
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
60
61
  className: "page-body",
61
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
62
- className: "page-logo",
63
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ServerLogoNotext.default, {
64
- style: {
65
- width: 48,
66
- height: 48
67
- }
68
- })
69
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
62
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
70
63
  className: "content",
71
- children: [state.loading && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
72
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {
73
- size: "3.5rem"
74
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
75
- className: "description",
76
- children: t('prepare.serverless.preparing')
77
- })]
78
- }), !state.loading && !state.error && t('prepare.serverless.prepared'), state.error && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
79
- style: {
80
- display: 'flex',
81
- flexDirection: 'column',
82
- justifyContent: 'center'
83
- },
84
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
85
- children: t('prepare.serverless.prepareFailed')
86
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.default, {
64
+ children: [state.loading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_launchResultMessage.default, {
65
+ variant: "loading",
66
+ title: t('prepare.serverless.allocate'),
67
+ subTitle: t('prepare.serverless.preparing')
68
+ }), state.error && /*#__PURE__*/(0, _jsxRuntime.jsx)(_launchResultMessage.default, {
69
+ variant: "error",
70
+ title: t('prepare.serverless.allocate'),
71
+ subTitle: t('prepare.serverless.prepareFailed', {
72
+ error: (0, _formatError.default)(state.error)
73
+ }),
74
+ footer: /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.default, {
87
75
  size: "small",
88
76
  style: {
89
77
  marginTop: '8px'
90
78
  },
91
79
  onClick: () => window.location.reload(),
92
80
  children: t('common.retry')
93
- })]
81
+ })
82
+ }), state.value && /*#__PURE__*/(0, _jsxRuntime.jsx)(_launchResultMessage.default, {
83
+ variant: "success",
84
+ title: t('prepare.serverless.allocate'),
85
+ subTitle: t('prepare.serverless.prepared')
94
86
  })]
95
- })]
87
+ })
96
88
  })]
97
89
  });
98
90
  }
99
- const Container = _styled.default.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n\n .page-logo {\n display: flex;\n justify-content: center;\n margin-top: 62px;\n ", " {\n margin-top: 48px;\n }\n }\n\n .page-body {\n .content {\n display: flex;\n align-items: center;\n flex-direction: column;\n text-align: center;\n margin-top: 64px;\n\n .loading-description {\n margin-top: 8px;\n }\n }\n }\n"])), props => props.theme.breakpoints.down('md'));
91
+ const Container = _styled.default.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n\n .page-logo {\n display: flex;\n justify-content: center;\n margin-top: 62px;\n ", " {\n margin-top: 48px;\n }\n }\n\n .page-body {\n margin-top: 128px;\n\n .content {\n display: flex;\n align-items: center;\n flex-direction: column;\n text-align: center;\n\n .loading-description {\n margin-top: 8px;\n }\n }\n }\n"])), props => props.theme.breakpoints.down('md'));
100
92
  LaunchServerless.propTypes = {
101
93
  nftId: _propTypes.default.string.isRequired
102
94
  };
@@ -7,6 +7,8 @@ exports.WorkflowProvider = WorkflowProvider;
7
7
  exports.useWorkflowContext = useWorkflowContext;
8
8
  var _react = require("react");
9
9
  var _propTypes = _interopRequireDefault(require("prop-types"));
10
+ var _reactRouterDom = require("react-router-dom");
11
+ var _useBrowser = _interopRequireDefault(require("@arcblock/react-hooks/lib/useBrowser"));
10
12
  var _locale = require("./locale");
11
13
  var _request = require("./request");
12
14
  var _locales = require("../locales");
@@ -25,11 +27,16 @@ function WorkflowProvider(_ref) {
25
27
  locale,
26
28
  children
27
29
  } = _ref;
30
+ const [params] = (0, _reactRouterDom.useSearchParams)();
31
+ const browser = (0, _useBrowser.default)();
32
+ // FIXME: @wangshijun this is not working in android wallet
33
+ const isPurchaseOnly = browser.wallet && params.get('source') === 'acquireUrl' || !params.get('blocklet_meta_url');
28
34
  const value = {
29
35
  embed,
30
36
  baseURL,
31
37
  didPayPrefix,
32
- routerPrefix
38
+ routerPrefix,
39
+ isPurchaseOnly
33
40
  };
34
41
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(Provider, {
35
42
  value: value,
package/lib/locales/en.js CHANGED
@@ -33,9 +33,10 @@ module.exports = {
33
33
  },
34
34
  prepare: {
35
35
  serverless: {
36
- preparing: 'Preparing...',
37
- prepared: 'The Blocklet Space is ready, redirecting...',
38
- prepareFailed: 'Prepare for instance failure!'
36
+ allocate: 'Waiting for space',
37
+ preparing: 'Preparing blocklet space for you launch request...',
38
+ prepared: 'The blocklet space is ready, redirecting...',
39
+ prepareFailed: 'Failed to prepare space! {error}'
39
40
  }
40
41
  },
41
42
  launch: {
package/lib/locales/zh.js CHANGED
@@ -33,9 +33,10 @@ module.exports = {
33
33
  },
34
34
  prepare: {
35
35
  serverless: {
36
- preparing: '准备中...',
36
+ allocate: '等待空间就绪',
37
+ preparing: '正在为应用启动准备空间...',
37
38
  prepared: '已准备好应用空间,跳转中...',
38
- prepareFailed: '准备空间失败!'
39
+ prepareFailed: '准备空间失败! {error}'
39
40
  }
40
41
  },
41
42
  launch: {
package/lib/purchase.js CHANGED
@@ -4,10 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireWildcard(require("react"));
8
- var _Connect = _interopRequireDefault(require("@arcblock/did-connect/lib/Connect"));
7
+ var _Connect = _interopRequireWildcard(require("@arcblock/did-connect/lib/Connect"));
9
8
  var _Button = _interopRequireDefault(require("@arcblock/ux/lib/Button"));
10
9
  var _Center = _interopRequireDefault(require("@arcblock/ux/lib/Center"));
10
+ var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
11
11
  var _compactLayout = _interopRequireDefault(require("@blocklet/launcher-layout/lib/compact-layout"));
12
12
  var _constant = require("@blocklet/launcher-util/lib/constant");
13
13
  var _useMobile = _interopRequireDefault(require("@blocklet/launcher-ux/lib/use-mobile"));
@@ -17,12 +17,13 @@ var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
17
17
  var _reactSplide = require("@splidejs/react-splide");
18
18
  var _splideExtensionGrid = require("@splidejs/splide-extension-grid");
19
19
  var _propTypes = _interopRequireDefault(require("prop-types"));
20
+ var _react = _interopRequireWildcard(require("react"));
20
21
  var _reactRouterDom = require("react-router-dom");
21
- var _useAsync = _interopRequireDefault(require("react-use/lib/useAsync"));
22
22
  var _useMeasure = _interopRequireDefault(require("react-use/lib/useMeasure"));
23
23
  var _useSetState = _interopRequireDefault(require("react-use/lib/useSetState"));
24
24
  var _urlJoin = _interopRequireDefault(require("url-join"));
25
25
  require("@splidejs/splide/dist/css/splide.min.css");
26
+ var _formatError = _interopRequireDefault(require("@blocklet/launcher-util/lib/format-error"));
26
27
  var _layout = _interopRequireDefault(require("./components/layout"));
27
28
  var _body = _interopRequireDefault(require("./components/layout/body"));
28
29
  var _footer = _interopRequireDefault(require("./components/layout/footer"));
@@ -32,8 +33,10 @@ var _locale = require("./contexts/locale");
32
33
  var _request = _interopRequireDefault(require("./contexts/request"));
33
34
  var _session = require("./contexts/session");
34
35
  var _workflow = require("./contexts/workflow");
36
+ var _util = require("./util");
35
37
  var _jsxRuntime = require("react/jsx-runtime");
36
38
  var _templateObject;
39
+ /* eslint-disable react-hooks/exhaustive-deps */
37
40
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
38
41
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
39
42
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -69,8 +72,17 @@ PrevIcon.defaultProps = {
69
72
  };
70
73
  const SLIDE_WIDTH = 300;
71
74
  const SLIDE_MIN_WIDTH = 280;
75
+ const getSlideConfig = (maxLength, planLength) => {
76
+ const factor = Math.min(maxLength, planLength);
77
+ const width = factor < 3 ? SLIDE_MIN_WIDTH : SLIDE_WIDTH;
78
+ return {
79
+ perPage: factor,
80
+ width: "".concat(factor * width, "px"),
81
+ gap: '24px'
82
+ };
83
+ };
72
84
  function PurchasePage(_ref) {
73
- var _planState$value4, _planState$value5;
85
+ var _state$plans3, _session$user;
74
86
  let {
75
87
  disableBack
76
88
  } = _ref;
@@ -84,112 +96,193 @@ function PurchasePage(_ref) {
84
96
  const {
85
97
  isMobile
86
98
  } = (0, _useMobile.default)();
99
+ const {
100
+ decrypt
101
+ } = (0, _Connect.useSecurity)();
87
102
  const navigate = (0, _reactRouterDom.useNavigate)();
88
103
  const {
89
104
  session
90
105
  } = (0, _session.useSessionContext)();
91
- const [searchParams] = (0, _reactRouterDom.useSearchParams)();
92
- const [selectedPlanId, setSelectedPlanId] = (0, _react.useState)();
93
- const [openMorePlanPrompt, setOpenMorePlanPrompt] = (0, _react.useState)(false);
94
- const [splideConfig, setSplideConfig] = (0, _useSetState.default)({
95
- arrows: false,
96
- perPage: 100,
97
- width: "".concat(SLIDE_WIDTH, "px"),
98
- gap: '16px'
99
- });
106
+ const [params, setParams] = (0, _reactRouterDom.useSearchParams)();
100
107
  const {
101
108
  routerPrefix,
102
109
  embed,
103
- didPayPrefix
110
+ didPayPrefix,
111
+ isPurchaseOnly
104
112
  } = (0, _workflow.useWorkflowContext)();
105
113
  const [planListRef, {
106
- width: planListWidth
114
+ width
107
115
  }] = (0, _useMeasure.default)();
108
116
  const [showRedeem, setShowRedeem] = (0, _react.useState)(false);
117
+ const [state, setState] = (0, _useSetState.default)({
118
+ launch: null,
119
+ loading: true,
120
+ error: '',
121
+ plans: [],
122
+ sessionId: params.get('sessionId'),
123
+ planId: params.get('planId'),
124
+ showMorePrompt: false,
125
+ arrows: false,
126
+ perPage: 100,
127
+ width: "".concat(SLIDE_WIDTH, "px"),
128
+ gap: '16px'
129
+ });
109
130
  const api = create({
110
131
  baseURL: didPayPrefix
111
132
  });
112
- const planState = (0, _useAsync.default)(async () => {
113
- const {
114
- data
115
- } = await api.get('/plans');
116
- const plans = (data || []).sort((itemX, itemY) => itemY.weight - itemX.weight);
117
- if (plans.length > 0) {
118
- const recommendPlan = plans.find(x => !!x.isRecommended) || plans[0];
119
- setSelectedPlanId(recommendPlan._id);
120
- }
121
- return plans;
122
- });
123
- const calculateConfig = (maxLength, tmpPlanLength) => {
124
- const factor = Math.min(maxLength, tmpPlanLength);
125
- const width = factor < 3 ? SLIDE_MIN_WIDTH : SLIDE_WIDTH;
126
- return {
127
- perPage: factor,
128
- width: "".concat(factor * width, "px"),
129
- gap: '24px'
130
- };
131
- };
132
133
  const selectCurrent = (perPage, curIndex) => {
133
- var _planState$value;
134
- if (!((_planState$value = planState.value) !== null && _planState$value !== void 0 && _planState$value.length)) {
134
+ if (!state.plans.length) {
135
135
  return;
136
136
  }
137
137
 
138
138
  // 如果每页只有一个,则在翻页的时候默认选中当前项
139
139
  if (perPage === 1) {
140
- var _planState$value$curI;
141
- setSelectedPlanId((_planState$value$curI = planState.value[curIndex]) === null || _planState$value$curI === void 0 ? void 0 : _planState$value$curI._id);
140
+ var _state$plans$curIndex;
141
+ setState({
142
+ planId: (_state$plans$curIndex = state.plans[curIndex]) === null || _state$plans$curIndex === void 0 ? void 0 : _state$plans$curIndex._id
143
+ });
142
144
  }
143
145
  };
144
146
  (0, _react.useEffect)(() => {
145
- selectCurrent(splideConfig.perPage, 0);
146
- // eslint-disable-next-line react-hooks/exhaustive-deps
147
- }, [splideConfig]);
147
+ selectCurrent(state.perPage, 0);
148
+ }, [state.perPage]);
149
+ const selectPlan = launch => {
150
+ if (!state.plans.length) {
151
+ return;
152
+ }
153
+ if (launch && launch.planId && state.plans.find(x => x._id === launch.planId)) {
154
+ setState({
155
+ planId: launch.planId
156
+ });
157
+ }
158
+ const recommended = state.plans.find(x => !!x.isRecommended);
159
+ if (recommended) {
160
+ setState({
161
+ planId: recommended._id
162
+ });
163
+ } else {
164
+ setState({
165
+ planId: state.plans[0]._id
166
+ });
167
+ }
168
+ };
169
+
170
+ // 创建启动会话或者加载现有的会话
148
171
  (0, _react.useEffect)(() => {
149
- var _planState$value2;
150
- if (!((_planState$value2 = planState.value) !== null && _planState$value2 !== void 0 && _planState$value2.length) || typeof splideConfig.perPage === 'undefined') {
172
+ api.get('/plans').then(_ref2 => {
173
+ let {
174
+ data
175
+ } = _ref2;
176
+ const plans = (data || []).sort((a, b) => b.weight - a.weight);
177
+ setState({
178
+ plans,
179
+ loading: false
180
+ });
181
+ if (isPurchaseOnly) {
182
+ selectPlan();
183
+ return;
184
+ }
185
+ const metaUrl = params.get('blocklet_meta_url');
186
+ if (params.get('sessionId')) {
187
+ _util.launchSession.load(api, routerPrefix, params.get('sessionId'), metaUrl, (err, launch) => {
188
+ setState({
189
+ launch
190
+ });
191
+ selectPlan(launch);
192
+ });
193
+ } else if (metaUrl) {
194
+ _util.launchSession.create(api, routerPrefix, metaUrl, (err, launch) => {
195
+ setState({
196
+ launch,
197
+ sessionId: launch._id
198
+ });
199
+ selectPlan(launch);
200
+ });
201
+ }
202
+ }).catch(err => {
203
+ setState({
204
+ error: (0, _formatError.default)(err)
205
+ });
206
+ });
207
+ }, []);
208
+ (0, _react.useEffect)(() => {
209
+ if (!state.sessionId) {
210
+ return;
211
+ }
212
+ if (state.sessionId !== params.get('sessionId')) {
213
+ params.set('sessionId', state.sessionId);
214
+ setParams(params);
215
+ }
216
+ }, [state.sessionId]);
217
+ (0, _react.useEffect)(() => {
218
+ var _state$plans;
219
+ if (!((_state$plans = state.plans) !== null && _state$plans !== void 0 && _state$plans.length) || typeof state.perPage === 'undefined') {
151
220
  return;
152
221
  }
153
- const index = planState.value.findIndex(x => !!x.isRecommended);
154
- const pageIndex = Math.floor(index / splideConfig.perPage);
222
+ const index = state.plans.findIndex(x => !!x.isRecommended);
223
+ const pageIndex = Math.floor(index / state.perPage);
155
224
 
156
225
  // 如果推荐 Plan 不在第一页,则将推荐 Plan 放在第一个
157
226
  if (pageIndex >= 1) {
158
- const recommend = planState.value[index];
159
- const copy = [...planState.value];
227
+ const recommend = state.plans[index];
228
+ const copy = [...state.plans];
160
229
  copy.splice(index, 1);
161
230
  copy.unshift(recommend);
162
- planState.value = copy;
231
+ setState({
232
+ plans: copy
233
+ });
163
234
  }
164
- }, [splideConfig.perPage, planState]);
235
+ }, [state.perPage, state.plans]);
165
236
  (0, _react.useEffect)(() => {
166
- var _planState$value3;
167
- if (!((_planState$value3 = planState.value) !== null && _planState$value3 !== void 0 && _planState$value3.length)) {
237
+ var _state$plans2;
238
+ if (!((_state$plans2 = state.plans) !== null && _state$plans2 !== void 0 && _state$plans2.length)) {
168
239
  return;
169
240
  }
170
- if (Number.isNaN(planListWidth)) {
241
+ if (Number.isNaN(width)) {
171
242
  return;
172
243
  }
173
- const planLength = planState.value.length;
174
244
 
175
245
  // 最小得有1个
176
- const temp = Math.max(Math.floor(planListWidth / SLIDE_WIDTH) - 1, 1);
177
- setSplideConfig(calculateConfig(temp, planLength));
178
- // eslint-disable-next-line react-hooks/exhaustive-deps
179
- }, [planListWidth, planState, setSplideConfig, isMobile]);
246
+ const tmp = Math.max(Math.floor(width / SLIDE_WIDTH) - 1, 1);
247
+ setState(getSlideConfig(tmp, state.plans.length));
248
+ }, [width, state.plans, isMobile]);
180
249
  const handleSelect = planId => {
181
- setSelectedPlanId(planId);
250
+ if (state.planId === planId) {
251
+ return;
252
+ }
253
+ setState({
254
+ planId
255
+ });
256
+ if (isPurchaseOnly) {
257
+ return;
258
+ }
259
+
260
+ // FIXME: @wangshijun should not always be serverless
261
+ _util.launchSession.select(api, routerPrefix, state.sessionId, 'serverless', planId, (err, launch) => {
262
+ setState({
263
+ launch
264
+ });
265
+ });
182
266
  };
267
+ (0, _react.useEffect)(() => {
268
+ if (!state.planId) {
269
+ return;
270
+ }
271
+ if (state.planId !== params.get('planId')) {
272
+ params.set('planId', state.planId);
273
+ setParams(params);
274
+ }
275
+ }, [state.planId]);
183
276
  const productFeatures = [];
184
- if (!planState.loading && ((_planState$value4 = planState.value) === null || _planState$value4 === void 0 ? void 0 : _planState$value4.length) > 0) {
277
+ if (!state.loading && ((_state$plans3 = state.plans) === null || _state$plans3 === void 0 ? void 0 : _state$plans3.length) > 0) {
185
278
  // TODO: Pricing Table: 临时做法
186
279
  try {
187
280
  const {
188
281
  features
189
- } = planState.value[0];
282
+ } = state.plans[0];
190
283
  if (features && features.length > 0) {
191
- const temp = JSON.parse(features[0].en);
192
- temp.forEach(item => {
284
+ const tmp = JSON.parse(features[0].en);
285
+ tmp.forEach(item => {
193
286
  productFeatures.push({
194
287
  _id: item.featureId,
195
288
  name: item.name,
@@ -203,40 +296,43 @@ function PurchasePage(_ref) {
203
296
  }
204
297
  const handleRedeem = async () => {
205
298
  if (session.user) {
299
+ _util.launchSession.connect(api, routerPrefix, state.sessionId, session.user.did, () => {
300
+ setShowRedeem(true);
301
+ });
302
+ } else {
206
303
  setShowRedeem(true);
207
- return;
208
304
  }
209
- const redeemConnectURL = (0, _urlJoin.default)(routerPrefix, '/did/redeem/token');
210
- const {
211
- data
212
- } = await api.get(redeemConnectURL);
213
- session.login({
214
- onSuccess: results => {
215
- const [, redeemResult] = results;
216
- handleRedeemed(redeemResult);
217
- },
218
- oncancel: () => setShowRedeem(false),
219
- extraParams: {
220
- nw: data.url,
221
- forceConnected: false,
222
- saveConnect: false
223
- }
224
- });
225
305
  };
226
- const handleRedeemed = _ref2 => {
306
+ const handleRedeemed = _ref3 => {
227
307
  let {
308
+ did,
309
+ loginToken,
228
310
  nftId,
229
311
  type
230
- } = _ref2;
312
+ } = _ref3;
231
313
  if (type === _constant.NFT_TYPE_SERVERLESS) {
232
- searchParams.set('launchType', 'serverless');
314
+ params.set('launchType', 'serverless');
315
+ }
316
+ const updateSessionAndRedirect = () => {
317
+ _util.launchSession.pay(api, routerPrefix, state.sessionId, nftId, 'redeem', '', err => {
318
+ if (err) {
319
+ _Toast.default.error(err.message);
320
+ } else {
321
+ navigate({
322
+ pathname: (0, _urlJoin.default)(routerPrefix, "/launch/".concat(nftId)),
323
+ search: params.toString()
324
+ });
325
+ }
326
+ });
327
+ };
328
+ if (session.user) {
329
+ updateSessionAndRedirect();
330
+ } else if (loginToken) {
331
+ _util.connectStorage.setToken(decrypt(loginToken));
332
+ session.refresh();
333
+ _util.launchSession.connect(api, routerPrefix, state.sessionId, did, updateSessionAndRedirect);
233
334
  }
234
- navigate({
235
- pathname: (0, _urlJoin.default)(routerPrefix, "/launch/".concat(nftId)),
236
- search: searchParams.toString()
237
- });
238
335
  };
239
- searchParams.set('planId', selectedPlanId);
240
336
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(Container, {
241
337
  embed: embed,
242
338
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_header.default, {
@@ -256,7 +352,7 @@ function PurchasePage(_ref) {
256
352
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_compactLayout.default, {
257
353
  bottom: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_footer.default, {
258
354
  className: "footer",
259
- children: [embed && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
355
+ children: [embed && isPurchaseOnly === false && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
260
356
  className: "footer-left",
261
357
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
262
358
  onClick: () => handleRedeem(),
@@ -270,8 +366,8 @@ function PurchasePage(_ref) {
270
366
  })]
271
367
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
272
368
  component: _reactRouterDom.Link,
273
- disabled: planState.loading || !selectedPlanId,
274
- to: (0, _urlJoin.default)(routerPrefix, "/purchase/checkout?".concat(searchParams.toString())),
369
+ disabled: state.loading || !state.planId,
370
+ to: (0, _urlJoin.default)(routerPrefix, "/purchase/checkout?".concat(params.toString())),
275
371
  className: "button-next",
276
372
  variant: "contained",
277
373
  children: t('common.next')
@@ -280,7 +376,7 @@ function PurchasePage(_ref) {
280
376
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
281
377
  ref: planListRef,
282
378
  className: "plan-list",
283
- children: planState.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Center.default, {
379
+ children: state.loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Center.default, {
284
380
  relative: "parent",
285
381
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, {})
286
382
  }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
@@ -288,21 +384,25 @@ function PurchasePage(_ref) {
288
384
  toc: true,
289
385
  productFeatures: productFeatures,
290
386
  className: "toc"
291
- }), ((_planState$value5 = planState.value) === null || _planState$value5 === void 0 ? void 0 : _planState$value5.length) > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactSplide.Splide, {
387
+ }), state.plans.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactSplide.Splide, {
292
388
  extensions: {
293
389
  Grid: _splideExtensionGrid.Grid
294
390
  },
295
391
  onPaginationMounted: splide => {
296
- const pageCount = Math.ceil(planState.value.length / splide.options.perPage);
392
+ const pageCount = Math.ceil(state.plans.length / splide.options.perPage);
297
393
  const showArrows = pageCount > 1;
298
- setSplideConfig({
394
+ setState({
299
395
  arrows: showArrows
300
396
  });
301
397
  if (showArrows) {
302
398
  setTimeout(() => {
303
- setOpenMorePlanPrompt(true);
399
+ setState({
400
+ showMorePrompt: true
401
+ });
304
402
  // 3s 后隐藏
305
- setTimeout(() => setOpenMorePlanPrompt(false), 3000);
403
+ setTimeout(() => setState({
404
+ showMorePrompt: false
405
+ }), 3000);
306
406
  }, 1000);
307
407
  }
308
408
  },
@@ -313,14 +413,14 @@ function PurchasePage(_ref) {
313
413
  },
314
414
  options: {
315
415
  pagination: true,
316
- arrows: splideConfig.arrows,
416
+ arrows: state.arrows,
317
417
  classes: {
318
418
  pagination: 'splide__pagination splide__pagination-custom'
319
419
  },
320
420
  trimSpace: true,
321
- width: splideConfig.width,
322
- perPage: splideConfig.perPage,
323
- gap: splideConfig.gap
421
+ width: state.width,
422
+ perPage: state.perPage,
423
+ gap: state.gap
324
424
  },
325
425
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
326
426
  className: "splide__arrows",
@@ -333,7 +433,7 @@ function PurchasePage(_ref) {
333
433
  viewBox: "0 0 40 40"
334
434
  })
335
435
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
336
- open: openMorePlanPrompt,
436
+ open: state.showMorePrompt,
337
437
  title: t('purchase.morePlanPrompt'),
338
438
  placement: "top",
339
439
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
@@ -346,13 +446,13 @@ function PurchasePage(_ref) {
346
446
  })
347
447
  })]
348
448
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactSplide.SplideTrack, {
349
- children: planState.value.map(plan => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactSplide.SplideSlide, {
449
+ children: state.plans.map(plan => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactSplide.SplideSlide, {
350
450
  style: {
351
451
  width: 'auto'
352
452
  },
353
453
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_plan.default, {
354
454
  recommend: !!plan.isRecommended,
355
- checked: plan._id === selectedPlanId,
455
+ checked: plan._id === state.planId,
356
456
  plan: plan,
357
457
  onClick: () => handleSelect(plan._id)
358
458
  })
@@ -369,8 +469,9 @@ function PurchasePage(_ref) {
369
469
  popup: true,
370
470
  useSocket: false,
371
471
  locale: locale,
372
- action: "redeem",
373
- checkFn: api.create().get,
472
+ action: (_session$user = session.user) !== null && _session$user !== void 0 && _session$user.did ? 'redeem' : 'redeem-with-connect',
473
+ prefix: "/did",
474
+ checkFn: create().get,
374
475
  onSuccess: handleRedeemed,
375
476
  onClose: () => setShowRedeem(false),
376
477
  checkTimeout: 60 * 5000,
package/lib/util.js CHANGED
@@ -3,18 +3,27 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getAsset = exports.getAPIResponseError = exports.BLOCKLET_STORE_URL = void 0;
6
+ exports.getAsset = exports.getAPIResponseError = exports.connectStorage = exports.BLOCKLET_STORE_URL = void 0;
7
7
  exports.getBlockletMetaUrl = getBlockletMetaUrl;
8
- exports.loadURL = exports.getPrice = exports.getLaunchBlockletUrl = void 0;
8
+ exports.loadURL = exports.launchSession = exports.getPrice = exports.getLaunchBlockletUrl = void 0;
9
9
  var _urlJoin = _interopRequireDefault(require("url-join"));
10
10
  var _lodash = _interopRequireDefault(require("lodash.get"));
11
+ var _lodash2 = _interopRequireDefault(require("lodash.noop"));
11
12
  var _axios = _interopRequireDefault(require("axios"));
13
+ var _Storage = _interopRequireDefault(require("@arcblock/did-connect/lib/Storage"));
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ const connectStorage = (0, _Storage.default)('login_token', 'cookie', {
16
+ returnDomain: false,
17
+ path: window.blocklet.groupPathPrefix || window.blocklet.pathPrefix || '/'
18
+ });
19
+ exports.connectStorage = connectStorage;
13
20
  const BLOCKLET_STORE_URL = (0, _lodash.default)(window, 'blocklet.LAUNCHER_BLOCKLET_STORE_URL') || 'https://store.blocklet.dev';
14
21
  exports.BLOCKLET_STORE_URL = BLOCKLET_STORE_URL;
15
22
  function getBlockletMetaUrl(registry, did) {
16
23
  return (0, _urlJoin.default)(registry, "/api/blocklets/".concat(did, "/blocklet.json?source=webapp"));
17
24
  }
25
+
26
+ // FIXME: @wangshijun just use sessionId and launcherUrl to make the whole workflow more simple
18
27
  const getLaunchBlockletUrl = _ref => {
19
28
  let {
20
29
  serverUrl,
@@ -22,16 +31,18 @@ const getLaunchBlockletUrl = _ref => {
22
31
  locale,
23
32
  launchType,
24
33
  nftId,
34
+ sessionId,
25
35
  chainHost,
26
36
  from
27
37
  } = _ref;
28
38
  if (!blockletMetaUrl) {
29
39
  return serverUrl;
30
40
  }
41
+ const launcherUrl = window.blocklet.LAUNCHER_URL || window.blocklet.appUrl;
31
42
  const serverPath = from === 'did-spaces' ? '/blocklets/restore/verify-ownership' : '/launch-blocklet/install';
32
43
 
33
- // TODO: 废除 fromLauncher
34
- let result = (0, _urlJoin.default)(serverUrl, serverPath, "?blocklet_meta_url=".concat(encodeURIComponent(blockletMetaUrl), "&fromLauncher=true&from=launcher"));
44
+ // FIXME: @zhenqiang 这里为何要写这个 TODO?我看 server 代码里面还有不少地方有 `fromLauncher`
45
+ let result = (0, _urlJoin.default)(serverUrl, serverPath, "?blocklet_meta_url=".concat(encodeURIComponent(blockletMetaUrl), "&fromLauncher=true&from=launcher&launcherUrl=").concat(encodeURIComponent(launcherUrl)));
35
46
  if (launchType) {
36
47
  result += "&launchType=".concat(launchType);
37
48
  }
@@ -41,6 +52,9 @@ const getLaunchBlockletUrl = _ref => {
41
52
  if (nftId) {
42
53
  result += "&nftId=".concat(nftId);
43
54
  }
55
+ if (sessionId) {
56
+ result += "&launcherSessionId=".concat(sessionId);
57
+ }
44
58
  result += "&chainHost=".concat(encodeURIComponent(chainHost));
45
59
  return result;
46
60
  };
@@ -105,4 +119,60 @@ const getPrice = (prices, providerName) => {
105
119
  }
106
120
  return formatPrice(price, providerName);
107
121
  };
108
- exports.getPrice = getPrice;
122
+ exports.getPrice = getPrice;
123
+ const launchSession = {
124
+ load: (api, prefix, sessionId, url, done) => {
125
+ api.get((0, _urlJoin.default)(prefix, "/launches/".concat(sessionId))).then(result => {
126
+ done(null, result.data.launch);
127
+ }).catch(err => {
128
+ console.error('Failed to load launch session', err);
129
+ launchSession.create(api, prefix, url, done);
130
+ });
131
+ },
132
+ create: (api, prefix, url, done) => {
133
+ api.post((0, _urlJoin.default)(prefix, '/launches'), {
134
+ blockletMetaUrl: url,
135
+ referrer: document.referrer
136
+ }).then(result => {
137
+ done(null, result.data.launch);
138
+ }).catch(err => {
139
+ console.error('Failed to create launch session', err);
140
+ done(err);
141
+ });
142
+ },
143
+ connect: function connect(api, prefix, sessionId, userDid) {
144
+ let done = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : _lodash2.default;
145
+ api.post((0, _urlJoin.default)(prefix, "/launches/".concat(sessionId, "/connect")), {
146
+ userDid
147
+ }).then(result => {
148
+ done(null, result.data.launch);
149
+ }).catch(err => {
150
+ console.error('Failed to set launch session as connected', err);
151
+ done(err);
152
+ });
153
+ },
154
+ pay: (api, prefix, sessionId, nftDid, nftSource, paymentId, done) => {
155
+ api.post((0, _urlJoin.default)(prefix, "/launches/".concat(sessionId, "/paid")), {
156
+ nftDid,
157
+ nftSource,
158
+ paymentId
159
+ }).then(result => {
160
+ done(null, result.data.launch);
161
+ }).catch(err => {
162
+ console.error('Failed to set launch session as paid', err);
163
+ done(err);
164
+ });
165
+ },
166
+ select: (api, prefix, sessionId, type, planId, done) => {
167
+ api.post((0, _urlJoin.default)(prefix, "/launches/".concat(sessionId, "/select")), {
168
+ type,
169
+ planId
170
+ }).then(result => {
171
+ done(null, result.data.launch);
172
+ }).catch(err => {
173
+ console.error('Failed to select launch session', err);
174
+ done(err);
175
+ });
176
+ }
177
+ };
178
+ exports.launchSession = launchSession;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/launcher-workflow",
3
- "version": "2.0.47",
3
+ "version": "2.1.0",
4
4
  "description": "Purchase components for Launcher UI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,10 +23,9 @@
23
23
  },
24
24
  "scripts": {
25
25
  "lint": "eslint src",
26
+ "lint:fix": "npm run lint -- --fix",
26
27
  "build": "rm -rf lib && babel src --out-dir lib --copy-files",
27
28
  "watch": "babel src --out-dir lib -w --copy-files",
28
- "precommit": "CI=1 yarn test",
29
- "prepush": "CI=1 yarn test",
30
29
  "prepublish": "npm run build"
31
30
  },
32
31
  "bugs": {
@@ -39,11 +38,12 @@
39
38
  "@arcblock/did-connect": "^2.5.47",
40
39
  "@arcblock/icons": "^2.5.47",
41
40
  "@arcblock/license": "^2.5.47",
41
+ "@arcblock/react-hooks": "^2.5.47",
42
42
  "@arcblock/ux": "^2.5.47",
43
- "@blocklet/launcher-layout": "2.0.47",
44
- "@blocklet/launcher-util": "2.0.47",
45
- "@blocklet/launcher-ux": "2.0.47",
46
- "@did-pay/react": "^1.10.4",
43
+ "@blocklet/launcher-layout": "2.1.0",
44
+ "@blocklet/launcher-util": "2.1.0",
45
+ "@blocklet/launcher-ux": "2.1.0",
46
+ "@blocklet/payment": "^1.11.0",
47
47
  "@emotion/react": "^11.11.0",
48
48
  "@emotion/styled": "^11.11.0",
49
49
  "@mui/icons-material": "^5.11.16",
@@ -54,10 +54,12 @@
54
54
  "@splidejs/splide-extension-grid": "^0.4.1",
55
55
  "@stripe/react-stripe-js": "^1.16.5",
56
56
  "@stripe/stripe-js": "^1.53.0",
57
- "axios": "^0.26.1",
57
+ "axios": "^0.27.2",
58
+ "dsbridge": "^3.1.4",
58
59
  "flat": "^5.0.2",
59
60
  "js-cookie": "^3.0.5",
60
61
  "lodash.get": "^4.4.2",
62
+ "lodash.noop": "^3.0.1",
61
63
  "lodash.throttle": "^4.1.1",
62
64
  "prop-types": "^15.8.1",
63
65
  "react-lottie-player": "^1.5.4",
@@ -70,7 +72,8 @@
70
72
  "@babel/core": "^7.22.1",
71
73
  "@babel/preset-env": "^7.22.4",
72
74
  "@babel/preset-react": "^7.22.3",
73
- "babel-plugin-inline-react-svg": "^2.0.2"
75
+ "babel-plugin-inline-react-svg": "^2.0.2",
76
+ "jest": "^27.5.1"
74
77
  },
75
- "gitHead": "430ea38cd0d899a69247d3979b67823f8eed5b9f"
78
+ "gitHead": "97e5570a03831f25b8ea796c9e523e65a3e821dd"
76
79
  }