Skip to content

Commit

Permalink
WIP - halp T_T
Browse files Browse the repository at this point in the history
  • Loading branch information
xlisachan committed Jan 13, 2025
1 parent 3b5ff7b commit c141087
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { headers } from 'next/headers';
import { MetricsWrapper, PurchaseDetails } from '@fxa/payments/ui';
import { fetchCMSData, getCartAction } from '@fxa/payments/ui/actions';
import { MetricsWrapper } from '@fxa/payments/ui';
import { fetchCMSData, getUpgradeCartAction } from '@fxa/payments/ui/actions';
import {
getApp,
CheckoutParams,
PriceHeader,
PriceInterval,
PriceItemized,
SubscriptionTitle,
TermsAndPrivacy,
UpgradePurchaseDetails,
} from '@fxa/payments/ui/server';
import { DEFAULT_LOCALE } from '@fxa/shared/l10n';
import { config } from 'apps/payments/next/config';
Expand All @@ -32,19 +30,20 @@ export default async function UpgradeLayout({
//);
const locale = headers().get('accept-language') || DEFAULT_LOCALE;

const cartDataPromise = getUpgradeCartAction(params.cartId);
const cmsDataPromise = fetchCMSData(params.offeringId, locale);
const cartDataPromise = getCartAction(params.cartId);
const l10n = getApp().getL10n(locale);
const [cms, cart] = await Promise.all([cmsDataPromise, cartDataPromise]);
const purchaseDetails =
cms.defaultPurchase.purchaseDetails.localizations.at(0) ||
cms.defaultPurchase.purchaseDetails;

// CURRENT PLAN
// const { price: currentPrice, offering: currentOffering } = cart.currentPlan;
// const currentPurchaseDetails =
// currentOffering?.defaultPurchase.purchaseDetails.localizations.at(0) ||
// currentOffering?.defaultPurchase.purchaseDetails;
const currentOfferingId = cart.fromOfferingConfigId;
const currentCmsDataPromise = fetchCMSData(currentOfferingId, locale);
const currentCms = await currentCmsDataPromise;
const currentPurchaseDetails =
currentCms.defaultPurchase.purchaseDetails.localizations.at(0) ||
currentCms.defaultPurchase.purchaseDetails;

return (
<MetricsWrapper cart={cart}>
Expand All @@ -55,40 +54,14 @@ export default async function UpgradeLayout({
className="mb-6 tablet:mt-6 tablet:min-w-[18rem] tablet:max-w-xs tablet:col-start-2 tablet:col-end-auto tablet:row-start-1 tablet:row-end-3"
aria-label="Upgrade details"
>
<PurchaseDetails
selectedPrice={
<PriceHeader
priceInterval={
<PriceInterval
l10n={l10n}
currency={cart.upcomingInvoicePreview.currency}
interval={cart.interval}
listAmount={cart.upcomingInvoicePreview.listAmount}
/>
}
purchaseDetails={purchaseDetails}
/>
}
// upgradeFrom={
// <PriceHeader
// priceInterval={
// <PriceInterval
// l10n={l10n}
// currency={currentPrice.currency}
// interval={currentPrice?.recurring.interval}
// listAmount={currentPrice?.unit_amount}
// />
// }
// purchaseDetails={currentPurchaseDetails}
// />
// }
>
<PriceItemized
l10n={l10n}
interval={cart.interval}
invoice={cart.upcomingInvoicePreview}
/>
</PurchaseDetails>
<UpgradePurchaseDetails
l10n={l10n}
interval={cart.interval}
invoice={cart.upcomingInvoicePreview}
currentPrice={cart.eligibleSourcePrice}
currentPurchaseDetails={currentPurchaseDetails}
purchaseDetails={purchaseDetails}
/>
</section>

<div className="bg-white rounded-b-lg shadow-sm shadow-grey-300 border-t-0 mb-6 pt-4 px-4 pb-14 rounded-t-lg text-grey-600 tablet:clip-shadow tablet:rounded-t-none desktop:px-12 desktop:pb-12">
Expand Down
16 changes: 16 additions & 0 deletions libs/payments/cart/src/lib/cart.error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,19 @@ export class CartSuccessMissingRequired extends CartError {
});
}
}

export class CartUpgradeMissingRequired extends CartError {
constructor(cartId: string) {
super('Upgrade cart is missing required fields', {
cartId,
});
}
}

export class CartUpgradeNotValid extends CartError {
constructor(cartId: string) {
super('Upgrade cart does not have current plan', {
cartId,
});
}
}
51 changes: 49 additions & 2 deletions libs/payments/cart/src/lib/cart.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { GeoDBManager } from '@fxa/shared/geodb';
import { CartManager } from './cart.manager';
import {
CheckoutCustomerData,
CurrentPrice,
GetNeedsInputResponse,
NeedsInputType,
NoInputNeededResponse,
Expand All @@ -40,6 +41,7 @@ import {
StripeHandleNextActionResponse,
SuccessCart,
UpdateCart,
UpgradeCart,
WithContextCart,
} from './cart.types';
import { handleEligibilityStatusMap } from './cart.utils';
Expand All @@ -53,6 +55,8 @@ import {
CartStateProcessingError,
CartSubscriptionNotFoundError,
CartSuccessMissingRequired,
CartUpgradeMissingRequired,
CartUpgradeNotValid,
} from './cart.error';
import { AccountManager } from '@fxa/shared/account/account';
import assert from 'assert';
Expand Down Expand Up @@ -215,7 +219,6 @@ export class CartService {
currency,
eligibilityStatus: cartEligibilityStatus,
couponCode: args.promoCode,
eligibleSourcePrice: eligibility.eligibleSourcePrice || undefined,
});

return cart;
Expand Down Expand Up @@ -438,6 +441,21 @@ export class CartService {
const cartEligibilityStatus =
handleEligibilityStatusMap[eligibility.subscriptionEligibilityResult];

let currentPrice: CurrentPrice | undefined;
if (cartEligibilityStatus === CartEligibilityStatus.UPGRADE) {
if (
!eligibility.eligibleSourcePrice ||
!eligibility.eligibleSourcePrice.recurring ||
!eligibility.eligibleSourcePrice.unit_amount
)
throw new CartUpgradeNotValid(cartId);
currentPrice = {
currency: eligibility.eligibleSourcePrice.currency,
interval: eligibility.eligibleSourcePrice.recurring?.interval,
listAmount: eligibility.eligibleSourcePrice.unit_amount,
};
}

const upcomingInvoicePreview = await this.invoiceManager.previewUpcoming({
priceId: price.id,
currency: cart.currency || DEFAULT_CURRENCY,
Expand Down Expand Up @@ -494,8 +512,10 @@ export class CartService {
latestInvoicePreview,
paymentInfo,
eligibilityStatus: cartEligibilityStatus,
eligibleSourcePrice: eligibility.eligibleSourcePrice,
eligibleSourcePrice: currentPrice,
fromOfferingConfigId: eligibility.fromOfferingConfigId,
proratedAmount: upcomingInvoicePreview.proratedAmount || undefined,
oneTimeCharge: upcomingInvoicePreview.oneTimeCharge || undefined,
};
}

Expand Down Expand Up @@ -524,6 +544,33 @@ export class CartService {
};
}

/**
* Fetch a upgrade cart
*/
async getUpgradeCart(cartId: string): Promise<UpgradeCart> {
const cart = await this.getCart(cartId);

if (cart.eligibilityStatus !== CartEligibilityStatus.UPGRADE)
throw new Error();

if (
!cart.eligibleSourcePrice ||
!cart.fromOfferingConfigId ||
!cart.proratedAmount ||
!cart.oneTimeCharge
) {
throw new CartUpgradeMissingRequired(cartId);
}

return {
...cart,
eligibleSourcePrice: cart.eligibleSourcePrice,
fromOfferingConfigId: cart.fromOfferingConfigId,
proratedAmount: cart.proratedAmount,
oneTimeCharge: cart.oneTimeCharge,
};
}

async metricsOptedOut(accountId?: string): Promise<boolean> {
if (accountId) {
const accountResp = await this.accountManager.getAccounts([accountId]);
Expand Down
22 changes: 18 additions & 4 deletions libs/payments/cart/src/lib/cart.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { TaxAddress } from '@fxa/payments/customer';
import { StripePrice } from '@fxa/payments/stripe';
import {
Cart,
CartEligibilityStatus,
Expand Down Expand Up @@ -62,20 +61,37 @@ export type ResultCart = Readonly<Omit<Cart, 'id' | 'uid'>> & {
readonly uid?: string;
};

type RecurringIntervalType = Stripe.Price.Recurring.Interval;

export interface CurrentPrice {
currency: string;
interval: RecurringIntervalType;
listAmount: number;
}

export type WithContextCart = ResultCart & {
metricsOptedOut: boolean;
upcomingInvoicePreview: Invoice;
latestInvoicePreview?: Invoice;
paymentInfo?: PaymentInfo;
eligibleSourcePrice?: StripePrice;
eligibleSourcePrice?: CurrentPrice;
fromOfferingConfigId?: string;
proratedAmount?: number;
oneTimeCharge?: number;
};

export type SuccessCart = WithContextCart & {
latestInvoicePreview: Invoice;
paymentInfo: PaymentInfo;
};

export type UpgradeCart = WithContextCart & {
eligibleSourcePrice: CurrentPrice;
fromOfferingConfigId: string;
proratedAmount: number;
oneTimeCharge: number;
};

export type SetupCart = {
uid?: string;
interval: string;
Expand All @@ -88,8 +104,6 @@ export type SetupCart = {
email?: string;
amount: number;
eligibilityStatus: CartEligibilityStatus;
eligibleSourcePrice?: StripePrice;
fromOfferingConfigId?: string;
};

export interface TaxAmount {
Expand Down
19 changes: 19 additions & 0 deletions libs/payments/ui/src/lib/actions/getUpgradeCart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use server';

import { plainToClass } from 'class-transformer';
import { getApp } from '../nestapp/app';
import { GetCartActionArgs } from '../nestapp/validators/GetCartActionArgs';

export const getUpgradeCartAction = async (cartId: string) => {
const cart = await getApp().getActionsService().getUpgradeCart(
plainToClass(GetCartActionArgs, {
cartId,
})
);

return cart;
};
1 change: 1 addition & 0 deletions libs/payments/ui/src/lib/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { getCartAction } from './getCart';
export { getCartOrRedirectAction } from './getCartOrRedirect';
export { getMetricsFlowAction } from './getMetricsFlow';
export { getPayPalCheckoutToken } from './getPayPalCheckoutToken';
export { getUpgradeCartAction } from './getUpgradeCart';
export { handleStripeErrorAction } from './handleStripeError';
export { recordEmitterEventAction } from './recordEmitterEvent';
export { restartCartAction } from './restartCart';
Expand Down
8 changes: 8 additions & 0 deletions libs/payments/ui/src/lib/nestapp/nextjs-actions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ export class NextJSActionsService {
return cart;
}

async getUpgradeCart(args: GetCartActionArgs) {
await new Validator().validateOrReject(args);

const cart = await this.cartService.getUpgradeCart(args.cartId);

return cart;
}

async updateCart(args: UpdateCartActionArgs) {
await new Validator().validateOrReject(args);

Expand Down
Loading

0 comments on commit c141087

Please sign in to comment.