diff --git a/frontend/app/(auth)/login/components/MagicLinkLogin/hooks/useMagicLinkLogin.ts b/frontend/app/(auth)/login/components/MagicLinkLogin/hooks/useMagicLinkLogin.ts index 699880ba5228..7a1db3666aa2 100644 --- a/frontend/app/(auth)/login/components/MagicLinkLogin/hooks/useMagicLinkLogin.ts +++ b/frontend/app/(auth)/login/components/MagicLinkLogin/hooks/useMagicLinkLogin.ts @@ -1,38 +1,39 @@ -import { useState } from "react"; +import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useSupabase } from "@/lib/context/SupabaseProvider"; import { useToast } from "@/lib/hooks"; -type UseMagicLinkLoginProps = { - email: string; - setEmail: (email: string) => void; -}; - -export const useMagicLinkLogin = ({ - email, - setEmail, -}: UseMagicLinkLoginProps): { - handleMagicLinkLogin: () => Promise; - isPending: boolean; -} => { +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export const useMagicLinkLogin = () => { const { supabase } = useSupabase(); - const [isPending, setIsPending] = useState(false); const { t } = useTranslation("login"); const { publish } = useToast(); - const handleMagicLinkLogin = async () => { + const { + register, + watch, + setValue, + formState: { isSubmitSuccessful, isSubmitting }, + handleSubmit, + reset, + } = useForm<{ email: string }>({ + defaultValues: { + email: "", + }, + }); + + const email = watch("email"); + + const handleMagicLinkLogin = handleSubmit(async (_, ev) => { + ev?.preventDefault(); if (email === "") { publish({ variant: "danger", text: t("errorMailMissed"), }); - - return; } - setIsPending(true); - const { error } = await supabase.auth.signInWithOtp({ email, options: { @@ -45,16 +46,24 @@ export const useMagicLinkLogin = ({ variant: "danger", text: error.message, }); - } else { - publish({ - variant: "success", - text: "Magic link sent successfully if email recognized", - }); - setEmail(""); + throw error; // this error is caught by react-hook-form } - setIsPending(false); - }; - return { handleMagicLinkLogin, isPending }; + publish({ + variant: "success", + text: "Magic link sent successfully if email recognized", + }); + + setValue("email", ""); + }); + + return { + handleMagicLinkLogin, + isSubmitting, + register, + handleSubmit, + isSubmitSuccessful, + reset, + }; }; diff --git a/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx b/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx index 1fb56a3c3dcb..855525527729 100644 --- a/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx +++ b/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx @@ -3,32 +3,50 @@ import { useTranslation } from "react-i18next"; import Button from "@/lib/components/ui/Button"; +import Field from "@/lib/components/ui/Field"; +import { emailPattern } from "@/lib/config/patterns"; import { useMagicLinkLogin } from "./hooks/useMagicLinkLogin"; -type MaginLinkLoginProps = { - email: string; - setEmail: (email: string) => void; -}; +export const MagicLinkLogin = (): JSX.Element => { + const { + handleMagicLinkLogin, + isSubmitting, + register, + isSubmitSuccessful, + reset, + } = useMagicLinkLogin(); + const { t } = useTranslation(["login", "translation"]); -export const MagicLinkLogin = ({ - email, - setEmail, -}: MaginLinkLoginProps): JSX.Element => { - const { handleMagicLinkLogin, isPending } = useMagicLinkLogin({ - email, - setEmail, - }); - const { t } = useTranslation(["login"]); + if (isSubmitSuccessful) { + return ( + <> +

{t("check_your_email", { ns: "login" })}

+

+ {t("cant_find", { ns: "login" })}{" "} + +

+ + ); + } return ( - +
void handleMagicLinkLogin(e)}> + + + ); }; diff --git a/frontend/app/(auth)/login/hooks/useLogin.ts b/frontend/app/(auth)/login/hooks/useLogin.ts index 5aa26e7f8650..6b76afcbe21b 100644 --- a/frontend/app/(auth)/login/hooks/useLogin.ts +++ b/frontend/app/(auth)/login/hooks/useLogin.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useSupabase } from "@/lib/context/SupabaseProvider"; import { redirectToPreviousPageOrChatPage } from "@/lib/helpers/redirectToPreviousPageOrChatPage"; @@ -6,8 +6,6 @@ import { useEventTracking } from "@/services/analytics/june/useEventTracking"; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export const useLogin = () => { - const [email, setEmail] = useState(""); - const { session } = useSupabase(); const { track } = useEventTracking(); @@ -18,9 +16,4 @@ export const useLogin = () => { redirectToPreviousPageOrChatPage(); } }, [session?.user]); - - return { - setEmail, - email, - }; }; diff --git a/frontend/app/(auth)/login/page.tsx b/frontend/app/(auth)/login/page.tsx index 6942239d18a4..313122998481 100644 --- a/frontend/app/(auth)/login/page.tsx +++ b/frontend/app/(auth)/login/page.tsx @@ -5,14 +5,14 @@ import { useTranslation } from "react-i18next"; import { QuivrLogo } from "@/lib/assets/QuivrLogo"; import { Divider } from "@/lib/components/ui/Divider"; -import Field from "@/lib/components/ui/Field"; import { GoogleLoginButton } from "./components/GoogleLogin"; import { MagicLinkLogin } from "./components/MagicLinkLogin"; import { useLogin } from "./hooks/useLogin"; const Main = (): JSX.Element => { - const { setEmail, email } = useLogin(); + useLogin(); + const { t } = useTranslation(["translation", "login"]); return ( @@ -27,16 +27,7 @@ const Main = (): JSX.Element => { Quivr

- setEmail(e.target.value)} - value={email} - label="Email" - inputClassName="py-1 mt-1 mb-3" - /> - +
diff --git a/frontend/app/contact/components/ContactForm.tsx b/frontend/app/contact/components/ContactForm.tsx index 30feaed3b38c..a7e517ad6e6b 100644 --- a/frontend/app/contact/components/ContactForm.tsx +++ b/frontend/app/contact/components/ContactForm.tsx @@ -1,15 +1,13 @@ -import React from "react"; import { SubmitHandler, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { LuChevronRight } from "react-icons/lu"; import Button from "@/lib/components/ui/Button"; import Spinner from "@/lib/components/ui/Spinner"; +import { emailPattern } from "@/lib/config/patterns"; import { usePostContactSales } from "../hooks/usePostContactSales"; -const emailPattern = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i; - export const ContactForm = (): JSX.Element => { const { t } = useTranslation("contact", { keyPrefix: "form" }); diff --git a/frontend/lib/config/patterns.ts b/frontend/lib/config/patterns.ts new file mode 100644 index 000000000000..2b29235704ae --- /dev/null +++ b/frontend/lib/config/patterns.ts @@ -0,0 +1 @@ +export const emailPattern = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i; diff --git a/frontend/public/locales/en/login.json b/frontend/public/locales/en/login.json index e20904c6eb26..4d14a49acf0d 100644 --- a/frontend/public/locales/en/login.json +++ b/frontend/public/locales/en/login.json @@ -4,5 +4,8 @@ "errorMailMissed": "Please enter your email address", "talk_to": "Talk to", "restriction_message": "Unpaid users have access to a free and limited demo of Quivr", - "email":"Email address" + "email":"Email address", + "cant_find":"Can't find it ?", + "try_again":"Try again", + "check_your_email":"We just sent you a Magic link, check your emails and follow the steps." } \ No newline at end of file