Skip to content

Commit 83e779d

Browse files
committed
Better settings layout
1 parent 2bc0b77 commit 83e779d

4 files changed

Lines changed: 43 additions & 37 deletions

File tree

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { type MetaFunction } from "@remix-run/react";
2+
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
3+
import { typedjson, useTypedLoaderData } from "remix-typedjson";
24
import {
35
MainHorizontallyCenteredContainer,
46
PageBody,
57
PageContainer,
68
} from "~/components/layout/AppLayout";
79
import { Header2 } from "~/components/primitives/Headers";
810
import { NavBar, PageTitle } from "~/components/primitives/PageHeader";
9-
import { MfaSetup } from "../resources.account.mfa.setup/route";
10-
import { SessionDurationSetting } from "../resources.account.session-duration/SessionDurationSetting";
11-
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
12-
import { requireUser } from "~/services/session.server";
13-
import { typedjson, useTypedLoaderData } from "remix-typedjson";
1411
import { prisma } from "~/db.server";
12+
import { requireUser } from "~/services/session.server";
1513
import {
14+
DEFAULT_SESSION_DURATION_SECONDS,
1615
getAllowedSessionOptions,
1716
getOrganizationSessionCap,
18-
DEFAULT_SESSION_DURATION_SECONDS,
1917
} from "~/services/sessionDuration.server";
18+
import { MfaSetup } from "../resources.account.mfa.setup/route";
19+
import { SessionDurationSetting } from "../resources.account.session-duration/SessionDurationSetting";
2020

2121
export const meta: MetaFunction = () => {
2222
return [
@@ -59,12 +59,14 @@ export default function Page() {
5959
</NavBar>
6060

6161
<PageBody>
62-
<MainHorizontallyCenteredContainer className="grid place-items-center overflow-visible">
63-
<div className="mb-3 w-full border-b border-grid-dimmed pb-3">
62+
<MainHorizontallyCenteredContainer className="max-w-[600px] overflow-visible">
63+
<div className="w-full border-b border-grid-dimmed pb-3">
6464
<Header2>Security</Header2>
6565
</div>
66-
<MfaSetup isEnabled={!!user.mfaEnabledAt} />
67-
<div className="mt-6 w-full border-t border-grid-dimmed pt-6">
66+
<div className="w-full border-b border-grid-dimmed py-4">
67+
<MfaSetup isEnabled={!!user.mfaEnabledAt} />
68+
</div>
69+
<div className="w-full border-b border-grid-dimmed py-4">
6870
<SessionDurationSetting
6971
currentValue={sessionDuration}
7072
options={sessionDurationOptions}

apps/webapp/app/routes/resources.account.mfa.setup/MfaToggle.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@ interface MfaToggleProps {
1212
export function MfaToggle({ isEnabled, onToggle }: MfaToggleProps) {
1313
return (
1414
<Form method="post" className="w-full">
15-
<InputGroup className="mb-4">
16-
<Label>Multi-factor authentication</Label>
17-
<Paragraph variant="small">
18-
Enable an extra layer of security by requiring a one-time code from your authenticator
19-
app (TOTP) each time you log in.
20-
</Paragraph>
21-
</InputGroup>
22-
<div className="flex items-center justify-between">
23-
<Switch
24-
id="mfa"
25-
variant="medium"
26-
label={isEnabled ? "Enabled" : "Enable"}
27-
labelPosition="right"
28-
className="-ml-2 w-fit pr-3"
29-
checked={isEnabled}
30-
onCheckedChange={onToggle}
31-
/>
15+
<div className="flex w-full items-center justify-between gap-4">
16+
<InputGroup className="flex-1">
17+
<Label>Multi-factor authentication</Label>
18+
<Paragraph variant="small">
19+
Require a one-time code from your authenticator app (TOTP).
20+
</Paragraph>
21+
</InputGroup>
22+
<div className="flex flex-none items-center">
23+
<Switch
24+
id="mfa"
25+
variant="medium"
26+
labelPosition="right"
27+
className="w-fit pr-3"
28+
checked={isEnabled}
29+
onCheckedChange={onToggle}
30+
/>
31+
</div>
3232
</div>
3333
</Form>
3434
);
35-
}
35+
}

apps/webapp/app/routes/resources.account.mfa.setup/route.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import { ActionFunctionArgs } from "@remix-run/server-runtime";
1+
import { type ActionFunctionArgs } from "@remix-run/server-runtime";
22
import { typedjson } from "remix-typedjson";
33
import { z } from "zod";
4-
import { redirectWithSuccessMessage, redirectWithErrorMessage, typedJsonWithSuccessMessage } from "~/models/message.server";
4+
import {
5+
redirectWithSuccessMessage,
6+
redirectWithErrorMessage,
7+
typedJsonWithSuccessMessage,
8+
} from "~/models/message.server";
59
import { MultiFactorAuthenticationService } from "~/services/mfa/multiFactorAuthentication.server";
610
import { requireUserId } from "~/services/session.server";
711
import { ServiceValidationError } from "~/v3/services/baseService.server";
@@ -132,14 +136,15 @@ export async function action({ request }: ActionFunctionArgs) {
132136
if (error instanceof ServiceValidationError) {
133137
return redirectWithErrorMessage("/account/security", request, error.message);
134138
}
135-
139+
136140
// Re-throw unexpected errors
137141
throw error;
138142
}
139143
}
140144

141145
export function MfaSetup({ isEnabled }: { isEnabled: boolean }) {
142-
const { state, actions, isQrDialogOpen, isRecoveryDialogOpen, isDisableDialogOpen } = useMfaSetup(isEnabled);
146+
const { state, actions, isQrDialogOpen, isRecoveryDialogOpen, isDisableDialogOpen } =
147+
useMfaSetup(isEnabled);
143148

144149
const handleToggle = (enabled: boolean) => {
145150
if (enabled && !state.isEnabled) {
@@ -151,10 +156,7 @@ export function MfaSetup({ isEnabled }: { isEnabled: boolean }) {
151156

152157
return (
153158
<>
154-
<MfaToggle
155-
isEnabled={state.isEnabled}
156-
onToggle={handleToggle}
157-
/>
159+
<MfaToggle isEnabled={state.isEnabled} onToggle={handleToggle} />
158160

159161
<MfaSetupDialog
160162
isOpen={isQrDialogOpen}

apps/webapp/test/sessionDuration.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { containerTest } from "@internal/testcontainers";
22
import { createCookieSessionStorage, type Session } from "@remix-run/node";
3-
import { describe, expect, it } from "vitest";
3+
import { describe, expect, it, vi } from "vitest";
4+
5+
vi.setConfig({ testTimeout: 60_000 });
46
import {
57
DEFAULT_SESSION_DURATION_SECONDS,
68
ensureSessionIssuedAt,

0 commit comments

Comments
 (0)