@shoppexio/storefront-react 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -0
- package/dist/account.css +4 -8
- package/dist/account.js +2387 -942
- package/dist/account.js.map +1 -1
- package/dist/{chunk-ZEFZPUAW.js → chunk-NBOIS53R.js} +2 -1
- package/dist/chunk-NBOIS53R.js.map +1 -0
- package/dist/index.d.ts +243 -29
- package/dist/index.js +221 -77
- package/dist/index.js.map +1 -1
- package/eject/account/account-availability.ts +4 -1
- package/eject/account/account-downloads.ts +89 -1
- package/eject/account/account-referrals.ts +249 -7
- package/eject/account/account-reseller.ts +6 -140
- package/eject/account/dashboard.tsx +1 -0
- package/eject/account/downloads.tsx +73 -4
- package/eject/account/hosted-page.ts +45 -0
- package/eject/account/messages/ar.json +94 -31
- package/eject/account/messages/de.json +94 -31
- package/eject/account/messages/en.json +94 -31
- package/eject/account/messages/es.json +94 -31
- package/eject/account/messages/fi.json +94 -31
- package/eject/account/messages/fr.json +94 -31
- package/eject/account/messages/hi.json +94 -31
- package/eject/account/messages/it.json +94 -31
- package/eject/account/messages/lt.json +94 -31
- package/eject/account/messages/nl.json +94 -31
- package/eject/account/messages/pl.json +94 -31
- package/eject/account/messages/pt.json +94 -31
- package/eject/account/messages/ru.json +94 -31
- package/eject/account/messages/tr.json +94 -31
- package/eject/account/messages/uk.json +94 -31
- package/eject/account/messages/zh.json +94 -31
- package/eject/account/orders.tsx +141 -0
- package/eject/account/overview.tsx +6 -0
- package/eject/account/referrals.tsx +444 -156
- package/eject/account/reseller.tsx +59 -306
- package/eject/account/rewards.tsx +43 -6
- package/eject/account/settings.tsx +98 -2
- package/eject/account/shared.tsx +42 -3
- package/eject/account/subscriptions.tsx +75 -16
- package/package.json +7 -4
- package/dist/chunk-ZEFZPUAW.js.map +0 -1
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"account": {
|
|
13
13
|
"title": "Ваш акаунт",
|
|
14
|
+
"secureLink": "Відкриється захищена сторінка Shoppex.",
|
|
14
15
|
"sections": "Розділи акаунта",
|
|
15
16
|
"signOut": "Вийти",
|
|
16
17
|
"signingOut": "Виходимо…",
|
|
@@ -107,6 +108,7 @@
|
|
|
107
108
|
"statTickets": "Звернення в підтримку",
|
|
108
109
|
"walletLabel": "Баланс магазину",
|
|
109
110
|
"walletNote": "Застосовується при оформленні",
|
|
111
|
+
"topUp": "Поповнити",
|
|
110
112
|
"recentOrders": "Останні замовлення",
|
|
111
113
|
"allOrders": "Усі замовлення"
|
|
112
114
|
},
|
|
@@ -159,7 +161,20 @@
|
|
|
159
161
|
"warrantyClaimSending": "Надсилаємо…",
|
|
160
162
|
"warrantyClaimDone": "Магазин отримав ваше звернення. Відповідь надійде на пошту.",
|
|
161
163
|
"warrantyClaimFailed": "Не вдалося надіслати звернення.",
|
|
162
|
-
"warrantyClaimTooLong": "Звернення не має перевищувати {max} символів."
|
|
164
|
+
"warrantyClaimTooLong": "Звернення не має перевищувати {max} символів.",
|
|
165
|
+
"invoicePdf": "Завантажити рахунок (PDF)",
|
|
166
|
+
"invoicePdfLoading": "Готуємо…",
|
|
167
|
+
"invoicePdfFailed": "Не вдалося завантажити цей рахунок. Спробуйте ще раз.",
|
|
168
|
+
"reviewTitle": "Ваш відгук",
|
|
169
|
+
"reviewPrompt": "Як вам {product}?",
|
|
170
|
+
"reviewPromptGeneric": "Як вам покупка?",
|
|
171
|
+
"reviewPositive": "Позитивна",
|
|
172
|
+
"reviewNeutral": "Нейтральна",
|
|
173
|
+
"reviewNegative": "Негативна",
|
|
174
|
+
"reviewEdit": "Редагувати відгук",
|
|
175
|
+
"reviewWrite": "Написати відгук",
|
|
176
|
+
"reviewAutomated": "Для цього замовлення було опубліковано автоматичний позитивний відгук. Ви можете замінити його своїм.",
|
|
177
|
+
"reviewFallbackLabel": "Відгук"
|
|
163
178
|
},
|
|
164
179
|
"downloads": {
|
|
165
180
|
"loading": "Завантажуємо ваші файли",
|
|
@@ -183,7 +198,25 @@
|
|
|
183
198
|
"renewAction": "Відкрити магазин",
|
|
184
199
|
"brokenTitle": "Не вдалося показати ваші завантаження",
|
|
185
200
|
"brokenBody": "Магазин надіслав запис ліцензії ({id}) без самої ліцензії, тож у цьому списку бракувало б того, що він називає.",
|
|
186
|
-
"brokenFileBody": "Магазин надіслав запис файлу ({id}), у якому немає чого завантажувати, тож список назвав би файл, який неможливо видати."
|
|
201
|
+
"brokenFileBody": "Магазин надіслав запис файлу ({id}), у якому немає чого завантажувати, тож список назвав би файл, який неможливо видати.",
|
|
202
|
+
"accessLeftOne": "Залишилося завантажень: {count}",
|
|
203
|
+
"accessLeftOther": "Залишилося завантажень: {count}",
|
|
204
|
+
"accessUntil": "до {date}",
|
|
205
|
+
"accessLimitReached": "Ви використали всі завантаження",
|
|
206
|
+
"accessLimitReachedOne": "Ви використали єдине завантаження",
|
|
207
|
+
"accessLimitReachedOther": "Ви використали всі завантаження ({count})",
|
|
208
|
+
"accessExpired": "Завантаження завершилися {date}",
|
|
209
|
+
"accessExpiredUndated": "Завантаження завершилися",
|
|
210
|
+
"accessRevoked": "Завантаження для цього замовлення вимкнено",
|
|
211
|
+
"accessRefunded": "Завантаження завершилися, бо за замовлення повернули кошти",
|
|
212
|
+
"askAccess": "Запросити доступ",
|
|
213
|
+
"askingAccess": "Надсилання…",
|
|
214
|
+
"accessRequested": "Запит надіслано",
|
|
215
|
+
"accessRequestDone": "Запит надіслано. Магазин відповість у розділі «Підтримка».",
|
|
216
|
+
"accessRequestFailed": "Не вдалося надіслати запит. Спробуйте ще раз.",
|
|
217
|
+
"accessRequestTitle": "Доступ до {file}",
|
|
218
|
+
"accessRequestMessage": "Я хочу знову завантажити {file} ({product}) з цього замовлення.",
|
|
219
|
+
"accessRequestReason": "На сторінці акаунта зазначено: {reason}."
|
|
187
220
|
},
|
|
188
221
|
"subscriptions": {
|
|
189
222
|
"loading": "Завантажуємо ваші підписки",
|
|
@@ -208,7 +241,6 @@
|
|
|
208
241
|
"paymentMethod": "Спосіб оплати",
|
|
209
242
|
"cardOnFile": "{brand}, що закінчується на {last4}",
|
|
210
243
|
"noPaymentMethod": "Не збережено",
|
|
211
|
-
"paymentMethodElsewhere": "Посилання для зміни платіжних даних надходить у листах самого магазину. Тут його не видають, бо будь-що на цій сторінці могло б його перехопити.",
|
|
212
244
|
"pause": "Призупинити",
|
|
213
245
|
"pausing": "Призупиняємо…",
|
|
214
246
|
"resume": "Відновити",
|
|
@@ -227,7 +259,12 @@
|
|
|
227
259
|
"historyLoading": "Завантажуємо історію платежів",
|
|
228
260
|
"historyEmptyTitle": "Історії платежів поки немає",
|
|
229
261
|
"historyEmptyBody": "Рахунки за продовження з’являться тут після першого циклу.",
|
|
230
|
-
"trial": "Пробний період до {date}"
|
|
262
|
+
"trial": "Пробний період до {date}",
|
|
263
|
+
"renewalDue": "За цією підпискою потрібно оплатити продовження.",
|
|
264
|
+
"payNow": "Оплатити",
|
|
265
|
+
"updateCard": "Оновити картку",
|
|
266
|
+
"pastDueCardTitle": "Останній платіж не пройшов",
|
|
267
|
+
"pastDueCardBody": "Оновіть картку, щоб зберегти підписку. Відкриється захищена сторінка Shoppex."
|
|
231
268
|
},
|
|
232
269
|
"favorites": {
|
|
233
270
|
"loading": "Завантажуємо ваше обране",
|
|
@@ -308,6 +345,18 @@
|
|
|
308
345
|
"primary": "Основне",
|
|
309
346
|
"commission": "{percent}% комісії",
|
|
310
347
|
"buyerDiscount": "{percent}% знижки покупцю",
|
|
348
|
+
"yourRates": "Ваші ставки",
|
|
349
|
+
"ratesEveryProduct": "{percent}% на всі товари",
|
|
350
|
+
"ratesMostProducts": "{percent}% на більшість товарів",
|
|
351
|
+
"ratesProductEarnsNothing": "{product} не приносить комісії",
|
|
352
|
+
"ratesProductsEarnNothing": "{products} не приносять комісії",
|
|
353
|
+
"ratesCustomRateProducts": "Деякі товари мають власну ставку",
|
|
354
|
+
"ratesMoreProducts": "ще {count}",
|
|
355
|
+
"ratesCap": "До {amount} за замовлення",
|
|
356
|
+
"ratesMinimum": "Замовлення до {amount} не приносять комісії",
|
|
357
|
+
"ratesBindingDays": "Покупці залишаються за вами {days} дн.",
|
|
358
|
+
"ratesBindingForever": "Покупці залишаються за вами назавжди",
|
|
359
|
+
"ratesBindingDetail": "Після їхнього першого оплаченого замовлення за вашим посиланням",
|
|
311
360
|
"awaitingApproval": "Очікує на схвалення цього посилання магазином.",
|
|
312
361
|
"clicks": "Кліки",
|
|
313
362
|
"sales": "Продажі",
|
|
@@ -316,6 +365,16 @@
|
|
|
316
365
|
"commissionsEmptyTitle": "Комісій поки немає",
|
|
317
366
|
"commissionsEmptyBody": "Схвалені реферальні продажі з’являться тут.",
|
|
318
367
|
"commissionFor": "Замовлення {id}",
|
|
368
|
+
"ledgerWaitingPayment": "В обробці",
|
|
369
|
+
"ledgerEarned": "Зароблено",
|
|
370
|
+
"ledgerInPayoutRequest": "У запиті на виплату",
|
|
371
|
+
"ledgerPaidOut": "Виплачено",
|
|
372
|
+
"ledgerStoreCredit": "Баланс магазину",
|
|
373
|
+
"ledgerSplit": "Розподілено",
|
|
374
|
+
"ledgerVoided": "Анульовано",
|
|
375
|
+
"paidOutPart": "Виплачено {amount}",
|
|
376
|
+
"storeCreditPart": "{amount} на баланс магазину",
|
|
377
|
+
"ofTotal": "з {total}",
|
|
319
378
|
"balanceTitle": "Рух коштів",
|
|
320
379
|
"balanceEmptyTitle": "Рухів коштів поки немає",
|
|
321
380
|
"balanceEmptyBody": "Конвертації та виплати з’являться тут.",
|
|
@@ -324,7 +383,23 @@
|
|
|
324
383
|
"claimAdjustment": "Коригування",
|
|
325
384
|
"differentCurrency": "Ваш реферальний баланс ведеться у валюті {currency}.",
|
|
326
385
|
"convertedLabel": "Переведено в баланс магазину",
|
|
327
|
-
"paidLabel": "Виплачено"
|
|
386
|
+
"paidLabel": "Виплачено",
|
|
387
|
+
"newLink": "Нове посилання",
|
|
388
|
+
"linkLabel": "Назва",
|
|
389
|
+
"linkLabelPlaceholder": "Кампанія на YouTube",
|
|
390
|
+
"linkCode": "Код",
|
|
391
|
+
"linkCommission": "Бажана комісія (%)",
|
|
392
|
+
"linkDiscount": "Бажана знижка для покупців (%)",
|
|
393
|
+
"linkRatePlaceholder": "Як у магазині",
|
|
394
|
+
"linkRatesHint": "Залиште обидві ставки порожніми, щоб використати ставки магазину. Посилання з власними ставками очікує на схвалення магазину.",
|
|
395
|
+
"createLink": "Створити посилання",
|
|
396
|
+
"creatingLink": "Створюємо…",
|
|
397
|
+
"linkCreated": "Ваше посилання готове — можна ділитися.",
|
|
398
|
+
"linkRequested": "Ваше посилання очікує на схвалення магазину.",
|
|
399
|
+
"linkFailed": "Не вдалося створити посилання. Спробуйте ще раз.",
|
|
400
|
+
"linkRequired": "Вкажіть назву й код посилання.",
|
|
401
|
+
"linkRateInvalid": "Введіть кожну ставку у відсотках від 0 до 100, не більше двох знаків після коми, наприклад 12,5.",
|
|
402
|
+
"linksEmptyCanCreate": "Створіть посилання з власним кодом."
|
|
328
403
|
},
|
|
329
404
|
"support": {
|
|
330
405
|
"loading": "Завантажуємо ваші звернення",
|
|
@@ -393,15 +468,15 @@
|
|
|
393
468
|
"signOutOthersDone": "Вихід виконано на всіх інших пристроях.",
|
|
394
469
|
"devicesFailed": "Не вдалося завантажити ваші пристрої.",
|
|
395
470
|
"signOutDeviceFailed": "Не вдалося вийти на цьому пристрої. Спробуйте ще раз.",
|
|
396
|
-
"deviceOn": "{browser} на {os}"
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
"
|
|
400
|
-
"
|
|
401
|
-
"
|
|
402
|
-
"
|
|
403
|
-
"
|
|
404
|
-
"
|
|
471
|
+
"deviceOn": "{browser} на {os}",
|
|
472
|
+
"orderEmailsTitle": "Листи про замовлення",
|
|
473
|
+
"orderEmailsLoading": "Завантажуємо налаштування листів про замовлення",
|
|
474
|
+
"orderCreated": "Підтвердження замовлень",
|
|
475
|
+
"orderCreatedNote": "Лист, коли ви оформлюєте замовлення.",
|
|
476
|
+
"orderCompleted": "Квитанції за замовленнями",
|
|
477
|
+
"orderCompletedNote": "Квитанції та сповіщення про виконання. Лист із вашими товарами надсилається завжди.",
|
|
478
|
+
"paymentIssue": "Проблеми з оплатою",
|
|
479
|
+
"paymentIssueNote": "Лист, коли платіж потребує вашої уваги."
|
|
405
480
|
},
|
|
406
481
|
"reseller": {
|
|
407
482
|
"disabledTitle": "Програма реселерів недоступна",
|
|
@@ -429,19 +504,12 @@
|
|
|
429
504
|
"walletTitle": "Оптовий баланс",
|
|
430
505
|
"balance": "Баланс",
|
|
431
506
|
"held": "Зарезервовано",
|
|
507
|
+
"topUp": "Поповнити баланс",
|
|
432
508
|
"catalogTitle": "Оптовий каталог",
|
|
433
509
|
"search": "Пошук товарів",
|
|
434
510
|
"catalogEmptyTitle": "Оптових товарів не знайдено",
|
|
435
511
|
"catalogEmptyBody": "Спробуйте інший пошук або поверніться після додавання товарів магазином.",
|
|
436
512
|
"volumePricing": "Доступні ціни за обсяг",
|
|
437
|
-
"supplierBacked": "Постачає постачальник",
|
|
438
|
-
"add": "Додати",
|
|
439
|
-
"basketTitle": "Оптовий кошик",
|
|
440
|
-
"basketEmpty": "Додайте товар з оптового каталогу, щоб почати замовлення.",
|
|
441
|
-
"quantity": "Кількість",
|
|
442
|
-
"basketNeedsQuote": "Розрахуйте кошик, щоб побачити актуальну суму перед замовленням.",
|
|
443
|
-
"quote": "Розрахувати кошик",
|
|
444
|
-
"place": "Оформити замовлення",
|
|
445
513
|
"ordersTitle": "Оптові замовлення",
|
|
446
514
|
"ordersEmptyTitle": "Оптових замовлень ще немає",
|
|
447
515
|
"ordersEmptyBody": "Тут з'являться замовлення, оплачені з оптового балансу.",
|
|
@@ -449,17 +517,12 @@
|
|
|
449
517
|
"lineQuantity": "Кількість: {count}",
|
|
450
518
|
"serials": "Доставлені серійні номери",
|
|
451
519
|
"apiKeysTitle": "API-ключі реселера",
|
|
452
|
-
"apiKeyName": "Назва ключа",
|
|
453
|
-
"createApiKey": "Створити ключ",
|
|
454
520
|
"apiKeysEmpty": "Ви ще не створили API-ключі реселера.",
|
|
455
|
-
"
|
|
456
|
-
"
|
|
457
|
-
"
|
|
458
|
-
"apiKeyCreatedBody": "Відкритий ключ показується один раз, і пізніше його неможливо відновити.",
|
|
459
|
-
"dismissKey": "Ключ збережено",
|
|
521
|
+
"manageKeys": "Керувати ключами",
|
|
522
|
+
"delivery": "URL доставки",
|
|
523
|
+
"deliveryHint": "Для поля Dynamic Delivery у вашому магазині. Відкриється захищена сторінка Shoppex.",
|
|
460
524
|
"lastUsed": "Останнє використання: {date}",
|
|
461
|
-
"neverUsed": "Не використовувався"
|
|
462
|
-
"revokeApiKey": "Відкликати"
|
|
525
|
+
"neverUsed": "Не використовувався"
|
|
463
526
|
}
|
|
464
527
|
}
|
|
465
528
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"account": {
|
|
13
13
|
"title": "你的账户",
|
|
14
|
+
"secureLink": "将打开一个安全的 Shoppex 页面。",
|
|
14
15
|
"sections": "账户板块",
|
|
15
16
|
"signOut": "退出登录",
|
|
16
17
|
"signingOut": "正在退出…",
|
|
@@ -107,6 +108,7 @@
|
|
|
107
108
|
"statTickets": "客服工单",
|
|
108
109
|
"walletLabel": "商店余额",
|
|
109
110
|
"walletNote": "结账时自动抵扣",
|
|
111
|
+
"topUp": "充值",
|
|
110
112
|
"recentOrders": "最近的订单",
|
|
111
113
|
"allOrders": "全部订单"
|
|
112
114
|
},
|
|
@@ -159,7 +161,20 @@
|
|
|
159
161
|
"warrantyClaimSending": "提交中…",
|
|
160
162
|
"warrantyClaimDone": "商店已收到你的申请,他们会通过邮件回复。",
|
|
161
163
|
"warrantyClaimFailed": "申请提交失败。",
|
|
162
|
-
"warrantyClaimTooLong": "申请内容不能超过 {max} 个字符。"
|
|
164
|
+
"warrantyClaimTooLong": "申请内容不能超过 {max} 个字符。",
|
|
165
|
+
"invoicePdf": "下载发票 (PDF)",
|
|
166
|
+
"invoicePdfLoading": "正在准备…",
|
|
167
|
+
"invoicePdfFailed": "无法下载此发票,请重试。",
|
|
168
|
+
"reviewTitle": "你的评价",
|
|
169
|
+
"reviewPrompt": "{product} 怎么样?",
|
|
170
|
+
"reviewPromptGeneric": "你的购物体验如何?",
|
|
171
|
+
"reviewPositive": "好评",
|
|
172
|
+
"reviewNeutral": "中评",
|
|
173
|
+
"reviewNegative": "差评",
|
|
174
|
+
"reviewEdit": "编辑评价",
|
|
175
|
+
"reviewWrite": "撰写评价",
|
|
176
|
+
"reviewAutomated": "此订单已自动发布一条好评。你可以用自己的评价替换它。",
|
|
177
|
+
"reviewFallbackLabel": "评价"
|
|
163
178
|
},
|
|
164
179
|
"downloads": {
|
|
165
180
|
"loading": "正在加载你的下载内容",
|
|
@@ -183,7 +198,25 @@
|
|
|
183
198
|
"renewAction": "打开商店",
|
|
184
199
|
"brokenTitle": "无法列出你的下载内容",
|
|
185
200
|
"brokenBody": "商店发来了一条许可证记录({id}),却没有对应的许可证,这份列表会缺少它所指的东西。",
|
|
186
|
-
"brokenFileBody": "商店发来了一条文件记录({id}),却没有可下载的内容,这份列表会列出一个交不出的文件。"
|
|
201
|
+
"brokenFileBody": "商店发来了一条文件记录({id}),却没有可下载的内容,这份列表会列出一个交不出的文件。",
|
|
202
|
+
"accessLeftOne": "剩余 {count} 次下载",
|
|
203
|
+
"accessLeftOther": "剩余 {count} 次下载",
|
|
204
|
+
"accessUntil": "有效期至 {date}",
|
|
205
|
+
"accessLimitReached": "你已用完所有下载次数",
|
|
206
|
+
"accessLimitReachedOne": "你已用完唯一的一次下载",
|
|
207
|
+
"accessLimitReachedOther": "你已用完全部 {count} 次下载",
|
|
208
|
+
"accessExpired": "下载已于 {date} 结束",
|
|
209
|
+
"accessExpiredUndated": "下载已结束",
|
|
210
|
+
"accessRevoked": "此订单的下载已被关闭",
|
|
211
|
+
"accessRefunded": "此订单已退款,下载已结束",
|
|
212
|
+
"askAccess": "申请访问",
|
|
213
|
+
"askingAccess": "正在发送…",
|
|
214
|
+
"accessRequested": "请求已发送",
|
|
215
|
+
"accessRequestDone": "请求已发送。商店会在“支持”中回复。",
|
|
216
|
+
"accessRequestFailed": "请求发送失败,请重试。",
|
|
217
|
+
"accessRequestTitle": "访问 {file}",
|
|
218
|
+
"accessRequestMessage": "我想再次下载此订单中的 {file}({product})。",
|
|
219
|
+
"accessRequestReason": "账户页面显示:{reason}。"
|
|
187
220
|
},
|
|
188
221
|
"subscriptions": {
|
|
189
222
|
"loading": "正在加载你的订阅",
|
|
@@ -208,7 +241,6 @@
|
|
|
208
241
|
"paymentMethod": "支付方式",
|
|
209
242
|
"cardOnFile": "{brand} 尾号 {last4}",
|
|
210
243
|
"noPaymentMethod": "未保存支付方式",
|
|
211
|
-
"paymentMethodElsewhere": "修改支付信息的链接来自商店发给你的邮件,不会在此页提供,因为本页上的任何内容都可能读取到它。",
|
|
212
244
|
"pause": "暂停",
|
|
213
245
|
"pausing": "正在暂停…",
|
|
214
246
|
"resume": "恢复",
|
|
@@ -227,7 +259,12 @@
|
|
|
227
259
|
"historyLoading": "正在加载账单记录",
|
|
228
260
|
"historyEmptyTitle": "还没有账单记录",
|
|
229
261
|
"historyEmptyBody": "首个周期结束后,续订账单会出现在这里。",
|
|
230
|
-
"trial": "试用期 {date} 结束"
|
|
262
|
+
"trial": "试用期 {date} 结束",
|
|
263
|
+
"renewalDue": "此订阅有一笔续费待支付。",
|
|
264
|
+
"payNow": "立即支付",
|
|
265
|
+
"updateCard": "更新银行卡",
|
|
266
|
+
"pastDueCardTitle": "你的上一笔付款失败了",
|
|
267
|
+
"pastDueCardBody": "请更新银行卡以保留此订阅。将打开一个安全的 Shoppex 页面。"
|
|
231
268
|
},
|
|
232
269
|
"favorites": {
|
|
233
270
|
"loading": "正在加载你的收藏",
|
|
@@ -308,6 +345,18 @@
|
|
|
308
345
|
"primary": "主链接",
|
|
309
346
|
"commission": "{percent}% 佣金",
|
|
310
347
|
"buyerDiscount": "买家享 {percent}% 优惠",
|
|
348
|
+
"yourRates": "你的费率",
|
|
349
|
+
"ratesEveryProduct": "所有商品 {percent}%",
|
|
350
|
+
"ratesMostProducts": "大多数商品 {percent}%",
|
|
351
|
+
"ratesProductEarnsNothing": "{product} 不产生佣金",
|
|
352
|
+
"ratesProductsEarnNothing": "{products} 不产生佣金",
|
|
353
|
+
"ratesCustomRateProducts": "部分商品使用单独的佣金比例",
|
|
354
|
+
"ratesMoreProducts": "另外 {count} 个",
|
|
355
|
+
"ratesCap": "每单最多 {amount}",
|
|
356
|
+
"ratesMinimum": "低于 {amount} 的订单不产生佣金",
|
|
357
|
+
"ratesBindingDays": "买家归属你 {days} 天",
|
|
358
|
+
"ratesBindingForever": "买家永久归属你",
|
|
359
|
+
"ratesBindingDetail": "在他们通过你的链接首次付款下单之后",
|
|
311
360
|
"awaitingApproval": "该链接正在等待商店审核。",
|
|
312
361
|
"clicks": "点击",
|
|
313
362
|
"sales": "成交",
|
|
@@ -316,6 +365,16 @@
|
|
|
316
365
|
"commissionsEmptyTitle": "还没有佣金",
|
|
317
366
|
"commissionsEmptyBody": "审核通过的推荐订单会显示在这里。",
|
|
318
367
|
"commissionFor": "订单 {id}",
|
|
368
|
+
"ledgerWaitingPayment": "处理中",
|
|
369
|
+
"ledgerEarned": "已赚取",
|
|
370
|
+
"ledgerInPayoutRequest": "提现申请中",
|
|
371
|
+
"ledgerPaidOut": "已打款",
|
|
372
|
+
"ledgerStoreCredit": "商店余额",
|
|
373
|
+
"ledgerSplit": "拆分结算",
|
|
374
|
+
"ledgerVoided": "已作废",
|
|
375
|
+
"paidOutPart": "已打款 {amount}",
|
|
376
|
+
"storeCreditPart": "商店余额 {amount}",
|
|
377
|
+
"ofTotal": "共 {total}",
|
|
319
378
|
"balanceTitle": "余额动态",
|
|
320
379
|
"balanceEmptyTitle": "还没有余额动态",
|
|
321
380
|
"balanceEmptyBody": "转换和打款记录会显示在这里。",
|
|
@@ -324,7 +383,23 @@
|
|
|
324
383
|
"claimAdjustment": "调整",
|
|
325
384
|
"differentCurrency": "你的推荐余额以 {currency} 结算。",
|
|
326
385
|
"convertedLabel": "已转为商店余额",
|
|
327
|
-
"paidLabel": "已打款"
|
|
386
|
+
"paidLabel": "已打款",
|
|
387
|
+
"newLink": "新建链接",
|
|
388
|
+
"linkLabel": "名称",
|
|
389
|
+
"linkLabelPlaceholder": "YouTube 推广",
|
|
390
|
+
"linkCode": "代码",
|
|
391
|
+
"linkCommission": "申请的佣金比例 (%)",
|
|
392
|
+
"linkDiscount": "申请的买家折扣 (%)",
|
|
393
|
+
"linkRatePlaceholder": "使用商店默认值",
|
|
394
|
+
"linkRatesHint": "两项比例留空即使用商店的默认比例。申请自定义比例的链接需等待商店审核。",
|
|
395
|
+
"createLink": "创建链接",
|
|
396
|
+
"creatingLink": "正在创建…",
|
|
397
|
+
"linkCreated": "您的链接已可分享。",
|
|
398
|
+
"linkRequested": "您的链接正在等待商店审核。",
|
|
399
|
+
"linkFailed": "无法创建您的链接,请重试。",
|
|
400
|
+
"linkRequired": "请填写链接的名称和代码。",
|
|
401
|
+
"linkRateInvalid": "请将每个比例填写为 0 到 100 之间的百分比,最多两位小数,例如 12.5。",
|
|
402
|
+
"linksEmptyCanCreate": "用您自己的代码创建一个。"
|
|
328
403
|
},
|
|
329
404
|
"support": {
|
|
330
405
|
"loading": "正在加载你的工单",
|
|
@@ -393,15 +468,15 @@
|
|
|
393
468
|
"signOutOthersDone": "其他所有设备已退出登录。",
|
|
394
469
|
"devicesFailed": "无法加载你的设备。",
|
|
395
470
|
"signOutDeviceFailed": "该设备退出登录失败,请重试。",
|
|
396
|
-
"deviceOn": "{os} 上的 {browser}"
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
"
|
|
400
|
-
"
|
|
401
|
-
"
|
|
402
|
-
"
|
|
403
|
-
"
|
|
404
|
-
"
|
|
471
|
+
"deviceOn": "{os} 上的 {browser}",
|
|
472
|
+
"orderEmailsTitle": "订单邮件",
|
|
473
|
+
"orderEmailsLoading": "正在加载订单邮件设置",
|
|
474
|
+
"orderCreated": "订单确认",
|
|
475
|
+
"orderCreatedNote": "下单时发送的邮件。",
|
|
476
|
+
"orderCompleted": "订单收据",
|
|
477
|
+
"orderCompletedNote": "收据和订单完成通知。用于交付商品的邮件始终会发送。",
|
|
478
|
+
"paymentIssue": "付款问题",
|
|
479
|
+
"paymentIssueNote": "付款需要您处理时发送的邮件。"
|
|
405
480
|
},
|
|
406
481
|
"reseller": {
|
|
407
482
|
"disabledTitle": "经销商计划暂不可用",
|
|
@@ -429,19 +504,12 @@
|
|
|
429
504
|
"walletTitle": "批发余额",
|
|
430
505
|
"balance": "余额",
|
|
431
506
|
"held": "冻结中",
|
|
507
|
+
"topUp": "充值",
|
|
432
508
|
"catalogTitle": "批发目录",
|
|
433
509
|
"search": "搜索商品",
|
|
434
510
|
"catalogEmptyTitle": "未找到批发商品",
|
|
435
511
|
"catalogEmptyBody": "请尝试其他搜索,或等待商店添加商品后再来。",
|
|
436
512
|
"volumePricing": "支持批量定价",
|
|
437
|
-
"supplierBacked": "由供应商履约",
|
|
438
|
-
"add": "添加",
|
|
439
|
-
"basketTitle": "批发购物篮",
|
|
440
|
-
"basketEmpty": "从批发目录添加商品即可开始下单。",
|
|
441
|
-
"quantity": "数量",
|
|
442
|
-
"basketNeedsQuote": "请先为购物篮询价,查看当前总额后再下单。",
|
|
443
|
-
"quote": "购物篮询价",
|
|
444
|
-
"place": "提交订单",
|
|
445
513
|
"ordersTitle": "批发订单",
|
|
446
514
|
"ordersEmptyTitle": "暂无批发订单",
|
|
447
515
|
"ordersEmptyBody": "使用批发余额支付的订单会显示在这里。",
|
|
@@ -449,17 +517,12 @@
|
|
|
449
517
|
"lineQuantity": "数量 {count}",
|
|
450
518
|
"serials": "已交付序列号",
|
|
451
519
|
"apiKeysTitle": "经销商 API 密钥",
|
|
452
|
-
"apiKeyName": "密钥名称",
|
|
453
|
-
"createApiKey": "创建密钥",
|
|
454
520
|
"apiKeysEmpty": "你还没有创建经销商 API 密钥。",
|
|
455
|
-
"
|
|
456
|
-
"
|
|
457
|
-
"
|
|
458
|
-
"apiKeyCreatedBody": "该明文密钥只显示一次,之后无法恢复。",
|
|
459
|
-
"dismissKey": "我已保存",
|
|
521
|
+
"manageKeys": "管理密钥",
|
|
522
|
+
"delivery": "交付 URL",
|
|
523
|
+
"deliveryHint": "用于你店铺的 Dynamic Delivery 字段。将打开一个安全的 Shoppex 页面。",
|
|
460
524
|
"lastUsed": "上次使用:{date}",
|
|
461
|
-
"neverUsed": "从未使用"
|
|
462
|
-
"revokeApiKey": "撤销"
|
|
525
|
+
"neverUsed": "从未使用"
|
|
463
526
|
}
|
|
464
527
|
}
|
|
465
528
|
|
package/eject/account/orders.tsx
CHANGED
|
@@ -356,6 +356,8 @@ export function AccountOrderDetail({ orderId }: { orderId: string }) {
|
|
|
356
356
|
<p className="sxa:mt-3 sxa:text-small sxa:leading-relaxed sxa:text-muted">{order.statusDetails}</p>
|
|
357
357
|
) : null}
|
|
358
358
|
|
|
359
|
+
<InvoicePdfButton orderUniqid={order.uniqid} />
|
|
360
|
+
|
|
359
361
|
<ul className="sxa:mt-6 sxa:space-y-3">
|
|
360
362
|
{order.lineItems.map((item) => (
|
|
361
363
|
<li key={item.id}>
|
|
@@ -443,6 +445,60 @@ export function AccountOrderDetail({ orderId }: { orderId: string }) {
|
|
|
443
445
|
order AFTER it was paid for.
|
|
444
446
|
*/}
|
|
445
447
|
<OrderWarranties orderUniqid={order.uniqid} />
|
|
448
|
+
|
|
449
|
+
{/* Keyed: a review posted on one order must not follow the buyer to the next. */}
|
|
450
|
+
<OrderReview key={order.uniqid} orderUniqid={order.uniqid} />
|
|
451
|
+
</div>
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* The invoice as a PDF.
|
|
457
|
+
*
|
|
458
|
+
* Fetched, not linked: a file that could not be made answers with JSON, and a
|
|
459
|
+
* link would open that in a new tab. Here the failure is a sentence beside the
|
|
460
|
+
* button, and the button is still there to press again. The save goes through
|
|
461
|
+
* a temporary object URL on an anchor the buyer never sees; the name is the
|
|
462
|
+
* producer's, and when it sent none the browser picks one.
|
|
463
|
+
*/
|
|
464
|
+
function InvoicePdfButton({ orderUniqid }: { orderUniqid: string }) {
|
|
465
|
+
const [busy, setBusy] = useState(false);
|
|
466
|
+
const [error, setError] = useState<string | null>(null);
|
|
467
|
+
|
|
468
|
+
const download = async () => {
|
|
469
|
+
setBusy(true);
|
|
470
|
+
setError(null);
|
|
471
|
+
const response = await callCustomerApi((sdk) => sdk.invoicePdf(orderUniqid));
|
|
472
|
+
setBusy(false);
|
|
473
|
+
|
|
474
|
+
if (!response.success || response.data === undefined) {
|
|
475
|
+
setError(response.message?.trim() || t('orders.invoicePdfFailed'));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const url = URL.createObjectURL(response.data.blob);
|
|
480
|
+
const anchor = document.createElement('a');
|
|
481
|
+
anchor.href = url;
|
|
482
|
+
anchor.download = response.data.filename ?? '';
|
|
483
|
+
anchor.click();
|
|
484
|
+
URL.revokeObjectURL(url);
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<div className="sxa:mt-4">
|
|
489
|
+
<button
|
|
490
|
+
type="button"
|
|
491
|
+
disabled={busy}
|
|
492
|
+
aria-busy={busy || undefined}
|
|
493
|
+
className="sx-account-button sxa:card-button sxa:card-button--add sxa:disabled:cursor-not-allowed sxa:disabled:opacity-50"
|
|
494
|
+
onClick={() => void download()}
|
|
495
|
+
>
|
|
496
|
+
{busy
|
|
497
|
+
? <BusySpinner className="sxa:mr-1.5 sxa:h-3.5 sxa:w-3.5" />
|
|
498
|
+
: <ReceiptIcon className="sxa:mr-1.5 sxa:h-3.5 sxa:w-3.5" />}
|
|
499
|
+
{busy ? t('orders.invoicePdfLoading') : t('orders.invoicePdf')}
|
|
500
|
+
</button>
|
|
501
|
+
{error ? <AccountFieldError message={error} /> : null}
|
|
446
502
|
</div>
|
|
447
503
|
);
|
|
448
504
|
}
|
|
@@ -633,6 +689,91 @@ function WarrantyRow({
|
|
|
633
689
|
);
|
|
634
690
|
}
|
|
635
691
|
|
|
692
|
+
/** The three scores the server keeps, as the buyer reads them. */
|
|
693
|
+
const REVIEW_SCORE_KEYS: Readonly<Record<number, string>> = {
|
|
694
|
+
5: 'orders.reviewPositive',
|
|
695
|
+
3: 'orders.reviewNeutral',
|
|
696
|
+
1: 'orders.reviewNegative',
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* The buyer's review of this order.
|
|
701
|
+
*
|
|
702
|
+
* The server decides whether the order can be reviewed (`can_review`: paid,
|
|
703
|
+
* reviews on, inside the edit window) and names the hosted review page for it
|
|
704
|
+
* (`review_url`, null otherwise); this only reads that state and never guesses
|
|
705
|
+
* it. The review is written on that page, never posted from here: this page
|
|
706
|
+
* runs beside merchant theme code that holds the buyer's session, and a review
|
|
707
|
+
* it could post would not be the buyer's own (#1152). Nothing is drawn while
|
|
708
|
+
* the read is in flight, or when there is neither a review page to open nor a
|
|
709
|
+
* review of the buyer's own to show. A failed read is shown with a retry,
|
|
710
|
+
* because it cannot be told apart from an order waiting for its review.
|
|
711
|
+
*/
|
|
712
|
+
export function OrderReview({ orderUniqid }: { orderUniqid: string }) {
|
|
713
|
+
const { state, reload } = useAccountResource(`review:${orderUniqid}`, () =>
|
|
714
|
+
callCustomerApi((sdk) => sdk.orderReview(orderUniqid)));
|
|
715
|
+
|
|
716
|
+
if (state.status === 'loading') return null;
|
|
717
|
+
|
|
718
|
+
if (state.status === 'error') {
|
|
719
|
+
return (
|
|
720
|
+
<ReviewSection>
|
|
721
|
+
<AccountError message={state.message} onRetry={reload} />
|
|
722
|
+
</ReviewSection>
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const review = state.data;
|
|
727
|
+
const ownReview = review.already_submitted && !review.is_automated;
|
|
728
|
+
// Absent on a backend that predates the link; a URL that fails the scheme check gets no anchor.
|
|
729
|
+
const href = safeExternalHref(review.review_url);
|
|
730
|
+
if (href === null && !ownReview) return null;
|
|
731
|
+
|
|
732
|
+
return (
|
|
733
|
+
<ReviewSection
|
|
734
|
+
description={review.product_title
|
|
735
|
+
? t('orders.reviewPrompt', { product: review.product_title })
|
|
736
|
+
: t('orders.reviewPromptGeneric')}
|
|
737
|
+
>
|
|
738
|
+
<AccountCard className="sxa:flex sxa:flex-col sxa:items-start sxa:gap-3 sxa:px-5 sxa:py-4">
|
|
739
|
+
{ownReview ? (
|
|
740
|
+
<div>
|
|
741
|
+
<p className="sxa:text-small sxa:font-semibold">
|
|
742
|
+
{t((review.score === null ? undefined : REVIEW_SCORE_KEYS[review.score]) ?? 'orders.reviewFallbackLabel')}
|
|
743
|
+
{review.submitted_at ? (
|
|
744
|
+
<span className="sxa:font-normal sxa:text-muted"> · {formatAccountDate(review.submitted_at)}</span>
|
|
745
|
+
) : null}
|
|
746
|
+
</p>
|
|
747
|
+
{review.message ? (
|
|
748
|
+
<p className="sxa:mt-1.5 sxa:text-small sxa:whitespace-pre-line sxa:text-muted">{review.message}</p>
|
|
749
|
+
) : null}
|
|
750
|
+
</div>
|
|
751
|
+
) : review.is_automated ? (
|
|
752
|
+
<p className="sxa:text-small sxa:text-muted">{t('orders.reviewAutomated')}</p>
|
|
753
|
+
) : null}
|
|
754
|
+
{href === null ? null : (
|
|
755
|
+
<a
|
|
756
|
+
href={href}
|
|
757
|
+
className="sx-account-cta sxa:cta-button sxa:inline-flex sxa:h-9 sxa:shrink-0 sxa:items-center sxa:px-4 sxa:text-small sxa:font-semibold"
|
|
758
|
+
>
|
|
759
|
+
{t(ownReview ? 'orders.reviewEdit' : 'orders.reviewWrite')}
|
|
760
|
+
</a>
|
|
761
|
+
)}
|
|
762
|
+
</AccountCard>
|
|
763
|
+
</ReviewSection>
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function ReviewSection({ description, children }: { description?: string; children: ReactNode }) {
|
|
768
|
+
return (
|
|
769
|
+
<section className="sxa:mt-8">
|
|
770
|
+
<AccountSectionTitle>{t('orders.reviewTitle')}</AccountSectionTitle>
|
|
771
|
+
{description ? <p className="sxa:mt-1.5 sxa:text-small sxa:text-muted">{description}</p> : null}
|
|
772
|
+
<div className="sxa:mt-4">{children}</div>
|
|
773
|
+
</section>
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
|
|
636
777
|
/** Cover as a sentence. Cancelled cover names no date, because it has none. */
|
|
637
778
|
function coverageLabel(coverage: WarrantyCoverage): string {
|
|
638
779
|
switch (coverage.kind) {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
AccountError,
|
|
22
22
|
AccountRowsSkeleton,
|
|
23
23
|
AccountSectionTitle,
|
|
24
|
+
HostedPageLink,
|
|
24
25
|
formatAccountAmount,
|
|
25
26
|
formatInvoiceAmount,
|
|
26
27
|
} from './shared';
|
|
@@ -78,6 +79,11 @@ export function AccountOverview() {
|
|
|
78
79
|
</div>
|
|
79
80
|
<p className="sxa:text-small sxa:text-muted">{t('overview.walletNote')}</p>
|
|
80
81
|
</div>
|
|
82
|
+
{/* Adding funds is a payment, so it happens on the hosted top-up page,
|
|
83
|
+
and only when the shop takes top-ups (decision T4). */}
|
|
84
|
+
{account.wallet.topups_allowed ? (
|
|
85
|
+
<HostedPageLink page="topup" hints={{}} label={t('overview.topUp')} className="sxa:mt-4 sxa:border-t sxa:pt-4" />
|
|
86
|
+
) : null}
|
|
81
87
|
</AccountCard>
|
|
82
88
|
) : null}
|
|
83
89
|
|