11import { useState , useEffect } from "react" ;
2- import type { ReactNode , FormEvent } from "react" ;
2+ import type { ReactNode , FormEvent , ComponentPropsWithoutRef , ElementType } from "react" ;
33import { motion } from "framer-motion" ;
44import { useNavigate } from 'react-router-dom' ;
55import { toast } from "react-hot-toast" ;
@@ -14,11 +14,10 @@ interface AuthLayoutProps {
1414 children : ReactNode ;
1515}
1616
17- interface InputFieldProps extends React . InputHTMLAttributes < HTMLInputElement > {
18- icon : React . ElementType ;
17+ interface InputFieldProps extends ComponentPropsWithoutRef < 'input' > {
18+ icon : ElementType ;
1919}
2020
21-
2221const AuthLayout = ( { children } : AuthLayoutProps ) => (
2322 < div className = "min-h-screen bg-gray-950 flex items-center justify-center p-4" >
2423 < motion . div
@@ -32,14 +31,14 @@ const AuthLayout = ({ children }: AuthLayoutProps) => (
3231 </ div >
3332) ;
3433
35- const InputField = ( { icon : Icon , ...props } : InputFieldProps ) => (
34+ const InputField = ( { icon : Icon , className , ...props } : InputFieldProps ) => (
3635 < div className = "relative" >
3736 < div className = "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none" >
3837 < Icon className = "h-5 w-5 text-gray-400" />
3938 </ div >
4039 < input
41- { ...props }
42- className = " block w-full pl-10 pr-3 py-2 border border-gray-800 rounded-lg bg-gray-900 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent"
40+ { ...props }
41+ className = { ` block w-full pl-10 pr-3 py-2 border border-gray-800 rounded-lg bg-gray-900 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent ${ className ?? '' } ` }
4342 />
4443 </ div >
4544) ;
@@ -53,15 +52,16 @@ export default function ResetPasswordPage() {
5352
5453
5554 useEffect ( ( ) => {
56- const params = new URLSearchParams ( window . location . hash . slice ( 1 ) ) ;
55+ const paramsHash = new URLSearchParams ( window . location . hash . slice ( 1 ) ) ;
56+ const paramsSearch = new URLSearchParams ( window . location . search ) ;
5757
58- const accessToken = params . get ( 'access_token' ) ;
59- const refreshToken = params . get ( 'refresh_token' ) ;
58+ const accessToken = paramsHash . get ( 'access_token' ) ;
59+ const refreshToken = paramsHash . get ( 'refresh_token' ) ;
60+ const code = paramsSearch . get ( 'code' ) ;
6061
61- const clearUrlHash = ( ) => {
62- if ( window . location . hash ) {
63- window . history . replaceState ( { } , document . title , window . location . pathname + window . location . search ) ;
64- }
62+ const clearUrl = ( ) => {
63+ const url = window . location . pathname ;
64+ window . history . replaceState ( { } , document . title , url ) ;
6565 } ;
6666
6767 if ( accessToken && refreshToken ) {
@@ -79,17 +79,33 @@ export default function ResetPasswordPage() {
7979 toast . error ( "Error setting session" ) ;
8080 navigate ( '/login' , { replace : true } ) ;
8181 } finally {
82- clearUrlHash ( ) ;
82+ clearUrl ( ) ;
83+ }
84+ } ) ( ) ;
85+ } else if ( code ) {
86+ ( async ( ) => {
87+ try {
88+ const { error } = await supabase . auth . exchangeCodeForSession ( code ) ;
89+ if ( error ) {
90+ toast . error ( "Error exchanging code: " + error . message ) ;
91+ navigate ( '/login' , { replace : true } ) ;
92+ }
93+ } catch {
94+ toast . error ( "Error exchanging code" ) ;
95+ navigate ( '/login' , { replace : true } ) ;
96+ } finally {
97+ clearUrl ( ) ;
8398 }
8499 } ) ( ) ;
85100 } else {
86101 toast . error ( "Access denied" ) ;
87102 navigate ( '/login' , { replace : true } ) ;
88- clearUrlHash ( ) ;
103+ clearUrl ( ) ;
89104 }
90105 } , [ navigate ] ) ;
91106
92107
108+
93109 const handleAuth = async ( e : FormEvent < HTMLFormElement > ) => {
94110 e . preventDefault ( ) ;
95111 const formData = new FormData ( e . currentTarget ) ;
0 commit comments