@blocklet/payment-react 1.18.16 → 1.18.18

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.
@@ -15,7 +15,7 @@ import {
15
15
  } from "@mui/material";
16
16
  import { useRequest, useSetState } from "ahooks";
17
17
  import omit from "lodash/omit";
18
- import uniqBy from "lodash/unionBy";
18
+ import uniqBy from "lodash/uniqBy";
19
19
  import { useEffect, useRef, useState } from "react";
20
20
  import { Settings } from "@mui/icons-material";
21
21
  import api from "../libs/api.js";
@@ -111,11 +111,14 @@ export function DonateDetails({ supporters = [], currency, method }) {
111
111
  Avatar,
112
112
  {
113
113
  src: getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : "", 20),
114
- alt: x.customer?.name,
114
+ alt: x.customer?.metadata?.anonymous ? "" : x.customer?.name,
115
115
  variant: "circular",
116
116
  sx: { width: 20, height: 20 },
117
117
  onClick: (e) => {
118
118
  e.stopPropagation();
119
+ if (x.customer?.metadata?.anonymous) {
120
+ return;
121
+ }
119
122
  if (x.customer?.did) {
120
123
  window.open(getUserProfileLink(x.customer?.did, locale), "_blank");
121
124
  }
@@ -135,6 +138,9 @@ export function DonateDetails({ supporters = [], currency, method }) {
135
138
  textOverflow: "ellipsis"
136
139
  },
137
140
  onClick: (e) => {
141
+ if (x.customer?.metadata?.anonymous) {
142
+ return;
143
+ }
138
144
  e.stopPropagation();
139
145
  if (x.customer?.did) {
140
146
  window.open(getUserProfileLink(x.customer?.did, locale), "_blank");
@@ -175,7 +181,7 @@ function SupporterAvatar({
175
181
  showDonateDetails = false
176
182
  }) {
177
183
  const [open, setOpen] = useState(false);
178
- const customers = uniqBy(supporters, "customer_did");
184
+ const customers = uniqBy(supporters, "customer_id");
179
185
  const customersNum = customers.length;
180
186
  if (customersNum === 0)
181
187
  return null;
@@ -186,7 +192,10 @@ function SupporterAvatar({
186
192
  max: 5,
187
193
  sx: {
188
194
  "& .MuiAvatar-root": {
189
- backgroundColor: "background.paper"
195
+ backgroundColor: "background.paper",
196
+ "&.MuiAvatar-colorDefault": {
197
+ backgroundColor: "#bdbdbd"
198
+ }
190
199
  }
191
200
  },
192
201
  children: customers.slice(0, 5).map((supporter) => /* @__PURE__ */ jsx(
@@ -197,7 +206,7 @@ function SupporterAvatar({
197
206
  supporter?.updated_at ? new Date(supporter.updated_at).toISOString() : "",
198
207
  24
199
208
  ),
200
- alt: supporter.customer?.name,
209
+ alt: supporter.customer?.metadata?.anonymous ? "" : supporter.customer?.name,
201
210
  sx: {
202
211
  width: "24px",
203
212
  height: "24px"
@@ -248,7 +257,7 @@ function SupporterAvatar({
248
257
  ] });
249
258
  }
250
259
  function SupporterTable({ supporters = [], totalAmount = "0", currency, method }) {
251
- const customers = uniqBy(supporters, "customer_did");
260
+ const customers = uniqBy(supporters, "customer_id");
252
261
  const customersNum = customers.length;
253
262
  if (customersNum === 0)
254
263
  return null;
@@ -259,7 +268,7 @@ function SupporterTable({ supporters = [], totalAmount = "0", currency, method }
259
268
  }
260
269
  function SupporterSimple({ supporters = [], totalAmount = "0", currency, method }) {
261
270
  const { t } = useLocaleContext();
262
- const customers = uniqBy(supporters, "customer_did");
271
+ const customers = uniqBy(supporters, "customer_id");
263
272
  const customersNum = customers.length;
264
273
  return /* @__PURE__ */ jsxs(
265
274
  Box,
@@ -281,7 +290,7 @@ function SupporterSimple({ supporters = [], totalAmount = "0", currency, method
281
290
  Avatar,
282
291
  {
283
292
  title: x.customer?.name,
284
- alt: x.customer?.name,
293
+ alt: x.customer?.metadata?.anonymous ? "" : x.customer?.name,
285
294
  src: getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : "", 48),
286
295
  variant: "circular",
287
296
  sx: { width: 24, height: 24 }
@@ -222,6 +222,12 @@ function OverdueInvoicePayment({
222
222
  }
223
223
  );
224
224
  };
225
+ const getMethodText = (method) => {
226
+ if (method.name && method.type !== "arcblock") {
227
+ return ` (${method.name})`;
228
+ }
229
+ return "";
230
+ };
225
231
  const getOverdueTitle = () => {
226
232
  if (subscriptionId && data.subscription) {
227
233
  if (summaryList.length === 1) {
@@ -229,7 +235,8 @@ function OverdueInvoicePayment({
229
235
  name: data.subscription?.description,
230
236
  count: data.invoices?.length,
231
237
  total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
232
- symbol: summaryList[0]?.currency?.symbol
238
+ symbol: summaryList[0]?.currency?.symbol,
239
+ method: getMethodText(summaryList[0]?.method)
233
240
  });
234
241
  }
235
242
  return t("payment.subscription.overdue.simpleTitle", {
@@ -243,7 +250,8 @@ function OverdueInvoicePayment({
243
250
  subscriptionCount: data.subscriptionCount || 0,
244
251
  count: data.invoices?.length,
245
252
  total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
246
- symbol: summaryList[0]?.currency?.symbol
253
+ symbol: summaryList[0]?.currency?.symbol,
254
+ method: getMethodText(summaryList[0]?.method)
247
255
  });
248
256
  }
249
257
  return t("payment.customer.overdue.simpleTitle", {
@@ -351,7 +359,8 @@ function OverdueInvoicePayment({
351
359
  children: [
352
360
  /* @__PURE__ */ jsx(Typography, { children: t("payment.subscription.overdue.total", {
353
361
  total: formatAmount(item?.amount, item?.currency?.decimal),
354
- currency: item?.currency?.symbol
362
+ currency: item?.currency?.symbol,
363
+ method: getMethodText(item?.method)
355
364
  }) }),
356
365
  renderPayButton(item, false, {
357
366
  variant: "text",
@@ -11,6 +11,7 @@ type Props = {
11
11
  action?: string;
12
12
  type?: 'list' | 'table';
13
13
  onTableDataChange?: Function;
14
+ relatedSubscription?: boolean;
14
15
  };
15
16
  declare function CustomerInvoiceList(props: Props): JSX.Element;
16
17
  declare namespace CustomerInvoiceList {
@@ -26,6 +27,7 @@ declare namespace CustomerInvoiceList {
26
27
  action: string;
27
28
  type: string;
28
29
  onTableDataChange: () => void;
30
+ relatedSubscription: boolean;
29
31
  };
30
32
  }
31
33
  export default CustomerInvoiceList;
@@ -72,7 +72,8 @@ const InvoiceTable = React.memo((props) => {
72
72
  include_staking,
73
73
  include_return_staking,
74
74
  include_recovered_from,
75
- onTableDataChange
75
+ onTableDataChange,
76
+ relatedSubscription
76
77
  } = props;
77
78
  const listKey = "invoice-table";
78
79
  const { t, locale } = useLocaleContext();
@@ -135,6 +136,11 @@ const InvoiceTable = React.memo((props) => {
135
136
  const { link } = getInvoiceLink(invoice, action);
136
137
  handleNavigation(e, link, navigate, { target: link.external ? "_blank" : target });
137
138
  };
139
+ const handleRelatedSubscriptionClick = (e, invoice) => {
140
+ if (invoice.subscription_id) {
141
+ handleNavigation(e, createLink(`/customer/subscription/${invoice.subscription_id}`), navigate);
142
+ }
143
+ };
138
144
  const columns = [
139
145
  {
140
146
  label: t("common.amount"),
@@ -173,13 +179,36 @@ const InvoiceTable = React.memo((props) => {
173
179
  }
174
180
  }
175
181
  },
182
+ ...relatedSubscription ? [
183
+ {
184
+ label: t("common.relatedSubscription"),
185
+ name: "subscription",
186
+ options: {
187
+ customBodyRenderLite: (_, index) => {
188
+ const invoice = data?.list[index];
189
+ return invoice.subscription_id ? /* @__PURE__ */ jsx(
190
+ Box,
191
+ {
192
+ onClick: (e) => handleRelatedSubscriptionClick(e, invoice),
193
+ sx: { color: "text.link", cursor: "pointer" },
194
+ children: invoice.subscription?.description
195
+ }
196
+ ) : /* @__PURE__ */ jsx(Box, { onClick: (e) => handleLinkClick(e, invoice), sx: { ...linkStyle, color: "text.lighter" }, children: t("common.none") });
197
+ }
198
+ }
199
+ }
200
+ ] : [],
176
201
  {
177
202
  label: t("common.updatedAt"),
178
203
  name: "name",
179
204
  options: {
180
205
  customBodyRenderLite: (val, index) => {
181
206
  const invoice = data?.list[index];
182
- return /* @__PURE__ */ jsx(Box, { onClick: (e) => handleLinkClick(e, invoice), sx: linkStyle, children: formatToDate(invoice.created_at, locale, "YYYY-MM-DD HH:mm:ss") });
207
+ return /* @__PURE__ */ jsx(Box, { onClick: (e) => handleLinkClick(e, invoice), sx: linkStyle, children: formatToDate(
208
+ invoice.created_at,
209
+ locale,
210
+ relatedSubscription ? "YYYY-MM-DD HH:mm" : "YYYY-MM-DD HH:mm:ss"
211
+ ) });
183
212
  }
184
213
  }
185
214
  },
@@ -489,7 +518,8 @@ CustomerInvoiceList.defaultProps = {
489
518
  action: "",
490
519
  type: "list",
491
520
  onTableDataChange: () => {
492
- }
521
+ },
522
+ relatedSubscription: false
493
523
  };
494
524
  const Root = styled(Stack)`
495
525
  @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
package/es/locales/en.js CHANGED
@@ -93,7 +93,8 @@ export default flat({
93
93
  saveAsDefaultPriceSuccess: "Set default price successfully",
94
94
  stakeAmount: "Stake Amount",
95
95
  slashStakeAmount: "Slash Stake Amount",
96
- know: "I know"
96
+ know: "I know",
97
+ relatedSubscription: "Subscription"
97
98
  },
98
99
  payment: {
99
100
  checkout: {
@@ -316,7 +317,7 @@ export default flat({
316
317
  owner: "Subscription Owner"
317
318
  },
318
319
  overdue: {
319
- title: "You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}. Please pay immediately to avoid service disruption.",
320
+ title: "You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. Please pay immediately to avoid service disruption.",
320
321
  simpleTitle: "You have {count} due invoices. Please pay now to ensure uninterrupted service.",
321
322
  empty: "Great! You have no due invoices."
322
323
  }
@@ -349,10 +350,10 @@ export default flat({
349
350
  subscription: {
350
351
  overdue: {
351
352
  simpleTitle: "There are {count} due invoices for your subscription {name}, you need to pay them to activate your subscription or before making new purchases.",
352
- title: "There are {count} due invoices for your subscription {name}, the total due amount is {total} {symbol}, you need to pay them to activate your subscription or before making new purchases.",
353
+ title: "There are {count} due invoices for your subscription {name}, the total due amount is {total} {symbol}{method}, you need to pay them to activate your subscription or before making new purchases.",
353
354
  payNow: "Pay Now",
354
355
  notSupport: "This payment method is not supported",
355
- total: "Total {total} {currency}",
356
+ total: "Total {total} {currency}{method}",
356
357
  view: "View Subscription Details",
357
358
  viewNow: "View Now",
358
359
  pastDue: "Past Due Invoices",
package/es/locales/zh.js CHANGED
@@ -93,7 +93,8 @@ export default flat({
93
93
  saveAsDefaultPriceSuccess: "\u8BBE\u7F6E\u9ED8\u8BA4\u4EF7\u683C\u6210\u529F",
94
94
  stakeAmount: "\u8D28\u62BC\u91D1\u989D",
95
95
  slashStakeAmount: "\u7F5A\u6CA1\u91D1\u989D",
96
- know: "\u6211\u77E5\u9053\u4E86"
96
+ know: "\u6211\u77E5\u9053\u4E86",
97
+ relatedSubscription: "\u8BA2\u9605"
97
98
  },
98
99
  payment: {
99
100
  checkout: {
@@ -316,7 +317,7 @@ export default flat({
316
317
  owner: "\u8BA2\u9605\u62E5\u6709\u8005"
317
318
  },
318
319
  overdue: {
319
- title: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u6D89\u53CA {subscriptionCount} \u4E2A\u8BA2\u9605\uFF0C\u603B\u91D1\u989D {total} {symbol}\u3002\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002",
320
+ title: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u6D89\u53CA {subscriptionCount} \u4E2A\u8BA2\u9605\uFF0C\u603B\u91D1\u989D {total} {symbol}{method}\u3002\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002",
320
321
  simpleTitle: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002",
321
322
  empty: "\u606D\u559C\uFF01\u60A8\u5F53\u524D\u6CA1\u6709\u6B20\u8D39\u8D26\u5355\u3002"
322
323
  }
@@ -348,11 +349,11 @@ export default flat({
348
349
  },
349
350
  subscription: {
350
351
  overdue: {
351
- title: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5171\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u603B\u8BA1 {total} {symbol}\uFF0C\u60A8\u9700\u8981\u652F\u4ED8\u8FD9\u4E9B\u8D26\u5355\u4EE5\u6FC0\u6D3B\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u5728\u8FDB\u884C\u65B0\u7684\u8D2D\u4E70\u4E4B\u524D\u5B8C\u6210\u652F\u4ED8\u3002",
352
+ title: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5171\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u603B\u8BA1 {total} {symbol}{method}\uFF0C\u60A8\u9700\u8981\u652F\u4ED8\u8FD9\u4E9B\u8D26\u5355\u4EE5\u6FC0\u6D3B\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u5728\u8FDB\u884C\u65B0\u7684\u8D2D\u4E70\u4E4B\u524D\u5B8C\u6210\u652F\u4ED8\u3002",
352
353
  simpleTitle: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5171\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u60A8\u9700\u8981\u652F\u4ED8\u8FD9\u4E9B\u8D26\u5355\u4EE5\u6FC0\u6D3B\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u5728\u8FDB\u884C\u65B0\u7684\u8D2D\u4E70\u4E4B\u524D\u5B8C\u6210\u652F\u4ED8\u3002",
353
354
  payNow: "\u7ACB\u5373\u652F\u4ED8",
354
355
  notSupport: "\u6682\u4E0D\u652F\u6301\u8BE5\u652F\u4ED8\u65B9\u5F0F",
355
- total: "\u603B\u8BA1 {total} {currency}",
356
+ total: "\u603B\u8BA1 {total} {currency}{method}",
356
357
  view: "\u67E5\u770B\u8BA2\u9605\u8BE6\u60C5",
357
358
  pastDue: "\u6B20\u8D39\u8D26\u5355",
358
359
  viewNow: "\u7ACB\u5373\u67E5\u770B",
@@ -319,7 +319,8 @@ function PaymentInner({
319
319
  onError,
320
320
  mode,
321
321
  action,
322
- onlyShowBtn: true
322
+ onlyShowBtn: true,
323
+ isDonation: true
323
324
  }
324
325
  )
325
326
  ]
@@ -4,11 +4,13 @@ export declare const waitForCheckoutComplete: (sessionId: string) => Promise<Che
4
4
  export declare const hasDidWallet: (user: any) => any;
5
5
  type PageData = CheckoutContext & CheckoutCallbacks & {
6
6
  onlyShowBtn?: boolean;
7
+ isDonation?: boolean;
7
8
  };
8
- declare function PaymentForm({ checkoutSession, paymentMethods, paymentIntent, paymentLink, customer, onPaid, onError, action, currencyId, onlyShowBtn, }: PageData): import("react").JSX.Element;
9
+ declare function PaymentForm({ checkoutSession, paymentMethods, paymentIntent, paymentLink, customer, onPaid, onError, action, currencyId, onlyShowBtn, isDonation, }: PageData): import("react").JSX.Element;
9
10
  declare namespace PaymentForm {
10
11
  var defaultProps: {
11
12
  onlyShowBtn: boolean;
13
+ isDonation: boolean;
12
14
  };
13
15
  }
14
16
  export default PaymentForm;
@@ -54,7 +54,8 @@ export const hasDidWallet = (user) => {
54
54
  return connected.some((x) => x.provider === "wallet");
55
55
  };
56
56
  PaymentForm.defaultProps = {
57
- onlyShowBtn: false
57
+ onlyShowBtn: false,
58
+ isDonation: false
58
59
  };
59
60
  export default function PaymentForm({
60
61
  checkoutSession,
@@ -67,7 +68,8 @@ export default function PaymentForm({
67
68
  // mode,
68
69
  action,
69
70
  currencyId,
70
- onlyShowBtn
71
+ onlyShowBtn,
72
+ isDonation = false
71
73
  }) {
72
74
  const { t } = useLocaleContext();
73
75
  const { isMobile } = useMobile();
@@ -170,8 +172,9 @@ export default function PaymentForm({
170
172
  } else {
171
173
  buttonText = t(`payment.checkout.${checkoutSession.mode}`);
172
174
  }
173
- buttonText = session?.user ? buttonText : t("payment.checkout.connect", { action: buttonText });
175
+ buttonText = session?.user || isDonation ? buttonText : t("payment.checkout.connect", { action: buttonText });
174
176
  const method = paymentMethods.find((x) => x.id === paymentMethod);
177
+ const isDonationMode = checkoutSession?.submit_type === "donate" && isDonation;
175
178
  const showForm = session?.user;
176
179
  const skipBindWallet = method.type === "stripe";
177
180
  const handleConnected = async () => {
@@ -228,7 +231,12 @@ export default function PaymentForm({
228
231
  const onFormSubmit = async (data) => {
229
232
  setState({ submitting: true });
230
233
  try {
231
- const result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
234
+ let result;
235
+ if (isDonationMode) {
236
+ result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/donate-submit`, data);
237
+ } else {
238
+ result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
239
+ }
232
240
  setState({
233
241
  paymentIntent: result.data.paymentIntent,
234
242
  stripeContext: result.data.stripeContext,
@@ -238,7 +246,7 @@ export default function PaymentForm({
238
246
  });
239
247
  if (["arcblock", "ethereum", "base"].includes(method.type)) {
240
248
  setState({ paying: true });
241
- if (result.data.balance?.sufficient || result.data.delegation?.sufficient) {
249
+ if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode) {
242
250
  await handleConnected();
243
251
  } else {
244
252
  connect.open({
@@ -314,6 +322,10 @@ export default function PaymentForm({
314
322
  });
315
323
  }
316
324
  } else {
325
+ if (isDonationMode) {
326
+ handleSubmit(onFormSubmit, onFormError)();
327
+ return;
328
+ }
317
329
  session?.login(() => {
318
330
  setState({ submitting: true });
319
331
  onUserLoggedIn().then(afterUserLoggedIn).catch((err) => {
@@ -11,7 +11,7 @@ var _context = require("@arcblock/ux/lib/Locale/context");
11
11
  var _material = require("@mui/material");
12
12
  var _ahooks = require("ahooks");
13
13
  var _omit = _interopRequireDefault(require("lodash/omit"));
14
- var _unionBy = _interopRequireDefault(require("lodash/unionBy"));
14
+ var _uniqBy = _interopRequireDefault(require("lodash/uniqBy"));
15
15
  var _react = require("react");
16
16
  var _iconsMaterial = require("@mui/icons-material");
17
17
  var _api = _interopRequireDefault(require("../libs/api"));
@@ -104,7 +104,7 @@ function DonateDetails({
104
104
  },
105
105
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Avatar, {
106
106
  src: (0, _util.getCustomerAvatar)(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : "", 20),
107
- alt: x.customer?.name,
107
+ alt: x.customer?.metadata?.anonymous ? "" : x.customer?.name,
108
108
  variant: "circular",
109
109
  sx: {
110
110
  width: 20,
@@ -112,6 +112,9 @@ function DonateDetails({
112
112
  },
113
113
  onClick: e => {
114
114
  e.stopPropagation();
115
+ if (x.customer?.metadata?.anonymous) {
116
+ return;
117
+ }
115
118
  if (x.customer?.did) {
116
119
  window.open((0, _util.getUserProfileLink)(x.customer?.did, locale), "_blank");
117
120
  }
@@ -126,6 +129,9 @@ function DonateDetails({
126
129
  textOverflow: "ellipsis"
127
130
  },
128
131
  onClick: e => {
132
+ if (x.customer?.metadata?.anonymous) {
133
+ return;
134
+ }
129
135
  e.stopPropagation();
130
136
  if (x.customer?.did) {
131
137
  window.open((0, _util.getUserProfileLink)(x.customer?.did, locale), "_blank");
@@ -172,7 +178,7 @@ function SupporterAvatar({
172
178
  showDonateDetails = false
173
179
  }) {
174
180
  const [open, setOpen] = (0, _react.useState)(false);
175
- const customers = (0, _unionBy.default)(supporters, "customer_did");
181
+ const customers = (0, _uniqBy.default)(supporters, "customer_id");
176
182
  const customersNum = customers.length;
177
183
  if (customersNum === 0) return null;
178
184
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
@@ -183,12 +189,15 @@ function SupporterAvatar({
183
189
  max: 5,
184
190
  sx: {
185
191
  "& .MuiAvatar-root": {
186
- backgroundColor: "background.paper"
192
+ backgroundColor: "background.paper",
193
+ "&.MuiAvatar-colorDefault": {
194
+ backgroundColor: "#bdbdbd"
195
+ }
187
196
  }
188
197
  },
189
198
  children: customers.slice(0, 5).map(supporter => /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Avatar, {
190
199
  src: (0, _util.getCustomerAvatar)(supporter.customer?.did, supporter?.updated_at ? new Date(supporter.updated_at).toISOString() : "", 24),
191
- alt: supporter.customer?.name,
200
+ alt: supporter.customer?.metadata?.anonymous ? "" : supporter.customer?.name,
192
201
  sx: {
193
202
  width: "24px",
194
203
  height: "24px"
@@ -238,7 +247,7 @@ function SupporterTable({
238
247
  currency,
239
248
  method
240
249
  }) {
241
- const customers = (0, _unionBy.default)(supporters, "customer_did");
250
+ const customers = (0, _uniqBy.default)(supporters, "customer_id");
242
251
  const customersNum = customers.length;
243
252
  if (customersNum === 0) return null;
244
253
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
@@ -271,7 +280,7 @@ function SupporterSimple({
271
280
  const {
272
281
  t
273
282
  } = (0, _context.useLocaleContext)();
274
- const customers = (0, _unionBy.default)(supporters, "customer_did");
283
+ const customers = (0, _uniqBy.default)(supporters, "customer_id");
275
284
  const customersNum = customers.length;
276
285
  return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
277
286
  display: "flex",
@@ -297,7 +306,7 @@ function SupporterSimple({
297
306
  max: 10,
298
307
  children: customers.map(x => /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Avatar, {
299
308
  title: x.customer?.name,
300
- alt: x.customer?.name,
309
+ alt: x.customer?.metadata?.anonymous ? "" : x.customer?.name,
301
310
  src: (0, _util.getCustomerAvatar)(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : "", 48),
302
311
  variant: "circular",
303
312
  sx: {
@@ -410,7 +419,7 @@ function CheckoutDonateInner({
410
419
  donateSettings,
411
420
  supportUpdateSettings
412
421
  } = useDonation(settings, livemode, mode);
413
- const customers = (0, _unionBy.default)(supporters?.data?.supporters || [], "customer_did");
422
+ const customers = (0, _uniqBy.default)(supporters?.data?.supporters || [], "customer_did");
414
423
  const {
415
424
  t
416
425
  } = (0, _context.useLocaleContext)();
@@ -251,6 +251,12 @@ function OverdueInvoicePayment({
251
251
  children: t("payment.subscription.overdue.payNow")
252
252
  });
253
253
  };
254
+ const getMethodText = method => {
255
+ if (method.name && method.type !== "arcblock") {
256
+ return ` (${method.name})`;
257
+ }
258
+ return "";
259
+ };
254
260
  const getOverdueTitle = () => {
255
261
  if (subscriptionId && data.subscription) {
256
262
  if (summaryList.length === 1) {
@@ -258,7 +264,8 @@ function OverdueInvoicePayment({
258
264
  name: data.subscription?.description,
259
265
  count: data.invoices?.length,
260
266
  total: (0, _util.formatAmount)(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
261
- symbol: summaryList[0]?.currency?.symbol
267
+ symbol: summaryList[0]?.currency?.symbol,
268
+ method: getMethodText(summaryList[0]?.method)
262
269
  });
263
270
  }
264
271
  return t("payment.subscription.overdue.simpleTitle", {
@@ -272,7 +279,8 @@ function OverdueInvoicePayment({
272
279
  subscriptionCount: data.subscriptionCount || 0,
273
280
  count: data.invoices?.length,
274
281
  total: (0, _util.formatAmount)(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
275
- symbol: summaryList[0]?.currency?.symbol
282
+ symbol: summaryList[0]?.currency?.symbol,
283
+ method: getMethodText(summaryList[0]?.method)
276
284
  });
277
285
  }
278
286
  return t("payment.customer.overdue.simpleTitle", {
@@ -407,7 +415,8 @@ function OverdueInvoicePayment({
407
415
  children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
408
416
  children: t("payment.subscription.overdue.total", {
409
417
  total: (0, _util.formatAmount)(item?.amount, item?.currency?.decimal),
410
- currency: item?.currency?.symbol
418
+ currency: item?.currency?.symbol,
419
+ method: getMethodText(item?.method)
411
420
  })
412
421
  }), renderPayButton(item, false, {
413
422
  variant: "text",
@@ -11,6 +11,7 @@ type Props = {
11
11
  action?: string;
12
12
  type?: 'list' | 'table';
13
13
  onTableDataChange?: Function;
14
+ relatedSubscription?: boolean;
14
15
  };
15
16
  declare function CustomerInvoiceList(props: Props): JSX.Element;
16
17
  declare namespace CustomerInvoiceList {
@@ -26,6 +27,7 @@ declare namespace CustomerInvoiceList {
26
27
  action: string;
27
28
  type: string;
28
29
  onTableDataChange: () => void;
30
+ relatedSubscription: boolean;
29
31
  };
30
32
  }
31
33
  export default CustomerInvoiceList;
@@ -73,7 +73,8 @@ const InvoiceTable = _react.default.memo(props => {
73
73
  include_staking,
74
74
  include_return_staking,
75
75
  include_recovered_from,
76
- onTableDataChange
76
+ onTableDataChange,
77
+ relatedSubscription
77
78
  } = props;
78
79
  const listKey = "invoice-table";
79
80
  const {
@@ -141,6 +142,11 @@ const InvoiceTable = _react.default.memo(props => {
141
142
  target: link.external ? "_blank" : target
142
143
  });
143
144
  };
145
+ const handleRelatedSubscriptionClick = (e, invoice) => {
146
+ if (invoice.subscription_id) {
147
+ (0, _navigation.handleNavigation)(e, (0, _navigation.createLink)(`/customer/subscription/${invoice.subscription_id}`), navigate);
148
+ }
149
+ };
144
150
  const columns = [{
145
151
  label: t("common.amount"),
146
152
  name: "total",
@@ -190,7 +196,30 @@ const InvoiceTable = _react.default.memo(props => {
190
196
  });
191
197
  }
192
198
  }
193
- }, {
199
+ }, ...(relatedSubscription ? [{
200
+ label: t("common.relatedSubscription"),
201
+ name: "subscription",
202
+ options: {
203
+ customBodyRenderLite: (_, index) => {
204
+ const invoice = data?.list[index];
205
+ return invoice.subscription_id ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
206
+ onClick: e => handleRelatedSubscriptionClick(e, invoice),
207
+ sx: {
208
+ color: "text.link",
209
+ cursor: "pointer"
210
+ },
211
+ children: invoice.subscription?.description
212
+ }) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
213
+ onClick: e => handleLinkClick(e, invoice),
214
+ sx: {
215
+ ...linkStyle,
216
+ color: "text.lighter"
217
+ },
218
+ children: t("common.none")
219
+ });
220
+ }
221
+ }
222
+ }] : []), {
194
223
  label: t("common.updatedAt"),
195
224
  name: "name",
196
225
  options: {
@@ -199,7 +228,7 @@ const InvoiceTable = _react.default.memo(props => {
199
228
  return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
200
229
  onClick: e => handleLinkClick(e, invoice),
201
230
  sx: linkStyle,
202
- children: (0, _util.formatToDate)(invoice.created_at, locale, "YYYY-MM-DD HH:mm:ss")
231
+ children: (0, _util.formatToDate)(invoice.created_at, locale, relatedSubscription ? "YYYY-MM-DD HH:mm" : "YYYY-MM-DD HH:mm:ss")
203
232
  });
204
233
  }
205
234
  }
@@ -651,7 +680,8 @@ CustomerInvoiceList.defaultProps = {
651
680
  target: "_self",
652
681
  action: "",
653
682
  type: "list",
654
- onTableDataChange: () => {}
683
+ onTableDataChange: () => {},
684
+ relatedSubscription: false
655
685
  };
656
686
  const Root = (0, _system.styled)(_material.Stack)`
657
687
  @media (max-width: ${({
package/lib/locales/en.js CHANGED
@@ -100,7 +100,8 @@ module.exports = (0, _flat.default)({
100
100
  saveAsDefaultPriceSuccess: "Set default price successfully",
101
101
  stakeAmount: "Stake Amount",
102
102
  slashStakeAmount: "Slash Stake Amount",
103
- know: "I know"
103
+ know: "I know",
104
+ relatedSubscription: "Subscription"
104
105
  },
105
106
  payment: {
106
107
  checkout: {
@@ -323,7 +324,7 @@ module.exports = (0, _flat.default)({
323
324
  owner: "Subscription Owner"
324
325
  },
325
326
  overdue: {
326
- title: "You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}. Please pay immediately to avoid service disruption.",
327
+ title: "You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. Please pay immediately to avoid service disruption.",
327
328
  simpleTitle: "You have {count} due invoices. Please pay now to ensure uninterrupted service.",
328
329
  empty: "Great! You have no due invoices."
329
330
  }
@@ -356,10 +357,10 @@ module.exports = (0, _flat.default)({
356
357
  subscription: {
357
358
  overdue: {
358
359
  simpleTitle: "There are {count} due invoices for your subscription {name}, you need to pay them to activate your subscription or before making new purchases.",
359
- title: "There are {count} due invoices for your subscription {name}, the total due amount is {total} {symbol}, you need to pay them to activate your subscription or before making new purchases.",
360
+ title: "There are {count} due invoices for your subscription {name}, the total due amount is {total} {symbol}{method}, you need to pay them to activate your subscription or before making new purchases.",
360
361
  payNow: "Pay Now",
361
362
  notSupport: "This payment method is not supported",
362
- total: "Total {total} {currency}",
363
+ total: "Total {total} {currency}{method}",
363
364
  view: "View Subscription Details",
364
365
  viewNow: "View Now",
365
366
  pastDue: "Past Due Invoices",
package/lib/locales/zh.js CHANGED
@@ -100,7 +100,8 @@ module.exports = (0, _flat.default)({
100
100
  saveAsDefaultPriceSuccess: "\u8BBE\u7F6E\u9ED8\u8BA4\u4EF7\u683C\u6210\u529F",
101
101
  stakeAmount: "\u8D28\u62BC\u91D1\u989D",
102
102
  slashStakeAmount: "\u7F5A\u6CA1\u91D1\u989D",
103
- know: "\u6211\u77E5\u9053\u4E86"
103
+ know: "\u6211\u77E5\u9053\u4E86",
104
+ relatedSubscription: "\u8BA2\u9605"
104
105
  },
105
106
  payment: {
106
107
  checkout: {
@@ -323,7 +324,7 @@ module.exports = (0, _flat.default)({
323
324
  owner: "\u8BA2\u9605\u62E5\u6709\u8005"
324
325
  },
325
326
  overdue: {
326
- title: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u6D89\u53CA {subscriptionCount} \u4E2A\u8BA2\u9605\uFF0C\u603B\u91D1\u989D {total} {symbol}\u3002\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002",
327
+ title: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u6D89\u53CA {subscriptionCount} \u4E2A\u8BA2\u9605\uFF0C\u603B\u91D1\u989D {total} {symbol}{method}\u3002\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002",
327
328
  simpleTitle: "\u60A8\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u8BF7\u7ACB\u5373\u652F\u4ED8\uFF0C\u4EE5\u514D\u5F71\u54CD\u60A8\u7684\u4F7F\u7528\u3002",
328
329
  empty: "\u606D\u559C\uFF01\u60A8\u5F53\u524D\u6CA1\u6709\u6B20\u8D39\u8D26\u5355\u3002"
329
330
  }
@@ -355,11 +356,11 @@ module.exports = (0, _flat.default)({
355
356
  },
356
357
  subscription: {
357
358
  overdue: {
358
- title: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5171\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u603B\u8BA1 {total} {symbol}\uFF0C\u60A8\u9700\u8981\u652F\u4ED8\u8FD9\u4E9B\u8D26\u5355\u4EE5\u6FC0\u6D3B\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u5728\u8FDB\u884C\u65B0\u7684\u8D2D\u4E70\u4E4B\u524D\u5B8C\u6210\u652F\u4ED8\u3002",
359
+ title: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5171\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u603B\u8BA1 {total} {symbol}{method}\uFF0C\u60A8\u9700\u8981\u652F\u4ED8\u8FD9\u4E9B\u8D26\u5355\u4EE5\u6FC0\u6D3B\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u5728\u8FDB\u884C\u65B0\u7684\u8D2D\u4E70\u4E4B\u524D\u5B8C\u6210\u652F\u4ED8\u3002",
359
360
  simpleTitle: "\u60A8\u7684\u3010{name}\u3011\u8BA2\u9605\u5171\u6709 {count} \u5F20\u6B20\u8D39\u8D26\u5355\uFF0C\u60A8\u9700\u8981\u652F\u4ED8\u8FD9\u4E9B\u8D26\u5355\u4EE5\u6FC0\u6D3B\u60A8\u7684\u8BA2\u9605\uFF0C\u6216\u5728\u8FDB\u884C\u65B0\u7684\u8D2D\u4E70\u4E4B\u524D\u5B8C\u6210\u652F\u4ED8\u3002",
360
361
  payNow: "\u7ACB\u5373\u652F\u4ED8",
361
362
  notSupport: "\u6682\u4E0D\u652F\u6301\u8BE5\u652F\u4ED8\u65B9\u5F0F",
362
- total: "\u603B\u8BA1 {total} {currency}",
363
+ total: "\u603B\u8BA1 {total} {currency}{method}",
363
364
  view: "\u67E5\u770B\u8BA2\u9605\u8BE6\u60C5",
364
365
  pastDue: "\u6B20\u8D39\u8D26\u5355",
365
366
  viewNow: "\u7ACB\u5373\u67E5\u770B",
@@ -344,7 +344,8 @@ function PaymentInner({
344
344
  onError,
345
345
  mode,
346
346
  action,
347
- onlyShowBtn: true
347
+ onlyShowBtn: true,
348
+ isDonation: true
348
349
  })]
349
350
  })]
350
351
  })]
@@ -4,11 +4,13 @@ export declare const waitForCheckoutComplete: (sessionId: string) => Promise<Che
4
4
  export declare const hasDidWallet: (user: any) => any;
5
5
  type PageData = CheckoutContext & CheckoutCallbacks & {
6
6
  onlyShowBtn?: boolean;
7
+ isDonation?: boolean;
7
8
  };
8
- declare function PaymentForm({ checkoutSession, paymentMethods, paymentIntent, paymentLink, customer, onPaid, onError, action, currencyId, onlyShowBtn, }: PageData): import("react").JSX.Element;
9
+ declare function PaymentForm({ checkoutSession, paymentMethods, paymentIntent, paymentLink, customer, onPaid, onError, action, currencyId, onlyShowBtn, isDonation, }: PageData): import("react").JSX.Element;
9
10
  declare namespace PaymentForm {
10
11
  var defaultProps: {
11
12
  onlyShowBtn: boolean;
13
+ isDonation: boolean;
12
14
  };
13
15
  }
14
16
  export default PaymentForm;
@@ -59,7 +59,8 @@ const hasDidWallet = user => {
59
59
  };
60
60
  exports.hasDidWallet = hasDidWallet;
61
61
  PaymentForm.defaultProps = {
62
- onlyShowBtn: false
62
+ onlyShowBtn: false,
63
+ isDonation: false
63
64
  };
64
65
  function PaymentForm({
65
66
  checkoutSession,
@@ -72,7 +73,8 @@ function PaymentForm({
72
73
  // mode,
73
74
  action,
74
75
  currencyId,
75
- onlyShowBtn
76
+ onlyShowBtn,
77
+ isDonation = false
76
78
  }) {
77
79
  const {
78
80
  t
@@ -192,10 +194,11 @@ function PaymentForm({
192
194
  } else {
193
195
  buttonText = t(`payment.checkout.${checkoutSession.mode}`);
194
196
  }
195
- buttonText = session?.user ? buttonText : t("payment.checkout.connect", {
197
+ buttonText = session?.user || isDonation ? buttonText : t("payment.checkout.connect", {
196
198
  action: buttonText
197
199
  });
198
200
  const method = paymentMethods.find(x => x.id === paymentMethod);
201
+ const isDonationMode = checkoutSession?.submit_type === "donate" && isDonation;
199
202
  const showForm = session?.user;
200
203
  const skipBindWallet = method.type === "stripe";
201
204
  const handleConnected = async () => {
@@ -263,7 +266,12 @@ function PaymentForm({
263
266
  submitting: true
264
267
  });
265
268
  try {
266
- const result = await _api.default.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
269
+ let result;
270
+ if (isDonationMode) {
271
+ result = await _api.default.put(`/api/checkout-sessions/${checkoutSession.id}/donate-submit`, data);
272
+ } else {
273
+ result = await _api.default.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
274
+ }
267
275
  setState({
268
276
  paymentIntent: result.data.paymentIntent,
269
277
  stripeContext: result.data.stripeContext,
@@ -275,7 +283,7 @@ function PaymentForm({
275
283
  setState({
276
284
  paying: true
277
285
  });
278
- if (result.data.balance?.sufficient || result.data.delegation?.sufficient) {
286
+ if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode) {
279
287
  await handleConnected();
280
288
  } else {
281
289
  connect.open({
@@ -372,6 +380,10 @@ function PaymentForm({
372
380
  });
373
381
  }
374
382
  } else {
383
+ if (isDonationMode) {
384
+ handleSubmit(onFormSubmit, onFormError)();
385
+ return;
386
+ }
375
387
  session?.login(() => {
376
388
  setState({
377
389
  submitting: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.18.16",
3
+ "version": "1.18.18",
4
4
  "description": "Reusable react components for payment kit v2",
5
5
  "keywords": [
6
6
  "react",
@@ -54,10 +54,10 @@
54
54
  }
55
55
  },
56
56
  "dependencies": {
57
- "@arcblock/did-connect": "^2.12.17",
58
- "@arcblock/ux": "^2.12.17",
57
+ "@arcblock/did-connect": "^2.12.26",
58
+ "@arcblock/ux": "^2.12.26",
59
59
  "@arcblock/ws": "^1.19.15",
60
- "@blocklet/ui-react": "^2.12.17",
60
+ "@blocklet/ui-react": "^2.12.26",
61
61
  "@mui/icons-material": "^5.16.6",
62
62
  "@mui/lab": "^5.0.0-alpha.173",
63
63
  "@mui/material": "^5.16.6",
@@ -93,7 +93,7 @@
93
93
  "@babel/core": "^7.25.2",
94
94
  "@babel/preset-env": "^7.25.2",
95
95
  "@babel/preset-react": "^7.24.7",
96
- "@blocklet/payment-types": "1.18.16",
96
+ "@blocklet/payment-types": "1.18.18",
97
97
  "@storybook/addon-essentials": "^7.6.20",
98
98
  "@storybook/addon-interactions": "^7.6.20",
99
99
  "@storybook/addon-links": "^7.6.20",
@@ -124,5 +124,5 @@
124
124
  "vite-plugin-babel": "^1.2.0",
125
125
  "vite-plugin-node-polyfills": "^0.21.0"
126
126
  },
127
- "gitHead": "676b921c6fc399d3a031b848bfbe0fbffee430a1"
127
+ "gitHead": "511a531693837c4e0784d4961f8755e5818a27d5"
128
128
  }
@@ -28,7 +28,7 @@ import {
28
28
  } from '@mui/material';
29
29
  import { useRequest, useSetState } from 'ahooks';
30
30
  import omit from 'lodash/omit';
31
- import uniqBy from 'lodash/unionBy';
31
+ import uniqBy from 'lodash/uniqBy';
32
32
  import { useEffect, useRef, useState } from 'react';
33
33
  import { Settings } from '@mui/icons-material';
34
34
 
@@ -190,11 +190,14 @@ export function DonateDetails({ supporters = [], currency, method }: DonateHisto
190
190
  <Avatar
191
191
  key={x.id}
192
192
  src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 20)}
193
- alt={x.customer?.name}
193
+ alt={x.customer?.metadata?.anonymous ? '' : x.customer?.name}
194
194
  variant="circular"
195
195
  sx={{ width: 20, height: 20 }}
196
196
  onClick={(e) => {
197
197
  e.stopPropagation();
198
+ if (x.customer?.metadata?.anonymous) {
199
+ return;
200
+ }
198
201
  if (x.customer?.did) {
199
202
  window.open(getUserProfileLink(x.customer?.did, locale), '_blank');
200
203
  }
@@ -210,6 +213,9 @@ export function DonateDetails({ supporters = [], currency, method }: DonateHisto
210
213
  textOverflow: 'ellipsis',
211
214
  }}
212
215
  onClick={(e) => {
216
+ if (x.customer?.metadata?.anonymous) {
217
+ return;
218
+ }
213
219
  e.stopPropagation();
214
220
  if (x.customer?.did) {
215
221
  window.open(getUserProfileLink(x.customer?.did, locale), '_blank');
@@ -244,7 +250,7 @@ function SupporterAvatar({
244
250
  showDonateDetails = false,
245
251
  }: DonateHistory & { showDonateDetails?: boolean }) {
246
252
  const [open, setOpen] = useState(false);
247
- const customers = uniqBy(supporters, 'customer_did');
253
+ const customers = uniqBy(supporters, 'customer_id');
248
254
  const customersNum = customers.length;
249
255
  if (customersNum === 0) return null;
250
256
  return (
@@ -254,6 +260,9 @@ function SupporterAvatar({
254
260
  sx={{
255
261
  '& .MuiAvatar-root': {
256
262
  backgroundColor: 'background.paper',
263
+ '&.MuiAvatar-colorDefault': {
264
+ backgroundColor: '#bdbdbd',
265
+ },
257
266
  },
258
267
  }}>
259
268
  {customers.slice(0, 5).map((supporter) => (
@@ -263,7 +272,7 @@ function SupporterAvatar({
263
272
  supporter?.updated_at ? new Date(supporter.updated_at).toISOString() : '',
264
273
  24
265
274
  )}
266
- alt={supporter.customer?.name}
275
+ alt={supporter.customer?.metadata?.anonymous ? '' : supporter.customer?.name}
267
276
  key={supporter.customer?.id}
268
277
  sx={{
269
278
  width: '24px',
@@ -312,7 +321,7 @@ function SupporterAvatar({
312
321
 
313
322
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
314
323
  function SupporterTable({ supporters = [], totalAmount = '0', currency, method }: DonateHistory) {
315
- const customers = uniqBy(supporters, 'customer_did');
324
+ const customers = uniqBy(supporters, 'customer_id');
316
325
  const customersNum = customers.length;
317
326
  if (customersNum === 0) return null;
318
327
  return (
@@ -326,7 +335,7 @@ function SupporterTable({ supporters = [], totalAmount = '0', currency, method }
326
335
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
327
336
  function SupporterSimple({ supporters = [], totalAmount = '0', currency, method }: DonateHistory) {
328
337
  const { t } = useLocaleContext();
329
- const customers = uniqBy(supporters, 'customer_did');
338
+ const customers = uniqBy(supporters, 'customer_id');
330
339
  const customersNum = customers.length;
331
340
 
332
341
  return (
@@ -354,7 +363,7 @@ function SupporterSimple({ supporters = [], totalAmount = '0', currency, method
354
363
  <Avatar
355
364
  key={x.id}
356
365
  title={x.customer?.name}
357
- alt={x.customer?.name}
366
+ alt={x.customer?.metadata?.anonymous ? '' : x.customer?.name}
358
367
  src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 48)}
359
368
  variant="circular"
360
369
  sx={{ width: 24, height: 24 }}
@@ -316,6 +316,13 @@ function OverdueInvoicePayment({
316
316
  );
317
317
  };
318
318
 
319
+ const getMethodText = (method: PaymentMethod) => {
320
+ if (method.name && method.type !== 'arcblock') {
321
+ return ` (${method.name})`;
322
+ }
323
+ return '';
324
+ };
325
+
319
326
  const getOverdueTitle = () => {
320
327
  if (subscriptionId && data.subscription) {
321
328
  if (summaryList.length === 1) {
@@ -324,6 +331,7 @@ function OverdueInvoicePayment({
324
331
  count: data.invoices?.length,
325
332
  total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
326
333
  symbol: summaryList[0]?.currency?.symbol,
334
+ method: getMethodText(summaryList[0]?.method),
327
335
  });
328
336
  }
329
337
  return t('payment.subscription.overdue.simpleTitle', {
@@ -338,6 +346,7 @@ function OverdueInvoicePayment({
338
346
  count: data.invoices?.length,
339
347
  total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
340
348
  symbol: summaryList[0]?.currency?.symbol,
349
+ method: getMethodText(summaryList[0]?.method),
341
350
  });
342
351
  }
343
352
  return t('payment.customer.overdue.simpleTitle', {
@@ -472,6 +481,7 @@ function OverdueInvoicePayment({
472
481
  {t('payment.subscription.overdue.total', {
473
482
  total: formatAmount(item?.amount, item?.currency?.decimal),
474
483
  currency: item?.currency?.symbol,
484
+ method: getMethodText(item?.method),
475
485
  })}
476
486
  </Typography>
477
487
  {renderPayButton(item, false, {
@@ -69,6 +69,7 @@ type Props = {
69
69
  action?: string;
70
70
  type?: 'list' | 'table';
71
71
  onTableDataChange?: Function;
72
+ relatedSubscription?: boolean;
72
73
  };
73
74
 
74
75
  const getInvoiceLink = (invoice: TInvoiceExpanded, action?: string) => {
@@ -104,6 +105,7 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
104
105
  include_return_staking,
105
106
  include_recovered_from,
106
107
  onTableDataChange,
108
+ relatedSubscription,
107
109
  } = props;
108
110
  const listKey = 'invoice-table';
109
111
  const { t, locale } = useLocaleContext();
@@ -177,6 +179,12 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
177
179
  handleNavigation(e, link, navigate, { target: link.external ? '_blank' : target });
178
180
  };
179
181
 
182
+ const handleRelatedSubscriptionClick = (e: React.MouseEvent, invoice: TInvoiceExpanded) => {
183
+ if (invoice.subscription_id) {
184
+ handleNavigation(e, createLink(`/customer/subscription/${invoice.subscription_id}`), navigate);
185
+ }
186
+ };
187
+
180
188
  const columns = [
181
189
  {
182
190
  label: t('common.amount'),
@@ -226,6 +234,30 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
226
234
  },
227
235
  },
228
236
  },
237
+ ...(relatedSubscription
238
+ ? [
239
+ {
240
+ label: t('common.relatedSubscription'),
241
+ name: 'subscription',
242
+ options: {
243
+ customBodyRenderLite: (_: string, index: number) => {
244
+ const invoice = data?.list[index] as TInvoiceExpanded;
245
+ return invoice.subscription_id ? (
246
+ <Box
247
+ onClick={(e) => handleRelatedSubscriptionClick(e, invoice)}
248
+ sx={{ color: 'text.link', cursor: 'pointer' }}>
249
+ {invoice.subscription?.description}
250
+ </Box>
251
+ ) : (
252
+ <Box onClick={(e) => handleLinkClick(e, invoice)} sx={{ ...linkStyle, color: 'text.lighter' }}>
253
+ {t('common.none')}
254
+ </Box>
255
+ );
256
+ },
257
+ },
258
+ },
259
+ ]
260
+ : []),
229
261
  {
230
262
  label: t('common.updatedAt'),
231
263
  name: 'name',
@@ -235,12 +267,17 @@ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) =>
235
267
 
236
268
  return (
237
269
  <Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
238
- {formatToDate(invoice.created_at, locale, 'YYYY-MM-DD HH:mm:ss')}
270
+ {formatToDate(
271
+ invoice.created_at,
272
+ locale,
273
+ relatedSubscription ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD HH:mm:ss'
274
+ )}
239
275
  </Box>
240
276
  );
241
277
  },
242
278
  },
243
279
  },
280
+
244
281
  {
245
282
  label: t('common.description'),
246
283
  name: '',
@@ -621,6 +658,7 @@ CustomerInvoiceList.defaultProps = {
621
658
  action: '',
622
659
  type: 'list',
623
660
  onTableDataChange: () => {},
661
+ relatedSubscription: false,
624
662
  };
625
663
 
626
664
  const Root = styled(Stack)`
@@ -96,6 +96,7 @@ export default flat({
96
96
  stakeAmount: 'Stake Amount',
97
97
  slashStakeAmount: 'Slash Stake Amount',
98
98
  know: 'I know',
99
+ relatedSubscription: 'Subscription',
99
100
  },
100
101
  payment: {
101
102
  checkout: {
@@ -329,7 +330,7 @@ export default flat({
329
330
  },
330
331
  overdue: {
331
332
  title:
332
- 'You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}. Please pay immediately to avoid service disruption.',
333
+ 'You have {count} due invoices for {subscriptionCount} subscriptions, totaling {total} {symbol}{method}. Please pay immediately to avoid service disruption.',
333
334
  simpleTitle: 'You have {count} due invoices. Please pay now to ensure uninterrupted service.',
334
335
  empty: 'Great! You have no due invoices.',
335
336
  },
@@ -364,10 +365,10 @@ export default flat({
364
365
  simpleTitle:
365
366
  'There are {count} due invoices for your subscription {name}, you need to pay them to activate your subscription or before making new purchases.',
366
367
  title:
367
- 'There are {count} due invoices for your subscription {name}, the total due amount is {total} {symbol}, you need to pay them to activate your subscription or before making new purchases.',
368
+ 'There are {count} due invoices for your subscription {name}, the total due amount is {total} {symbol}{method}, you need to pay them to activate your subscription or before making new purchases.',
368
369
  payNow: 'Pay Now',
369
370
  notSupport: 'This payment method is not supported',
370
- total: 'Total {total} {currency}',
371
+ total: 'Total {total} {currency}{method}',
371
372
  view: 'View Subscription Details',
372
373
  viewNow: 'View Now',
373
374
  pastDue: 'Past Due Invoices',
@@ -96,6 +96,7 @@ export default flat({
96
96
  stakeAmount: '质押金额',
97
97
  slashStakeAmount: '罚没金额',
98
98
  know: '我知道了',
99
+ relatedSubscription: '订阅',
99
100
  },
100
101
  payment: {
101
102
  checkout: {
@@ -320,7 +321,7 @@ export default flat({
320
321
  },
321
322
  overdue: {
322
323
  title:
323
- '您有 {count} 张欠费账单,涉及 {subscriptionCount} 个订阅,总金额 {total} {symbol}。请立即支付,以免影响您的使用。',
324
+ '您有 {count} 张欠费账单,涉及 {subscriptionCount} 个订阅,总金额 {total} {symbol}{method}。请立即支付,以免影响您的使用。',
324
325
  simpleTitle: '您有 {count} 张欠费账单,请立即支付,以免影响您的使用。',
325
326
  empty: '恭喜!您当前没有欠费账单。',
326
327
  },
@@ -353,12 +354,12 @@ export default flat({
353
354
  subscription: {
354
355
  overdue: {
355
356
  title:
356
- '您的【{name}】订阅共有 {count} 张欠费账单,总计 {total} {symbol},您需要支付这些账单以激活您的订阅,或在进行新的购买之前完成支付。',
357
+ '您的【{name}】订阅共有 {count} 张欠费账单,总计 {total} {symbol}{method},您需要支付这些账单以激活您的订阅,或在进行新的购买之前完成支付。',
357
358
  simpleTitle:
358
359
  '您的【{name}】订阅共有 {count} 张欠费账单,您需要支付这些账单以激活您的订阅,或在进行新的购买之前完成支付。',
359
360
  payNow: '立即支付',
360
361
  notSupport: '暂不支持该支付方式',
361
- total: '总计 {total} {currency}',
362
+ total: '总计 {total} {currency}{method}',
362
363
  view: '查看订阅详情',
363
364
  pastDue: '欠费账单',
364
365
  viewNow: '立即查看',
@@ -343,6 +343,7 @@ function PaymentInner({
343
343
  mode={mode}
344
344
  action={action}
345
345
  onlyShowBtn
346
+ isDonation
346
347
  />
347
348
  </Box>
348
349
  )}
@@ -80,10 +80,12 @@ export const hasDidWallet = (user: any) => {
80
80
  type PageData = CheckoutContext &
81
81
  CheckoutCallbacks & {
82
82
  onlyShowBtn?: boolean;
83
+ isDonation?: boolean;
83
84
  };
84
85
 
85
86
  PaymentForm.defaultProps = {
86
87
  onlyShowBtn: false,
88
+ isDonation: false,
87
89
  };
88
90
 
89
91
  // FIXME: https://stripe.com/docs/elements/address-element
@@ -103,6 +105,7 @@ export default function PaymentForm({
103
105
  action,
104
106
  currencyId,
105
107
  onlyShowBtn,
108
+ isDonation = false,
106
109
  }: PageData) {
107
110
  // const theme = useTheme();
108
111
  const { t } = useLocaleContext();
@@ -241,10 +244,10 @@ export default function PaymentForm({
241
244
  } else {
242
245
  buttonText = t(`payment.checkout.${checkoutSession.mode}`);
243
246
  }
244
- buttonText = session?.user ? buttonText : t('payment.checkout.connect', { action: buttonText });
247
+ buttonText = session?.user || isDonation ? buttonText : t('payment.checkout.connect', { action: buttonText });
245
248
 
246
249
  const method = paymentMethods.find((x) => x.id === paymentMethod) as TPaymentMethodExpanded;
247
-
250
+ const isDonationMode = checkoutSession?.submit_type === 'donate' && isDonation;
248
251
  const showForm = session?.user;
249
252
  const skipBindWallet = method.type === 'stripe';
250
253
 
@@ -305,7 +308,12 @@ export default function PaymentForm({
305
308
  const onFormSubmit = async (data: any) => {
306
309
  setState({ submitting: true });
307
310
  try {
308
- const result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
311
+ let result;
312
+ if (isDonationMode) {
313
+ result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/donate-submit`, data);
314
+ } else {
315
+ result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
316
+ }
309
317
 
310
318
  setState({
311
319
  paymentIntent: result.data.paymentIntent,
@@ -317,7 +325,7 @@ export default function PaymentForm({
317
325
 
318
326
  if (['arcblock', 'ethereum', 'base'].includes(method.type)) {
319
327
  setState({ paying: true });
320
- if (result.data.balance?.sufficient || result.data.delegation?.sufficient) {
328
+ if ((result.data.balance?.sufficient || result.data.delegation?.sufficient) && !isDonationMode) {
321
329
  await handleConnected();
322
330
  } else {
323
331
  connect.open({
@@ -396,6 +404,10 @@ export default function PaymentForm({
396
404
  });
397
405
  }
398
406
  } else {
407
+ if (isDonationMode) {
408
+ handleSubmit(onFormSubmit, onFormError)();
409
+ return;
410
+ }
399
411
  session?.login(() => {
400
412
  setState({ submitting: true });
401
413
  onUserLoggedIn()