Skip to content

Commit

Permalink
Use new price_options field
Browse files Browse the repository at this point in the history
  • Loading branch information
gdbroman committed Oct 10, 2023
1 parent dc650f4 commit f8add9c
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 78 deletions.
51 changes: 30 additions & 21 deletions hosting-holium-com/src/pages/payment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
OnboardingPage,
OnboardingStorage,
PaymentDialog,
ThirdEarthPeriodicity,
ThirdEarthProduct,
ThirdEarthProductId,
ThirdEarthProductType,
} from '@holium/shared';

Expand All @@ -16,8 +18,7 @@ import { thirdEarthApi } from '../util/thirdEarthApi';
import { useNavigation } from '../util/useNavigation';

type ServerSideProps = {
products: ThirdEarthProduct[];
// We use underscore to highlight that this is a query param.
product: ThirdEarthProduct | undefined;
product_type: ThirdEarthProductType;
back_url?: string;
};
Expand All @@ -28,17 +29,22 @@ export const getServerSideProps: GetServerSideProps = async ({ query }) => {
const product_type = (query.product_type ??
'planet') as ThirdEarthProductType;

const product = products.find((p) => {
if (product_type === 'planet') return p.id === ThirdEarthProductId.PLANET;
else return p.id === ThirdEarthProductId.BYOP_P;
});

return {
props: {
products,
product,
product_type,
back_url,
} as ServerSideProps,
};
};

