diff --git a/public/locales/en/user.json b/public/locales/en/user.json index e09a8e353..c8f4a5931 100644 --- a/public/locales/en/user.json +++ b/public/locales/en/user.json @@ -75,6 +75,7 @@ "complete_subscription": "Complete subscription", "current_plan": "CURRENT PLAN", "daily_subscription": "Daily subscription", + "downgrade_on": "Pending downgrade on {{date}}", "downgrade_plan_success": "You've successfully changed the subscription plan. Your new plan will start after the end of the current cycle ({{date}}).", "expiry_date": "Expiry date", "granted_subscription": "Granted subscription", @@ -88,6 +89,7 @@ "no_transactions": "No transactions", "other": "other", "payment_method": "Payment method", + "pending_downgrade": "Pending downgrade", "pending_offer_switch": "Will update to a \"{{title}}\" after the next billing date", "price_payed_with": "{{price}} payed with {{method}}", "price_payed_with_card": "Price payed with card", diff --git a/public/locales/es/user.json b/public/locales/es/user.json index 6a15608a3..64315f0cb 100644 --- a/public/locales/es/user.json +++ b/public/locales/es/user.json @@ -75,6 +75,7 @@ "complete_subscription": "Completar suscripción", "current_plan": "", "daily_subscription": "Suscripción diaria", + "downgrade_on": "", "downgrade_plan_success": "", "expiry_date": "Fecha de vencimiento", "granted_subscription": "Suscripción otorgada", @@ -89,6 +90,7 @@ "no_transactions": "No hay transacciones", "other": "otro", "payment_method": "Método de pago", + "pending_downgrade": "", "pending_offer_switch": "Se actualizará a \"{{title}}\" después de la próxima fecha de facturación", "price_payed_with": "{{price}} pagado con {{method}}", "price_payed_with_card": "Precio pagado con tarjeta", diff --git a/src/components/OfferSwitch/OfferSwitch.tsx b/src/components/OfferSwitch/OfferSwitch.tsx index 11c33cfc2..92c2d172b 100644 --- a/src/components/OfferSwitch/OfferSwitch.tsx +++ b/src/components/OfferSwitch/OfferSwitch.tsx @@ -10,6 +10,7 @@ import { useAccountStore } from '#src/stores/AccountStore'; interface OfferSwitchProps { isCurrentOffer: boolean; + pendingDowngradeOfferId: string; offer: Offer; selected: { value: boolean; @@ -17,23 +18,31 @@ interface OfferSwitchProps { }; } -const OfferSwitch = ({ isCurrentOffer, offer, selected }: OfferSwitchProps) => { +const OfferSwitch = ({ isCurrentOffer, pendingDowngradeOfferId, offer, selected }: OfferSwitchProps) => { const { t, i18n } = useTranslation('user'); const { customerPriceInclTax, customerCurrency, period } = offer; const expiresAt = useAccountStore((state) => state.subscription?.expiresAt); + const isPendingDowngrade = pendingDowngradeOfferId === offer.offerId; + return (
- selected.set(offer.offerId)} /> + selected.set(offer.offerId)} />
- {isCurrentOffer && ( -
{t('payment.current_plan')}
+ {(isCurrentOffer || isPendingDowngrade) && ( +
+ {isCurrentOffer && t('payment.current_plan').toUpperCase()} + {isPendingDowngrade && t('payment.pending_downgrade').toUpperCase()} +
)}
{t(`payment.${period === 'month' ? 'monthly' : 'annual'}_subscription`)}
- {isCurrentOffer && expiresAt && ( + {(isCurrentOffer || isPendingDowngrade) && expiresAt && (
- {t('payment.next_billing_date_on', { date: formatLocalizedDate(new Date(expiresAt * 1000), i18n.language) })} + {isCurrentOffer && + !pendingDowngradeOfferId && + t('payment.next_billing_date_on', { date: formatLocalizedDate(new Date(expiresAt * 1000), i18n.language) })} + {isPendingDowngrade && t('payment.downgrade_on', { date: formatLocalizedDate(new Date(expiresAt * 1000), i18n.language) })}
)}
diff --git a/src/components/Payment/Payment.tsx b/src/components/Payment/Payment.tsx index b4f7080df..a3099d837 100644 --- a/src/components/Payment/Payment.tsx +++ b/src/components/Payment/Payment.tsx @@ -23,6 +23,8 @@ import useOffers from '#src/hooks/useOffers'; import OfferSwitch from '#components/OfferSwitch/OfferSwitch'; import { changeSubscription } from '#src/stores/CheckoutController'; import Alert from '#components/Alert/Alert'; +import { updateUser } from '#src/stores/AccountController'; +import { useAccountStore } from '#src/stores/AccountStore'; const VISIBLE_TRANSACTIONS = 4; @@ -81,8 +83,6 @@ const Payment = ({ const [selectedOfferId, setSelectedOfferId] = useState(activeSubscription?.accessFeeId ?? null); const [isUpgradeOffer, setIsUpgradeOffer] = useState(undefined); - // TODO: debug why offer upgrade works but downgrade doesn't - useEffect(() => { if (!isChangingOffer) { setSelectedOfferId(activeSubscription?.accessFeeId ?? null); @@ -98,7 +98,28 @@ const Payment = ({ } }, [selectedOfferId, offers, activeSubscription]); - const changeSubscriptionPlan = useMutation(changeSubscription); + const updateSubscriptionMetadata = useMutation(updateUser, { + onSuccess: () => { + useAccountStore.setState({ + loading: false, + }); + }, + }); + const changeSubscriptionPlan = useMutation(changeSubscription, { + onSuccess: () => { + if (!isUpgradeOffer && selectedOfferId) { + updateSubscriptionMetadata.mutate({ + firstName: customer.firstName || '', + lastName: customer.lastName || '', + metadata: { + [`${activeSubscription?.subscriptionId}_pending_downgrade`]: selectedOfferId, + }, + }); + } + }, + }); + + const pendingDowngradeOfferId = (customer.metadata?.[`${activeSubscription?.subscriptionId}_pending_downgrade`] as string) || ''; const onChangePlanClick = async () => { if (selectedOfferId && activeSubscription?.subscriptionId) { @@ -173,11 +194,15 @@ const Payment = ({

{getTitle(activeSubscription.period)}
- {activeSubscription.status === 'active' && !isGrantedSubscription + {activeSubscription.status === 'active' && !isGrantedSubscription && !pendingDowngradeOfferId ? t('user:payment.next_billing_date_on', { date: formatLocalizedDate(new Date(activeSubscription.expiresAt * 1000), i18n.language) }) : t('user:payment.subscription_expires_on', { date: formatLocalizedDate(new Date(activeSubscription.expiresAt * 1000), i18n.language) })} - {pendingOffer && ( - {t('user:payment.pending_offer_switch', { title: getTitle(pendingOffer.period) })} + {(pendingOffer || pendingDowngradeOfferId) && ( + + {t('user:payment.pending_offer_switch', { + title: getTitle(pendingOffer?.period || offers.find((offer) => offer.offerId === pendingDowngradeOfferId)?.period || 'month'), + })} + )}

{!isGrantedSubscription && ( @@ -224,6 +249,7 @@ const Payment = ({ diff --git a/src/pages/User/__snapshots__/User.test.tsx.snap b/src/pages/User/__snapshots__/User.test.tsx.snap index 7b099412b..7001fd16d 100644 --- a/src/pages/User/__snapshots__/User.test.tsx.snap +++ b/src/pages/User/__snapshots__/User.test.tsx.snap @@ -636,6 +636,7 @@ exports[`User Component tests > Payments Page 1`] = `
user:payment.next_billing_date_on +

; }; export type EmailConfirmPasswordInput = {