From 50943685c06238d6e18cffdabe0ad15b4109b2e3 Mon Sep 17 00:00:00 2001 From: Timothy Armes Date: Thu, 11 Apr 2024 13:31:21 +0200 Subject: [PATCH] Require logon for Zone pages --- src/app/[locale]/(main)/auth/sign-in/page.tsx | 87 ++--------------- src/app/[locale]/(main)/zones/create/page.tsx | 2 +- .../[locale]/(main)/zones/edit/[id]/page.tsx | 5 +- src/app/[locale]/(main)/zones/layout.tsx | 36 +++++++ src/app/[locale]/(main)/zones/page.tsx | 2 +- src/components/SignInForm.tsx | 96 +++++++++++++++++++ src/messages/en.json | 3 + src/messages/fr.json | 2 + src/utils/navigation.ts | 2 - src/utils/nodemailerProvider.ts | 10 +- 10 files changed, 155 insertions(+), 90 deletions(-) create mode 100644 src/app/[locale]/(main)/zones/layout.tsx create mode 100644 src/components/SignInForm.tsx diff --git a/src/app/[locale]/(main)/auth/sign-in/page.tsx b/src/app/[locale]/(main)/auth/sign-in/page.tsx index af151b0..5c6381f 100644 --- a/src/app/[locale]/(main)/auth/sign-in/page.tsx +++ b/src/app/[locale]/(main)/auth/sign-in/page.tsx @@ -1,65 +1,13 @@ "use client"; -import { useState } from "react"; +import { useTranslations } from "next-intl"; +import { useSearchParams } from "next/navigation"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { signIn } from "next-auth/react"; -import { useLocale, useTranslations } from "next-intl"; -import { FormProvider, useForm } from "react-hook-form"; -import { z } from "zod"; - -import { clearMessage } from "@/components/InfoMessage"; -import InfoMessage from "@/components/InfoMessage"; -import { TextField } from "@/components/form/TextField"; - -const signInSchema = z.object({ - email: z.string().email(), -}); - -type SignInFormValues = z.infer; +import { SignInForm } from "@/components/SignInForm"; export default function SignIn() { const t = useTranslations("SignIn"); - const locale = useLocale(); - - const [responseMessage, setResponseMessage] = useState({ - isSuccessful: false, - message: "", - }); - - const form = useForm({ - resolver: zodResolver(signInSchema), - }); - - const onSubmit = async ({ email }: SignInFormValues) => { - try { - const result = await signIn("nodemailer", { - email, - redirect: false, - callbackUrl: `/${locale}/tournaments`, - }); - - if (result?.error) { - throw new Error(result.error); - } else if (result?.ok) { - setResponseMessage({ - isSuccessful: true, - message: t("checkEmail"), - }); - - form.reset(); - } - } catch (err: unknown) { - console.log(err); - - setResponseMessage({ - isSuccessful: false, - message: t("failure"), - }); - - clearMessage(setResponseMessage); - } - }; + const params = useSearchParams(); return (
@@ -74,30 +22,9 @@ export default function SignIn() { {t("info")}

- -
- - - - - - -
+
); diff --git a/src/app/[locale]/(main)/zones/create/page.tsx b/src/app/[locale]/(main)/zones/create/page.tsx index 38446f6..5a0a280 100644 --- a/src/app/[locale]/(main)/zones/create/page.tsx +++ b/src/app/[locale]/(main)/zones/create/page.tsx @@ -35,7 +35,7 @@ const CreateZone = () => { }; return ( -
+

{ const t = useTranslations("Zones"); const router = useRouter(); const params = useParams(); - const queryClient = useQueryClient(); const [responseMessage, setResponseMessage] = useState({ isSuccessful: false, @@ -75,7 +74,7 @@ const EditZone = () => { }; return ( -
+

+ {!sessionData ? ( +
+

+ {t("title")} +

+ +

+ {t("logonRequired")} +

+ + +
+ ) : ( + children + )} +

+ ); +} diff --git a/src/app/[locale]/(main)/zones/page.tsx b/src/app/[locale]/(main)/zones/page.tsx index 8aab6e4..cc1e646 100644 --- a/src/app/[locale]/(main)/zones/page.tsx +++ b/src/app/[locale]/(main)/zones/page.tsx @@ -34,7 +34,7 @@ const Zones = () => { const zones = data?.data ?? []; return ( -
+

; + +type SignInFormProps = { + callbackPath?: string; +}; + +export const SignInForm = ({ callbackPath }: SignInFormProps) => { + const t = useTranslations("SignIn"); + const locale = useLocale(); + const path = usePathname(); + + const [responseMessage, setResponseMessage] = useState({ + isSuccessful: false, + message: "", + }); + + const form = useForm({ + resolver: zodResolver(signInSchema), + }); + + const onSubmit = async ({ email }: SignInFormValues) => { + try { + const result = await signIn("nodemailer", { + email, + redirect: false, + callbackUrl: callbackPath ?? `/${locale}/${path}`, + }); + + if (result?.error) { + throw new Error(result.error); + } else if (result?.ok) { + setResponseMessage({ + isSuccessful: true, + message: t("checkEmail"), + }); + + form.reset(); + } + } catch (err: unknown) { + console.log(err); + + setResponseMessage({ + isSuccessful: false, + message: t("failure"), + }); + + clearMessage(setResponseMessage); + } + }; + + return ( + +
+ + + + + + +
+ ); +}; diff --git a/src/messages/en.json b/src/messages/en.json index e271dfe..1d5115a 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -219,6 +219,7 @@ "SignIn": { "title": "Sign In", "info": "Sign in to access additional features, such as receiving email notifications for tournaments in your area. There's no need to create an account, just sign in with your email address and we'll send you a link.", + "emailLabel": "Email", "emailPlaceholder": "Your email", "signInButton": "Sign In", @@ -236,6 +237,8 @@ "Zones": { "title": "Your Zones", "info": "You can set up zones to receive email notifications for tournaments in these areas. These zones can also be used to filter tournaments on the main map.", + "logonRequired": "You must be signed in to access this feature so that we can store your personalized Zones. There's no need to create an account, just sign in with your email address and we'll send you a link.", + "noNotifications": "You have not enabled email notifications for this zone.", "withNotifications": "You will receive email notifications for new tournaments with {list} time control in this region.", "editButton": "Edit", diff --git a/src/messages/fr.json b/src/messages/fr.json index 30765c0..933fb70 100644 --- a/src/messages/fr.json +++ b/src/messages/fr.json @@ -237,6 +237,8 @@ "Zones": { "title": "Vos régions", "info": "Vous pouvez définir des zones personnalisées pour recevoir des notifications par e-mail pour les tournois dans ces zones. Ces zones peuvent aussi être utiliser pour filtrer les tournois sur la carte.", + "logonRequired": "Vous devez être connecté pour accéder à cette fonctionnalité afin que nous puissions stocker vos régions personnalisées. Vous n'avez pas besoin de créer un compte, connectez-vous simplement avec votre adresse e-mail et nous vous enverrons un lien.", + "noNotifications": "Vous n'avez pas activé les notifications par email pour cette région.", "withNotifications": "Vous allez recevoir des notifications par e-mail pour les nouveaux tournois de cadences {list} dans cette région.", "editButton": "Modifier", diff --git a/src/utils/navigation.ts b/src/utils/navigation.ts index 4ffb2c0..92adadd 100644 --- a/src/utils/navigation.ts +++ b/src/utils/navigation.ts @@ -41,8 +41,6 @@ export const pathnames = { fr: "/contactez-nous", en: "/contact-us", }, - - "[...rest]": "[...rest]", } satisfies Pathnames; export const { Link, redirect, usePathname, useRouter, getPathname } = diff --git a/src/utils/nodemailerProvider.ts b/src/utils/nodemailerProvider.ts index 488b7a2..317e496 100644 --- a/src/utils/nodemailerProvider.ts +++ b/src/utils/nodemailerProvider.ts @@ -133,16 +133,20 @@ export default function Nodemailer( maxAge: 24 * 60 * 60, async sendVerificationRequest(params) { + const { identifier, url, provider } = params; + let locale = "fr"; - const { searchParams } = new URL(params.url); + const { searchParams } = new URL(url); if (searchParams.has("callbackUrl")) { const { pathname } = new URL(searchParams.get("callbackUrl")!); - locale = pathname.split("/")[1]; + const maybeLocale = pathname.split("/")[1]; + if (["en", "fr"].includes(maybeLocale)) { + locale = maybeLocale; + } } const t = await getTranslations({ locale, namespace: "SignIn" }); - const { identifier, url, provider } = params; const { host } = new URL(url); const transport = createTransport(provider.server); const result = await transport.sendMail({