Skip to content

Commit 347fabe

Browse files
committed
feat(webapp): redesign the account profile page with a row-based layout
Adopt the Security page's row-and-divider pattern on /account: each setting is a row with the title on the left and its control on the right. Profile picture, Full name, Email address, and a "Receive onboarding emails" toggle switch sit on equal-height rows, and the Update button is now a primary button.
1 parent 6d701ab commit 347fabe

2 files changed

Lines changed: 75 additions & 53 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
area: webapp
3+
type: improvement
4+
---
5+
6+
Redesign the account Profile page (`/account`) to use the same row-and-divider
7+
layout as the Security page: each setting is a full-width row with the title on
8+
the left and its control on the right, separated by divider lines. Profile
9+
picture, Full name, Email address, and a "Receive onboarding emails" toggle
10+
(replacing the old checkbox) each sit on equal-height rows, and the Update
11+
button is now a primary button.

apps/webapp/app/routes/account._index/route.tsx

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,19 @@ import { conformZodMessage, parseWithZod } from "@conform-to/zod";
33
import { Form, type MetaFunction, useActionData } from "@remix-run/react";
44
import { type ActionFunction, json } from "@remix-run/server-runtime";
55
import { z } from "zod";
6-
import { AvatarCircleIcon } from "~/assets/icons/AvatarCircleIcon";
7-
import { EnvelopeIcon } from "~/assets/icons/EnvelopeIcon";
86
import { UserProfilePhoto } from "~/components/UserProfilePhoto";
97
import {
108
MainHorizontallyCenteredContainer,
119
PageBody,
1210
PageContainer,
1311
} from "~/components/layout/AppLayout";
1412
import { Button } from "~/components/primitives/Buttons";
15-
import { CheckboxWithLabel } from "~/components/primitives/Checkbox";
16-
import { Fieldset } from "~/components/primitives/Fieldset";
17-
import { FormButtons } from "~/components/primitives/FormButtons";
1813
import { FormError } from "~/components/primitives/FormError";
1914
import { Header2 } from "~/components/primitives/Headers";
20-
import { Hint } from "~/components/primitives/Hint";
2115
import { Input } from "~/components/primitives/Input";
2216
import { InputGroup } from "~/components/primitives/InputGroup";
2317
import { Label } from "~/components/primitives/Label";
18+
import { Switch } from "~/components/primitives/Switch";
2419
import { NavBar, PageTitle } from "~/components/primitives/PageHeader";
2520
import { prisma } from "~/db.server";
2621
import { useUser } from "~/hooks/useUser";
@@ -144,56 +139,72 @@ export default function Page() {
144139
</NavBar>
145140

146141
<PageBody>
147-
<MainHorizontallyCenteredContainer className="grid place-items-center">
148-
<div className="mb-3 w-full border-b border-grid-dimmed pb-3">
142+
<MainHorizontallyCenteredContainer className="max-w-[37.5rem] overflow-visible">
143+
<div className="w-full border-b border-grid-dimmed pb-3">
149144
<Header2>Profile</Header2>
150145
</div>
151146
<Form method="post" {...getFormProps(form)} className="w-full">
152-
<InputGroup className="mb-4">
153-
<Label htmlFor={name.id}>Profile picture</Label>
154-
<UserProfilePhoto className="size-24" />
155-
</InputGroup>
156-
<Fieldset>
157-
<InputGroup fullWidth>
158-
<Label htmlFor={name.id}>Full name</Label>
159-
<Input
160-
{...getInputProps(name, { type: "text" })}
161-
placeholder="Your full name"
162-
defaultValue={user?.name ?? ""}
163-
icon={AvatarCircleIcon}
164-
/>
165-
<Hint>Your teammates will see this</Hint>
166-
<FormError id={name.errorId}>{name.errors}</FormError>
167-
</InputGroup>
168-
<InputGroup fullWidth>
169-
<Label htmlFor={email.id}>Email address</Label>
170-
<Input
171-
{...getInputProps(email, { type: "text" })}
172-
placeholder="Your email"
173-
defaultValue={user?.email ?? ""}
174-
icon={EnvelopeIcon}
175-
/>
176-
<FormError id={email.errorId}>{email.errors}</FormError>
177-
</InputGroup>
178-
<InputGroup>
179-
<Label>Notifications</Label>
180-
<CheckboxWithLabel
181-
{...getInputProps(marketingEmails, { type: "checkbox" })}
182-
label="Receive onboarding emails"
183-
variant="simple/small"
184-
defaultChecked={user.marketingEmails}
185-
/>
186-
<FormError id={marketingEmails.errorId}>{marketingEmails.errors}</FormError>
187-
</InputGroup>
188-
189-
<FormButtons
190-
confirmButton={
191-
<Button type="submit" variant={"secondary/small"}>
192-
Update
193-
</Button>
194-
}
195-
/>
196-
</Fieldset>
147+
<div className="flex min-h-16 w-full items-center border-b border-grid-dimmed">
148+
<div className="flex w-full items-center justify-between gap-4">
149+
<InputGroup className="flex-1">
150+
<Label>Profile picture</Label>
151+
</InputGroup>
152+
<div className="flex flex-none items-center">
153+
<UserProfilePhoto className="size-8" />
154+
</div>
155+
</div>
156+
</div>
157+
<div className="flex min-h-16 w-full items-center border-b border-grid-dimmed">
158+
<div className="flex w-full items-center justify-between gap-4">
159+
<InputGroup className="flex-1">
160+
<Label htmlFor={name.id}>Full name</Label>
161+
</InputGroup>
162+
<div className="flex w-56 flex-none flex-col gap-1">
163+
<Input
164+
{...getInputProps(name, { type: "text" })}
165+
placeholder="Your full name"
166+
defaultValue={user?.name ?? ""}
167+
/>
168+
<FormError id={name.errorId}>{name.errors}</FormError>
169+
</div>
170+
</div>
171+
</div>
172+
<div className="flex min-h-16 w-full items-center border-b border-grid-dimmed">
173+
<div className="flex w-full items-center justify-between gap-4">
174+
<InputGroup className="flex-1">
175+
<Label htmlFor={email.id}>Email address</Label>
176+
</InputGroup>
177+
<div className="flex w-56 flex-none flex-col gap-1">
178+
<Input
179+
{...getInputProps(email, { type: "text" })}
180+
placeholder="Your email"
181+
defaultValue={user?.email ?? ""}
182+
/>
183+
<FormError id={email.errorId}>{email.errors}</FormError>
184+
</div>
185+
</div>
186+
</div>
187+
<div className="flex min-h-16 w-full items-center border-b border-grid-dimmed">
188+
<div className="flex w-full items-center justify-between gap-4">
189+
<InputGroup className="flex-1">
190+
<Label htmlFor={marketingEmails.id}>Receive onboarding emails</Label>
191+
</InputGroup>
192+
<div className="flex flex-none items-center">
193+
<Switch
194+
id={marketingEmails.id}
195+
name={marketingEmails.name}
196+
variant="medium"
197+
defaultChecked={user.marketingEmails}
198+
className="w-fit pr-3"
199+
/>
200+
</div>
201+
</div>
202+
</div>
203+
<div className="flex w-full justify-end pt-4">
204+
<Button type="submit" variant="primary/small">
205+
Update
206+
</Button>
207+
</div>
197208
</Form>
198209
</MainHorizontallyCenteredContainer>
199210
</PageBody>

0 commit comments

Comments
 (0)