diff --git a/.changeset/brown-guests-roll.md b/.changeset/brown-guests-roll.md new file mode 100644 index 00000000000..c0e1854f831 --- /dev/null +++ b/.changeset/brown-guests-roll.md @@ -0,0 +1,8 @@ +--- +'@clerk/localizations': minor +'@clerk/clerk-js': minor +'@clerk/shared': minor +'@clerk/ui': minor +--- + +Add support for applying promo codes at checkout diff --git a/integration/tests/pricing-table.test.ts b/integration/tests/pricing-table.test.ts index 98b2b0a7e53..e0876409bd8 100644 --- a/integration/tests/pricing-table.test.ts +++ b/integration/tests/pricing-table.test.ts @@ -356,7 +356,7 @@ testAgainstRunningApps({})('pricing table @billing', ({ app }) => { await expect(matchLineItem(u.po.checkout.root, 'Total Due after')).toBeHidden(); await expect(matchLineItem(u.po.checkout.root, 'Total due today', '$999.00')).toBeVisible(); - expect(await countLineItems(u.po.checkout.root)).toBe(3); + expect(await countLineItems(u.po.checkout.root)).toBe(4); await u.po.checkout.root.getByRole('button', { name: /^pay\s\$/i }).waitFor({ state: 'visible' }); await u.po.checkout.clickPayOrSubscribe(); diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index a9bf078f735..018bebef844 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -1,8 +1,8 @@ { "files": [ { "path": "./dist/clerk.js", "maxSize": "549KB" }, - { "path": "./dist/clerk.browser.js", "maxSize": "75KB" }, - { "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" }, + { "path": "./dist/clerk.browser.js", "maxSize": "77KB" }, + { "path": "./dist/clerk.legacy.browser.js", "maxSize": "119KB" }, { "path": "./dist/clerk.no-rhc.js", "maxSize": "316KB" }, { "path": "./dist/clerk.native.js", "maxSize": "76KB" }, { "path": "./dist/vendors*.js", "maxSize": "7KB" }, diff --git a/packages/clerk-js/src/core/modules/billing/namespace.ts b/packages/clerk-js/src/core/modules/billing/namespace.ts index 99f06cd319c..cb6874463d5 100644 --- a/packages/clerk-js/src/core/modules/billing/namespace.ts +++ b/packages/clerk-js/src/core/modules/billing/namespace.ts @@ -21,6 +21,7 @@ import type { GetPlansParams, GetStatementsParams, GetSubscriptionParams, + UpdateCheckoutParams, } from '@clerk/shared/types'; import { convertPageToOffsetSearchParams } from '../../../utils/convertPageToOffsetSearchParams'; @@ -149,6 +150,19 @@ export class Billing implements BillingNamespace { return new BillingCheckout(json); }; + updateCheckout = async (params: UpdateCheckoutParams) => { + const { id, orgId, ...rest } = params; + const json = ( + await BaseResource._fetch({ + path: Billing.path(`/checkouts/${id}`, { orgId }), + method: 'PATCH', + body: rest as any, + }) + )?.response as unknown as BillingCheckoutJSON; + + return new BillingCheckout(json); + }; + getCreditBalance = async (params: GetCreditBalanceParams): Promise => { return await BaseResource._fetch({ path: Billing.path('/credits', { orgId: params.orgId }), diff --git a/packages/clerk-js/src/core/resources/BillingCheckout.ts b/packages/clerk-js/src/core/resources/BillingCheckout.ts index 19b9d8c5dc0..4e08ae2ef2c 100644 --- a/packages/clerk-js/src/core/resources/BillingCheckout.ts +++ b/packages/clerk-js/src/core/resources/BillingCheckout.ts @@ -14,6 +14,7 @@ import type { CheckoutSignalValue, ConfirmCheckoutParams, CreateCheckoutParams, + UpdateCheckoutParams, } from '@clerk/shared/types'; import { computed, endBatch, signal, startBatch } from 'alien-signals'; @@ -117,7 +118,7 @@ export const createSignals = () => { return { resourceSignal, errorSignal, fetchSignal, computedSignal }; }; -type CheckoutTask = 'start' | 'confirm' | 'finalize'; +type CheckoutTask = 'start' | 'update' | 'confirm' | 'finalize'; export class CheckoutFlow implements CheckoutFlowResourceNonStrict { private resource = new BillingCheckout(null); @@ -197,6 +198,24 @@ export class CheckoutFlow implements CheckoutFlowResourceNonStrict { }); } + async update(params: Pick): Promise<{ error: ClerkError | null }> { + if (!this.resource.id) { + throw new Error('Clerk: `start()` must be called before `update()`'); + } + return this.runAsyncCheckoutTask( + 'update', + async () => { + this.resource = (await BillingCheckout.clerk.billing?.updateCheckout({ + id: this.resource.id, + orgId: this.resource.payer.organizationId || undefined, + ...params, + })) as BillingCheckout; + }, + undefined, + false, + ); + } + async finalize(params?: CheckoutFlowFinalizeParams): Promise<{ error: ClerkError | null }> { const { navigate } = params || {}; return this.runAsyncCheckoutTask('finalize', async () => { @@ -208,13 +227,23 @@ export class CheckoutFlow implements CheckoutFlowResourceNonStrict { }); } - private runAsyncCheckoutTask(operationType: CheckoutTask, task: () => Promise, beforeTask?: () => void) { + private runAsyncCheckoutTask( + operationType: CheckoutTask, + task: () => Promise, + beforeTask?: () => void, + updateErrorSignal = true, + ) { // Noops during transitive state if (typeof BillingCheckout.clerk.user === 'undefined') { console.warn('Clerk: Checkout operations cannot be performed during transitive state'); return { error: null }; } - return createRunAsyncCheckoutTask(this, this.signals, this.pendingOperations)(operationType, task, beforeTask); + return createRunAsyncCheckoutTask(this, this.signals, this.pendingOperations)( + operationType, + task, + beforeTask, + updateErrorSignal, + ); } } @@ -226,8 +255,9 @@ function createRunAsyncCheckoutTask( operationType: CheckoutTask, task: () => Promise, beforeTask?: () => void, + updateErrorSignal?: boolean, ) => Promise<{ error: ClerkError | null }> { - return async (operationType, task, beforeTask?: () => void) => { + return async (operationType, task, beforeTask?: () => void, updateErrorSignal = true) => { if (pendingOperations.get(operationType)) { // Wait for the existing operation to complete and return its result // If it fails, all callers should receive the same error @@ -246,7 +276,9 @@ function createRunAsyncCheckoutTask( signals.resourceSignal({ resource: resource }); return { error: null }; } catch (err) { - signals.errorSignal({ error: err }); + if (updateErrorSignal) { + signals.errorSignal({ error: err }); + } return { error: err }; } finally { pendingOperations.delete(operationType); diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index 596a5584f6f..9cd27120c13 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -100,8 +100,11 @@ export const arSA: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const arSA: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index dc084c9cb5c..431205e47ca 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -100,8 +100,11 @@ export const beBY: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const beBY: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index e745c6c0113..9306da5af14 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -101,8 +101,11 @@ export const bgBG: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -117,6 +120,8 @@ export const bgBG: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index 246d73cdabc..b95016e9eea 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -105,8 +105,11 @@ export const bnIN: LocalizationResource = { cannotSubscribeUnrecoverable: 'আপনি এই প্ল্যানে সাবস্ক্রাইব করতে পারবেন না। আপনার বিদ্যমান সাবস্ক্রিপশন এই প্ল্যানের চেয়ে বেশি ব্যয়বহুল।', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'আপনার পেমেন্ট সফল হয়েছে।', description__subscriptionSuccessful: 'আপনার নতুন সাবস্ক্রিপশন সম্পূর্ণ প্রস্তুত।', + discount: undefined, downgradeNotice: 'বিলিং চক্রের শেষ পর্যন্ত আপনি আপনার বর্তমান সাবস্ক্রিপশন এবং এর বৈশিষ্ট্যগুলি রাখবেন, তারপরে আপনাকে এই সাবস্ক্রিপশনে স্যুইচ করা হবে।', emailForm: { @@ -122,6 +125,8 @@ export const bnIN: LocalizationResource = { }, pastDueNotice: 'আপনার পূর্ববর্তী সাবস্ক্রিপশন বকেয়া ছিল, কোনো পেমেন্ট ছাড়াই।', perMonth: 'প্রতি মাসে', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'চেকআউট', title__paymentSuccessful: 'পেমেন্ট সফল হয়েছে!', title__subscriptionSuccessful: 'সফল!', diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index b072019fa84..335fd3f6198 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -105,8 +105,11 @@ export const caES: LocalizationResource = { cannotSubscribeUnrecoverable: "No pots subscriure't a aquest pla. La teva subscripció actual és més cara que aquest pla.", checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: "El teu pagament s'ha realitzat correctament.", description__subscriptionSuccessful: 'La teva nova subscripció està a punt.', + discount: undefined, downgradeNotice: 'Mantindràs la teva subscripció actual i les seves funcions fins al final del cicle de facturació; després es canviarà a aquesta subscripció.', emailForm: { @@ -123,6 +126,8 @@ export const caES: LocalizationResource = { }, pastDueNotice: 'La teva subscripció anterior tenia un pagament pendent.', perMonth: 'al mes', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Pagament', title__paymentSuccessful: 'Pagament realitzat amb èxit!', title__subscriptionSuccessful: 'Tot a punt!', diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index 515881fbf28..d071a25cee0 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -103,8 +103,11 @@ export const csCZ: LocalizationResource = { 'Nelze se přihlásit k tomuto plánu s měsíční platbou. Abyste se k němu přihlásili, musíte zvolit roční platbu.', cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Vaše platba byla úspěšná.', description__subscriptionSuccessful: 'Vaše nové předplatné je nastaveno.', + discount: undefined, downgradeNotice: 'Současné předplatné a jeho funkce si ponecháte do konce fakturačního cyklu, poté budete převedeni na toto předplatné.', emailForm: { @@ -120,6 +123,8 @@ export const csCZ: LocalizationResource = { }, pastDueNotice: 'Vaše předchozí předplatné bylo po splatnosti, bez platby.', perMonth: 'měsíčně', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Pokladna', title__paymentSuccessful: 'Platba byla úspěšná!', title__subscriptionSuccessful: 'Úspěch!', diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index bf4b56f20c5..4b92e5824ad 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -100,8 +100,11 @@ export const daDK: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const daDK: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index d296dd770e6..3452a759cf2 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -105,8 +105,11 @@ export const deDE: LocalizationResource = { cannotSubscribeUnrecoverable: 'Sie können diesen Plan nicht abonnieren. Ihr vorhandenes Abonnement ist teurer als dieser Plan.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Ihre Bezahlung war erfolgreich.', description__subscriptionSuccessful: 'Ihr Abonnement wurde erfolgreich aktiviert.', + discount: undefined, downgradeNotice: 'Sie behalten Ihr aktuelles Abonnement bis zum Ende des Abrechnungszeitraums. So lange können Sie weiterhin alle Funktionen nutzen, danach werden Sie auf dieses Abonnement umgestellt.', emailForm: { @@ -122,6 +125,8 @@ export const deDE: LocalizationResource = { }, pastDueNotice: 'Ihr vorheriges Abonnement war überfällig, ohne Zahlung.', perMonth: 'pro Monat', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Bezahlung', title__paymentSuccessful: 'Zahlung erfolgreich!', title__subscriptionSuccessful: 'Geschafft!', diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index a3ab5b1daaf..f8eafb4d040 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -100,8 +100,11 @@ export const elGR: LocalizationResource = { cannotSubscribeMonthly: 'Δεν μπορείτε να εγγραφείτε μηνιαίως σε αυτό το πλάνο', cannotSubscribeUnrecoverable: 'Δεν μπορείτε να εγγραφείτε σε αυτό το πλάνο αυτήν τη στιγμή', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Η πληρωμή σας ολοκληρώθηκε επιτυχώς', description__subscriptionSuccessful: 'Η συνδρομή σας ξεκίνησε επιτυχώς', + discount: undefined, downgradeNotice: 'Θα υποβαθμιστείτε στο τέλος της τρέχουσας περιόδου χρέωσης', emailForm: { subtitle: 'Εισάγετε τη διεύθυνση email σας για να συνεχίσετε', @@ -116,6 +119,8 @@ export const elGR: LocalizationResource = { }, pastDueNotice: 'Η συνδρομή σας είναι ληξιπρόθεσμη. Παρακαλώ ενημερώστε τη μέθοδο πληρωμής σας.', perMonth: 'ανά μήνα', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Ολοκλήρωση πληρωμής', title__paymentSuccessful: 'Επιτυχής πληρωμή', title__subscriptionSuccessful: 'Επιτυχής συνδρομή', diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index bd379c1eacc..28d1b445039 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -100,8 +100,11 @@ export const enGB: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const enGB: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 86d4c3ab782..3c558fba21a 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -94,8 +94,11 @@ export const enUS: LocalizationResource = { cannotSubscribeUnrecoverable: 'You cannot subscribe to this plan. Your existing subscription is more expensive than this plan.', checkout: { + addPromoCode: 'Add promo code', + applyPromoCode: 'Apply', description__paymentSuccessful: 'Your payment was successful.', description__subscriptionSuccessful: 'Your new subscription is all set.', + discount: 'Discount', downgradeNotice: 'You will keep your current subscription and its features until the end of the billing cycle, then you will be switched to this subscription.', emailForm: { @@ -111,6 +114,8 @@ export const enUS: LocalizationResource = { }, pastDueNotice: 'Your previous subscription was past due, with no payment.', perMonth: 'per month', + promoCodePlaceholder: 'Enter promo code', + removePromoCode: 'Remove promo code', title: 'Checkout', title__paymentSuccessful: 'Payment was successful!', title__subscriptionSuccessful: 'Success!', @@ -121,9 +126,9 @@ export const enUS: LocalizationResource = { credit: 'Credit', creditRemainder: 'Credit for the remainder of your current subscription.', defaultFreePlanActive: "You're currently on the Free plan", - discountAmount: '({{amount}} off)', + discountAmount: '{{amount}} off', discountCyclesRemaining: '{{cycles}} {{period}} remaining', - discountDuration: '({{amount}} off first {{cycles}} {{period}})', + discountDuration: '{{amount}} off first {{cycles}} {{period}}', free: 'Free', getStarted: 'Get started', highlightedPlanBadge: 'Popular', diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index fe7b4477816..529164af2b0 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -100,8 +100,11 @@ export const esCR: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Tu nueva suscripción está lista.', description__subscriptionSuccessful: 'Tu nueva suscripción está lista.', + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const esCR: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: '¡Pago exitoso!', title__subscriptionSuccessful: '¡Éxito!', diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index 5e70ef929cd..9278ddc234c 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -104,8 +104,11 @@ export const esES: LocalizationResource = { 'No puedes suscribirte a este plan con pago mensual. Para suscribirte, debes elegir el pago anual.', cannotSubscribeUnrecoverable: 'No puedes suscribirte a este plan. Tu suscripción actual es más cara que este plan.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Tu pago se ha realizado correctamente.', description__subscriptionSuccessful: 'Tu nueva suscripción está lista.', + discount: undefined, downgradeNotice: 'Mantendrás tu suscripción actual y sus funciones hasta el final del ciclo de facturación; después se te cambiará a esta suscripción.', emailForm: { @@ -122,6 +125,8 @@ export const esES: LocalizationResource = { }, pastDueNotice: 'Tu suscripción anterior tenía un pago pendiente.', perMonth: 'al mes', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Pago', title__paymentSuccessful: '¡Pago realizado con éxito!', title__subscriptionSuccessful: '¡Todo listo!', diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index 130e9fae55e..5aac172a435 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -101,8 +101,11 @@ export const esMX: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -117,6 +120,8 @@ export const esMX: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: '¡Pago exitoso!', title__subscriptionSuccessful: '¡Éxito!', diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index 7a3fc1447e6..f6eaf9d3813 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -100,8 +100,11 @@ export const esUY: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const esUY: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 18620d3648f..549f81c35db 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -103,8 +103,11 @@ export const faIR: LocalizationResource = { 'شما نمی‌توانید با پرداخت ماهانه در این طرح مشترک شوید. برای عضویت در این طرح، باید پرداخت سالانه را انتخاب کنید.', cannotSubscribeUnrecoverable: 'شما نمی‌توانید در این طرح مشترک شوید. اشتراک موجود شما گران‌تر از این طرح است.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'پرداخت شما با موفقیت انجام شد.', description__subscriptionSuccessful: 'اشتراک شما با موفقیت ایجاد شد.', + discount: undefined, downgradeNotice: 'شما اشتراک فعلی و ویژگی‌های آن را تا پایان دوره صورتحساب حفظ خواهید کرد، سپس به این اشتراک منتقل خواهید شد.', emailForm: { @@ -121,6 +124,8 @@ export const faIR: LocalizationResource = { }, pastDueNotice: 'اشتراک قبلی شما سررسید گذشته بود، بدون پرداخت.', perMonth: 'ماهانه', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'تسویه حساب', title__paymentSuccessful: 'پرداخت موفقیت آمیز بود!', title__subscriptionSuccessful: 'موفقیت آمیز!', diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index 65802a743c7..c9db40cff10 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -105,8 +105,11 @@ export const fiFI: LocalizationResource = { 'Et voi tilata tätä pakettia kuukausimaksulla. Tilataksesi tämän sinun on valittava vuositilaus.', cannotSubscribeUnrecoverable: 'Et voi tilata tätä pakettia. Nykyinen tilauksesi on kalliimpi kuin tämä paketti.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Maksusi onnistui.', description__subscriptionSuccessful: 'Uusi tilauksesi on valmis.', + discount: undefined, downgradeNotice: 'Säilytät nykyisen tilauksesi ja sen ominaisuudet laskutuskauden loppuun asti, minkä jälkeen siirryt tähän tilaukseen.', emailForm: { @@ -122,6 +125,8 @@ export const fiFI: LocalizationResource = { }, pastDueNotice: 'Edellinen tilauksesi oli erääntynyt eikä maksua ole suoritettu.', perMonth: 'kuukaudessa', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Kassa', title__paymentSuccessful: 'Maksu onnistui!', title__subscriptionSuccessful: 'Onnistui!', diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index 1d60760ae9b..da88015b5ac 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -106,8 +106,11 @@ export const frFR: LocalizationResource = { cannotSubscribeUnrecoverable: 'Vous ne pouvez pas souscrire à ce plan. Votre abonnement actuel est plus cher que celui-ci.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Votre paiement a été effectué avec succès.', description__subscriptionSuccessful: 'Votre nouvel abonnement est prêt.', + discount: undefined, downgradeNotice: "Vous conserverez votre abonnement actuel et ses fonctionnalités jusqu'à la fin du cycle de facturation, puis vous passerez à cet abonnement.", emailForm: { @@ -124,6 +127,8 @@ export const frFR: LocalizationResource = { }, pastDueNotice: 'Votre abonnement précédent était en retard de paiement.', perMonth: 'par mois', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Paiement', title__paymentSuccessful: 'Le paiement a réussi !', title__subscriptionSuccessful: 'Succès !', diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index 59a888b6cbc..6061280e560 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -100,8 +100,11 @@ export const heIL: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const heIL: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index f98367ebfe2..731f704f194 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -105,8 +105,11 @@ export const hiIN: LocalizationResource = { 'आप मासिक भुगतान करके इस योजना की सदस्यता नहीं ले सकते। इस योजना की सदस्यता लेने के लिए, आपको वार्षिक भुगतान करना चुनना होगा।', cannotSubscribeUnrecoverable: 'आप इस योजना की सदस्यता नहीं ले सकते। आपकी मौजूदा सदस्यता इस योजना से अधिक महंगी है।', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'आपका भुगतान सफल रहा।', description__subscriptionSuccessful: 'आपकी नई सदस्यता पूरी तरह तैयार है।', + discount: undefined, downgradeNotice: 'बिलिंग चक्र के अंत तक आप अपनी मौजूदा सदस्यता और उसकी सुविधाएँ रखेंगे, फिर आपको इस सदस्यता पर स्विच कर दिया जाएगा।', emailForm: { @@ -122,6 +125,8 @@ export const hiIN: LocalizationResource = { }, pastDueNotice: 'आपकी पिछली सदस्यता बकाया थी, बिना किसी भुगतान के।', perMonth: 'प्रति माह', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'चेकआउट', title__paymentSuccessful: 'भुगतान सफल रहा!', title__subscriptionSuccessful: 'सफल!', diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 07769ee5155..51e7055601e 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -106,8 +106,11 @@ export const hrHR: LocalizationResource = { cannotSubscribeUnrecoverable: 'Ne možete se pretplatiti na ovaj plan. Vaša postojeća pretplata je skuplja od ovog plana.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Vaše plaćanje je uspješno.', description__subscriptionSuccessful: 'Vaša nova pretplata je spremna.', + discount: undefined, downgradeNotice: 'Zadržat ćete svoju trenutnu pretplatu i njezine značajke do kraja obračunskog razdoblja, nakon čega ćete biti prebačeni na ovu pretplatu.', emailForm: { @@ -123,6 +126,8 @@ export const hrHR: LocalizationResource = { }, pastDueNotice: 'Vaša prethodna pretplata je bila dospjela, bez plaćanja.', perMonth: 'mjesečno', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Naplata', title__paymentSuccessful: 'Plaćanje je uspjelo!', title__subscriptionSuccessful: 'Uspjeh!', diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index 9567f27be83..3c81b4651de 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -106,8 +106,11 @@ export const huHU: LocalizationResource = { cannotSubscribeUnrecoverable: 'Nem tudsz előfizetni erre a csomagra. A jelenlegi előfizetésed drágább, mint ez a csomag.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'A fizetés sikeres volt.', description__subscriptionSuccessful: 'Az új előfizetésed beállítva.', + discount: undefined, downgradeNotice: 'A jelenlegi előfizetésed és funkciói a számlázási ciklus végéig megmaradnak, ezután átváltunk erre az előfizetésre.', emailForm: { @@ -123,6 +126,8 @@ export const huHU: LocalizationResource = { }, pastDueNotice: 'Az előző előfizetésed lejárt, fizetés nélkül.', perMonth: 'havonta', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Pénztár', title__paymentSuccessful: 'Sikeres fizetés!', title__subscriptionSuccessful: 'Sikeres!', diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index 7f2ccfcf54f..4d1348a7e16 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -100,8 +100,11 @@ export const idID: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const idID: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index 05bfdadb026..c38e7410f2b 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -105,8 +105,11 @@ export const isIS: LocalizationResource = { 'Þú getur ekki skráð þig í þessa áskrift með mánaðarlegri greiðslu. Til að skrá þig þarftu að velja árlega greiðslu.', cannotSubscribeUnrecoverable: 'Þú getur ekki skráð þig í þessa áskrift. Núverandi áskrift þín er dýrari en þessi.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Greiðsla þín tókst.', description__subscriptionSuccessful: 'Nýja áskriftin þín er tilbúin.', + discount: undefined, downgradeNotice: 'Þú heldur núverandi áskrift og eiginleikum hennar til loka greiðslutímabilsins, síðan verður þú flutt yfir í þessa áskrift.', emailForm: { @@ -122,6 +125,8 @@ export const isIS: LocalizationResource = { }, pastDueNotice: 'Fyrri áskrift þín var gjaldfallin, án greiðslu.', perMonth: 'á mánuði', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Greiðsla', title__paymentSuccessful: 'Greiðsla tókst!', title__subscriptionSuccessful: 'Tókst!', diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index f605a2ce8df..126242f8e81 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -104,8 +104,11 @@ export const itIT: LocalizationResource = { cannotSubscribeUnrecoverable: 'Non puoi abbonarti a questo piano. Il tuo abbonamento esistente è più costoso di questo piano.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Il pagamento è andato a buon fine.', description__subscriptionSuccessful: 'Il tuo nuovo abbonamento è pronto.', + discount: undefined, downgradeNotice: 'Manterrai il tuo abbonamento attuale e le sue funzionalità fino alla fine del ciclo di fatturazione, quindi passerai a questo abbonamento.', emailForm: { @@ -122,6 +125,8 @@ export const itIT: LocalizationResource = { }, pastDueNotice: 'Il tuo precedente abbonamento era scaduto, senza alcun pagamento.', perMonth: 'al mese', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Checkout', title__paymentSuccessful: 'Pagamento riuscito!', title__subscriptionSuccessful: 'Successo!', diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index 34f10d76d06..db672198c3f 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -106,8 +106,11 @@ export const jaJP: LocalizationResource = { cannotSubscribeUnrecoverable: 'このプランを契約することはできません。現在のサブスクリプションの方がこのプランより高額です。', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: '支払いが完了しました。', description__subscriptionSuccessful: '新しいサブスクリプションの設定が完了しました。', + discount: undefined, downgradeNotice: '現在の請求期間が終了するまでは既存のサブスクリプションとその機能を利用でき、その後このサブスクリプションに切り替わります。', emailForm: { @@ -123,6 +126,8 @@ export const jaJP: LocalizationResource = { }, pastDueNotice: '前回のサブスクリプションには未払い分が残っています。', perMonth: '月あたり', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'チェックアウト', title__paymentSuccessful: '支払いが完了しました!', title__subscriptionSuccessful: '成功しました!', diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index a7a835090e7..e7e9b32406d 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -100,8 +100,11 @@ export const kkKZ: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Сіздің жаңа жазылымыңыз дайын.', description__subscriptionSuccessful: 'Сіздің жаңа жазылымыңыз дайын.', + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const kkKZ: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: 'Төлем сәтті аяқталды!', title__subscriptionSuccessful: 'Сәтті!', diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index a7c5739f8ee..fb6314dd941 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -104,8 +104,11 @@ export const koKR: LocalizationResource = { cannotSubscribeMonthly: '이 플랜은 월간 결제가 불가해요. 연간 결제를 선택해 주세요.', cannotSubscribeUnrecoverable: '이 플랜으로 구독할 수 없어요. 현재 구독이 더 높은 요금제예요.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: '결제가 완료됐어요.', description__subscriptionSuccessful: '새 구독이 준비됐어요.', + discount: undefined, downgradeNotice: '현재 구독은 결제 주기 종료까지 유지되고, 이후 이 구독으로 전환돼요.', emailForm: { subtitle: '결제를 완료하려면 영수증을 받을 이메일 주소를 추가해야 해요.', @@ -120,6 +123,8 @@ export const koKR: LocalizationResource = { }, pastDueNotice: '이전 구독이 연체되어 결제가 되지 않았어요.', perMonth: '월', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: '결제', title__paymentSuccessful: '결제가 완료됐어요!', title__subscriptionSuccessful: '성공!', diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 3719a4c6625..6f5b02c1cfd 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -100,8 +100,11 @@ export const mnMN: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const mnMN: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index 319765d7d5b..dafaf669dc4 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -106,8 +106,11 @@ export const msMY: LocalizationResource = { cannotSubscribeUnrecoverable: 'Anda tidak boleh melanggan pelan ini. Langganan sedia ada anda lebih mahal daripada pelan ini.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Pembayaran anda berjaya.', description__subscriptionSuccessful: 'Langganan baharu anda telah sedia.', + discount: undefined, downgradeNotice: 'Anda akan mengekalkan langganan semasa anda dan cirinya sehingga akhir kitaran pengebilan, kemudian anda akan ditukar kepada langganan ini.', emailForm: { @@ -124,6 +127,8 @@ export const msMY: LocalizationResource = { }, pastDueNotice: 'Langganan anda sebelum ini tertunggak, tanpa pembayaran.', perMonth: 'sebulan', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Pembayaran', title__paymentSuccessful: 'Pembayaran berjaya!', title__subscriptionSuccessful: 'Berjaya!', diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index 665c9f8f746..bae7549516c 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -106,8 +106,11 @@ export const nbNO: LocalizationResource = { cannotSubscribeUnrecoverable: 'Du kan ikke abonnere på denne planen. Ditt eksisterende abonnement er dyrere enn denne planen.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Betalingen din var vellykket.', description__subscriptionSuccessful: 'Ditt nye abonnement er klart.', + discount: undefined, downgradeNotice: 'Du beholder ditt nåværende abonnement og dets funksjoner til slutten av faktureringsperioden, deretter byttes du til dette abonnementet.', emailForm: { @@ -123,6 +126,8 @@ export const nbNO: LocalizationResource = { }, pastDueNotice: 'Ditt forrige abonnement var forfalt, uten betaling.', perMonth: 'per måned', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Kasse', title__paymentSuccessful: 'Betalingen var vellykket!', title__subscriptionSuccessful: 'Fullført!', diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index ff7e9b30a40..5c6b71f19fd 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -100,8 +100,11 @@ export const nlBE: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const nlBE: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index 135300b7d98..eb730b5c818 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -100,8 +100,11 @@ export const nlNL: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const nlNL: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index 55a39875928..46b4ae7d912 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -100,8 +100,11 @@ export const plPL: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const plPL: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index 1690a10bdb3..37c396d3fe8 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -104,8 +104,11 @@ export const ptBR: LocalizationResource = { cannotSubscribeUnrecoverable: 'Você não pode assinar este plano. Sua assinatura existente é mais cara que este plano.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Seu pagamento foi realizado com sucesso.', description__subscriptionSuccessful: 'Sua nova assinatura está pronta.', + discount: undefined, downgradeNotice: 'Você manterá sua assinatura atual e seus recursos até o final do ciclo de faturamento, após o qual você será transferido para este plano.', emailForm: { @@ -122,6 +125,8 @@ export const ptBR: LocalizationResource = { }, pastDueNotice: 'Sua assinatura anterior estava em atraso, sem pagamento.', perMonth: 'por mês', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Checkout', title__paymentSuccessful: 'Pagamento realizado com sucesso!', title__subscriptionSuccessful: 'Sucesso!', diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index 71a1fe6f066..6c7d7fb0291 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -106,8 +106,11 @@ export const ptPT: LocalizationResource = { cannotSubscribeUnrecoverable: 'Não pode subscrever este plano. A sua subscrição atual é mais dispendiosa do que este plano.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'O seu pagamento foi efetuado com sucesso.', description__subscriptionSuccessful: 'A sua nova subscrição está pronta.', + discount: undefined, downgradeNotice: 'Manterá a sua subscrição atual e respetivas funcionalidades até ao fim do ciclo de faturação e, depois disso, passará para esta subscrição.', emailForm: { @@ -124,6 +127,8 @@ export const ptPT: LocalizationResource = { }, pastDueNotice: 'A sua subscrição anterior encontrava-se em atraso, sem pagamento.', perMonth: 'por mês', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Finalizar compra', title__paymentSuccessful: 'Pagamento efetuado com sucesso!', title__subscriptionSuccessful: 'Sucesso!', diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index f66fb24d412..f541ec4b043 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -105,8 +105,11 @@ export const roRO: LocalizationResource = { cannotSubscribeUnrecoverable: 'Nu te poți abona la acest plan. Abonamentul tău actual este mai scump decât acest plan.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Plata ta a fost efectuată cu succes.', description__subscriptionSuccessful: 'Noul tău abonament este configurat.', + discount: undefined, downgradeNotice: 'Vei păstra abonamentul curent și funcțiile sale până la finalul ciclului de facturare, apoi vei fi schimbat la acest abonament.', emailForm: { @@ -122,6 +125,8 @@ export const roRO: LocalizationResource = { }, pastDueNotice: 'Abonamentul anterior era restant, fără plată.', perMonth: 'pe lună', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Plată', title__paymentSuccessful: 'Plata a reușit!', title__subscriptionSuccessful: 'Succes!', diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index 242bfdfb0fc..f289adaa41f 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -100,8 +100,11 @@ export const ruRU: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const ruRU: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index 331ef956835..a972297b275 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -100,8 +100,11 @@ export const skSK: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const skSK: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 1eaff6c0504..eedbe97319e 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -100,8 +100,11 @@ export const srRS: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const srRS: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index 5696ee4a76b..fa4746e80da 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -100,8 +100,11 @@ export const svSE: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const svSE: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index 72322b38fa3..821ce49c87b 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -107,8 +107,11 @@ export const taIN: LocalizationResource = { cannotSubscribeUnrecoverable: 'இந்த திட்டத்திற்கு நீங்கள் சந்தா செலுத்த முடியாது. உங்கள் தற்போதைய சந்தா இந்த திட்டத்தை விட விலை அதிகம்.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'உங்கள் கட்டணம் வெற்றிகரமாக முடிந்தது.', description__subscriptionSuccessful: 'உங்கள் புதிய சந்தா முழுமையாகத் தயாராக உள்ளது.', + discount: undefined, downgradeNotice: 'பில்லிங் சுழற்சியின் முடிவு வரை உங்கள் தற்போதைய சந்தாவையும் அதன் அம்சங்களையும் வைத்திருப்பீர்கள், பின்னர் நீங்கள் இந்த சந்தாவிற்கு மாற்றப்படுவீர்கள்.', emailForm: { @@ -124,6 +127,8 @@ export const taIN: LocalizationResource = { }, pastDueNotice: 'உங்கள் முந்தைய சந்தா நிலுவையில் இருந்தது, கட்டணம் எதுவும் இல்லாமல்.', perMonth: 'மாதத்திற்கு', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'செக்அவுட்', title__paymentSuccessful: 'கட்டணம் வெற்றிகரமாக முடிந்தது!', title__subscriptionSuccessful: 'வெற்றி!', diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index 52afc8d930c..207a330b33b 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -106,8 +106,11 @@ export const teIN: LocalizationResource = { cannotSubscribeUnrecoverable: 'మీరు ఈ ప్లాన్‌కు సబ్‌స్క్రైబ్ చేయలేరు. మీ ప్రస్తుత సబ్‌స్క్రిప్షన్ ఈ ప్లాన్ కంటే ఖరీదైనది.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'మీ చెల్లింపు విజయవంతమైంది.', description__subscriptionSuccessful: 'మీ కొత్త సబ్‌స్క్రిప్షన్ పూర్తిగా సిద్ధంగా ఉంది.', + discount: undefined, downgradeNotice: 'బిల్లింగ్ చక్రం ముగిసే వరకు మీరు మీ ప్రస్తుత సబ్‌స్క్రిప్షన్‌ను మరియు దాని ఫీచర్లను ఉంచుకుంటారు, ఆ తర్వాత మీరు ఈ సబ్‌స్క్రిప్షన్‌కు మార్చబడతారు.', emailForm: { @@ -123,6 +126,8 @@ export const teIN: LocalizationResource = { }, pastDueNotice: 'మీ మునుపటి సబ్‌స్క్రిప్షన్ చెల్లింపు లేకుండా బకాయిగా ఉంది.', perMonth: 'నెలకు', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'చెక్అవుట్', title__paymentSuccessful: 'చెల్లింపు విజయవంతమైంది!', title__subscriptionSuccessful: 'విజయం!', diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index 612c2ae5651..8cd8bc93cec 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -103,8 +103,11 @@ export const thTH: LocalizationResource = { cannotSubscribeMonthly: 'คุณไม่สามารถสมัครแผนนี้โดยการชำระรายเดือน หากต้องการสมัครแผนนี้ คุณต้องเลือกชำระรายปี', cannotSubscribeUnrecoverable: 'คุณไม่สามารถสมัครแผนนี้ได้ การสมัครสมาชิกปัจจุบันของคุณมีราคาแพงกว่าแผนนี้', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'การชำระเงินของคุณสำเร็จ', description__subscriptionSuccessful: 'การสมัครสมาชิกใหม่ของคุณพร้อมแล้ว', + discount: undefined, downgradeNotice: 'คุณจะยังคงใช้การสมัครสมาชิกปัจจุบันและฟีเจอร์ของมันจนจบรอบบิล จากนั้นคุณจะถูกเปลี่ยนไปใช้การสมัครสมาชิกนี้', emailForm: { @@ -120,6 +123,8 @@ export const thTH: LocalizationResource = { }, pastDueNotice: 'การสมัครสมาชิกก่อนหน้าของคุณเกินกำหนดและไม่มีการชำระเงิน', perMonth: 'ต่อเดือน', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'ชำระเงิน', title__paymentSuccessful: 'ชำระเงินสำเร็จ!', title__subscriptionSuccessful: 'สำเร็จ!', diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index 0396bedcad3..1d2544e54d6 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -100,8 +100,11 @@ export const trTR: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const trTR: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index eb102f1969d..1f59d61c211 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -100,8 +100,11 @@ export const ukUA: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const ukUA: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index d9c0fad274d..ad8368e63ae 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -105,8 +105,11 @@ export const viVN: LocalizationResource = { 'Bạn không thể đăng ký gói này bằng cách thanh toán hàng tháng. Để đăng ký gói này, bạn cần chọn thanh toán hàng năm.', cannotSubscribeUnrecoverable: 'Bạn không thể đăng ký gói này. Gói đăng ký hiện tại của bạn đắt hơn gói này.', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: 'Thanh toán của bạn đã thành công.', description__subscriptionSuccessful: 'Đăng ký mới của bạn đã được thiết lập.', + discount: undefined, downgradeNotice: 'Bạn sẽ giữ đăng ký hiện tại và các tính năng của nó cho đến cuối chu kỳ thanh toán, sau đó bạn sẽ được chuyển sang đăng ký này.', emailForm: { @@ -122,6 +125,8 @@ export const viVN: LocalizationResource = { }, pastDueNotice: 'Đăng ký trước của bạn đã quá hạn và chưa thanh toán.', perMonth: 'hàng tháng', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: 'Thanh toán', title__paymentSuccessful: 'Thanh toán thành công!', title__subscriptionSuccessful: 'Thành công!', diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index 9e32d56b1bb..ee47c162a81 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -100,8 +100,11 @@ export const zhCN: LocalizationResource = { cannotSubscribeMonthly: undefined, cannotSubscribeUnrecoverable: undefined, checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: undefined, description__subscriptionSuccessful: undefined, + discount: undefined, downgradeNotice: undefined, emailForm: { subtitle: undefined, @@ -116,6 +119,8 @@ export const zhCN: LocalizationResource = { }, pastDueNotice: undefined, perMonth: undefined, + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: undefined, title__paymentSuccessful: undefined, title__subscriptionSuccessful: undefined, diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index 8cbc5c3451a..bdfc40a0d19 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -103,8 +103,11 @@ export const zhTW: LocalizationResource = { cannotSubscribeMonthly: '您無法每月支付訂閱此計劃。要訂閱此計劃,您需要選擇每年支付。', cannotSubscribeUnrecoverable: '您無法訂閱此計劃。您的現有訂閱比此計劃更昂貴。', checkout: { + addPromoCode: undefined, + applyPromoCode: undefined, description__paymentSuccessful: '您的付款已成功。', description__subscriptionSuccessful: '您的訂閱已成功設定。', + discount: undefined, downgradeNotice: '您將保留目前的訂閱及其功能直到本計費週期結束,然後您將被切換到此訂閱。', emailForm: { subtitle: '在您可以完成購買之前,您必須新增一個電子郵件地址,以便發送收據。', @@ -119,6 +122,8 @@ export const zhTW: LocalizationResource = { }, pastDueNotice: '您的上一個訂閱已逾期,未付款。', perMonth: '每月', + promoCodePlaceholder: undefined, + removePromoCode: undefined, title: '結帳', title__paymentSuccessful: '付款成功!', title__subscriptionSuccessful: '成功!', diff --git a/packages/react/src/stateProxy.ts b/packages/react/src/stateProxy.ts index 47832c63227..3066d4e1583 100644 --- a/packages/react/src/stateProxy.ts +++ b/packages/react/src/stateProxy.ts @@ -439,6 +439,7 @@ export class StateProxy implements State { }, start: this.gateMethod, 'start'>(target, 'start'), + update: this.gateMethod, 'update'>(target, 'update'), confirm: this.gateMethod, 'confirm'>(target, 'confirm'), finalize: this.gateMethod, 'finalize'>(target, 'finalize'), }, diff --git a/packages/shared/src/react/__tests__/payment-element.test.tsx b/packages/shared/src/react/__tests__/payment-element.test.tsx index 4138738d563..82bd939516c 100644 --- a/packages/shared/src/react/__tests__/payment-element.test.tsx +++ b/packages/shared/src/react/__tests__/payment-element.test.tsx @@ -143,6 +143,7 @@ describe('PaymentElement Localization', () => { error: null, fetchStatus: 'idle' as const, confirm: vi.fn(), + update: vi.fn(), start: vi.fn(), clear: vi.fn(), finalize: vi.fn(), diff --git a/packages/shared/src/types/billing.ts b/packages/shared/src/types/billing.ts index 65615681856..5d90e45d24b 100644 --- a/packages/shared/src/types/billing.ts +++ b/packages/shared/src/types/billing.ts @@ -85,6 +85,14 @@ export interface BillingNamespace { */ startCheckout: (params: CreateCheckoutParams) => Promise; + /** + * Applies or removes a promo code on an existing Billing checkout for the current user or supplied Organization. + * @returns A [`BillingCheckoutResource`](/docs/reference/types/billing-checkout-resource) object. + * + * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. + */ + updateCheckout: (params: UpdateCheckoutParams) => Promise; + /** * Gets the credit balance for the current payer. * @returns A [`BillingCreditBalanceResource`](https://clerk.com/docs/reference/types/billing-credit-balance-resource) object. @@ -1288,6 +1296,22 @@ export type CreateCheckoutParams = WithOptionalOrgType<{ priceId?: string; }>; +/** + * The `updateCheckout()` method accepts the following parameters. + * + * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes. + */ +export type UpdateCheckoutParams = WithOptionalOrgType<{ + /** + * The unique identifier for the checkout session. + */ + id: string; + /** + * The promo code to apply. Use an empty string to remove the applied promo code. + */ + promoCode: string; +}>; + /** * The `confirm()` method accepts the following parameters. **Only one of `paymentMethodId`, `paymentToken`, or `useTestCard` should be provided.** * @@ -1516,6 +1540,11 @@ export interface CheckoutFlowFinalizeParams { * Common methods available on all checkout flow instances. */ interface CheckoutFlowMethods { + /** + * Updates the current checkout. Use an empty promo code to remove the applied promo code. + */ + update: (params: Pick) => Promise<{ error: ClerkError | null }>; + /** * A function to confirm and finalize the checkout process, usually after payment information has been provided and validated. [Learn more.](#confirm) */ diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 2c073be283c..5f2a29de1c2 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -303,6 +303,11 @@ export type __internal_LocalizationResource = { }; }; checkout: { + addPromoCode: LocalizationValue; + applyPromoCode: LocalizationValue; + discount: LocalizationValue; + promoCodePlaceholder: LocalizationValue; + removePromoCode: LocalizationValue; title: LocalizationValue; title__paymentSuccessful: LocalizationValue; title__subscriptionSuccessful: LocalizationValue; diff --git a/packages/ui/src/components/Checkout/CheckoutForm.tsx b/packages/ui/src/components/Checkout/CheckoutForm.tsx index 00e23e79ff1..6c6c708383e 100644 --- a/packages/ui/src/components/Checkout/CheckoutForm.tsx +++ b/packages/ui/src/components/Checkout/CheckoutForm.tsx @@ -1,3 +1,4 @@ +import { isClerkAPIResponseError } from '@clerk/shared/error'; import { __experimental_useCheckout as useCheckout } from '@clerk/shared/react'; import type { BillingPaymentMethodResource, ConfirmCheckoutParams, RemoveFunctions } from '@clerk/shared/types'; import { useMemo, useState } from 'react'; @@ -10,7 +11,7 @@ import { LineItems } from '@/ui/elements/LineItems'; import { SegmentedControl } from '@/ui/elements/SegmentedControl'; import { Select, SelectButton, SelectOptionList } from '@/ui/elements/Select'; import { Tooltip } from '@/ui/elements/Tooltip'; -import { toNegativeAmount } from '@/ui/utils/billing'; +import { getDiscountDescription, toNegativeAmount } from '@/ui/utils/billing'; import { getCheckoutSeatUnitTotal, getIncludedSeatsUnitTotalTier, @@ -28,12 +29,14 @@ import { descriptors, Flex, Form, + Icon, + Input, localizationKeys, Spinner, Text, useLocalizations, } from '../../customizables'; -import { ChevronUpDown, InformationCircle } from '../../icons'; +import { ChevronUpDown, Close, InformationCircle } from '../../icons'; import type { PropsOfComponent, ThemableCssProp } from '../../styledSystem'; import * as AddPaymentMethod from '../PaymentMethods/AddPaymentMethod'; import { PaymentMethodRow } from '../PaymentMethods/PaymentMethodRow'; @@ -45,6 +48,165 @@ const capitalize = (name: string) => name[0].toUpperCase() + name.slice(1); const HIDDEN_INPUT_NAME = 'payment_method_id'; +const promoCodeErrorMessage = (error: unknown) => { + if (isClerkAPIResponseError(error)) { + return error.errors[0]?.longMessage || error.errors[0]?.message; + } + return error instanceof Error ? error.message : undefined; +}; + +const useUpdatePromoCode = () => { + const { checkout } = useCheckout(); + const { t } = useLocalizations(); + const [error, setError] = useState(); + const [isLoading, setIsLoading] = useState(false); + + const updatePromoCode = async (value: string) => { + setError(undefined); + setIsLoading(true); + const result = await checkout.update({ promoCode: value }); + setIsLoading(false); + + if (result.error) { + setError(promoCodeErrorMessage(result.error) || t(localizationKeys('unstable__errors.form_param_value_invalid'))); + return false; + } + + return true; + }; + + return { error, isLoading, setError, updatePromoCode }; +}; + +const AppliedPromoCodeRow = () => { + const { checkout } = useCheckout(); + const { $, t } = useLocalizations(); + const { isLoading, updatePromoCode } = useUpdatePromoCode(); + const discount = checkout.status === 'needs_confirmation' ? checkout.totals.discounts?.discount : undefined; + const appliedPromoCode = discount?.promoCode; + + if (!discount || !appliedPromoCode) { + return null; + } + + return ( + + void updatePromoCode('')} + sx={{ + padding: 0, + position: 'relative', + '&::after': { + content: '""', + position: 'absolute', + inset: '-18px', + }, + }} + > + + + } + /> + + + ); +}; + +const PromoCodeInput = () => { + const { checkout } = useCheckout(); + const { t } = useLocalizations(); + const [promoCode, setPromoCode] = useState(''); + const { error, isLoading, setError, updatePromoCode } = useUpdatePromoCode(); + + if (checkout.status !== 'needs_confirmation' || checkout.totals.discounts?.discount) { + return null; + } + + const errorId = 'checkout-promo-code-error'; + + return ( + ({ + padding: theme.space.$4, + borderBottomWidth: theme.borderWidths.$normal, + borderBottomStyle: theme.borderStyles.$solid, + borderBottomColor: theme.colors.$borderAlpha100, + })} + > + { + event.preventDefault(); + void updatePromoCode(promoCode.trim()).then(success => { + if (success) { + setPromoCode(''); + } + }); + }} + sx={theme => ({ + display: 'grid', + gridTemplateColumns: 'minmax(0, 1fr) auto', + gap: theme.space.$2, + })} + > + { + setPromoCode(event.target.value); + setError(undefined); + }} + /> +