import { useState } from "react"; import { Form, required, useNotify, useTranslate } from "ra-core"; import { Layout } from "@/components/supabase/layout"; import type { FieldValues, SubmitHandler } from "react-hook-form"; import { TextInput } from "@/components/admin/text-input"; import { Button } from "@/components/ui/button"; import { OtpInput } from "@/components/supabase/otp-input"; import { supabase } from "@/components/atomic-crm/providers/supabase/supabase"; import { Link } from "react-router"; interface EmailFormData { email: string; } type Step = "email" | "otp"; export const ForgotPasswordPage = () => { const [loading, setLoading] = useState(false); const [step, setStep] = useState("email"); const [email, setEmail] = useState(""); const [otp, setOtp] = useState(""); const [otpError, setOtpError] = useState(false); const notify = useNotify(); const translate = useTranslate(); const submitEmail = async (values: EmailFormData) => { try { setLoading(true); // Normalize email to lowercase const normalizedEmail = values.email.trim().toLowerCase(); setEmail(normalizedEmail); const { error } = await supabase.auth.signInWithOtp({ email: normalizedEmail, options: { shouldCreateUser: false, // Only allow existing users to reset password }, }); if (error) { throw error; } notify(translate("crm.auth.code_sent"), { type: "success" }); setStep("otp"); } catch (error: any) { notify( typeof error === "string" ? error : typeof error === "undefined" || !error.message ? "ra.auth.sign_in_error" : error.message, { type: "warning", messageArgs: { _: typeof error === "string" ? error : error && error.message ? error.message : undefined, }, }, ); } finally { setLoading(false); } }; const verifyOtp = async (otpCode: string) => { try { setLoading(true); setOtpError(false); // Trim whitespace from OTP code const cleanOtp = otpCode.trim(); const { data, error } = await supabase.auth.verifyOtp({ email: email.trim().toLowerCase(), // Normalize email token: cleanOtp, type: "magiclink", // Changed from 'email' - some Supabase versions treat OTP as magiclink }); if (error) { throw error; } if (!data.session) { throw new Error("Failed to create session"); } // User is now logged in, redirect to change password page notify(translate("crm.auth.forgot_password_code_verified"), { type: "success", }); // Navigate to change password page with reload window.location.href = "#/change-password"; window.location.reload(); } catch (error: any) { setOtpError(true); notify( typeof error === "string" ? error : typeof error === "undefined" || !error.message ? translate("crm.auth.invalid_code") : error.message, { type: "warning", messageArgs: { _: typeof error === "string" ? error : error && error.message ? error.message : undefined, }, }, ); } finally { setLoading(false); } }; const handleOtpComplete = (otpCode: string) => { verifyOtp(otpCode); }; const handleResendCode = async () => { setOtp(""); setOtpError(false); await submitEmail({ email }); }; return ( {step === "email" ? ( <>

{translate("ra-supabase.reset_password.forgot_password")}

{translate("ra-supabase.reset_password.forgot_password_details")}

className="space-y-8" onSubmit={submitEmail as SubmitHandler} >
{translate("crm.auth.back_to_login")}
) : ( <>

{translate("crm.auth.enter_verification_code")}

{translate("crm.auth.code_sent_to", { email })}

{otpError && (

{translate("crm.auth.invalid_code")}

)}
{translate("crm.auth.back_to_login")}
)}
); }; ForgotPasswordPage.path = "forgot-password";