Skip to content

Commit 07d1019

Browse files
committed
Formatting
1 parent 39bd4bd commit 07d1019

File tree

10 files changed

+85
-107
lines changed

10 files changed

+85
-107
lines changed

app/Providers/FortifyServiceProvider.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ public function register(): void
2424
*/
2525
public function boot(): void
2626
{
27-
Fortify::twoFactorChallengeView(fn() => Inertia::render('auth/two-factor-challenge'));
27+
Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/two-factor-challenge'));
2828

29-
Fortify::confirmPasswordView(fn() => Inertia::render('auth/confirm-password'));
29+
Fortify::confirmPasswordView(fn () => Inertia::render('auth/confirm-password'));
3030

3131
RateLimiter::for('two-factor', function (Request $request) {
3232
return Limit::perMinute(5)->by($request->session()->get('login.id'));

resources/js/app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { initializeTheme } from './hooks/use-appearance';
88
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
99

1010
createInertiaApp({
11-
title: (title) => title ? `${title} - ${appName}` : appName,
11+
title: (title) => (title ? `${title} - ${appName}` : appName),
1212
resolve: (name) => resolvePageComponent(`./pages/${name}.tsx`, import.meta.glob('./pages/**/*.tsx')),
1313
setup({ el, App, props }) {
1414
const root = createRoot(el);

resources/js/components/two-factor-setup-modal.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ export default function TwoFactorSetupModal({
3131
fetchSetupData,
3232
}: TwoFactorSetupModalProps) {
3333
const [copiedText, copy] = useClipboard();
34+
const OTP_MAX_LENGTH = 6;
3435

3536
const [showVerificationStep, setShowVerificationStep] = useState<boolean>(false);
3637
const [code, setCode] = useState<string>('');
37-
const codeValue = useMemo(() => code, [code]);
3838

3939
const pinInputContainerRef = useRef<HTMLDivElement>(null);
4040

@@ -175,21 +175,20 @@ export default function TwoFactorSetupModal({
175175
</div>
176176
</>
177177
) : (
178-
<Form {...confirm.form()} onFinish={() => setCode('')} onSuccess={() => onClose()} resetOnError>
178+
<Form {...confirm.form()} onSuccess={() => onClose()} resetOnError transform={(data) => ({ ...data, code })}>
179179
{({ processing, errors }: { processing: boolean; errors?: { confirmTwoFactorAuthentication?: { code?: string } } }) => (
180180
<>
181-
<input type="hidden" name="code" value={codeValue} />
182181
<div ref={pinInputContainerRef} className="relative w-full space-y-3">
183182
<div className="flex w-full flex-col items-center justify-center space-y-3 py-2">
184183
<InputOTP
185-
maxLength={6}
186-
value={codeValue}
187-
onChange={setCode}
184+
id="otp"
185+
maxLength={OTP_MAX_LENGTH}
186+
onChange={(value) => setCode(value)}
188187
disabled={processing}
189188
pattern={REGEXP_ONLY_DIGITS}
190189
>
191190
<InputOTPGroup>
192-
{Array.from({ length: 6 }, (_, index) => (
191+
{Array.from({ length: OTP_MAX_LENGTH }, (_, index) => (
193192
<InputOTPSlot key={index} index={index} />
194193
))}
195194
</InputOTPGroup>
@@ -207,7 +206,7 @@ export default function TwoFactorSetupModal({
207206
>
208207
Back
209208
</Button>
210-
<Button type="submit" className="w-auto flex-1" disabled={processing || codeValue.length < 6}>
209+
<Button type="submit" className="w-auto flex-1" disabled={processing || code.length < 6}>
211210
{processing ? 'Confirming...' : 'Confirm'}
212211
</Button>
213212
</div>
Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,69 @@
11
import * as React from "react"
22
import { OTPInput, OTPInputContext } from "input-otp"
3-
import { MinusIcon } from "lucide-react"
3+
import { Minus } from "lucide-react"
44

55
import { cn } from "@/lib/utils"
66

7-
function InputOTP({
8-
className,
9-
containerClassName,
10-
...props
11-
}: React.ComponentProps<typeof OTPInput> & {
12-
containerClassName?: string
13-
}) {
14-
return (
15-
<OTPInput
16-
data-slot="input-otp"
17-
containerClassName={cn(
18-
"flex items-center gap-2 has-disabled:opacity-50",
19-
containerClassName
20-
)}
21-
className={cn("disabled:cursor-not-allowed", className)}
22-
{...props}
23-
/>
24-
)
25-
}
7+
const InputOTP = React.forwardRef<
8+
React.ElementRef<typeof OTPInput>,
9+
React.ComponentPropsWithoutRef<typeof OTPInput>
10+
>(({ className, containerClassName, ...props }, ref) => (
11+
<OTPInput
12+
ref={ref}
13+
containerClassName={cn(
14+
"flex items-center gap-2 has-[:disabled]:opacity-50",
15+
containerClassName
16+
)}
17+
className={cn("disabled:cursor-not-allowed", className)}
18+
{...props}
19+
/>
20+
))
21+
InputOTP.displayName = "InputOTP"
2622

27-
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
28-
return (
29-
<div
30-
data-slot="input-otp-group"
31-
className={cn("flex items-center", className)}
32-
{...props}
33-
/>
34-
)
35-
}
23+
const InputOTPGroup = React.forwardRef<
24+
React.ElementRef<"div">,
25+
React.ComponentPropsWithoutRef<"div">
26+
>(({ className, ...props }, ref) => (
27+
<div ref={ref} className={cn("flex items-center", className)} {...props} />
28+
))
29+
InputOTPGroup.displayName = "InputOTPGroup"
3630

37-
function InputOTPSlot({
38-
index,
39-
className,
40-
...props
41-
}: React.ComponentProps<"div"> & {
42-
index: number
43-
}) {
31+
const InputOTPSlot = React.forwardRef<
32+
React.ElementRef<"div">,
33+
React.ComponentPropsWithoutRef<"div"> & { index: number }
34+
>(({ index, className, ...props }, ref) => {
4435
const inputOTPContext = React.useContext(OTPInputContext)
45-
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
36+
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
4637

4738
return (
4839
<div
49-
data-slot="input-otp-slot"
50-
data-active={isActive}
40+
ref={ref}
5141
className={cn(
52-
"data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
42+
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
43+
isActive && "z-10 ring-1 ring-ring",
5344
className
5445
)}
5546
{...props}
5647
>
5748
{char}
5849
{hasFakeCaret && (
5950
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
60-
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
51+
<div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
6152
</div>
6253
)}
6354
</div>
6455
)
65-
}
56+
})
57+
InputOTPSlot.displayName = "InputOTPSlot"
6658

67-
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
68-
return (
69-
<div data-slot="input-otp-separator" role="separator" {...props}>
70-
<MinusIcon />
71-
</div>
72-
)
73-
}
59+
const InputOTPSeparator = React.forwardRef<
60+
React.ElementRef<"div">,
61+
React.ComponentPropsWithoutRef<"div">
62+
>(({ ...props }, ref) => (
63+
<div ref={ref} role="separator" {...props}>
64+
<Minus />
65+
</div>
66+
))
67+
InputOTPSeparator.displayName = "InputOTPSeparator"
7468

7569
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }

resources/js/hooks/use-two-factor-auth.tsx

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ export const useTwoFactorAuth = () => {
1919
const [manualSetupKey, setManualSetupKey] = useState<string | null>(null);
2020
const [recoveryCodesList, setRecoveryCodesList] = useState<string[]>([]);
2121

22-
const hasSetupData = useMemo<boolean>(
23-
() => qrCodeSvg !== null && manualSetupKey !== null,
24-
[qrCodeSvg, manualSetupKey]
25-
);
22+
const hasSetupData = useMemo<boolean>(() => qrCodeSvg !== null && manualSetupKey !== null, [qrCodeSvg, manualSetupKey]);
2623

2724
const fetchQrCode = useCallback(async (): Promise<void> => {
2825
try {
@@ -69,25 +66,18 @@ export const useTwoFactorAuth = () => {
6966
}
7067
}, [fetchQrCode, fetchSetupKey]);
7168

72-
return useMemo(() => ({
73-
qrCodeSvg,
74-
manualSetupKey,
75-
recoveryCodesList,
76-
hasSetupData,
77-
clearSetupData,
78-
fetchQrCode,
79-
fetchSetupKey,
80-
fetchSetupData,
81-
fetchRecoveryCodes,
82-
}), [
83-
qrCodeSvg,
84-
manualSetupKey,
85-
recoveryCodesList,
86-
hasSetupData,
87-
clearSetupData,
88-
fetchQrCode,
89-
fetchSetupKey,
90-
fetchSetupData,
91-
fetchRecoveryCodes,
92-
]);
69+
return useMemo(
70+
() => ({
71+
qrCodeSvg,
72+
manualSetupKey,
73+
recoveryCodesList,
74+
hasSetupData,
75+
clearSetupData,
76+
fetchQrCode,
77+
fetchSetupKey,
78+
fetchSetupData,
79+
fetchRecoveryCodes,
80+
}),
81+
[qrCodeSvg, manualSetupKey, recoveryCodesList, hasSetupData, clearSetupData, fetchQrCode, fetchSetupKey, fetchSetupData, fetchRecoveryCodes],
82+
);
9383
};

resources/js/layouts/settings/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { Separator } from '@/components/ui/separator';
44
import { cn } from '@/lib/utils';
55
import { appearance } from '@/routes';
66
import { edit as editPassword } from '@/routes/password';
7-
import { show } from '@/routes/two-factor';
87
import { edit } from '@/routes/profile';
8+
import { show } from '@/routes/two-factor';
99
import { type NavItem } from '@/types';
1010
import { Link } from '@inertiajs/react';
1111
import { type PropsWithChildren } from 'react';

resources/js/pages/auth/confirm-password.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { store } from '@/routes/password/confirm'
21
import InputError from '@/components/input-error';
32
import { Button } from '@/components/ui/button';
43
import { Input } from '@/components/ui/input';
54
import { Label } from '@/components/ui/label';
65
import AuthLayout from '@/layouts/auth-layout';
6+
import { store } from '@/routes/password/confirm';
77
import { Form, Head } from '@inertiajs/react';
88
import { LoaderCircle } from 'lucide-react';
99

resources/js/pages/auth/two-factor-challenge.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ interface AuthConfigContent {
1515
}
1616

1717
export default function TwoFactorChallenge() {
18+
const OTP_MAX_LENGTH = 6;
1819
const [showRecoveryInput, setShowRecoveryInput] = useState<boolean>(false);
19-
const [code, setCode] = useState<number[]>([]);
20-
21-
const codeValue = useMemo<string>(() => code.join(''), [code]);
20+
const [code, setCode] = useState<string>('');
2221

2322
const authConfigContent = useMemo<AuthConfigContent>(() => {
2423
if (showRecoveryInput) {
@@ -39,7 +38,7 @@ export default function TwoFactorChallenge() {
3938
const toggleRecoveryMode = (clearErrors: () => void): void => {
4039
setShowRecoveryInput(!showRecoveryInput);
4140
clearErrors();
42-
setCode([]);
41+
setCode('');
4342
};
4443

4544
return (
@@ -48,29 +47,28 @@ export default function TwoFactorChallenge() {
4847

4948
<div className="space-y-6">
5049
{!showRecoveryInput ? (
51-
<Form {...store.form()} className="space-y-4" resetOnError onError={() => setCode([])}>
50+
<Form {...store.form()} className="space-y-4" resetOnError transform={(data) => ({ ...data, code })}>
5251
{({ errors, processing, clearErrors }) => (
5352
<>
54-
<input type="hidden" name="code" value={codeValue} />
5553
<div className="flex flex-col items-center justify-center space-y-3 text-center">
5654
<div className="flex w-full items-center justify-center">
5755
<InputOTP
58-
maxLength={6}
59-
value={codeValue}
60-
onChange={(value) => setCode(value.split('').map(Number))}
56+
maxLength={OTP_MAX_LENGTH}
57+
value={code}
58+
onChange={(value) => setCode(value)}
6159
disabled={processing}
6260
pattern={REGEXP_ONLY_DIGITS}
6361
>
6462
<InputOTPGroup>
65-
{Array.from({ length: 6 }, (_, index) => (
63+
{Array.from({ length: OTP_MAX_LENGTH }, (_, index) => (
6664
<InputOTPSlot key={index} index={index} />
6765
))}
6866
</InputOTPGroup>
6967
</InputOTP>
7068
</div>
7169
<InputError message={errors.code} />
7270
</div>
73-
<Button type="submit" className="w-full" disabled={processing}>
71+
<Button type="submit" className="w-full" disabled={processing || code.length < OTP_MAX_LENGTH}>
7472
Continue
7573
</Button>
7674
<div className="text-center text-sm text-muted-foreground">

resources/js/pages/settings/two-factor.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export default function TwoFactor({ requiresConfirmation = false, twoFactorEnabl
3939
<div className="flex flex-col items-start justify-start space-y-4">
4040
<Badge variant="destructive">Disabled</Badge>
4141
<p className="text-muted-foreground">
42-
When you enable two-factor authentication, you will be prompted for a secure pin during login. This pin can
43-
be retrieved from a TOTP-supported application on your phone.
42+
When you enable two-factor authentication, you will be prompted for a secure pin during login. This pin can be
43+
retrieved from a TOTP-supported application on your phone.
4444
</p>
4545

4646
<div>
@@ -65,14 +65,11 @@ export default function TwoFactor({ requiresConfirmation = false, twoFactorEnabl
6565
<div className="flex flex-col items-start justify-start space-y-4">
6666
<Badge variant="default">Enabled</Badge>
6767
<p className="text-muted-foreground">
68-
With two-factor authentication enabled, you will be prompted for a secure, random pin during login, which you
69-
can retrieve from the TOTP-supported application on your phone.
68+
With two-factor authentication enabled, you will be prompted for a secure, random pin during login, which you can
69+
retrieve from the TOTP-supported application on your phone.
7070
</p>
7171

72-
<TwoFactorRecoveryCodes
73-
recoveryCodesList={recoveryCodesList}
74-
fetchRecoveryCodes={fetchRecoveryCodes}
75-
/>
72+
<TwoFactorRecoveryCodes recoveryCodesList={recoveryCodesList} fetchRecoveryCodes={fetchRecoveryCodes} />
7673

7774
<div className="relative inline">
7875
<Form {...disable.form()}>

routes/settings.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@
2323
return Inertia::render('settings/appearance');
2424
})->name('appearance');
2525

26-
Route::get('settings/two-factor', [TwoFactorAuthenticationController::class, 'show'])
26+
Route::get('settings/two-factor', [TwoFactorAuthenticationController::class, 'show'])
2727
->name('two-factor.show');
2828
});

0 commit comments

Comments
 (0)