diff --git a/src/components/StripeForm/StripeForm.tsx b/src/components/StripeForm/StripeForm.tsx index d18c0fbf..f4858343 100644 --- a/src/components/StripeForm/StripeForm.tsx +++ b/src/components/StripeForm/StripeForm.tsx @@ -1,17 +1,72 @@ import { Elements } from "@stripe/react-stripe-js"; -import { loadStripe } from "@stripe/stripe-js"; -import { ENV } from "@app/env"; -import { StripeFormElements, type StripeFormElementsProps } from "./StripeFormElements"; +import { loadStripe, type StripeElementsOptionsMode } from "@stripe/stripe-js"; +import { useTheme, rgbToHex } from "@mui/material/styles"; +import { ENV } from "@/app/env"; +import { StripeFormContent, type StripeFormContentProps } from "./StripeFormContent"; +import type { Simplify, Except } from "type-fest"; + +if (!ENV.STRIPE_PUBLISHABLE_KEY) { + throw new Error("Unable to load Stripe."); +} const stripePromise = loadStripe(ENV.STRIPE_PUBLISHABLE_KEY); /** - * A form wrapped in the Stripe Elements provider. + * A form wrapped in the Stripe {@link Elements} provider. + * + * Relevant Stripe Docs: + * + * - [Stripe Elements](https://stripe.com/docs/stripe-js/react#elements-provider) + * - [Stripe Appearance API](https://stripe.com/docs/elements/appearance-api?platform=web) + * - [Stripe Appearance API: Variables](https://stripe.com/docs/elements/appearance-api?platform=web#variables) + */ +export const StripeForm = ({ stripeElementsOptions = {}, ...props }: StripeFormProps) => { + const { palette } = useTheme(); + + const { mode, secondary, text, success, warning, error } = palette; + + const elementsOptions: StripeElementsOptionsMode = { + // CALLER-PROVIDED OPTIONS: + ...stripeElementsOptions, + paymentMethodCreation: "manual", + // https://stripe.com/docs/elements/appearance-api?platform=web + appearance: { + theme: mode === "dark" ? "night" : "stripe", + labels: "floating", + // https://stripe.com/docs/elements/appearance-api?platform=web#variables + variables: { + // font + fontFamily: "Roboto, sans-serif", + fontSizeBase: "16px", + fontSmooth: "always", // enables anti-aliasing + // colors + colorPrimary: secondary.main, // the PaymentInput doesn't look good with orange + colorText: text.primary, + colorTextPlaceholder: text.disabled, + colorSuccess: success.main, + colorSuccessText: success.main, + colorWarning: warning.main, + colorWarningText: warning.main, + colorDanger: rgbToHex(error.main), // <-- Stripe logs warning if provided rgba here + colorDangerText: error.main, + colorIconCardError: error.main, + colorIconCardCvcError: error.main, + }, + }, + }; + + return ( + + + + ); +}; + +/** + * Options for the {@link Elements|Stripe Elements context provider} (uses "mode"). */ -export const StripeForm = (props: StripeFormElementsProps) => ( - - - -); +export type StripeFormElementsOptions = Simplify; -export type StripeFormProps = StripeFormElementsProps; +export type StripeFormProps = { + stripeElementsOptions?: Except; +} & StripeFormContentProps;