From 27851f20c85094e16dac70c665172d40b9104f3f Mon Sep 17 00:00:00 2001 From: Developing-Gamer Date: Tue, 2 Jun 2026 10:57:31 -0700 Subject: [PATCH] Add PurchaseQuantitySelector for stackable product purchases. Extract quantity controls and total amount display into a dedicated component with design-system inputs. Co-authored-by: Cursor --- .../payments/purchase-quantity-selector.tsx | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 apps/dashboard/src/components/payments/purchase-quantity-selector.tsx diff --git a/apps/dashboard/src/components/payments/purchase-quantity-selector.tsx b/apps/dashboard/src/components/payments/purchase-quantity-selector.tsx new file mode 100644 index 000000000..10325ceab --- /dev/null +++ b/apps/dashboard/src/components/payments/purchase-quantity-selector.tsx @@ -0,0 +1,99 @@ +"use client"; + +import { DesignInput } from "@/components/design-components/input"; +import { DesignButton } from "@/components/design-components/button"; +import { Typography } from "@/components/ui"; +import { MinusIcon, PlusIcon } from "@phosphor-icons/react"; +import { shortenedInterval } from "./purchase-utils"; + +type PriceData = { + USD?: string, + interval?: [number, string], +}; + +type Props = { + quantityInput: string, + quantityNumber: number, + onQuantityChange: (value: string) => void, + isTooLarge: boolean, + selectedPriceId: string, + priceData: PriceData, +}; + +export function PurchaseQuantitySelector({ + quantityInput, + quantityNumber, + onQuantityChange, + isTooLarge, + selectedPriceId, + priceData, +}: Props) { + return ( +
+
+
+ + Quantity + +
+ onQuantityChange(String(Math.max(1, quantityNumber - 1)))} + > + + + { + const digitsOnly = event.target.value.replace(/[^0-9]/g, ""); + onQuantityChange(digitsOnly); + }} + /> + onQuantityChange(String(quantityNumber + 1))} + > + + +
+
+ {(quantityNumber < 1 || isTooLarge) && ( + + {quantityNumber < 1 + ? "Please enter a quantity of at least 1." + : "Amount exceeds the maximum limit of $999,999. Please reduce the quantity."} + + )} +
+ +
+
+ + Total Amount + +
+ + ${selectedPriceId ? (Number(priceData.USD) * Math.max(0, quantityNumber)).toFixed(2) : "0.00"} + + {selectedPriceId && priceData.interval && ( + + per {shortenedInterval(priceData.interval)} + + )} +
+
+
+
+ ); +}