diff --git a/src/pages/CheckoutPage/helpers/getTotalForDisplay.ts b/src/pages/CheckoutPage/helpers/getTotalForDisplay.ts new file mode 100644 index 00000000..ca467b07 --- /dev/null +++ b/src/pages/CheckoutPage/helpers/getTotalForDisplay.ts @@ -0,0 +1,24 @@ +import { isSafeInteger } from "@nerdware/ts-type-safety-utils"; +import { fmt } from "@/utils/formatters"; +import type { OpenApiSchemas } from "@/types/open-api"; + +/** + * > `The values used here are for DISPLAY PURPOSES ONLY and merely convey + * information to the user. All pricing/product info is stored and calculated + * by the backend API. Sending invalid pricing/product info to the server + * results a 400 response.` + */ +export const getPrice_FOR_DISPLAY_ONLY = ( + price: number, + discountPercentage?: OpenApiSchemas["PromoCodeInfo"]["discountPercentage"] | null, // 10 = 10% off + { formatAsCurrency }: FormatOpts = {} as FormatOpts +) => { + const priceWithDiscount = isSafeInteger(discountPercentage) + ? price - price * (discountPercentage / 100) + : price; + + const returnValue = + formatAsCurrency === true ? fmt.intToCurrencyStr(priceWithDiscount) : priceWithDiscount; + + return returnValue as FormatOpts["formatAsCurrency"] extends true ? string : number; +}; diff --git a/src/pages/CheckoutPage/helpers/index.ts b/src/pages/CheckoutPage/helpers/index.ts new file mode 100644 index 00000000..75f89402 --- /dev/null +++ b/src/pages/CheckoutPage/helpers/index.ts @@ -0,0 +1,2 @@ +export * from "./getTotalForDisplay"; +export * from "./subPricingDisplayConfigs"; diff --git a/src/pages/CheckoutPage/helpers/subPricingDisplayConfigs.ts b/src/pages/CheckoutPage/helpers/subPricingDisplayConfigs.ts new file mode 100644 index 00000000..7a8998af --- /dev/null +++ b/src/pages/CheckoutPage/helpers/subPricingDisplayConfigs.ts @@ -0,0 +1,55 @@ +import type { SubscriptionPriceLabel } from "@/graphql/types"; + +/** + * > `The values used here are for DISPLAY PURPOSES ONLY and merely convey + * information to the user. All pricing/product info is stored and calculated + * by the backend API. Sending invalid pricing/product info to the server + * results a 400 response.` + */ +export const SUB_PRICING_DISPLAY_CONFIGS = { + TRIAL: { + label: "Try Fixit", + price: 0, + trialDays: 14, + afterTrial: { + price: 500, + billingPeriod: "month", + }, + }, + MONTHLY: { + label: "Monthly Subscription", + price: 500, + billingPeriod: "month", + }, + ANNUAL: { + label: "Annual Subscription", + price: 5000, + billingPeriod: "year", + }, +} as { + readonly [Sub in SubscriptionPriceLabel]: Sub extends "TRIAL" + ? TrialSubBillingDisplayConfigs + : PaidSubBillingDisplayConfigs; +}; + +interface BaseSubPricingDisplayConfigs { + label: string; +} + +type SubBillingInfo = { + price: number; + billingPeriod: "month" | "year"; +}; + +type PaidSubBillingDisplayConfigs = BaseSubPricingDisplayConfigs & + SubBillingInfo & { + trialDays?: never; + afterTrial?: never; + }; + +type TrialSubBillingDisplayConfigs = BaseSubPricingDisplayConfigs & { + price: 0; + trialDays: number; + afterTrial: SubBillingInfo; + billingPeriod?: never; +};