chore: handled the auto form submit for all authenticators (#5139)

This commit is contained in:
guru_sainath 2024-07-16 14:16:10 +05:30 committed by GitHub
parent 6ade86f89d
commit cd85a9fe09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 15 deletions

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Eye, EyeOff, XCircle } from "lucide-react"; import { Eye, EyeOff, XCircle } from "lucide-react";
import { Button, Input, Spinner } from "@plane/ui"; import { Button, Input, Spinner } from "@plane/ui";
@ -39,8 +39,10 @@ const authService = new AuthService();
export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => { export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
const { email, nextPath, isSMTPConfigured, handleAuthStep, handleEmailClear, mode } = props; const { email, nextPath, isSMTPConfigured, handleAuthStep, handleEmailClear, mode } = props;
// ref
const formRef = useRef<HTMLFormElement>(null);
// states // states
const [csrfToken, setCsrfToken] = useState<string | undefined>(undefined); const [csrfPromise, setCsrfPromise] = useState<Promise<{ csrf_token: string }> | undefined>(undefined);
const [passwordFormData, setPasswordFormData] = useState<TPasswordFormValues>({ ...defaultValues, email }); const [passwordFormData, setPasswordFormData] = useState<TPasswordFormValues>({ ...defaultValues, email });
const [showPassword, setShowPassword] = useState({ const [showPassword, setShowPassword] = useState({
password: false, password: false,
@ -57,9 +59,11 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
setPasswordFormData((prev) => ({ ...prev, [key]: value })); setPasswordFormData((prev) => ({ ...prev, [key]: value }));
useEffect(() => { useEffect(() => {
if (csrfToken === undefined) if (csrfPromise === undefined) {
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token)); const promise = authService.requestCSRFToken();
}, [csrfToken]); setCsrfPromise(promise);
}
}, [csrfPromise]);
const redirectToUniqueCodeSignIn = async () => { const redirectToUniqueCodeSignIn = async () => {
handleAuthStep(EAuthSteps.UNIQUE_CODE); handleAuthStep(EAuthSteps.UNIQUE_CODE);
@ -88,15 +92,29 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
const confirmPassword = passwordFormData.confirm_password ?? ""; const confirmPassword = passwordFormData.confirm_password ?? "";
const renderPasswordMatchError = !isRetryPasswordInputFocused || confirmPassword.length >= password.length; const renderPasswordMatchError = !isRetryPasswordInputFocused || confirmPassword.length >= password.length;
const handleCSRFToken = async () => {
if (!formRef || !formRef.current) return;
const token = await csrfPromise;
if (!token?.csrf_token) return;
const csrfElement = formRef.current.querySelector("input[name=csrfmiddlewaretoken]");
csrfElement?.setAttribute("value", token?.csrf_token);
};
return ( return (
<form <form
ref={formRef}
className="mt-5 space-y-4" className="mt-5 space-y-4"
method="POST" method="POST"
action={`${API_BASE_URL}/auth/spaces/${mode === EAuthModes.SIGN_IN ? "sign-in" : "sign-up"}/`} action={`${API_BASE_URL}/auth/spaces/${mode === EAuthModes.SIGN_IN ? "sign-in" : "sign-up"}/`}
onSubmit={() => setIsSubmitting(true)} onSubmit={async (event) => {
event.preventDefault();
await handleCSRFToken();
formRef.current && formRef.current.submit();
setIsSubmitting(true);
}}
onError={() => setIsSubmitting(false)} onError={() => setIsSubmitting(false)}
> >
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} /> <input type="hidden" name="csrfmiddlewaretoken" />
<input type="hidden" value={passwordFormData.email} name="email" /> <input type="hidden" value={passwordFormData.email} name="email" />
<input type="hidden" value={nextPath} name="next_path" /> <input type="hidden" value={nextPath} name="next_path" />
<div className="space-y-1"> <div className="space-y-1">

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import Link from "next/link"; import Link from "next/link";
// icons // icons
@ -51,8 +51,10 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
const { email, isSMTPConfigured, handleAuthStep, handleEmailClear, mode, nextPath } = props; const { email, isSMTPConfigured, handleAuthStep, handleEmailClear, mode, nextPath } = props;
// hooks // hooks
const { captureEvent } = useEventTracker(); const { captureEvent } = useEventTracker();
// ref
const formRef = useRef<HTMLFormElement>(null);
// states // states
const [csrfToken, setCsrfToken] = useState<string | undefined>(undefined); const [csrfPromise, setCsrfPromise] = useState<Promise<{ csrf_token: string }> | undefined>(undefined);
const [passwordFormData, setPasswordFormData] = useState<TPasswordFormValues>({ ...defaultValues, email }); const [passwordFormData, setPasswordFormData] = useState<TPasswordFormValues>({ ...defaultValues, email });
const [showPassword, setShowPassword] = useState({ const [showPassword, setShowPassword] = useState({
password: false, password: false,
@ -70,9 +72,11 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
setPasswordFormData((prev) => ({ ...prev, [key]: value })); setPasswordFormData((prev) => ({ ...prev, [key]: value }));
useEffect(() => { useEffect(() => {
if (csrfToken === undefined) if (csrfPromise === undefined) {
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token)); const promise = authService.requestCSRFToken();
}, [csrfToken]); setCsrfPromise(promise);
}
}, [csrfPromise]);
const redirectToUniqueCodeSignIn = async () => { const redirectToUniqueCodeSignIn = async () => {
handleAuthStep(EAuthSteps.UNIQUE_CODE); handleAuthStep(EAuthSteps.UNIQUE_CODE);
@ -115,6 +119,14 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
const confirmPassword = passwordFormData?.confirm_password ?? ""; const confirmPassword = passwordFormData?.confirm_password ?? "";
const renderPasswordMatchError = !isRetryPasswordInputFocused || confirmPassword.length >= password.length; const renderPasswordMatchError = !isRetryPasswordInputFocused || confirmPassword.length >= password.length;
const handleCSRFToken = async () => {
if (!formRef || !formRef.current) return;
const token = await csrfPromise;
if (!token?.csrf_token) return;
const csrfElement = formRef.current.querySelector("input[name=csrfmiddlewaretoken]");
csrfElement?.setAttribute("value", token?.csrf_token);
};
return ( return (
<> <>
{isBannerMessage && mode === EAuthModes.SIGN_UP && ( {isBannerMessage && mode === EAuthModes.SIGN_UP && (
@ -132,11 +144,13 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
</div> </div>
)} )}
<form <form
ref={formRef}
className="mt-5 space-y-4" className="mt-5 space-y-4"
method="POST" method="POST"
action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "sign-in" : "sign-up"}/`} action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "sign-in" : "sign-up"}/`}
onSubmit={(event) => { onSubmit={async (event) => {
event.preventDefault(); // Prevent form from submitting by default event.preventDefault(); // Prevent form from submitting by default
await handleCSRFToken();
const isPasswordValid = const isPasswordValid =
mode === EAuthModes.SIGN_UP mode === EAuthModes.SIGN_UP
? getPasswordStrength(passwordFormData.password) === E_PASSWORD_STRENGTH.STRENGTH_VALID ? getPasswordStrength(passwordFormData.password) === E_PASSWORD_STRENGTH.STRENGTH_VALID
@ -144,14 +158,14 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
if (isPasswordValid) { if (isPasswordValid) {
setIsSubmitting(true); setIsSubmitting(true);
captureEvent(mode === EAuthModes.SIGN_IN ? SIGN_IN_WITH_PASSWORD : SIGN_UP_WITH_PASSWORD); captureEvent(mode === EAuthModes.SIGN_IN ? SIGN_IN_WITH_PASSWORD : SIGN_UP_WITH_PASSWORD);
event.currentTarget.submit(); // Manually submit the form if the condition is met formRef.current && formRef.current.submit(); // Manually submit the form if the condition is met
} else { } else {
setBannerMessage(true); setBannerMessage(true);
} }
}} }}
onError={() => setIsSubmitting(false)} onError={() => setIsSubmitting(false)}
> >
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} /> <input type="hidden" name="csrfmiddlewaretoken" />
<input type="hidden" value={passwordFormData.email} name="email" /> <input type="hidden" value={passwordFormData.email} name="email" />
{nextPath && <input type="hidden" value={nextPath} name="next_path" />} {nextPath && <input type="hidden" value={nextPath} name="next_path" />}
<div className="space-y-1"> <div className="space-y-1">