Skip to content

Commit 7644bc6

Browse files
committed
Don't let free plan users change the billing alert amount
1 parent 52679af commit 7644bc6

File tree

2 files changed

+37
-24
lines changed
  • apps/webapp/app
    • components/primitives
    • routes/_app.orgs.$organizationSlug.settings.billing-alerts

2 files changed

+37
-24
lines changed

apps/webapp/app/components/primitives/Input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const containerBase =
77
"has-[:focus-visible]:outline-none has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-charcoal-650 has-[:focus-visible]:ring-offset-0 has-[:focus]:border-ring has-[:focus]:outline-none has-[:focus]:ring-1 has-[:focus]:ring-ring has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 ring-offset-background transition cursor-text";
88

99
const inputBase =
10-
"h-full w-full text-text-bright bg-transparent file:border-0 file:bg-transparent file:text-base file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed outline-none ring-0 border-none";
10+
"h-full w-full text-text-bright bg-transparent file:border-0 file:bg-transparent file:text-base file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed outline-none ring-0 border-none [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-inner-spin-button]:m-0 [&]:[-moz-appearance:textfield]";
1111

1212
const variants = {
1313
large: {

apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.billing-alerts/route.tsx

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { conform, list, requestIntent, useFieldList, useForm } from "@conform-to/react";
22
import { parse } from "@conform-to/zod";
3-
import { BellAlertIcon, CurrencyDollarIcon, EnvelopeIcon } from "@heroicons/react/20/solid";
43
import { Form, useActionData, type MetaFunction } from "@remix-run/react";
5-
import { type ActionFunction, json, type LoaderFunctionArgs } from "@remix-run/server-runtime";
4+
import { json, type ActionFunction, type LoaderFunctionArgs } from "@remix-run/server-runtime";
65
import { Fragment, useEffect, useRef, useState } from "react";
76
import { redirect, typedjson, useTypedLoaderData } from "remix-typedjson";
87
import { z } from "zod";
@@ -12,12 +11,11 @@ import {
1211
PageBody,
1312
PageContainer,
1413
} from "~/components/layout/AppLayout";
15-
import { Button, LinkButton } from "~/components/primitives/Buttons";
14+
import { Button } from "~/components/primitives/Buttons";
1615
import { CheckboxWithLabel } from "~/components/primitives/Checkbox";
1716
import { Fieldset } from "~/components/primitives/Fieldset";
1817
import { FormButtons } from "~/components/primitives/FormButtons";
1918
import { FormError } from "~/components/primitives/FormError";
20-
import { FormTitle } from "~/components/primitives/FormTitle";
2119
import { Header2 } from "~/components/primitives/Headers";
2220
import { Input } from "~/components/primitives/Input";
2321
import { InputGroup } from "~/components/primitives/InputGroup";
@@ -26,16 +24,16 @@ import { NavBar, PageAccessories, PageTitle } from "~/components/primitives/Page
2624
import { Paragraph } from "~/components/primitives/Paragraph";
2725
import { prisma } from "~/db.server";
2826
import { featuresForRequest } from "~/features.server";
29-
import { useOrganization } from "~/hooks/useOrganizations";
3027
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
3128
import { getBillingAlerts, setBillingAlert } from "~/services/platform.v3.server";
3229
import { requireUserId } from "~/services/session.server";
33-
import { formatCurrency, formatNumber } from "~/utils/numberFormatter";
30+
import { formatCurrency } from "~/utils/numberFormatter";
3431
import {
3532
OrganizationParamsSchema,
3633
organizationPath,
3734
v3BillingAlertsPath,
3835
} from "~/utils/pathBuilder";
36+
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
3937

4038
export const meta: MetaFunction = () => {
4139
return [
@@ -146,6 +144,7 @@ export const action: ActionFunction = async ({ request, params }) => {
146144

147145
export default function Page() {
148146
const { alerts } = useTypedLoaderData<typeof loader>();
147+
const plan = useCurrentPlan();
149148
const [dollarAmount, setDollarAmount] = useState(alerts.amount.toFixed(2));
150149

151150
const lastSubmission = useActionData();
@@ -173,6 +172,8 @@ export default function Page() {
173172
}
174173
}, []);
175174

175+
const isFree = !plan?.v3Subscription?.isPaying;
176+
176177
return (
177178
<PageContainer>
178179
<NavBar>
@@ -192,24 +193,36 @@ export default function Page() {
192193
<Fieldset>
193194
<InputGroup fullWidth>
194195
<Label htmlFor={amount.id}>Amount</Label>
195-
<Input
196-
{...conform.input(amount, { type: "number" })}
197-
value={dollarAmount}
198-
onChange={(e) => {
199-
const numberValue = Number(e.target.value);
200-
if (numberValue < 0) {
201-
setDollarAmount("");
202-
return;
196+
{isFree ? (
197+
<>
198+
<Paragraph variant="small" className="text-text-dimmed">
199+
${dollarAmount}
200+
</Paragraph>
201+
<input type="hidden" name={amount.name} value={dollarAmount} />
202+
</>
203+
) : (
204+
<Input
205+
{...conform.input(amount, { type: "number" })}
206+
value={dollarAmount}
207+
onChange={(e) => {
208+
const numberValue = Number(e.target.value);
209+
if (numberValue < 0) {
210+
setDollarAmount("");
211+
return;
212+
}
213+
setDollarAmount(e.target.value);
214+
}}
215+
step={0.01}
216+
min={0}
217+
placeholder="Enter an amount"
218+
icon={
219+
<span className="-mt-0.5 block pl-0.5 text-sm text-text-dimmed">$</span>
203220
}
204-
setDollarAmount(e.target.value);
205-
}}
206-
step={0.01}
207-
min={0}
208-
placeholder="Enter an amount"
209-
icon={<span className="-mt-0.5 block pl-0.5 text-sm text-text-dimmed">$</span>}
210-
className="pl-px"
211-
fullWidth
212-
/>
221+
className="pl-px"
222+
fullWidth
223+
readOnly={isFree}
224+
/>
225+
)}
213226
<FormError id={amount.errorId}>{amount.error}</FormError>
214227
</InputGroup>
215228
<InputGroup fullWidth>

0 commit comments

Comments
 (0)