@blocklet/payment-react 1.20.13 → 1.20.14
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/es/components/source-data-viewer.d.ts +23 -0
- package/es/components/source-data-viewer.js +228 -0
- package/es/history/credit/transactions-list.d.ts +1 -0
- package/es/history/credit/transactions-list.js +137 -20
- package/es/index.d.ts +2 -1
- package/es/index.js +3 -1
- package/es/locales/en.js +2 -1
- package/es/locales/zh.js +2 -1
- package/es/payment/index.js +31 -4
- package/es/payment/summary.js +6 -6
- package/lib/components/source-data-viewer.d.ts +23 -0
- package/lib/components/source-data-viewer.js +236 -0
- package/lib/history/credit/transactions-list.d.ts +1 -0
- package/lib/history/credit/transactions-list.js +132 -16
- package/lib/index.d.ts +2 -1
- package/lib/index.js +8 -0
- package/lib/locales/en.js +2 -1
- package/lib/locales/zh.js +2 -1
- package/lib/payment/index.js +31 -4
- package/lib/payment/summary.js +6 -6
- package/package.json +3 -3
- package/src/components/source-data-viewer.tsx +295 -0
- package/src/history/credit/transactions-list.tsx +142 -18
- package/src/index.ts +2 -0
- package/src/locales/en.tsx +1 -0
- package/src/locales/zh.tsx +1 -0
- package/src/payment/index.tsx +32 -4
- package/src/payment/summary.tsx +7 -7
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type LocalizedText = {
|
|
2
|
+
zh: string;
|
|
3
|
+
en: string;
|
|
4
|
+
};
|
|
5
|
+
type SimpleSourceData = Record<string, string>;
|
|
6
|
+
type StructuredSourceDataField = {
|
|
7
|
+
key: string;
|
|
8
|
+
label: string | LocalizedText;
|
|
9
|
+
value: string;
|
|
10
|
+
type?: 'text' | 'image' | 'url';
|
|
11
|
+
url?: string;
|
|
12
|
+
group?: string;
|
|
13
|
+
};
|
|
14
|
+
type SourceData = SimpleSourceData | StructuredSourceDataField[];
|
|
15
|
+
interface SourceDataViewerProps {
|
|
16
|
+
data: SourceData;
|
|
17
|
+
compact?: boolean;
|
|
18
|
+
maxItems?: number;
|
|
19
|
+
locale?: 'en' | 'zh';
|
|
20
|
+
showGroups?: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare function SourceDataViewer({ data, compact, maxItems, locale: propLocale, showGroups, }: SourceDataViewerProps): import("react").JSX.Element | null;
|
|
23
|
+
export default SourceDataViewer;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Empty from "@arcblock/ux/lib/Empty";
|
|
3
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
4
|
+
import { Box, Chip, Link, Stack, Typography } from "@mui/material";
|
|
5
|
+
function SourceDataViewer({
|
|
6
|
+
data,
|
|
7
|
+
compact = false,
|
|
8
|
+
maxItems = void 0,
|
|
9
|
+
locale: propLocale = void 0,
|
|
10
|
+
showGroups = false
|
|
11
|
+
}) {
|
|
12
|
+
const { locale: contextLocale, t } = useLocaleContext();
|
|
13
|
+
const currentLocale = propLocale || contextLocale || "en";
|
|
14
|
+
if (!data || Array.isArray(data) && data.length === 0 || typeof data === "object" && Object.keys(data).length === 0) {
|
|
15
|
+
return /* @__PURE__ */ jsx(Empty, { children: t("common.none") });
|
|
16
|
+
}
|
|
17
|
+
const getLocalizedText = (text) => {
|
|
18
|
+
if (typeof text === "string") {
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
21
|
+
return text[currentLocale] || text.en || "";
|
|
22
|
+
};
|
|
23
|
+
const isSimpleSourceData = (sourceData) => {
|
|
24
|
+
return typeof sourceData === "object" && !Array.isArray(sourceData) && sourceData !== null;
|
|
25
|
+
};
|
|
26
|
+
const isUrlLike = (str) => {
|
|
27
|
+
try {
|
|
28
|
+
new URL(str);
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
return /^https?:\/\/.+/.test(str) || /^www\..+/.test(str);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const normalizeData = (inputData) => {
|
|
35
|
+
if (isSimpleSourceData(inputData)) {
|
|
36
|
+
return Object.entries(inputData).map(([key, value]) => {
|
|
37
|
+
const stringValue = String(value);
|
|
38
|
+
const isUrl = isUrlLike(stringValue);
|
|
39
|
+
return {
|
|
40
|
+
key,
|
|
41
|
+
label: key.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
42
|
+
value: stringValue,
|
|
43
|
+
type: isUrl ? "url" : "text",
|
|
44
|
+
url: isUrl ? stringValue : void 0
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return inputData;
|
|
49
|
+
};
|
|
50
|
+
const renderFieldValue = (field) => {
|
|
51
|
+
const displayValue = field.value;
|
|
52
|
+
if (field.type === "url") {
|
|
53
|
+
return /* @__PURE__ */ jsx(
|
|
54
|
+
Link,
|
|
55
|
+
{
|
|
56
|
+
href: field.url || field.value,
|
|
57
|
+
target: "_blank",
|
|
58
|
+
rel: "noopener noreferrer",
|
|
59
|
+
sx: {
|
|
60
|
+
color: "primary.main",
|
|
61
|
+
textDecoration: "none",
|
|
62
|
+
fontSize: "0.85rem",
|
|
63
|
+
fontWeight: 600,
|
|
64
|
+
lineHeight: 1.4,
|
|
65
|
+
"&:hover": {
|
|
66
|
+
textDecoration: "underline",
|
|
67
|
+
color: "primary.dark"
|
|
68
|
+
},
|
|
69
|
+
"&:visited": {
|
|
70
|
+
color: "primary.main"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
children: displayValue
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (field.type === "image") {
|
|
78
|
+
return /* @__PURE__ */ jsxs(
|
|
79
|
+
Box,
|
|
80
|
+
{
|
|
81
|
+
sx: {
|
|
82
|
+
display: "flex",
|
|
83
|
+
alignItems: "center",
|
|
84
|
+
gap: 1
|
|
85
|
+
},
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
Box,
|
|
89
|
+
{
|
|
90
|
+
component: "img",
|
|
91
|
+
src: field.url || field.value,
|
|
92
|
+
alt: displayValue,
|
|
93
|
+
sx: {
|
|
94
|
+
width: 24,
|
|
95
|
+
height: 24,
|
|
96
|
+
borderRadius: 1,
|
|
97
|
+
objectFit: "cover"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 500 }, children: displayValue })
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
return /* @__PURE__ */ jsx(
|
|
107
|
+
Typography,
|
|
108
|
+
{
|
|
109
|
+
variant: "body2",
|
|
110
|
+
sx: {
|
|
111
|
+
fontWeight: 500,
|
|
112
|
+
color: "text.primary"
|
|
113
|
+
},
|
|
114
|
+
children: displayValue
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
if (!data || Array.isArray(data) && data.length === 0 || typeof data === "object" && Object.keys(data).length === 0) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const normalizedData = normalizeData(data);
|
|
122
|
+
const displayItems = maxItems ? normalizedData.slice(0, maxItems) : normalizedData;
|
|
123
|
+
if (compact) {
|
|
124
|
+
return /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, flexWrap: "wrap", useFlexGap: true, children: [
|
|
125
|
+
displayItems.map((field) => /* @__PURE__ */ jsx(
|
|
126
|
+
Chip,
|
|
127
|
+
{
|
|
128
|
+
label: `${getLocalizedText(field.label)}: ${field.value}`,
|
|
129
|
+
size: "small",
|
|
130
|
+
variant: "outlined",
|
|
131
|
+
sx: { maxWidth: 200 }
|
|
132
|
+
},
|
|
133
|
+
field.key
|
|
134
|
+
)),
|
|
135
|
+
maxItems && normalizedData.length > maxItems && /* @__PURE__ */ jsx(Chip, { label: `+${normalizedData.length - maxItems} more`, size: "small", color: "primary", variant: "outlined" })
|
|
136
|
+
] });
|
|
137
|
+
}
|
|
138
|
+
if (showGroups) {
|
|
139
|
+
const groupedData = displayItems.reduce(
|
|
140
|
+
(acc, field) => {
|
|
141
|
+
const group = field.group || "default";
|
|
142
|
+
if (!acc[group]) acc[group] = [];
|
|
143
|
+
acc[group].push(field);
|
|
144
|
+
return acc;
|
|
145
|
+
},
|
|
146
|
+
{}
|
|
147
|
+
);
|
|
148
|
+
return /* @__PURE__ */ jsx(Stack, { spacing: 2.5, children: Object.entries(groupedData).map(([group, fields]) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
149
|
+
group !== "default" && /* @__PURE__ */ jsx(
|
|
150
|
+
Typography,
|
|
151
|
+
{
|
|
152
|
+
variant: "subtitle2",
|
|
153
|
+
sx: {
|
|
154
|
+
mb: 1.5,
|
|
155
|
+
fontWeight: 700,
|
|
156
|
+
color: "text.primary",
|
|
157
|
+
letterSpacing: "0.5px",
|
|
158
|
+
borderBottom: "1px solid",
|
|
159
|
+
borderColor: "divider",
|
|
160
|
+
pb: 0.5
|
|
161
|
+
},
|
|
162
|
+
children: group.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())
|
|
163
|
+
}
|
|
164
|
+
),
|
|
165
|
+
/* @__PURE__ */ jsx(Stack, { spacing: 1.2, sx: { pl: group !== "default" ? 1 : 0 }, children: fields.map((field) => /* @__PURE__ */ jsxs(
|
|
166
|
+
Box,
|
|
167
|
+
{
|
|
168
|
+
sx: {
|
|
169
|
+
display: "flex",
|
|
170
|
+
flexDirection: "row",
|
|
171
|
+
alignItems: "flex-start",
|
|
172
|
+
gap: 3,
|
|
173
|
+
minHeight: 20
|
|
174
|
+
},
|
|
175
|
+
children: [
|
|
176
|
+
/* @__PURE__ */ jsx(
|
|
177
|
+
Typography,
|
|
178
|
+
{
|
|
179
|
+
variant: "body2",
|
|
180
|
+
color: "text.secondary",
|
|
181
|
+
sx: {
|
|
182
|
+
fontSize: "0.8rem",
|
|
183
|
+
minWidth: 100,
|
|
184
|
+
fontWeight: 600,
|
|
185
|
+
lineHeight: 1.4
|
|
186
|
+
},
|
|
187
|
+
children: getLocalizedText(field.label)
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ jsx(Box, { sx: { flex: 1, minWidth: 0, wordBreak: "break-all", whiteSpace: "wrap" }, children: renderFieldValue(field) })
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
field.key
|
|
194
|
+
)) })
|
|
195
|
+
] }, group)) });
|
|
196
|
+
}
|
|
197
|
+
return /* @__PURE__ */ jsx(Stack, { spacing: 1.5, children: displayItems.map((field) => /* @__PURE__ */ jsxs(
|
|
198
|
+
Box,
|
|
199
|
+
{
|
|
200
|
+
sx: {
|
|
201
|
+
display: "flex",
|
|
202
|
+
flexDirection: "row",
|
|
203
|
+
alignItems: "flex-start",
|
|
204
|
+
gap: 3,
|
|
205
|
+
minHeight: 20
|
|
206
|
+
},
|
|
207
|
+
children: [
|
|
208
|
+
/* @__PURE__ */ jsx(
|
|
209
|
+
Typography,
|
|
210
|
+
{
|
|
211
|
+
variant: "body2",
|
|
212
|
+
color: "text.secondary",
|
|
213
|
+
sx: {
|
|
214
|
+
fontSize: "0.8rem",
|
|
215
|
+
minWidth: 100,
|
|
216
|
+
fontWeight: 600,
|
|
217
|
+
lineHeight: 1.4
|
|
218
|
+
},
|
|
219
|
+
children: getLocalizedText(field.label)
|
|
220
|
+
}
|
|
221
|
+
),
|
|
222
|
+
/* @__PURE__ */ jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: renderFieldValue(field) })
|
|
223
|
+
]
|
|
224
|
+
},
|
|
225
|
+
field.key
|
|
226
|
+
)) });
|
|
227
|
+
}
|
|
228
|
+
export default SourceDataViewer;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
-
import { Box, Typography, Stack, Link,
|
|
3
|
+
import { Box, Typography, Grid, Stack, Link, Button, Popover } from "@mui/material";
|
|
4
4
|
import { useRequest } from "ahooks";
|
|
5
5
|
import { useNavigate } from "react-router-dom";
|
|
6
6
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
7
|
-
import { joinURL } from "ufo";
|
|
8
7
|
import { styled } from "@mui/system";
|
|
8
|
+
import { joinURL } from "ufo";
|
|
9
9
|
import DateRangePicker from "../../components/date-range-picker.js";
|
|
10
10
|
import { formatBNStr, formatToDate, getPrefix } from "../../libs/util.js";
|
|
11
11
|
import { usePaymentContext } from "../../contexts/payment.js";
|
|
12
12
|
import api from "../../libs/api.js";
|
|
13
13
|
import Table from "../../components/table.js";
|
|
14
14
|
import { createLink, handleNavigation } from "../../libs/navigation.js";
|
|
15
|
+
import SourceDataViewer from "../../components/source-data-viewer.js";
|
|
15
16
|
const fetchData = (params = {}) => {
|
|
16
17
|
const search = new URLSearchParams();
|
|
17
18
|
Object.keys(params).forEach((key) => {
|
|
@@ -31,6 +32,16 @@ const getGrantDetailLink = (grantId, inDashboard) => {
|
|
|
31
32
|
connect: false
|
|
32
33
|
};
|
|
33
34
|
};
|
|
35
|
+
const getInvoiceDetailLink = (invoiceId, inDashboard) => {
|
|
36
|
+
let path = `/customer/invoice/${invoiceId}`;
|
|
37
|
+
if (inDashboard) {
|
|
38
|
+
path = `/admin/billing/${invoiceId}`;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
link: createLink(path),
|
|
42
|
+
connect: false
|
|
43
|
+
};
|
|
44
|
+
};
|
|
34
45
|
const TransactionsTable = React.memo((props) => {
|
|
35
46
|
const {
|
|
36
47
|
pageSize,
|
|
@@ -40,6 +51,7 @@ const TransactionsTable = React.memo((props) => {
|
|
|
40
51
|
onTableDataChange,
|
|
41
52
|
showAdminColumns = false,
|
|
42
53
|
showTimeFilter = false,
|
|
54
|
+
includeGrants = false,
|
|
43
55
|
source,
|
|
44
56
|
mode = "portal"
|
|
45
57
|
} = props;
|
|
@@ -57,6 +69,7 @@ const TransactionsTable = React.memo((props) => {
|
|
|
57
69
|
start: void 0,
|
|
58
70
|
end: void 0
|
|
59
71
|
});
|
|
72
|
+
const [sourceDataPopover, setSourceDataPopover] = useState({ anchorEl: null, data: null });
|
|
60
73
|
const handleDateRangeChange = useCallback((newValue) => {
|
|
61
74
|
setFilters(newValue);
|
|
62
75
|
setSearch((prev) => ({
|
|
@@ -72,10 +85,11 @@ const TransactionsTable = React.memo((props) => {
|
|
|
72
85
|
customer_id: effectiveCustomerId,
|
|
73
86
|
subscription_id,
|
|
74
87
|
credit_grant_id,
|
|
75
|
-
source
|
|
88
|
+
source,
|
|
89
|
+
include_grants: includeGrants
|
|
76
90
|
}),
|
|
77
91
|
{
|
|
78
|
-
refreshDeps: [search, effectiveCustomerId, subscription_id, credit_grant_id, source]
|
|
92
|
+
refreshDeps: [search, effectiveCustomerId, subscription_id, credit_grant_id, source, includeGrants]
|
|
79
93
|
}
|
|
80
94
|
);
|
|
81
95
|
useEffect(() => {
|
|
@@ -97,35 +111,59 @@ const TransactionsTable = React.memo((props) => {
|
|
|
97
111
|
align: "right",
|
|
98
112
|
options: {
|
|
99
113
|
customBodyRenderLite: (_, index) => {
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
const item = data?.list[index];
|
|
115
|
+
const isGrant = item.activity_type === "grant";
|
|
116
|
+
const amount = isGrant ? item.amount : item.credit_amount;
|
|
117
|
+
const currency = item.paymentCurrency || item.currency;
|
|
118
|
+
const unit = !isGrant && item.meter?.unit ? item.meter.unit : currency?.symbol;
|
|
119
|
+
const displayAmount = formatBNStr(amount, currency?.decimal || 0);
|
|
120
|
+
if (!includeGrants) {
|
|
121
|
+
return /* @__PURE__ */ jsxs(Typography, { children: [
|
|
122
|
+
displayAmount,
|
|
123
|
+
" ",
|
|
124
|
+
unit
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
return /* @__PURE__ */ jsxs(
|
|
128
|
+
Typography,
|
|
129
|
+
{
|
|
130
|
+
sx: {
|
|
131
|
+
color: isGrant ? "success.main" : "error.main"
|
|
132
|
+
},
|
|
133
|
+
children: [
|
|
134
|
+
isGrant ? "+" : "-",
|
|
135
|
+
" ",
|
|
136
|
+
displayAmount,
|
|
137
|
+
" ",
|
|
138
|
+
unit
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
);
|
|
107
142
|
}
|
|
108
143
|
}
|
|
109
144
|
},
|
|
110
|
-
|
|
145
|
+
{
|
|
111
146
|
label: t("common.creditGrant"),
|
|
112
147
|
name: "credit_grant",
|
|
113
148
|
options: {
|
|
114
149
|
customBodyRenderLite: (_, index) => {
|
|
115
|
-
const
|
|
150
|
+
const item = data?.list[index];
|
|
151
|
+
const isGrant = item.activity_type === "grant";
|
|
152
|
+
const grantName = isGrant ? item.name : item.creditGrant.name;
|
|
153
|
+
const grantId = isGrant ? item.id : item.credit_grant_id;
|
|
116
154
|
return /* @__PURE__ */ jsx(
|
|
117
155
|
Stack,
|
|
118
156
|
{
|
|
119
157
|
direction: "row",
|
|
120
158
|
spacing: 1,
|
|
121
159
|
onClick: (e) => {
|
|
122
|
-
const link = getGrantDetailLink(
|
|
160
|
+
const link = getGrantDetailLink(grantId, isAdmin && mode === "dashboard");
|
|
123
161
|
handleNavigation(e, link.link, navigate);
|
|
124
162
|
},
|
|
125
163
|
sx: {
|
|
126
164
|
alignItems: "center"
|
|
127
165
|
},
|
|
128
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: {
|
|
166
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { cursor: "pointer" }, children: grantName || `Grant ${grantId.slice(-6)}` })
|
|
129
167
|
}
|
|
130
168
|
);
|
|
131
169
|
}
|
|
@@ -133,11 +171,13 @@ const TransactionsTable = React.memo((props) => {
|
|
|
133
171
|
},
|
|
134
172
|
{
|
|
135
173
|
label: t("common.description"),
|
|
136
|
-
name: "
|
|
174
|
+
name: "description",
|
|
137
175
|
options: {
|
|
138
176
|
customBodyRenderLite: (_, index) => {
|
|
139
|
-
const
|
|
140
|
-
|
|
177
|
+
const item = data?.list[index];
|
|
178
|
+
const isGrant = item.activity_type === "grant";
|
|
179
|
+
const description = isGrant ? item.name || item.description || "Credit Granted" : item.subscription?.description || item.description || `${item.meter_event_name} usage`;
|
|
180
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 400 }, children: description });
|
|
141
181
|
}
|
|
142
182
|
}
|
|
143
183
|
},
|
|
@@ -161,8 +201,52 @@ const TransactionsTable = React.memo((props) => {
|
|
|
161
201
|
name: "created_at",
|
|
162
202
|
options: {
|
|
163
203
|
customBodyRenderLite: (_, index) => {
|
|
164
|
-
const
|
|
165
|
-
return /* @__PURE__ */ jsx(Typography, { variant: "body2", children: formatToDate(
|
|
204
|
+
const item = data?.list[index];
|
|
205
|
+
return /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { fontSize: "0.875rem" }, children: formatToDate(item.created_at, locale, "YYYY-MM-DD HH:mm") });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
label: t("common.actions"),
|
|
211
|
+
name: "actions",
|
|
212
|
+
options: {
|
|
213
|
+
customBodyRenderLite: (_, index) => {
|
|
214
|
+
const item = data?.list[index];
|
|
215
|
+
const isGrant = item.activity_type === "grant";
|
|
216
|
+
const invoiceId = isGrant ? item.metadata?.invoice_id : null;
|
|
217
|
+
const sourceData = !isGrant && item.meterEvent?.source_data;
|
|
218
|
+
return /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", gap: 1, alignItems: "center" }, children: [
|
|
219
|
+
isGrant && invoiceId && /* @__PURE__ */ jsx(
|
|
220
|
+
Button,
|
|
221
|
+
{
|
|
222
|
+
variant: "text",
|
|
223
|
+
size: "small",
|
|
224
|
+
color: "primary",
|
|
225
|
+
onClick: (e) => {
|
|
226
|
+
e.preventDefault();
|
|
227
|
+
const link = getInvoiceDetailLink(invoiceId, isAdmin && mode === "dashboard");
|
|
228
|
+
handleNavigation(e, link.link, navigate);
|
|
229
|
+
},
|
|
230
|
+
children: t("common.viewInvoice")
|
|
231
|
+
}
|
|
232
|
+
),
|
|
233
|
+
sourceData && /* @__PURE__ */ jsx(
|
|
234
|
+
Button,
|
|
235
|
+
{
|
|
236
|
+
variant: "text",
|
|
237
|
+
size: "small",
|
|
238
|
+
color: "primary",
|
|
239
|
+
onClick: (e) => {
|
|
240
|
+
e.preventDefault();
|
|
241
|
+
setSourceDataPopover({
|
|
242
|
+
anchorEl: e.currentTarget,
|
|
243
|
+
data: sourceData
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
children: t("common.viewSourceData")
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
] });
|
|
166
250
|
}
|
|
167
251
|
}
|
|
168
252
|
}
|
|
@@ -217,6 +301,38 @@ const TransactionsTable = React.memo((props) => {
|
|
|
217
301
|
mobileTDFlexDirection: "row",
|
|
218
302
|
emptyNodeText: t("admin.creditTransactions.noTransactions")
|
|
219
303
|
}
|
|
304
|
+
),
|
|
305
|
+
/* @__PURE__ */ jsx(
|
|
306
|
+
Popover,
|
|
307
|
+
{
|
|
308
|
+
open: Boolean(sourceDataPopover.anchorEl),
|
|
309
|
+
anchorEl: sourceDataPopover.anchorEl,
|
|
310
|
+
onClose: () => setSourceDataPopover({ anchorEl: null, data: null }),
|
|
311
|
+
anchorOrigin: {
|
|
312
|
+
vertical: "bottom",
|
|
313
|
+
horizontal: "left"
|
|
314
|
+
},
|
|
315
|
+
transformOrigin: {
|
|
316
|
+
vertical: "top",
|
|
317
|
+
horizontal: "left"
|
|
318
|
+
},
|
|
319
|
+
slotProps: {
|
|
320
|
+
paper: {
|
|
321
|
+
sx: {
|
|
322
|
+
minWidth: {
|
|
323
|
+
xs: 0,
|
|
324
|
+
md: 320
|
|
325
|
+
},
|
|
326
|
+
maxHeight: 450,
|
|
327
|
+
p: {
|
|
328
|
+
xs: 1,
|
|
329
|
+
md: 3
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
children: sourceDataPopover.data && /* @__PURE__ */ jsx(SourceDataViewer, { data: sourceDataPopover.data, showGroups: true })
|
|
335
|
+
}
|
|
220
336
|
)
|
|
221
337
|
] });
|
|
222
338
|
});
|
|
@@ -246,6 +362,7 @@ export default function CreditTransactionsList(rawProps) {
|
|
|
246
362
|
},
|
|
247
363
|
showAdminColumns: false,
|
|
248
364
|
showTimeFilter: false,
|
|
365
|
+
includeGrants: false,
|
|
249
366
|
mode: "portal"
|
|
250
367
|
},
|
|
251
368
|
rawProps
|
package/es/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ import AutoTopupModal from './components/auto-topup/modal';
|
|
|
40
40
|
import AutoTopup from './components/auto-topup';
|
|
41
41
|
import Collapse from './components/collapse';
|
|
42
42
|
import PromotionCode from './components/promotion-code';
|
|
43
|
+
import SourceDataViewer from './components/source-data-viewer';
|
|
43
44
|
export { PaymentThemeProvider } from './theme';
|
|
44
45
|
export * from './libs/util';
|
|
45
46
|
export * from './libs/connect';
|
|
@@ -54,4 +55,4 @@ export * from './hooks/scroll';
|
|
|
54
55
|
export * from './hooks/keyboard';
|
|
55
56
|
export * from './libs/validator';
|
|
56
57
|
export { translations, createTranslator } from './locales';
|
|
57
|
-
export { createLazyComponent, api, dayjs, FormInput, FormLabel, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, PaymentBeneficiaries, LoadingButton, DonateDetails, ResumeSubscription, CreditGrantsList, CreditTransactionsList, DateRangePicker, CreditStatusChip, AutoTopupModal, AutoTopup, Collapse, PromotionCode, };
|
|
58
|
+
export { createLazyComponent, api, dayjs, FormInput, FormLabel, PhoneInput, AddressForm, StripeForm, Status, Livemode, Switch, ConfirmDialog, CheckoutForm, CheckoutTable, CheckoutDonate, CurrencySelector, Payment, PaymentSummary, PricingTable, ProductSkeleton, Amount, CustomerInvoiceList, CustomerPaymentList, TxLink, TxGas, SafeGuard, PricingItem, CountrySelect, Table, TruncatedText, Link, OverdueInvoicePayment, PaymentBeneficiaries, LoadingButton, DonateDetails, ResumeSubscription, CreditGrantsList, CreditTransactionsList, DateRangePicker, CreditStatusChip, AutoTopupModal, AutoTopup, Collapse, PromotionCode, SourceDataViewer, };
|
package/es/index.js
CHANGED
|
@@ -40,6 +40,7 @@ import AutoTopupModal from "./components/auto-topup/modal.js";
|
|
|
40
40
|
import AutoTopup from "./components/auto-topup/index.js";
|
|
41
41
|
import Collapse from "./components/collapse.js";
|
|
42
42
|
import PromotionCode from "./components/promotion-code.js";
|
|
43
|
+
import SourceDataViewer from "./components/source-data-viewer.js";
|
|
43
44
|
export { PaymentThemeProvider } from "./theme/index.js";
|
|
44
45
|
export * from "./libs/util.js";
|
|
45
46
|
export * from "./libs/connect.js";
|
|
@@ -98,5 +99,6 @@ export {
|
|
|
98
99
|
AutoTopupModal,
|
|
99
100
|
AutoTopup,
|
|
100
101
|
Collapse,
|
|
101
|
-
PromotionCode
|
|
102
|
+
PromotionCode,
|
|
103
|
+
SourceDataViewer
|
|
102
104
|
};
|
package/es/locales/en.js
CHANGED
package/es/locales/zh.js
CHANGED
|
@@ -107,7 +107,8 @@ export default flat({
|
|
|
107
107
|
confirm: "\u786E\u8BA4",
|
|
108
108
|
cancel: "\u53D6\u6D88"
|
|
109
109
|
},
|
|
110
|
-
paymentMethod: "\u652F\u4ED8\u65B9\u5F0F"
|
|
110
|
+
paymentMethod: "\u652F\u4ED8\u65B9\u5F0F",
|
|
111
|
+
viewInvoice: "\u67E5\u770B\u8D26\u5355"
|
|
111
112
|
},
|
|
112
113
|
payment: {
|
|
113
114
|
checkout: {
|
package/es/payment/index.js
CHANGED
|
@@ -135,10 +135,7 @@ function PaymentInner({
|
|
|
135
135
|
const currencyId = useWatch({ control: methods.control, name: "payment_currency", defaultValue: defaultCurrencyId });
|
|
136
136
|
const currency = findCurrency(paymentMethods, currencyId) || settings.baseCurrency;
|
|
137
137
|
const method = paymentMethods.find((x) => x.id === currency.payment_method_id);
|
|
138
|
-
|
|
139
|
-
if (onChange) {
|
|
140
|
-
onChange(methods.getValues());
|
|
141
|
-
}
|
|
138
|
+
const recalculatePromotion = () => {
|
|
142
139
|
if (state.checkoutSession?.discounts?.length) {
|
|
143
140
|
api.post(`/api/checkout-sessions/${state.checkoutSession.id}/recalculate-promotion`, {
|
|
144
141
|
currency_id: currencyId
|
|
@@ -146,10 +143,20 @@ function PaymentInner({
|
|
|
146
143
|
onPromotionUpdate();
|
|
147
144
|
});
|
|
148
145
|
}
|
|
146
|
+
};
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (onChange) {
|
|
149
|
+
onChange(methods.getValues());
|
|
150
|
+
}
|
|
151
|
+
recalculatePromotion();
|
|
149
152
|
}, [currencyId]);
|
|
150
153
|
const onUpsell = async (from, to) => {
|
|
151
154
|
try {
|
|
152
155
|
const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/upsell`, { from, to });
|
|
156
|
+
if (data.discounts?.length) {
|
|
157
|
+
recalculatePromotion();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
153
160
|
setState({ checkoutSession: data });
|
|
154
161
|
} catch (err) {
|
|
155
162
|
console.error(err);
|
|
@@ -159,6 +166,10 @@ function PaymentInner({
|
|
|
159
166
|
const onDownsell = async (from) => {
|
|
160
167
|
try {
|
|
161
168
|
const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/downsell`, { from });
|
|
169
|
+
if (data.discounts?.length) {
|
|
170
|
+
recalculatePromotion();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
162
173
|
setState({ checkoutSession: data });
|
|
163
174
|
} catch (err) {
|
|
164
175
|
console.error(err);
|
|
@@ -168,6 +179,10 @@ function PaymentInner({
|
|
|
168
179
|
const onApplyCrossSell = async (to) => {
|
|
169
180
|
try {
|
|
170
181
|
const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/cross-sell`, { to });
|
|
182
|
+
if (data.discounts?.length) {
|
|
183
|
+
recalculatePromotion();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
171
186
|
setState({ checkoutSession: data });
|
|
172
187
|
} catch (err) {
|
|
173
188
|
console.error(err);
|
|
@@ -180,6 +195,10 @@ function PaymentInner({
|
|
|
180
195
|
itemId,
|
|
181
196
|
quantity
|
|
182
197
|
});
|
|
198
|
+
if (data.discounts?.length) {
|
|
199
|
+
recalculatePromotion();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
183
202
|
setState({ checkoutSession: data });
|
|
184
203
|
} catch (err) {
|
|
185
204
|
console.error(err);
|
|
@@ -189,6 +208,10 @@ function PaymentInner({
|
|
|
189
208
|
const onCancelCrossSell = async () => {
|
|
190
209
|
try {
|
|
191
210
|
const { data } = await api.delete(`/api/checkout-sessions/${state.checkoutSession.id}/cross-sell`);
|
|
211
|
+
if (data.discounts?.length) {
|
|
212
|
+
recalculatePromotion();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
192
215
|
setState({ checkoutSession: data });
|
|
193
216
|
} catch (err) {
|
|
194
217
|
console.error(err);
|
|
@@ -201,6 +224,10 @@ function PaymentInner({
|
|
|
201
224
|
priceId,
|
|
202
225
|
amount: fromTokenToUnit(amount, currency.decimal).toString()
|
|
203
226
|
});
|
|
227
|
+
if (data.discounts?.length) {
|
|
228
|
+
recalculatePromotion();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
204
231
|
setState({ checkoutSession: data });
|
|
205
232
|
} catch (err) {
|
|
206
233
|
console.error(err);
|