Skip to content

Commit bae3631

Browse files
committed
fix(webapp): purchase extra schedules in bundles of 1,000
1 parent 4ed272b commit bae3631

1 file changed

Lines changed: 32 additions & 18 deletions

File tree

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.schedules

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.schedules/route.tsx

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { conform, useForm } from "@conform-to/react";
1+
import { useForm } from "@conform-to/react";
22
import { parse } from "@conform-to/zod";
33
import { ArrowUpCircleIcon, EnvelopeIcon, PlusIcon } from "@heroicons/react/20/solid";
44
import { BookOpenIcon } from "@heroicons/react/24/solid";
@@ -126,11 +126,19 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
126126
const PurchaseSchema = z.discriminatedUnion("action", [
127127
z.object({
128128
action: z.literal("purchase"),
129-
amount: z.coerce.number().int("Must be a whole number").min(0, "Amount must be 0 or more"),
129+
amount: z.coerce
130+
.number()
131+
.int("Must be a whole number")
132+
.min(0, "Amount must be 0 or more")
133+
.refine((n) => n % 1000 === 0, "Schedules are sold in bundles of 1,000"),
130134
}),
131135
z.object({
132136
action: z.literal("quota-increase"),
133-
amount: z.coerce.number().int("Must be a whole number").min(1, "Amount must be greater than 0"),
137+
amount: z.coerce
138+
.number()
139+
.int("Must be a whole number")
140+
.min(1, "Amount must be greater than 0")
141+
.refine((n) => n % 1000 === 0, "Schedules are sold in bundles of 1,000"),
134142
}),
135143
]);
136144

@@ -623,10 +631,12 @@ function PurchaseSchedulesModal({
623631
shouldRevalidate: "onSubmit",
624632
});
625633

626-
const [amountValue, setAmountValue] = useState(extraSchedules);
634+
const stepSize = schedulePricing.stepSize;
635+
const [bundles, setBundles] = useState(Math.round(extraSchedules / stepSize));
627636
useEffect(() => {
628-
setAmountValue(extraSchedules);
629-
}, [extraSchedules]);
637+
setBundles(Math.round(extraSchedules / stepSize));
638+
}, [extraSchedules, stepSize]);
639+
const amountValue = bundles * stepSize;
630640
const isLoading = fetcher.state !== "idle";
631641

632642
const [open, setOpen] = useState(false);
@@ -653,9 +663,9 @@ function PurchaseSchedulesModal({
653663
const changeClassName =
654664
state === "decrease" ? "text-error" : state === "increase" ? "text-success" : undefined;
655665

656-
const pricePerSchedule = schedulePricing.centsPerStep / schedulePricing.stepSize / 100;
666+
const pricePerSchedule = schedulePricing.centsPerStep / stepSize / 100;
657667
const pricePerStep = schedulePricing.centsPerStep / 100;
658-
const stepUnit = formatNumber(schedulePricing.stepSize);
668+
const stepUnit = formatNumber(stepSize);
659669
const title = extraSchedules === 0 ? "Purchase extra schedules…" : "Add/remove extra schedules…";
660670

661671
return (
@@ -673,25 +683,29 @@ function PurchaseSchedulesModal({
673683
<div className="flex flex-col gap-4 pt-2">
674684
<div className="flex flex-col gap-1">
675685
<Paragraph variant="small/bright">
676-
Purchase extra schedules at {formatCurrency(pricePerStep, false)}/month per{" "}
677-
{stepUnit} schedules. Reducing the number of schedules will take effect at the start
678-
of the next billing cycle (1st of the month).
686+
Schedules are purchased in bundles of {stepUnit}, at{" "}
687+
{formatCurrency(pricePerStep, false)}/month per bundle. Reducing will take effect at
688+
the start of the next billing cycle (1st of the month).
679689
</Paragraph>
680690
</div>
681691
<Fieldset>
682692
<InputGroup fullWidth>
683-
<Label htmlFor="amount" className="text-text-dimmed">
684-
Total extra schedules
693+
<Label htmlFor="schedule-bundles" className="text-text-dimmed">
694+
Bundles of {stepUnit} schedules
685695
</Label>
686696
<InputNumberStepper
687-
{...conform.input(amount, { type: "number" })}
688-
step={schedulePricing.stepSize}
697+
id="schedule-bundles"
698+
step={1}
689699
min={0}
690-
max={undefined}
691-
value={amountValue}
692-
onChange={(e) => setAmountValue(Number(e.target.value))}
700+
value={bundles}
701+
onChange={(e) => setBundles(Number(e.target.value))}
693702
disabled={isLoading}
694703
/>
704+
<input type="hidden" name="amount" value={amountValue} />
705+
<Paragraph variant="small" className="text-text-dimmed">
706+
{formatNumber(bundles)} {bundles === 1 ? "bundle" : "bundles"} ={" "}
707+
{formatNumber(amountValue)} schedules
708+
</Paragraph>
695709
<FormError id={amount.errorId}>
696710
{amount.error ?? amount.initialError?.[""]?.[0]}
697711
</FormError>

0 commit comments

Comments
 (0)