11"use client" ;
22
3- import { ThemeContext } from "@components/contexts" ;
3+ import { ServerConfigContext , ThemeContext } from "@components/contexts" ;
44import {
55 Button ,
66 Caption ,
@@ -32,7 +32,8 @@ import {
3232} from "@/ui-config/strings" ;
3333import Link from "next/link" ;
3434import { TriangleAlert } from "lucide-react" ;
35- import { useRouter } from "next/navigation" ;
35+ import { useRecaptcha } from "@/hooks/use-recaptcha" ;
36+ import RecaptchaScriptLoader from "@/components/recaptcha-script-loader" ;
3637
3738export default function LoginForm ( { redirectTo } : { redirectTo ?: string } ) {
3839 const { theme } = useContext ( ThemeContext ) ;
@@ -42,26 +43,98 @@ export default function LoginForm({ redirectTo }: { redirectTo?: string }) {
4243 const [ error , setError ] = useState ( "" ) ;
4344 const [ loading , setLoading ] = useState ( false ) ;
4445 const { toast } = useToast ( ) ;
45- const router = useRouter ( ) ;
46+ const serverConfig = useContext ( ServerConfigContext ) ;
47+ const { executeRecaptcha } = useRecaptcha ( ) ;
4648
4749 const requestCode = async function ( e : FormEvent ) {
4850 e . preventDefault ( ) ;
49- const url = `/api/auth/code/generate?email=${ encodeURIComponent (
50- email ,
51- ) } `;
51+ setLoading ( true ) ;
52+ setError ( "" ) ;
53+
54+ if ( serverConfig . recaptchaSiteKey ) {
55+ if ( ! executeRecaptcha ) {
56+ toast ( {
57+ title : TOAST_TITLE_ERROR ,
58+ description :
59+ "reCAPTCHA service not available. Please try again later." ,
60+ variant : "destructive" ,
61+ } ) ;
62+ setLoading ( false ) ;
63+ return ;
64+ }
65+
66+ const recaptchaToken = await executeRecaptcha ( "login_code_request" ) ;
67+ if ( ! recaptchaToken ) {
68+ toast ( {
69+ title : TOAST_TITLE_ERROR ,
70+ description :
71+ "reCAPTCHA validation failed. Please try again." ,
72+ variant : "destructive" ,
73+ } ) ;
74+ setLoading ( false ) ;
75+ return ;
76+ }
77+ try {
78+ const recaptchaVerificationResponse = await fetch (
79+ "/api/recaptcha" ,
80+ {
81+ method : "POST" ,
82+ headers : { "Content-Type" : "application/json" } ,
83+ body : JSON . stringify ( { token : recaptchaToken } ) ,
84+ } ,
85+ ) ;
86+
87+ const recaptchaData =
88+ await recaptchaVerificationResponse . json ( ) ;
89+
90+ if (
91+ ! recaptchaVerificationResponse . ok ||
92+ ! recaptchaData . success ||
93+ ( recaptchaData . score && recaptchaData . score < 0.5 )
94+ ) {
95+ toast ( {
96+ title : TOAST_TITLE_ERROR ,
97+ description : `reCAPTCHA verification failed. ${ recaptchaData . score ? `Score: ${ recaptchaData . score . toFixed ( 2 ) } .` : "" } Please try again.` ,
98+ variant : "destructive" ,
99+ } ) ;
100+ setLoading ( false ) ;
101+ return ;
102+ }
103+ } catch ( err ) {
104+ console . error ( "Error during reCAPTCHA verification:" , err ) ;
105+ toast ( {
106+ title : TOAST_TITLE_ERROR ,
107+ description :
108+ "reCAPTCHA verification failed. Please try again." ,
109+ variant : "destructive" ,
110+ } ) ;
111+ setLoading ( false ) ;
112+ return ;
113+ }
114+ }
115+
52116 try {
53- setLoading ( true ) ;
117+ const url = `/api/auth/code/generate?email=${ encodeURIComponent (
118+ email ,
119+ ) } `;
54120 const response = await fetch ( url ) ;
55121 const resp = await response . json ( ) ;
56122 if ( response . ok ) {
57123 setShowCode ( true ) ;
58124 } else {
59125 toast ( {
60126 title : TOAST_TITLE_ERROR ,
61- description : resp . error ,
127+ description : resp . error || "Failed to request code." ,
62128 variant : "destructive" ,
63129 } ) ;
64130 }
131+ } catch ( err ) {
132+ console . error ( "Error during requestCode:" , err ) ;
133+ toast ( {
134+ title : TOAST_TITLE_ERROR ,
135+ description : "An unexpected error occurred. Please try again." ,
136+ variant : "destructive" ,
137+ } ) ;
65138 } finally {
66139 setLoading ( false ) ;
67140 }
@@ -79,11 +152,6 @@ export default function LoginForm({ redirectTo }: { redirectTo?: string }) {
79152 if ( response ?. error ) {
80153 setError ( `Can't sign you in at this time` ) ;
81154 } else {
82- // toast({
83- // title: TOAST_TITLE_SUCCESS,
84- // description: LOGIN_SUCCESS,
85- // });
86- // router.replace(redirectTo || "/dashboard/my-content");
87155 window . location . href = redirectTo || "/dashboard/my-content" ;
88156 }
89157 } finally {
@@ -99,7 +167,8 @@ export default function LoginForm({ redirectTo }: { redirectTo?: string }) {
99167 { error && (
100168 < div
101169 style = { {
102- color : theme ?. theme ?. colors ?. error ,
170+ color : theme ?. theme ?. colors ?. light
171+ ?. destructive ,
103172 } }
104173 className = "flex items-center gap-2 mb-4"
105174 >
@@ -218,6 +287,7 @@ export default function LoginForm({ redirectTo }: { redirectTo?: string }) {
218287 </ div >
219288 </ div >
220289 </ div >
290+ < RecaptchaScriptLoader />
221291 </ Section >
222292 ) ;
223293}
0 commit comments