export default function Payment({
products: unfilteredProducts,
product,
product_type,
back_url,
}: ServerSideProps) {
Expand All @@ -51,11 +57,7 @@ export default function Payment({
const [stripe, setStripe] = useState<Stripe>();
const [clientSecret, setClientSecret] = useState<string>();

const products = unfilteredProducts.filter(
(product) => product.product_type === product_type
);

const [productId, setProductId] = useState(products[0].id);
const [periodicity, setPeriodicity] = useState(ThirdEarthPeriodicity.MONTH);
const [invoiceId, setInvoiceId] = useState<string>();

useEffect(() => {
Expand All @@ -72,9 +74,17 @@ export default function Payment({
setToken(token);

const getSecretAndSetupStripe = async () => {
if (!product) return;

const priceOption = product.price_options.find(
(po) => po.periodicity === periodicity
);
if (!priceOption) return;

const response = await thirdEarthApi.stripeMakePayment(
token,
productId.toString(),
product.id.toString(),
priceOption.stripe_price_id,
// Don't pass serverId for byop-p.
product_type !== 'byop-p' && serverId ? serverId : undefined
);
Expand All @@ -90,7 +100,7 @@ export default function Payment({
} catch (e) {
console.error(e);
}
}, [productId]);
});

const stripeOptions: StripeElementsOptions = {
clientSecret: clientSecret,
Expand All @@ -112,15 +122,15 @@ export default function Payment({
};

const onNext = async () => {
if (!token || !invoiceId || !productId) return false;
if (!token || !invoiceId || !product) return false;

if (product_type === 'byop-p') {
await thirdEarthApi.log(token, {
file: 'purchases',
type: 'info',
subject: 'FRONTEND: payment step (email notify)',
message: `Succesful stripe purchase of byop-p by ${email}.`,
productId: productId.toString(),
productId: product.id.toString(),
auditTrailCode: 1000,
});

Expand All @@ -136,7 +146,7 @@ export default function Payment({
// This server call should be non-blocking since the user has already paid.
await thirdEarthApi.provisionalShipEntry({
token,
product: productId.toString(),
product: product.id.toString(),
invoiceId,
shipType: 'provisional',
});
Expand All @@ -156,7 +166,7 @@ export default function Payment({
type: 'info',
subject: 'FRONTEND: payment step (email notify)',
message: `Succesful stripe purchase of planet by ${email}.`,
productId: productId.toString(),
productId: product.id.toString(),
auditTrailCode: 1000,
});

Expand All @@ -174,7 +184,7 @@ export default function Payment({
await thirdEarthApi.provisionalShipEntry({
token,
patp: serverId,
product: productId.toString(),
product: product.id.toString(),
invoiceId,
shipType: 'planet',
});
Expand All @@ -191,14 +201,13 @@ export default function Payment({
return (
<Page title="Payment" isProtected>
<PaymentDialog
productType={product_type}
products={products}
productId={productId}
patp={serverId}
priceOptions={product?.price_options ?? []}
periodicity={periodicity}
setPeriodicity={setPeriodicity}
patp={product_type === 'planet' ? serverId : undefined}
email={email}
stripe={stripe as any}
stripeOptions={stripeOptions as any}
setProductId={setProductId}
onBack={onBack}
onNext={onNext}
/>
Expand Down
40 changes: 16 additions & 24 deletions shared/src/onboarding/dialogs/Payment/PaymentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,30 @@ import { Flex, Spinner } from '@holium/design-system/general';
import { OnboardDialog } from '../../components/OnboardDialog';
import { OnboardDialogTitle } from '../../components/OnboardDialog.styles';
import { PaymentIcon } from '../../icons/PaymentIcon';
import { ThirdEarthProduct, ThirdEarthProductType } from '../../types';
import { ThirdEarthPeriodicity, ThirdEarthPriceOption } from '../../types';
import { AccountInformation } from './AccountInformation';
import { PaymentForm } from './PaymentForm';
import { ProductCards } from './ProductCards';

type Props = {
productType: ThirdEarthProductType;
products: ThirdEarthProduct[];
productId: number;
patp: string;
priceOptions: ThirdEarthPriceOption[];
periodicity: ThirdEarthPeriodicity;
setPeriodicity: (periodicity: ThirdEarthPeriodicity) => void;
patp: string | undefined;
email: string;
stripe: Stripe | undefined;
stripeOptions: StripeElementsOptions | undefined;
setProductId: (productId: number) => void;
onBack: () => void;
onNext: () => Promise<boolean>;
};

const PaymentDialogPresenter = ({
productType,
products,
productId,
priceOptions,
periodicity,
setPeriodicity,
patp,
email,
stripeOptions,
setProductId,
onBack,
onNext,
}: Props) => {
Expand Down Expand Up @@ -84,14 +82,11 @@ const PaymentDialogPresenter = ({
<>
<OnboardDialogTitle>Payment</OnboardDialogTitle>
<ProductCards
products={products}
productId={productId}
setProductId={setProductId}
/>
<AccountInformation
patp={productType === 'planet' ? patp : undefined}
email={email}
priceOptions={priceOptions}
periodicity={periodicity}
setPeriodicity={setPeriodicity}
/>
<AccountInformation patp={patp} email={email} />
<PaymentForm />
</>
}
Expand All @@ -111,14 +106,11 @@ export const PaymentDialog = ({ stripe, stripeOptions, ...props }: Props) => {
<>
<OnboardDialogTitle>Payment</OnboardDialogTitle>
<ProductCards
products={props.products}
productId={props.productId}
setProductId={props.setProductId}
/>
<AccountInformation
patp={props.productType === 'planet' ? props.patp : undefined}
email={props.email}
priceOptions={props.priceOptions}
periodicity={props.periodicity}
setPeriodicity={props.setPeriodicity}
/>
<AccountInformation patp={props.patp} email={props.email} />
<Flex justifyContent="center" alignItems="center" my={30}>
<Spinner size={3} />
</Flex>
Expand Down
60 changes: 28 additions & 32 deletions shared/src/onboarding/dialogs/Payment/ProductCards.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
import { useEffect } from 'react';

import { Flex } from '@holium/design-system/general';

import { ThirdEarthProduct } from '../../types/index';
import {
ThirdEarthPeriodicity,
ThirdEarthPriceOption,
} from '../../types/index';
import { ProductCard } from './ProductCard';

type Props = {
products: ThirdEarthProduct[];
productId: number;
setProductId: (productId: number) => void;
priceOptions: ThirdEarthPriceOption[];
periodicity: ThirdEarthPeriodicity;
setPeriodicity: (periodicity: ThirdEarthPeriodicity) => void;
};

export const ProductCards = ({ products, productId, setProductId }: Props) => {
const byopProduct = products.find(
(product) => product.product_type === 'byop-p'
);

useEffect(() => {
if (byopProduct) {
setProductId(byopProduct.id);
}
}, [byopProduct, setProductId]);
export const ProductCards = ({
priceOptions,
periodicity,
setPeriodicity,
}: Props) => (
<Flex gap={16}>
{/* Assume the cheapest is monthly and the second yearly. */}
{priceOptions.sort().map((priceOption) => {
const isMonthly = priceOption.periodicity === ThirdEarthPeriodicity.MONTH;
const isSelected = priceOption.periodicity === periodicity;

return (
<Flex gap={16}>
{/* Assume the cheapest is monthly and the second yearly. */}
{products.sort().map((product, index) => (
return (
<ProductCard
key={product.id}
h2Text={`$${product.subscription_price}.00`}
bodyText={index === 0 ? 'Monthly' : 'Yearly'}
key={priceOption.stripe_price_id}
h2Text={`$${priceOption.recurring_price}.00`}
bodyText={isMonthly ? 'Monthly' : 'Yearly'}
hintText={
index === 0
? `$${product.subscription_price * 12} yearly`
: undefined
isMonthly ? undefined : `$${priceOption.one_time_price} yearly`
}
isSelected={productId === product.id}
onClick={() => setProductId(product.id)}
isSelected={isSelected}
onClick={() => setPeriodicity(priceOption.periodicity)}
/>
))}
</Flex>
);
};
);
})}
</Flex>
);
18 changes: 18 additions & 0 deletions shared/src/onboarding/dialogs/util.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ export const thirdEarthMockProduct: ThirdEarthProduct = {
long_description: 'Monthly subscription',
price_id: '11',
subscription_price: 15,
price_options: [
{
unit: 'usd',
description: 'monthly subscription',
periodicity: 'month',
one_time_price: 0,
recurring_price: 15,
stripe_price_id: 'price_1MDqoIHhoM3uGGuYAZZN23Yr',
},
{
unit: 'usd',
description: 'yearly subscription',
periodicity: 'year',
one_time_price: 0,
recurring_price: 150,
stripe_price_id: 'price_1MDqoIHhoM3uGGuY00mWc29l',
},
],
};

export const thirdEarthMockProducts = [
Expand Down
2 changes: 2 additions & 0 deletions shared/src/onboarding/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ export type {
RealmOnboardingStep,
ThirdEarthAlert,
ThirdEarthPortalSession,
ThirdEarthPriceOption,
ThirdEarthProduct,
ThirdEarthProductType,
ThirdEarthShip,
} from './types';
export { ThirdEarthPeriodicity, ThirdEarthProductId } from './types/index';
8 changes: 7 additions & 1 deletion shared/src/onboarding/services/ThirdEarthApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,20 @@ export class ThirdEarthApi {
);
}

stripeMakePayment(token: string, productId: string, patp?: string) {
stripeMakePayment(
token: string,
productId: string,
priceId: string,
patp?: string
) {
return http<StripeMakePaymentResponse>(
`${this.apiBaseUrl}/stripe-make-payment`,
{
method: 'POST',
headers: this.getHeaders(token),
body: JSON.stringify({
productId,
priceId,
patp,
}),
}
Expand Down
20 changes: 20 additions & 0 deletions shared/src/onboarding/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ export type ThirdEarthProductType =
| 'byop-nk'
| 'subscription';

export enum ThirdEarthPeriodicity {
MONTH = 'month',
YEAR = 'year',
}

export type ThirdEarthPriceOption = {
unit: string;
description: string;
periodicity: ThirdEarthPeriodicity;
one_time_price: number;
recurring_price: number;
stripe_price_id: string;
};

export enum ThirdEarthProductId {
PLANET = 30,
BYOP_P = 101,
}

export type ThirdEarthProduct = {
client_id: number;
comet_count: string;
Expand All @@ -16,6 +35,7 @@ export type ThirdEarthProduct = {
long_description: string;
price_id: string;
priority: number;
price_options: ThirdEarthPriceOption[];
product_status: string;
product_type: ThirdEarthProductType;
subscription_price: number;
Expand Down

0 comments on commit f8add9c

Please sign in to comment.