Skip to content

Commit 52679af

Browse files
committed
Budget alert form working
1 parent 98cd56d commit 52679af

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

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

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { parse } from "@conform-to/zod";
33
import { BellAlertIcon, CurrencyDollarIcon, EnvelopeIcon } from "@heroicons/react/20/solid";
44
import { Form, useActionData, type MetaFunction } from "@remix-run/react";
55
import { type ActionFunction, json, type LoaderFunctionArgs } from "@remix-run/server-runtime";
6-
import { Fragment, useRef, useState } from "react";
6+
import { Fragment, useEffect, useRef, useState } from "react";
77
import { redirect, typedjson, useTypedLoaderData } from "remix-typedjson";
88
import { z } from "zod";
99
import { AdminDebugTooltip } from "~/components/admin/debugTooltip";
@@ -30,6 +30,7 @@ import { useOrganization } from "~/hooks/useOrganizations";
3030
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
3131
import { getBillingAlerts, setBillingAlert } from "~/services/platform.v3.server";
3232
import { requireUserId } from "~/services/session.server";
33+
import { formatCurrency, formatNumber } from "~/utils/numberFormatter";
3334
import {
3435
OrganizationParamsSchema,
3536
organizationPath,
@@ -146,7 +147,6 @@ export const action: ActionFunction = async ({ request, params }) => {
146147
export default function Page() {
147148
const { alerts } = useTypedLoaderData<typeof loader>();
148149
const [dollarAmount, setDollarAmount] = useState(alerts.amount.toFixed(2));
149-
const organization = useOrganization();
150150

151151
const lastSubmission = useActionData();
152152

@@ -162,11 +162,17 @@ export default function Page() {
162162
},
163163
});
164164

165-
const fieldValues = useRef<string[]>([""]);
165+
const fieldValues = useRef<string[]>(alerts.emails);
166166
const emailFields = useFieldList(form.ref, { ...emails, defaultValue: alerts.emails });
167167

168168
const checkboxLevels = [0.75, 0.9, 1.0];
169169

170+
useEffect(() => {
171+
if (alerts.emails.length > 0) {
172+
requestIntent(form.ref.current ?? undefined, list.append(emails.name));
173+
}
174+
}, []);
175+
170176
return (
171177
<PageContainer>
172178
<NavBar>
@@ -180,11 +186,11 @@ export default function Page() {
180186
<div>
181187
<Header2 spacing>Billing alerts</Header2>
182188
<Paragraph spacing variant="small">
183-
Receive emails when your compute spend crosses the thresholds set below.
189+
Receive an email when your compute spend crosses different thresholds.
184190
</Paragraph>
185191
<Form method="post" {...form.props}>
186192
<Fieldset>
187-
<InputGroup>
193+
<InputGroup fullWidth>
188194
<Label htmlFor={amount.id}>Amount</Label>
189195
<Input
190196
{...conform.input(amount, { type: "number" })}
@@ -202,32 +208,40 @@ export default function Page() {
202208
placeholder="Enter an amount"
203209
icon={<span className="-mt-0.5 block pl-0.5 text-sm text-text-dimmed">$</span>}
204210
className="pl-px"
211+
fullWidth
205212
/>
206213
<FormError id={amount.errorId}>{amount.error}</FormError>
207214
</InputGroup>
208-
<InputGroup>
215+
<InputGroup fullWidth>
209216
<Label htmlFor={alertLevels.id}>Alert me when I reach</Label>
210217
{checkboxLevels.map((level) => (
211218
<CheckboxWithLabel
212219
name={alertLevels.name}
213220
id={`level_${level}`}
214221
value={level.toString()}
215222
variant="simple/small"
216-
label={`${level * 100}% ($${(Number(dollarAmount) * level).toFixed(2)})`}
217-
defaultChecked
223+
label={
224+
<span>
225+
{level * 100}%{" "}
226+
<span className="text-text-dimmed">
227+
({formatCurrency(Number(dollarAmount) * level, false)})
228+
</span>
229+
</span>
230+
}
231+
defaultChecked={alerts.alertLevels.includes(level)}
218232
className="pr-0"
233+
readOnly={level === 1.0}
219234
/>
220235
))}
221236
<FormError id={alertLevels.errorId}>{alertLevels.error}</FormError>
222237
</InputGroup>
223-
<InputGroup>
238+
<InputGroup fullWidth>
224239
<Label htmlFor={emails.id}>Email addresses</Label>
225240
{emailFields.map((email, index) => (
226241
<Fragment key={email.key}>
227242
<Input
228243
{...conform.input(email, { type: "email" })}
229244
placeholder={index === 0 ? "Enter an email address" : "Add another email"}
230-
icon={EnvelopeIcon}
231245
autoFocus={index === 0}
232246
onChange={(e) => {
233247
fieldValues.current[index] = e.target.value;
@@ -238,6 +252,7 @@ export default function Page() {
238252
requestIntent(form.ref.current ?? undefined, list.append(emails.name));
239253
}
240254
}}
255+
fullWidth
241256
/>
242257
<FormError id={email.errorId}>{email.error}</FormError>
243258
</Fragment>

apps/webapp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,4 @@
278278
"engines": {
279279
"node": ">=16.0.0"
280280
}
281-
}
281+
}

0 commit comments

Comments
 (0)