diff --git a/app/search/page.tsx b/app/search/page.tsx index e23d01e..bc0f2a3 100644 --- a/app/search/page.tsx +++ b/app/search/page.tsx @@ -7,7 +7,6 @@ import { ExternalLinkIcon, Gamepad2Icon, MessageSquareIcon, - MonitorIcon, SettingsIcon, TrendingUpIcon, DatabaseIcon, @@ -50,13 +49,11 @@ function SearchContent() { const [results, setResults] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) + const isValidQuery = query && query.length >= 2 + // Handle direct navigation / browser back-forward useEffect(() => { - if (!query || query.length < 2) { - setResults([]) - setError(null) - return - } + if (!isValidQuery) return let cancelled = false @@ -85,7 +82,7 @@ function SearchContent() { return () => { cancelled = true } - }, [query]) + }, [isValidQuery, query]) function handleClick(result: UnifiedResult) { const path = result.appId @@ -114,7 +111,7 @@ function SearchContent() { : "Enter a game name or AppID to find benchmarks, settings, and reviews."} - {!query && ( + {!isValidQuery && ( )} - {query && loading && ( + {isValidQuery && loading && (
)} - {query && !loading && error && ( + {isValidQuery && !loading && error && ( )} - {query && !loading && !error && results.length === 0 && ( + {isValidQuery && !loading && !error && results.length === 0 && ( )} - {query && !loading && !error && results.length > 0 && ( + {isValidQuery && !loading && !error && results.length > 0 && (

- Enter your email and we'll send you a verification code to + Enter your email and we'll send you a verification code to reset your password.

diff --git a/components/auth/login-form.tsx b/components/auth/login-form.tsx index c9d06cb..d69ff3e 100644 --- a/components/auth/login-form.tsx +++ b/components/auth/login-form.tsx @@ -1,12 +1,11 @@ "use client" -import { useState, useEffect, useCallback } from "react" +import { useState, useEffect } from "react" import { Loader2 } from "lucide-react" import { authClient } from "@/lib/auth-client" import { loginEmailSchema, loginSchema, - type LoginInput, } from "@/lib/auth/validation" import SocialButtons from "./social-buttons" import Link from "next/link" @@ -221,7 +220,7 @@ export default function LoginForm() { )}

- Don't have an account?{" "} + Don't have an account?{" "} ( - value.split("").concat(Array(length).fill("")).slice(0, length), + const digits = useMemo( + () => + value + .split("") + .concat(Array(length).fill("")) + .slice(0, length), + [value, length], ) const refs = useRef<(HTMLInputElement | null)[]>([]) - // Sync with external value - useEffect(() => { - const newDigits = value - .split("") - .concat(Array(length).fill("")) - .slice(0, length) - setDigits(newDigits) - }, [value, length]) - const updateDigits = useCallback( (newDigits: string[]) => { - setDigits(newDigits) onChange(newDigits.join("")) }, [onChange], diff --git a/components/auth/otp-verification-step.tsx b/components/auth/otp-verification-step.tsx index cc6fa6c..8b8ced8 100644 --- a/components/auth/otp-verification-step.tsx +++ b/components/auth/otp-verification-step.tsx @@ -20,14 +20,11 @@ export default function OtpVerificationStep({ const [error, setError] = useState("") const [isLoading, setIsLoading] = useState(false) const [resendTimer, setResendTimer] = useState(300) // 5 minutes - const [canResend, setCanResend] = useState(false) + const canResend = resendTimer <= 0 // Countdown timer useEffect(() => { - if (resendTimer <= 0) { - setCanResend(true) - return - } + if (resendTimer <= 0) return const interval = setInterval(() => { setResendTimer((prev) => prev - 1) }, 1000) @@ -40,37 +37,33 @@ export default function OtpVerificationStep({ return `${mins}:${secs.toString().padStart(2, "0")}` } - const handleVerify = useCallback(async () => { - if (otp.length !== 6) return + const handleVerify = useCallback( + async (otpValue: string) => { + if (otpValue.length !== 6) return - setIsLoading(true) - setError("") + setIsLoading(true) + setError("") - const { error } = await authClient.emailOtp.verifyEmail({ - email, - otp, - }) + const { error } = await authClient.emailOtp.verifyEmail({ + email, + otp: otpValue, + }) - setIsLoading(false) + setIsLoading(false) - if (error) { - setError( - error.code === "TOO_MANY_ATTEMPTS" - ? "Too many attempts. Please request a new code." - : "Invalid code. Please try again.", - ) - return - } + if (error) { + setError( + error.code === "TOO_MANY_ATTEMPTS" + ? "Too many attempts. Please request a new code." + : "Invalid code. Please try again.", + ) + return + } - onSuccess() - }, [otp, email, onSuccess]) - - // Auto-submit when all digits entered - useEffect(() => { - if (otp.length === 6) { - handleVerify() - } - }, [otp, handleVerify]) + onSuccess() + }, + [email, onSuccess], + ) const handleResend = async () => { setError("") @@ -79,7 +72,6 @@ export default function OtpVerificationStep({ type: "email-verification", }) setResendTimer(300) - setCanResend(false) } return ( @@ -101,7 +93,12 @@ export default function OtpVerificationStep({ { + setOtp(value) + if (value.length === 6) { + handleVerify(value) + } + }} disabled={isLoading} error={error} /> @@ -126,7 +123,7 @@ export default function OtpVerificationStep({