payment-kit 1.18.12 → 1.18.13
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/api/src/libs/notification/template/one-time-payment-succeeded.ts +5 -3
- package/api/src/libs/notification/template/subscription-canceled.ts +3 -3
- package/api/src/libs/notification/template/subscription-refund-succeeded.ts +4 -3
- package/api/src/libs/notification/template/subscription-renew-failed.ts +5 -4
- package/api/src/libs/notification/template/subscription-renewed.ts +2 -1
- package/api/src/libs/notification/template/subscription-stake-slash-succeeded.ts +3 -4
- package/api/src/libs/notification/template/subscription-succeeded.ts +2 -1
- package/api/src/libs/notification/template/subscription-upgraded.ts +6 -4
- package/api/src/libs/notification/template/subscription-will-canceled.ts +6 -3
- package/api/src/libs/notification/template/subscription-will-renew.ts +1 -1
- package/api/src/routes/customers.ts +79 -5
- package/api/src/routes/subscriptions.ts +13 -1
- package/api/src/store/models/invoice.ts +4 -2
- package/blocklet.yml +2 -2
- package/package.json +4 -4
- package/src/app.tsx +17 -17
- package/src/components/actions.tsx +32 -9
- package/src/components/copyable.tsx +2 -2
- package/src/components/layout/user.tsx +37 -0
- package/src/components/subscription/portal/actions.tsx +26 -5
- package/src/components/subscription/portal/list.tsx +24 -6
- package/src/components/subscription/status.tsx +2 -2
- package/src/libs/util.ts +15 -0
- package/src/pages/admin/payments/payouts/detail.tsx +6 -1
- package/src/pages/customer/index.tsx +247 -154
- package/src/pages/customer/invoice/detail.tsx +1 -1
- package/src/pages/customer/payout/detail.tsx +9 -2
- package/src/pages/customer/recharge.tsx +6 -2
- package/src/pages/customer/subscription/change-payment.tsx +1 -1
- package/src/pages/customer/subscription/change-plan.tsx +1 -1
- package/src/pages/customer/subscription/detail.tsx +8 -3
- package/src/pages/customer/subscription/embed.tsx +142 -84
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
import type { GroupedBN, TCustomerExpanded } from '@blocklet/payment-types';
|
|
15
15
|
import { ExpandMore } from '@mui/icons-material';
|
|
16
16
|
import {
|
|
17
|
-
Alert,
|
|
18
17
|
Avatar,
|
|
19
18
|
Box,
|
|
20
19
|
Button,
|
|
@@ -22,9 +21,11 @@ import {
|
|
|
22
21
|
Grid,
|
|
23
22
|
MenuItem,
|
|
24
23
|
Select,
|
|
24
|
+
Skeleton,
|
|
25
25
|
Stack,
|
|
26
26
|
Tooltip,
|
|
27
27
|
Typography,
|
|
28
|
+
Alert,
|
|
28
29
|
} from '@mui/material';
|
|
29
30
|
import type { SelectChangeEvent } from '@mui/material/Select';
|
|
30
31
|
import { styled, SxProps } from '@mui/system';
|
|
@@ -37,7 +38,7 @@ import { joinURL } from 'ufo';
|
|
|
37
38
|
|
|
38
39
|
import EditCustomer from '../../components/customer/edit';
|
|
39
40
|
import InfoRow from '../../components/info-row';
|
|
40
|
-
import
|
|
41
|
+
import { useTransitionContext } from '../../components/progress-bar';
|
|
41
42
|
import CurrentSubscriptions from '../../components/subscription/portal/list';
|
|
42
43
|
import { useSessionContext } from '../../contexts/session';
|
|
43
44
|
import api from '../../libs/api';
|
|
@@ -46,7 +47,7 @@ import CustomerRevenueList from '../../components/payouts/portal/list';
|
|
|
46
47
|
type Result = TCustomerExpanded & { summary: { [key: string]: GroupedBN }; error?: string };
|
|
47
48
|
|
|
48
49
|
const fetchData = (): Promise<Result> => {
|
|
49
|
-
return api.get('/api/customers/me').then((res) => res.data);
|
|
50
|
+
return api.get('/api/customers/me?skipError=true&create=true').then((res) => res.data);
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
const emptyObject = {};
|
|
@@ -68,7 +69,8 @@ const CurrencyCard = memo(
|
|
|
68
69
|
};
|
|
69
70
|
sx: SxProps;
|
|
70
71
|
}) => {
|
|
71
|
-
const
|
|
72
|
+
const safeData = data || {};
|
|
73
|
+
const value = formatBNStr(safeData[currency?.id], currency?.decimal, 6, false);
|
|
72
74
|
return (
|
|
73
75
|
<Box
|
|
74
76
|
sx={{
|
|
@@ -87,11 +89,68 @@ const CurrencyCard = memo(
|
|
|
87
89
|
}
|
|
88
90
|
);
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
const CardSkeleton = memo(({ height = 100 }: { height: number }) => {
|
|
93
|
+
return (
|
|
94
|
+
<Box className="base-card section">
|
|
95
|
+
<Box className="section-header" display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
96
|
+
<Skeleton variant="text" width={150} height={32} />
|
|
97
|
+
</Box>
|
|
98
|
+
<Skeleton variant="rectangular" height={height} />
|
|
99
|
+
</Box>
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
function SummaryCardSkeleton() {
|
|
104
|
+
return (
|
|
105
|
+
<Box className="base-card section section-summary">
|
|
106
|
+
<Skeleton variant="text" width={150} height={32} sx={{ mb: 2 }} />
|
|
107
|
+
<Stack gap={1}>
|
|
108
|
+
<Stack direction="row" spacing={2}>
|
|
109
|
+
<Skeleton variant="rectangular" height={88} width="100%" />
|
|
110
|
+
<Skeleton variant="rectangular" height={88} width="100%" />
|
|
111
|
+
</Stack>
|
|
112
|
+
<Stack direction="row" spacing={2}>
|
|
113
|
+
<Skeleton variant="rectangular" height={88} width="100%" />
|
|
114
|
+
<Skeleton variant="rectangular" height={88} width="100%" />
|
|
115
|
+
</Stack>
|
|
116
|
+
<Stack direction="row">
|
|
117
|
+
<Skeleton variant="rectangular" height={88} width="calc(50% - 8px)" />
|
|
118
|
+
</Stack>
|
|
119
|
+
</Stack>
|
|
120
|
+
</Box>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function DetailCardSkeleton() {
|
|
125
|
+
return (
|
|
126
|
+
<Box className="base-card section section-detail">
|
|
127
|
+
<Box className="section-header" display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
128
|
+
<Skeleton variant="text" width={150} height={32} />
|
|
129
|
+
<Skeleton variant="text" width={80} height={20} />
|
|
130
|
+
</Box>
|
|
131
|
+
<Stack direction="row" spacing={2} mb={3}>
|
|
132
|
+
<Skeleton variant="circular" width={48} height={48} sx={{ minWidth: '48px' }} />
|
|
133
|
+
<Box width="100%">
|
|
134
|
+
<Skeleton variant="text" width="80%" />
|
|
135
|
+
<Skeleton variant="text" width="60%" />
|
|
136
|
+
</Box>
|
|
137
|
+
</Stack>
|
|
138
|
+
<Stack spacing={1}>
|
|
139
|
+
{[...Array(7)].map((_, i) => (
|
|
140
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
141
|
+
<Stack key={i} direction="column" spacing={0.5}>
|
|
142
|
+
<Skeleton variant="text" width="30%" />
|
|
143
|
+
<Skeleton variant="text" width="70%" />
|
|
144
|
+
</Stack>
|
|
145
|
+
))}
|
|
146
|
+
</Stack>
|
|
147
|
+
</Box>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
91
150
|
|
|
92
151
|
export default function CustomerHome() {
|
|
93
152
|
const { t } = useLocaleContext();
|
|
94
|
-
const { events } = useSessionContext();
|
|
153
|
+
const { events, session } = useSessionContext();
|
|
95
154
|
const { settings } = usePaymentContext();
|
|
96
155
|
const [currency, setCurrency] = useState(settings?.baseCurrency);
|
|
97
156
|
const [subscriptionLoading, setSubscriptionLoading] = useState(false);
|
|
@@ -113,11 +172,19 @@ export default function CustomerHome() {
|
|
|
113
172
|
});
|
|
114
173
|
const navigate = useNavigate();
|
|
115
174
|
const { isMobile } = useMobile('lg');
|
|
116
|
-
const
|
|
117
|
-
const {
|
|
175
|
+
const [subscriptionStatus, setSubscriptionStatus] = useState(false);
|
|
176
|
+
const { startTransition } = useTransitionContext();
|
|
177
|
+
const {
|
|
178
|
+
data,
|
|
179
|
+
error,
|
|
180
|
+
runAsync,
|
|
181
|
+
loading = true,
|
|
182
|
+
} = useRequest(fetchData, {
|
|
118
183
|
manual: true,
|
|
119
184
|
});
|
|
120
185
|
|
|
186
|
+
const loadingCard = loading || !data;
|
|
187
|
+
|
|
121
188
|
const countryDetail = useMemo(() => {
|
|
122
189
|
const item = defaultCountries.find((v) => v[1] === data?.address?.country);
|
|
123
190
|
return item ? parseCountry(item) : { name: '' };
|
|
@@ -131,39 +198,33 @@ export default function CustomerHome() {
|
|
|
131
198
|
}, []);
|
|
132
199
|
|
|
133
200
|
useEffect(() => {
|
|
134
|
-
if (data && data.livemode !== livemode) {
|
|
201
|
+
if (data && !data.error && data.livemode !== livemode) {
|
|
135
202
|
setLivemode(data.livemode);
|
|
136
203
|
}
|
|
137
204
|
}, [data]);
|
|
138
205
|
|
|
139
|
-
if (loading) {
|
|
140
|
-
return <ProgressBar pending />;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
206
|
if (error) {
|
|
144
207
|
return (
|
|
145
|
-
<
|
|
146
|
-
{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
{t('payment.customer.empty')}
|
|
159
|
-
</Alert>
|
|
208
|
+
<Box
|
|
209
|
+
sx={{
|
|
210
|
+
backgroundColor: 'error.light',
|
|
211
|
+
color: 'error.dark',
|
|
212
|
+
p: 1,
|
|
213
|
+
mb: 2,
|
|
214
|
+
borderRadius: 1,
|
|
215
|
+
display: 'flex',
|
|
216
|
+
alignItems: 'center',
|
|
217
|
+
justifyContent: 'center',
|
|
218
|
+
}}>
|
|
219
|
+
<Typography variant="body2">{formatError(error)}</Typography>
|
|
220
|
+
</Box>
|
|
160
221
|
);
|
|
161
222
|
}
|
|
162
223
|
|
|
163
224
|
const onUpdateInfo = async (updates: TCustomerExpanded) => {
|
|
164
225
|
try {
|
|
165
226
|
setState({ loading: true });
|
|
166
|
-
await api.put(`/api/customers/${data
|
|
227
|
+
await api.put(`/api/customers/${data?.id}`, updates).then((res) => res.data);
|
|
167
228
|
Toast.success(t('common.saved'));
|
|
168
229
|
runAsync();
|
|
169
230
|
} catch (err) {
|
|
@@ -181,43 +242,46 @@ export default function CustomerHome() {
|
|
|
181
242
|
setSubscriptionLoading(false);
|
|
182
243
|
}, 300);
|
|
183
244
|
};
|
|
184
|
-
|
|
185
245
|
const handleCurrencyChange = (e: SelectChangeEvent) => {
|
|
186
246
|
const newCurrency = currencies.find((c) => c.id === e.target.value) || settings?.baseCurrency;
|
|
187
247
|
setCurrency(newCurrency);
|
|
188
248
|
};
|
|
189
249
|
|
|
190
|
-
const SubscriptionCard = (
|
|
250
|
+
const SubscriptionCard = loadingCard ? (
|
|
251
|
+
<CardSkeleton height={200} />
|
|
252
|
+
) : (
|
|
191
253
|
<Box className="base-card section section-subscription">
|
|
192
254
|
<Box className="section-header">
|
|
193
255
|
<Typography variant="h3">{t('admin.subscription.name')}</Typography>
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
256
|
+
{subscriptionStatus && (
|
|
257
|
+
<FormControl
|
|
258
|
+
sx={{
|
|
259
|
+
'.MuiInputBase-root': {
|
|
260
|
+
background: 'none',
|
|
261
|
+
border: 'none',
|
|
262
|
+
},
|
|
263
|
+
'.MuiOutlinedInput-notchedOutline': {
|
|
264
|
+
border: 'none',
|
|
265
|
+
},
|
|
266
|
+
}}>
|
|
267
|
+
<Select
|
|
268
|
+
value={state.onlyActive ? 'active' : ''}
|
|
269
|
+
onChange={onToggleActive}
|
|
270
|
+
displayEmpty
|
|
271
|
+
IconComponent={ExpandMore}
|
|
272
|
+
inputProps={{ 'aria-label': 'Without label' }}>
|
|
273
|
+
<MenuItem value="">All</MenuItem>
|
|
274
|
+
<MenuItem value="active">Active</MenuItem>
|
|
275
|
+
</Select>
|
|
276
|
+
</FormControl>
|
|
277
|
+
)}
|
|
214
278
|
</Box>
|
|
215
279
|
<Box className="section-body">
|
|
216
280
|
{subscriptionLoading ? (
|
|
217
281
|
<Box>{t('common.loading')}</Box>
|
|
218
282
|
) : (
|
|
219
283
|
<CurrentSubscriptions
|
|
220
|
-
id={data
|
|
284
|
+
id={data?.id}
|
|
221
285
|
onlyActive={state.onlyActive}
|
|
222
286
|
changeActive={(v) => setState({ onlyActive: v })}
|
|
223
287
|
status={state.onlyActive ? 'active,trialing,past_due' : 'active,trialing,paused,past_due,canceled'}
|
|
@@ -229,99 +293,110 @@ export default function CustomerHome() {
|
|
|
229
293
|
navigate(`/customer/subscription/${subscription.id}`);
|
|
230
294
|
});
|
|
231
295
|
}}
|
|
296
|
+
setStatusState={setSubscriptionStatus}
|
|
232
297
|
/>
|
|
233
298
|
)}
|
|
234
299
|
</Box>
|
|
235
300
|
</Box>
|
|
236
301
|
);
|
|
237
|
-
|
|
302
|
+
|
|
303
|
+
const SummaryCard = loadingCard ? (
|
|
304
|
+
<SummaryCardSkeleton />
|
|
305
|
+
) : (
|
|
238
306
|
<Box className="base-card section section-summary">
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
307
|
+
{data?.summary && (
|
|
308
|
+
<>
|
|
309
|
+
<Box className="section-header">
|
|
310
|
+
<Typography variant="h3">{t('admin.customer.summary.stats')}</Typography>
|
|
311
|
+
<FormControl
|
|
312
|
+
sx={{
|
|
313
|
+
'.MuiInputBase-root': {
|
|
314
|
+
background: 'none',
|
|
315
|
+
border: 'none',
|
|
316
|
+
},
|
|
317
|
+
'.MuiOutlinedInput-notchedOutline': {
|
|
318
|
+
border: 'none',
|
|
319
|
+
},
|
|
320
|
+
}}>
|
|
321
|
+
<Select
|
|
322
|
+
value={currency?.id}
|
|
323
|
+
onChange={handleCurrencyChange}
|
|
324
|
+
displayEmpty
|
|
325
|
+
IconComponent={ExpandMore}
|
|
326
|
+
inputProps={{ 'aria-label': 'Without label' }}>
|
|
327
|
+
{currencies.map((c) => (
|
|
328
|
+
<MenuItem key={c.id} value={c.id}>
|
|
329
|
+
<Box alignItems="center" display="flex" gap={1}>
|
|
330
|
+
<Avatar src={c?.logo} alt={c?.symbol} sx={{ width: 18, height: 18 }} />
|
|
331
|
+
<Typography
|
|
332
|
+
variant="h5"
|
|
333
|
+
component="div"
|
|
334
|
+
sx={{ fontSize: '16px', color: 'text.primary', fontWeight: '500' }}>
|
|
335
|
+
{c?.symbol}
|
|
336
|
+
</Typography>
|
|
337
|
+
<Typography sx={{ fontSize: 12 }} color="text.lighter">
|
|
338
|
+
{c?.methodName}
|
|
339
|
+
</Typography>
|
|
340
|
+
</Box>
|
|
341
|
+
</MenuItem>
|
|
342
|
+
))}
|
|
343
|
+
</Select>
|
|
344
|
+
</FormControl>
|
|
345
|
+
</Box>
|
|
346
|
+
<Stack
|
|
347
|
+
className="section-body"
|
|
348
|
+
sx={{
|
|
349
|
+
display: 'grid',
|
|
350
|
+
gridTemplateColumns: '1fr 1fr',
|
|
351
|
+
gap: 2,
|
|
352
|
+
mt: 1.5,
|
|
353
|
+
}}>
|
|
354
|
+
<CurrencyCard
|
|
355
|
+
label={t('admin.customer.summary.balance')}
|
|
356
|
+
data={data?.summary?.token || emptyObject}
|
|
357
|
+
currency={currency}
|
|
358
|
+
sx={{
|
|
359
|
+
background: 'var(--tags-tag-orange-bg, #B7FEE3)',
|
|
360
|
+
color: 'var(--tags-tag-orange-text, #007C52)',
|
|
361
|
+
}}
|
|
362
|
+
/>
|
|
363
|
+
<CurrencyCard
|
|
364
|
+
label={t('admin.customer.summary.spent')}
|
|
365
|
+
data={data?.summary?.paid || emptyObject}
|
|
366
|
+
currency={currency}
|
|
367
|
+
sx={{ background: 'var(--tags-tag-green-bg, #B7FEE3)', color: 'var(--tags-tag-green-text, #007C52)' }}
|
|
368
|
+
/>
|
|
369
|
+
<CurrencyCard
|
|
370
|
+
label={t('admin.customer.summary.stake')}
|
|
371
|
+
data={data?.summary?.stake || emptyObject}
|
|
372
|
+
currency={currency}
|
|
373
|
+
sx={{ background: 'var(--tags-tag-blue-bg, #D2ECFF)', color: 'var(--tags-tag-blue-text, #0051E9)' }}
|
|
374
|
+
/>
|
|
375
|
+
<CurrencyCard
|
|
376
|
+
label={t('admin.customer.summary.refund')}
|
|
377
|
+
data={data?.summary?.refund || emptyObject}
|
|
378
|
+
currency={currency}
|
|
379
|
+
sx={{ background: 'var(--tags-tag-purple-bg, #EFE9FF)', color: 'var(--tags-tag-purple-text, #007C52)' }}
|
|
380
|
+
/>
|
|
381
|
+
<CurrencyCard
|
|
382
|
+
label={t('admin.customer.summary.due')}
|
|
383
|
+
data={data?.summary?.due || emptyObject}
|
|
384
|
+
currency={currency}
|
|
385
|
+
sx={{ background: 'var(--tags-tag-red-bg, #FFE2E6)', color: 'var(--tags-tag-red-text, #E40031)' }}
|
|
386
|
+
/>
|
|
387
|
+
</Stack>
|
|
388
|
+
</>
|
|
389
|
+
)}
|
|
318
390
|
</Box>
|
|
319
391
|
);
|
|
320
|
-
|
|
321
|
-
|
|
392
|
+
|
|
393
|
+
const InvoiceCard = loadingCard ? (
|
|
394
|
+
<CardSkeleton height={300} />
|
|
395
|
+
) : (
|
|
396
|
+
<Box className="base-card section section-invoices">
|
|
322
397
|
<Box className="section-header">
|
|
323
398
|
<Typography variant="h3">{t('customer.invoiceHistory')}</Typography>
|
|
324
|
-
{isEmpty(data
|
|
399
|
+
{isEmpty(data?.summary?.due) === false && (
|
|
325
400
|
<Tooltip title={t('payment.customer.pastDue.warning')}>
|
|
326
401
|
<Button
|
|
327
402
|
variant="text"
|
|
@@ -338,12 +413,14 @@ export default function CustomerHome() {
|
|
|
338
413
|
)}
|
|
339
414
|
</Box>
|
|
340
415
|
<Box className="section-body">
|
|
341
|
-
<CustomerInvoiceList customer_id={data
|
|
416
|
+
<CustomerInvoiceList customer_id={data?.id} type="table" include_staking />
|
|
342
417
|
</Box>
|
|
343
418
|
</Box>
|
|
344
419
|
);
|
|
345
420
|
|
|
346
|
-
const DetailCard = (
|
|
421
|
+
const DetailCard = loadingCard ? (
|
|
422
|
+
<DetailCardSkeleton />
|
|
423
|
+
) : (
|
|
347
424
|
<Box className="base-card section section-detail">
|
|
348
425
|
<Box className="section-header" sx={{ mb: 2 }}>
|
|
349
426
|
<Typography variant="h3">{t('payment.customer.details')}</Typography>
|
|
@@ -355,33 +432,40 @@ export default function CustomerHome() {
|
|
|
355
432
|
{t('common.edit')}
|
|
356
433
|
</Button>
|
|
357
434
|
</Box>
|
|
358
|
-
<Box display="flex" alignItems="center" gap={1}
|
|
435
|
+
<Box display="flex" alignItems="center" gap={1} sx={{ mb: 3 }}>
|
|
359
436
|
<Avatar
|
|
360
437
|
title={data?.name}
|
|
361
438
|
src={getCustomerAvatar(data?.did, data?.updated_at ? new Date(data.updated_at).toISOString() : '', 48)}
|
|
362
439
|
variant="circular"
|
|
363
440
|
sx={{ width: 48, height: 48 }}
|
|
364
441
|
/>
|
|
365
|
-
<Box>
|
|
442
|
+
<Box sx={{ minWidth: 0, flexGrow: 1 }}>
|
|
366
443
|
<Typography variant="h4" gutterBottom>
|
|
367
|
-
{data.
|
|
444
|
+
{data?.name || t('common.none')}
|
|
368
445
|
</Typography>
|
|
369
446
|
<Typography variant="body2" color="text.secondary">
|
|
370
|
-
|
|
447
|
+
{(data?.did || session.user?.did) && (
|
|
448
|
+
<DID
|
|
449
|
+
did={data?.did || session.user?.did || ''}
|
|
450
|
+
copyable
|
|
451
|
+
showQrcode
|
|
452
|
+
chainId={livemode ? 'main' : 'beta'}
|
|
453
|
+
/>
|
|
454
|
+
)}
|
|
371
455
|
</Typography>
|
|
372
456
|
</Box>
|
|
373
457
|
</Box>
|
|
374
458
|
<Stack>
|
|
375
459
|
<InfoRow
|
|
376
460
|
label={t('admin.customer.phone')}
|
|
377
|
-
value={data
|
|
461
|
+
value={data?.phone}
|
|
378
462
|
sizes={[1, 1]}
|
|
379
463
|
alignItems="normal"
|
|
380
464
|
direction="column"
|
|
381
465
|
/>
|
|
382
466
|
<InfoRow
|
|
383
467
|
label={t('admin.customer.email')}
|
|
384
|
-
value={data
|
|
468
|
+
value={data?.email}
|
|
385
469
|
sizes={[1, 1]}
|
|
386
470
|
alignItems="normal"
|
|
387
471
|
direction="column"
|
|
@@ -389,13 +473,13 @@ export default function CustomerHome() {
|
|
|
389
473
|
<InfoRow
|
|
390
474
|
label={t('admin.customer.address.country')}
|
|
391
475
|
value={
|
|
392
|
-
data
|
|
476
|
+
data?.address?.country ? (
|
|
393
477
|
<Box display="flex" alignItems="center" flexWrap="nowrap" gap={0.5} sx={{ cursor: 'pointer' }}>
|
|
394
478
|
<FlagEmoji iso2={data.address?.country} style={{ display: 'flex', width: 24 }} />
|
|
395
479
|
<Typography>{countryDetail?.name}</Typography>
|
|
396
480
|
</Box>
|
|
397
481
|
) : (
|
|
398
|
-
''
|
|
482
|
+
t('common.none')
|
|
399
483
|
)
|
|
400
484
|
}
|
|
401
485
|
sizes={[1, 1]}
|
|
@@ -404,36 +488,35 @@ export default function CustomerHome() {
|
|
|
404
488
|
/>
|
|
405
489
|
<InfoRow
|
|
406
490
|
label={t('admin.customer.address.state')}
|
|
407
|
-
value={data
|
|
491
|
+
value={data?.address?.state}
|
|
408
492
|
sizes={[1, 1]}
|
|
409
493
|
alignItems="normal"
|
|
410
494
|
direction="column"
|
|
411
495
|
/>
|
|
412
496
|
<InfoRow
|
|
413
497
|
label={t('admin.customer.address.city')}
|
|
414
|
-
value={data
|
|
415
|
-
// value={data.address?.city}
|
|
498
|
+
value={data?.address?.city && <TruncatedText text={data.address?.city} maxLength={280} useWidth />}
|
|
416
499
|
sizes={[1, 1]}
|
|
417
500
|
alignItems="normal"
|
|
418
501
|
direction="column"
|
|
419
502
|
/>
|
|
420
503
|
<InfoRow
|
|
421
504
|
label={t('admin.customer.address.line1')}
|
|
422
|
-
value={data
|
|
505
|
+
value={data?.address?.line1 && <TruncatedText text={data.address?.line1} maxLength={280} useWidth />}
|
|
423
506
|
sizes={[1, 1]}
|
|
424
507
|
alignItems="normal"
|
|
425
508
|
direction="column"
|
|
426
509
|
/>
|
|
427
510
|
<InfoRow
|
|
428
511
|
label={t('admin.customer.address.line2')}
|
|
429
|
-
value={data
|
|
512
|
+
value={data?.address?.line2 && <TruncatedText text={data.address?.line2} maxLength={280} useWidth />}
|
|
430
513
|
sizes={[1, 1]}
|
|
431
514
|
alignItems="normal"
|
|
432
515
|
direction="column"
|
|
433
516
|
/>
|
|
434
517
|
<InfoRow
|
|
435
518
|
label={t('admin.customer.address.postal_code')}
|
|
436
|
-
value={data
|
|
519
|
+
value={data?.address?.postal_code}
|
|
437
520
|
sizes={[1, 1]}
|
|
438
521
|
alignItems="normal"
|
|
439
522
|
direction="column"
|
|
@@ -450,7 +533,9 @@ export default function CustomerHome() {
|
|
|
450
533
|
</Box>
|
|
451
534
|
);
|
|
452
535
|
|
|
453
|
-
const RevenueCard = (
|
|
536
|
+
const RevenueCard = loadingCard ? (
|
|
537
|
+
<CardSkeleton height={200} />
|
|
538
|
+
) : (
|
|
454
539
|
<Box className="base-card section section-revenue">
|
|
455
540
|
<Box className="section-header">
|
|
456
541
|
<Typography variant="h3">{t('customer.payout.title')}</Typography>
|
|
@@ -461,7 +546,11 @@ export default function CustomerHome() {
|
|
|
461
546
|
|
|
462
547
|
return (
|
|
463
548
|
<Content>
|
|
464
|
-
|
|
549
|
+
{data?.error && (
|
|
550
|
+
<Alert severity="error" sx={{ mb: 2 }}>
|
|
551
|
+
{data?.error}
|
|
552
|
+
</Alert>
|
|
553
|
+
)}
|
|
465
554
|
{isMobile ? (
|
|
466
555
|
<Root>
|
|
467
556
|
{SummaryCard}
|
|
@@ -492,7 +581,6 @@ export default function CustomerHome() {
|
|
|
492
581
|
}
|
|
493
582
|
|
|
494
583
|
const Content = styled(Stack)`
|
|
495
|
-
padding: 20px;
|
|
496
584
|
height: 100%;
|
|
497
585
|
.section-header {
|
|
498
586
|
display: flex;
|
|
@@ -521,9 +609,14 @@ const Root = styled(Stack)`
|
|
|
521
609
|
.base-card {
|
|
522
610
|
border: none;
|
|
523
611
|
box-shadow: none;
|
|
612
|
+
padding-left: 0;
|
|
613
|
+
padding-right: 0;
|
|
524
614
|
}
|
|
525
615
|
.section-header h3 {
|
|
526
616
|
font-size: 18px;
|
|
527
617
|
}
|
|
618
|
+
.section-summary {
|
|
619
|
+
padding-top: 0;
|
|
620
|
+
}
|
|
528
621
|
}
|
|
529
622
|
`;
|
|
@@ -125,7 +125,7 @@ export default function CustomerInvoiceDetail() {
|
|
|
125
125
|
const hidePayButton = data.billing_reason === 'overdraft_protection';
|
|
126
126
|
const paymentDetails = data.paymentIntent?.payment_details || data.metadata?.payment_details;
|
|
127
127
|
return (
|
|
128
|
-
<InvoiceDetailRoot direction="column" spacing={3}
|
|
128
|
+
<InvoiceDetailRoot direction="column" spacing={3}>
|
|
129
129
|
<Stack direction="row" justifyContent="space-between">
|
|
130
130
|
<Stack
|
|
131
131
|
direction="row"
|