mirror of
https://github.com/makeplane/plane.git
synced 2026-01-20 21:31:31 -06:00
chore: handled the auto form submit for all authenticators (#5139)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Eye, EyeOff, XCircle } from "lucide-react";
|
||||
import { Button, Input, Spinner } from "@plane/ui";
|
||||
@@ -39,8 +39,10 @@ const authService = new AuthService();
|
||||
|
||||
export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
const { email, nextPath, isSMTPConfigured, handleAuthStep, handleEmailClear, mode } = props;
|
||||
// ref
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
// 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 [showPassword, setShowPassword] = useState({
|
||||
password: false,
|
||||
@@ -57,9 +59,11 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
setPasswordFormData((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
useEffect(() => {
|
||||
if (csrfToken === undefined)
|
||||
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
|
||||
}, [csrfToken]);
|
||||
if (csrfPromise === undefined) {
|
||||
const promise = authService.requestCSRFToken();
|
||||
setCsrfPromise(promise);
|
||||
}
|
||||
}, [csrfPromise]);
|
||||
|
||||
const redirectToUniqueCodeSignIn = async () => {
|
||||
handleAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||
@@ -88,15 +92,29 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
const confirmPassword = passwordFormData.confirm_password ?? "";
|
||||
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 (
|
||||
<form
|
||||
ref={formRef}
|
||||
className="mt-5 space-y-4"
|
||||
method="POST"
|
||||
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)}
|
||||
>
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
||||
<input type="hidden" name="csrfmiddlewaretoken" />
|
||||
<input type="hidden" value={passwordFormData.email} name="email" />
|
||||
<input type="hidden" value={nextPath} name="next_path" />
|
||||
<div className="space-y-1">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
// icons
|
||||
@@ -51,8 +51,10 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
const { email, isSMTPConfigured, handleAuthStep, handleEmailClear, mode, nextPath } = props;
|
||||
// hooks
|
||||
const { captureEvent } = useEventTracker();
|
||||
// ref
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
// 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 [showPassword, setShowPassword] = useState({
|
||||
password: false,
|
||||
@@ -70,9 +72,11 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
setPasswordFormData((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
useEffect(() => {
|
||||
if (csrfToken === undefined)
|
||||
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
|
||||
}, [csrfToken]);
|
||||
if (csrfPromise === undefined) {
|
||||
const promise = authService.requestCSRFToken();
|
||||
setCsrfPromise(promise);
|
||||
}
|
||||
}, [csrfPromise]);
|
||||
|
||||
const redirectToUniqueCodeSignIn = async () => {
|
||||
handleAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||
@@ -115,6 +119,14 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
const confirmPassword = passwordFormData?.confirm_password ?? "";
|
||||
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 (
|
||||
<>
|
||||
{isBannerMessage && mode === EAuthModes.SIGN_UP && (
|
||||
@@ -132,11 +144,13 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
</div>
|
||||
)}
|
||||
<form
|
||||
ref={formRef}
|
||||
className="mt-5 space-y-4"
|
||||
method="POST"
|
||||
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
|
||||
await handleCSRFToken();
|
||||
const isPasswordValid =
|
||||
mode === EAuthModes.SIGN_UP
|
||||
? getPasswordStrength(passwordFormData.password) === E_PASSWORD_STRENGTH.STRENGTH_VALID
|
||||
@@ -144,14 +158,14 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
||||
if (isPasswordValid) {
|
||||
setIsSubmitting(true);
|
||||
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 {
|
||||
setBannerMessage(true);
|
||||
}
|
||||
}}
|
||||
onError={() => setIsSubmitting(false)}
|
||||
>
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
||||
<input type="hidden" name="csrfmiddlewaretoken" />
|
||||
<input type="hidden" value={passwordFormData.email} name="email" />
|
||||
{nextPath && <input type="hidden" value={nextPath} name="next_path" />}
|
||||
<div className="space-y-1">
|
||||
|
||||
Reference in New Issue
Block a user