fix: authentication redirection and UI (#4432)
* dev: update python version * dev: handle magic code attempt exhausted * dev: update app, space and god mode redirection paths * fix: handled signup and signin workflow * chore: auth input error indication and autofill styling improvement * dev: add app redirection urls * dev: update redirections * chore: onboarding improvement * chore: onboarding improvement * chore: redirection issue in space resolved * chore: instance empty state added * dev: fix app, space, admin redirection in docker setitngs --------- Co-authored-by: guru_sainath <gurusainath007@gmail.com> Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
parent
2d1201cc92
commit
88ebda42ff
49 changed files with 1336 additions and 541 deletions
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { CircleCheck, XCircle } from "lucide-react";
|
||||
import { IEmailCheckData } from "@plane/types";
|
||||
import { Button, Input, Spinner, TOAST_TYPE, setToast } from "@plane/ui";
|
||||
import { Button, Input, Spinner } from "@plane/ui";
|
||||
// helpers
|
||||
import { EAuthModes } from "@/helpers/authentication.helper";
|
||||
import { API_BASE_URL } from "@/helpers/common.helper";
|
||||
|
|
@ -10,11 +9,14 @@ import useTimer from "@/hooks/use-timer";
|
|||
// services
|
||||
import { AuthService } from "@/services/auth.service";
|
||||
|
||||
type Props = {
|
||||
// services
|
||||
const authService = new AuthService();
|
||||
|
||||
type TAuthUniqueCodeForm = {
|
||||
mode: EAuthModes;
|
||||
email: string;
|
||||
handleEmailClear: () => void;
|
||||
submitButtonText: string;
|
||||
mode: EAuthModes;
|
||||
generateEmailUniqueCode: (email: string) => Promise<{ code: string } | undefined>;
|
||||
};
|
||||
|
||||
type TUniqueCodeFormValues = {
|
||||
|
|
@ -27,55 +29,35 @@ const defaultValues: TUniqueCodeFormValues = {
|
|||
code: "",
|
||||
};
|
||||
|
||||
// services
|
||||
const authService = new AuthService();
|
||||
|
||||
export const AuthUniqueCodeForm: React.FC<Props> = (props) => {
|
||||
const { email, handleEmailClear, submitButtonText, mode } = props;
|
||||
export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
|
||||
const { mode, email, handleEmailClear, generateEmailUniqueCode } = props;
|
||||
// hooks
|
||||
// const { captureEvent } = useEventTracker();
|
||||
// derived values
|
||||
const defaultResetTimerValue = 5;
|
||||
// states
|
||||
const [uniqueCodeFormData, setUniqueCodeFormData] = useState<TUniqueCodeFormValues>({ ...defaultValues, email });
|
||||
const [isRequestingNewCode, setIsRequestingNewCode] = useState(false);
|
||||
const [csrfToken, setCsrfToken] = useState<string | undefined>(undefined);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
// store hooks
|
||||
// const { captureEvent } = useEventTracker();
|
||||
// timer
|
||||
const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(30);
|
||||
const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(0);
|
||||
|
||||
const handleFormChange = (key: keyof TUniqueCodeFormValues, value: string) =>
|
||||
setUniqueCodeFormData((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
const handleSendNewCode = async (email: string) => {
|
||||
const payload: IEmailCheckData = {
|
||||
email,
|
||||
};
|
||||
|
||||
await authService
|
||||
.generateUniqueCode(payload)
|
||||
.then(() => {
|
||||
setResendCodeTimer(30);
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
title: "Success!",
|
||||
message: "A new unique code has been sent to your email.",
|
||||
});
|
||||
handleFormChange("code", "");
|
||||
})
|
||||
.catch((err) =>
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: err?.error ?? "Something went wrong while generating unique code. Please try again.",
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleRequestNewCode = async (email: string) => {
|
||||
setIsRequestingNewCode(true);
|
||||
|
||||
await handleSendNewCode(email)
|
||||
.then(() => setResendCodeTimer(30))
|
||||
.finally(() => setIsRequestingNewCode(false));
|
||||
const generateNewCode = async (email: string) => {
|
||||
try {
|
||||
setIsRequestingNewCode(true);
|
||||
const uniqueCode = await generateEmailUniqueCode(email);
|
||||
setResendCodeTimer(defaultResetTimerValue);
|
||||
handleFormChange("code", uniqueCode?.code || "");
|
||||
setIsRequestingNewCode(false);
|
||||
} catch {
|
||||
setResendCodeTimer(0);
|
||||
console.error("Error while requesting new code");
|
||||
setIsRequestingNewCode(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -83,11 +65,6 @@ export const AuthUniqueCodeForm: React.FC<Props> = (props) => {
|
|||
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
|
||||
}, [csrfToken]);
|
||||
|
||||
useEffect(() => {
|
||||
handleRequestNewCode(email);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const isRequestNewCodeDisabled = isRequestingNewCode || resendTimerCode > 0;
|
||||
const isButtonDisabled = isRequestingNewCode || !uniqueCodeFormData.code || isSubmitting;
|
||||
|
||||
|
|
@ -100,11 +77,14 @@ export const AuthUniqueCodeForm: React.FC<Props> = (props) => {
|
|||
onError={() => setIsSubmitting(false)}
|
||||
>
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
||||
<input type="hidden" value={uniqueCodeFormData.email} name="email" />
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-medium text-onboarding-text-300" htmlFor="email">
|
||||
Email
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-onboarding-background-200">
|
||||
<div
|
||||
className={`relative flex items-center rounded-md bg-onboarding-background-200 border border-onboarding-border-100`}
|
||||
>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
|
|
@ -112,18 +92,17 @@ export const AuthUniqueCodeForm: React.FC<Props> = (props) => {
|
|||
value={uniqueCodeFormData.email}
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
placeholder="name@company.com"
|
||||
className="h-[46px] w-full border border-onboarding-border-100 pr-12 placeholder:text-onboarding-text-400"
|
||||
className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 border-0`}
|
||||
disabled
|
||||
/>
|
||||
{uniqueCodeFormData.email.length > 0 && (
|
||||
<XCircle
|
||||
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
||||
onClick={handleEmailClear}
|
||||
/>
|
||||
<div className="flex-shrink-0 h-5 w-5 mr-2 bg-onboarding-background-200 hover:cursor-pointer">
|
||||
<XCircle className="h-5 w-5 stroke-custom-text-400" onClick={handleEmailClear} />
|
||||
</div>
|
||||
)}
|
||||
<input type="hidden" value={uniqueCodeFormData.email} name="email" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm font-medium text-onboarding-text-300" htmlFor="code">
|
||||
Unique code
|
||||
|
|
@ -132,22 +111,18 @@ export const AuthUniqueCodeForm: React.FC<Props> = (props) => {
|
|||
name="code"
|
||||
value={uniqueCodeFormData.code}
|
||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||
// FIXME:
|
||||
// hasError={Boolean(errors.code)}
|
||||
placeholder="gets-sets-flys"
|
||||
className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400"
|
||||
className="disable-autofill-style h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400"
|
||||
autoFocus
|
||||
/>
|
||||
{/* )}
|
||||
/> */}
|
||||
<div className="flex w-full items-center justify-between px-1 text-xs">
|
||||
<div className="flex w-full items-center justify-between px-1 text-xs pt-1">
|
||||
<p className="flex items-center gap-1 font-medium text-green-700">
|
||||
<CircleCheck height={12} width={12} />
|
||||
Paste the code sent to your email
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRequestNewCode(uniqueCodeFormData.email)}
|
||||
onClick={() => generateNewCode(uniqueCodeFormData.email)}
|
||||
className={`${
|
||||
isRequestNewCodeDisabled
|
||||
? "text-onboarding-text-400"
|
||||
|
|
@ -163,15 +138,12 @@ export const AuthUniqueCodeForm: React.FC<Props> = (props) => {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
|
||||
{isRequestingNewCode ? (
|
||||
"Sending code"
|
||||
) : isSubmitting ? (
|
||||
<Spinner height="20px" width="20px" />
|
||||
) : (
|
||||
submitButtonText
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<div className="space-y-2.5">
|
||||
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
|
||||
{isRequestingNewCode ? "Sending code" : isSubmitting ? <Spinner height="20px" width="20px" /> : "Continue"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue