[MOBIL-612] chore: updated the mobile auth imports #3369

This commit is contained in:
guru_sainath
2025-06-10 14:09:32 +05:30
committed by GitHub
parent 1c227a8108
commit 4e3ea24009
15 changed files with 534 additions and 72 deletions

View File

@@ -11,8 +11,7 @@ export const SPACE_PASSWORD_CRITERIA = [
{
key: "min_8_char",
label: "Min 8 characters",
isCriteriaValid: (password: string) =>
password.length >= PASSWORD_MIN_LENGTH,
isCriteriaValid: (password: string) => password.length >= PASSWORD_MIN_LENGTH,
},
// {
// key: "min_1_upper_case",

View File

@@ -22,11 +22,9 @@ export const SILO_BASE_URL = process.env.NEXT_PUBLIC_SILO_BASE_URL || "";
export const SILO_BASE_PATH = process.env.NEXT_PUBLIC_SILO_BASE_PATH || "";
export const SILO_URL = encodeURI(`${SILO_BASE_URL}${SILO_BASE_PATH}/`);
// plane website url
export const WEBSITE_URL =
process.env.NEXT_PUBLIC_WEBSITE_URL || "https://plane.so";
export const WEBSITE_URL = process.env.NEXT_PUBLIC_WEBSITE_URL || "https://plane.so";
// support email
export const SUPPORT_EMAIL =
process.env.NEXT_PUBLIC_SUPPORT_EMAIL || "support@plane.so";
export const SUPPORT_EMAIL = process.env.NEXT_PUBLIC_SUPPORT_EMAIL || "support@plane.so";
// marketing links
export const MARKETING_PRICING_PAGE_LINK = "https://plane.so/pricing";
export const MARKETING_CONTACT_US_PAGE_LINK = "https://plane.so/contact";

View File

@@ -49,3 +49,4 @@ export * from "./customers";
export * from "./projects-extended";
export * from "./state-extended";
export * from "./analytics";
export * from "./mobile";

View File

@@ -0,0 +1,100 @@
// error codes for mobile auth
export const EMobileAuthErrorCodes = {
// Global
INSTANCE_NOT_CONFIGURED: "5000",
INVALID_EMAIL: "5005",
EMAIL_REQUIRED: "5010",
SIGNUP_DISABLED: "5015",
MAGIC_LINK_LOGIN_DISABLED: "5016",
PASSWORD_LOGIN_DISABLED: "5018",
USER_ACCOUNT_DEACTIVATED: "5019",
// Password strength
INVALID_PASSWORD: "5020",
SMTP_NOT_CONFIGURED: "5025",
// Sign Up
USER_ALREADY_EXIST: "5030",
AUTHENTICATION_FAILED_SIGN_UP: "5035",
REQUIRED_EMAIL_PASSWORD_SIGN_UP: "5040",
INVALID_EMAIL_SIGN_UP: "5045",
INVALID_EMAIL_MAGIC_SIGN_UP: "5050",
MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED: "5055",
// Sign In
USER_DOES_NOT_EXIST: "5060",
AUTHENTICATION_FAILED_SIGN_IN: "5065",
REQUIRED_EMAIL_PASSWORD_SIGN_IN: "5070",
INVALID_EMAIL_SIGN_IN: "5075",
INVALID_EMAIL_MAGIC_SIGN_IN: "5080",
MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED: "5085",
// Both Sign in and Sign up for magic
INVALID_MAGIC_CODE_SIGN_IN: "5090",
INVALID_MAGIC_CODE_SIGN_UP: "5092",
EXPIRED_MAGIC_CODE_SIGN_IN: "5095",
EXPIRED_MAGIC_CODE_SIGN_UP: "5097",
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN: "5100",
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP: "5102",
// Oauth
OAUTH_NOT_CONFIGURED: "5104",
GOOGLE_NOT_CONFIGURED: "5105",
GITHUB_NOT_CONFIGURED: "5110",
GITLAB_NOT_CONFIGURED: "5111",
GOOGLE_OAUTH_PROVIDER_ERROR: "5115",
GITHUB_OAUTH_PROVIDER_ERROR: "5120",
GITLAB_OAUTH_PROVIDER_ERROR: "5121",
// Reset Password
INVALID_PASSWORD_TOKEN: "5125",
EXPIRED_PASSWORD_TOKEN: "5130",
// Change password
INCORRECT_OLD_PASSWORD: "5135",
MISSING_PASSWORD: "5138",
INVALID_NEW_PASSWORD: "5140",
// set passowrd
PASSWORD_ALREADY_SET: "5145",
// Admin
ADMIN_ALREADY_EXIST: "5150",
REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME: "5155",
INVALID_ADMIN_EMAIL: "5160",
INVALID_ADMIN_PASSWORD: "5165",
REQUIRED_ADMIN_EMAIL_PASSWORD: "5170",
ADMIN_AUTHENTICATION_FAILED: "5175",
ADMIN_USER_ALREADY_EXIST: "5180",
ADMIN_USER_DOES_NOT_EXIST: "5185",
ADMIN_USER_DEACTIVATED: "5190",
// Rate limit
RATE_LIMIT_EXCEEDED: "5900",
// mobile specific codes
USER_NOT_ONBOARDED: "6000",
TOKEN_NOT_SET: "6005",
MOBILE_SIGNUP_DISABLED: "6010",
};
export type TMobileAuthErrorCodes = (typeof EMobileAuthErrorCodes)[keyof typeof EMobileAuthErrorCodes];
export const EMobileErrorAlertType = {
BANNER_ALERT: "BANNER_ALERT",
TOAST_ALERT: "TOAST_ALERT",
INLINE_FIRST_NAME: "INLINE_FIRST_NAME",
INLINE_EMAIL: "INLINE_EMAIL",
INLINE_PASSWORD: "INLINE_PASSWORD",
INLINE_EMAIL_CODE: "INLINE_EMAIL_CODE",
} as const;
export type TMobileErrorAlertType = (typeof EMobileErrorAlertType)[keyof typeof EMobileErrorAlertType];
export type TMobileAuthErrorInfo = {
type: TMobileErrorAlertType;
code: TMobileAuthErrorCodes;
title: string;
message: any;
};
// mobile auth modes and steps
export const EMobileAuthModes = {
SIGN_IN: "SIGN_IN",
SIGN_UP: "SIGN_UP",
} as const;
export type TMobileAuthModes = (typeof EMobileAuthModes)[keyof typeof EMobileAuthModes];
export const EMobileAuthSteps = {
EMAIL: "EMAIL",
PASSWORD: "PASSWORD",
UNIQUE_CODE: "UNIQUE_CODE",
} as const;
export type TMobileAuthSteps = (typeof EMobileAuthSteps)[keyof typeof EMobileAuthSteps];

View File

@@ -0,0 +1 @@
export * from "./auth";

View File

@@ -21,3 +21,4 @@ export * from "./work-item-properties";
export * from "./work-item-types";
export * from "./workflow";
export * from "./workspace";
export * from "./mobile";

View File

@@ -0,0 +1,314 @@
import { ReactNode } from "react";
import {
TMobileAuthErrorCodes,
TMobileAuthErrorInfo,
EMobileAuthErrorCodes,
EMobileErrorAlertType,
SUPPORT_EMAIL,
} from "@plane/constants";
const mobileAuthErrorCodeMessages: {
[key in TMobileAuthErrorCodes]: { title: string; message: (email?: string | undefined) => ReactNode };
} = {
// global
[EMobileAuthErrorCodes.INSTANCE_NOT_CONFIGURED]: {
title: `Instance not configured`,
message: () => `Instance not configured. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.INVALID_EMAIL]: {
title: `Invalid email`,
message: () => `Invalid email. Please try again.`,
},
[EMobileAuthErrorCodes.EMAIL_REQUIRED]: {
title: `Email required`,
message: () => `Email required. Please try again.`,
},
[EMobileAuthErrorCodes.SIGNUP_DISABLED]: {
title: `Sign up disabled`,
message: () => `Sign up disabled. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.MAGIC_LINK_LOGIN_DISABLED]: {
title: `Magic link login disabled`,
message: () => `Magic link login disabled. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.PASSWORD_LOGIN_DISABLED]: {
title: `Password login disabled`,
message: () => `Password login disabled. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
title: `User account deactivated`,
message: () => `User account deactivated. Please contact ${!!SUPPORT_EMAIL ? SUPPORT_EMAIL : "administrator"}.`,
},
[EMobileAuthErrorCodes.INVALID_PASSWORD]: {
title: `Invalid password`,
message: () => `Invalid password. Please try again.`,
},
[EMobileAuthErrorCodes.SMTP_NOT_CONFIGURED]: {
title: `SMTP not configured`,
message: () => `SMTP not configured. Please contact your administrator.`,
},
// sign up
[EMobileAuthErrorCodes.USER_ALREADY_EXIST]: {
title: `User already exists`,
message: () => `Your account is already registered. Please try again.`,
},
[EMobileAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: {
title: `Email and password required`,
message: () => `Email and password required. Please try again.`,
},
[EMobileAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_UP]: {
title: `Authentication failed`,
message: () => `Authentication failed. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_EMAIL_SIGN_UP]: {
title: `Invalid email`,
message: () => `Invalid email. Please try again.`,
},
[EMobileAuthErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: {
title: `Email and code required`,
message: () => `Email and code required. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP]: {
title: `Invalid email`,
message: () => `Invalid email. Please try again.`,
},
[EMobileAuthErrorCodes.USER_DOES_NOT_EXIST]: {
title: `User does not exist`,
message: () => `No account found. Please try again.`,
},
[EMobileAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: {
title: `Email and password required`,
message: () => `Email and password required. Please try again.`,
},
[EMobileAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN]: {
title: `Authentication failed`,
message: () => `Authentication failed. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_EMAIL_SIGN_IN]: {
title: `Invalid email`,
message: () => `Invalid email. Please try again.`,
},
[EMobileAuthErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: {
title: `Email and code required`,
message: () => `Email and code required. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN]: {
title: `Invalid email`,
message: () => `Invalid email. Please try again.`,
},
// Both Sign in and Sign up
[EMobileAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN]: {
title: `Authentication failed`,
message: () => `Invalid magic code. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_UP]: {
title: `Authentication failed`,
message: () => `Invalid magic code. Please try again.`,
},
[EMobileAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN]: {
title: `Expired magic code`,
message: () => `Expired magic code. Please try again.`,
},
[EMobileAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP]: {
title: `Expired magic code`,
message: () => `Expired magic code. Please try again.`,
},
[EMobileAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN]: {
title: `Expired magic code`,
message: () => `Expired magic code. Please try again.`,
},
[EMobileAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP]: {
title: `Expired magic code`,
message: () => `Expired magic code. Please try again.`,
},
// Oauth
[EMobileAuthErrorCodes.OAUTH_NOT_CONFIGURED]: {
title: `OAuth not configured`,
message: () => `OAuth not configured. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.GOOGLE_NOT_CONFIGURED]: {
title: `Google not configured`,
message: () => `Google not configured. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.GITHUB_NOT_CONFIGURED]: {
title: `GitHub not configured`,
message: () => `GitHub not configured. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.GITLAB_NOT_CONFIGURED]: {
title: `GitLab not configured`,
message: () => `GitLab not configured. Please contact your administrator.`,
},
[EMobileAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR]: {
title: `Google OAuth provider error`,
message: () => `Google OAuth provider error. Please try again.`,
},
[EMobileAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR]: {
title: `GitHub OAuth provider error`,
message: () => `GitHub OAuth provider error. Please try again.`,
},
[EMobileAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR]: {
title: `GitLab OAuth provider error`,
message: () => `GitLab OAuth provider error. Please try again.`,
},
// Reset Password
[EMobileAuthErrorCodes.INVALID_PASSWORD_TOKEN]: {
title: `Invalid password token`,
message: () => `Invalid password token.`,
},
[EMobileAuthErrorCodes.EXPIRED_PASSWORD_TOKEN]: {
title: `Expired password token`,
message: () => `Expired password token. Please try again.`,
},
// Change password
[EMobileAuthErrorCodes.MISSING_PASSWORD]: {
title: `Password required`,
message: () => `Password required. Please try again.`,
},
[EMobileAuthErrorCodes.INCORRECT_OLD_PASSWORD]: {
title: `Incorrect old password`,
message: () => `Incorrect old password. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_NEW_PASSWORD]: {
title: `Invalid new password`,
message: () => `Invalid new password. Please try again.`,
},
// set password
[EMobileAuthErrorCodes.PASSWORD_ALREADY_SET]: {
title: `Password already set`,
message: () => `Password already set. Please try again.`,
},
// admin
[EMobileAuthErrorCodes.ADMIN_ALREADY_EXIST]: {
title: `Admin already exists`,
message: () => `Admin already exists. Please try again.`,
},
[EMobileAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: {
title: `Email, password and first name required`,
message: () => `Email, password and first name required. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_ADMIN_EMAIL]: {
title: `Invalid admin email`,
message: () => `Invalid admin email. Please try again.`,
},
[EMobileAuthErrorCodes.INVALID_ADMIN_PASSWORD]: {
title: `Invalid admin password`,
message: () => `Invalid admin password. Please try again.`,
},
[EMobileAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: {
title: `Email and password required`,
message: () => `Email and password required. Please try again.`,
},
[EMobileAuthErrorCodes.ADMIN_AUTHENTICATION_FAILED]: {
title: `Authentication failed`,
message: () => `Authentication failed. Please try again.`,
},
[EMobileAuthErrorCodes.ADMIN_USER_ALREADY_EXIST]: {
title: `Admin user already exists`,
message: () => `Admin user already exists. Please try again.`,
},
[EMobileAuthErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: {
title: `Admin user does not exist`,
message: () => `Admin user does not exist. Please try again.`,
},
[EMobileAuthErrorCodes.ADMIN_USER_DEACTIVATED]: {
title: `Admin user deactivated`,
message: () => `Your account is deactivated`,
},
[EMobileAuthErrorCodes.RATE_LIMIT_EXCEEDED]: {
title: "",
message: () => `Rate limit exceeded. Please try again later.`,
},
// mobile specific codes
[EMobileAuthErrorCodes.USER_NOT_ONBOARDED]: {
title: `User not onboarded`,
message: () => `User not onboarded. Please try again.`,
},
[EMobileAuthErrorCodes.TOKEN_NOT_SET]: {
title: `Token not set`,
message: () => `Token not set. Please try again.`,
},
[EMobileAuthErrorCodes.MOBILE_SIGNUP_DISABLED]: {
title: `Mobile sign up disabled`,
message: () => `Mobile sign up disabled. Please contact your administrator.`,
},
};
export const mobileAuthErrorHandler = (
errorCode: TMobileAuthErrorCodes,
email?: string | undefined
): TMobileAuthErrorInfo | undefined => {
const bannerAlertErrorCodes = [
EMobileAuthErrorCodes.INSTANCE_NOT_CONFIGURED,
EMobileAuthErrorCodes.INVALID_EMAIL,
EMobileAuthErrorCodes.EMAIL_REQUIRED,
EMobileAuthErrorCodes.SIGNUP_DISABLED,
EMobileAuthErrorCodes.MAGIC_LINK_LOGIN_DISABLED,
EMobileAuthErrorCodes.PASSWORD_LOGIN_DISABLED,
EMobileAuthErrorCodes.USER_ACCOUNT_DEACTIVATED,
EMobileAuthErrorCodes.INVALID_PASSWORD,
EMobileAuthErrorCodes.SMTP_NOT_CONFIGURED,
EMobileAuthErrorCodes.USER_ALREADY_EXIST,
EMobileAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_UP,
EMobileAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP,
EMobileAuthErrorCodes.INVALID_EMAIL_SIGN_UP,
EMobileAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP,
EMobileAuthErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED,
EMobileAuthErrorCodes.USER_DOES_NOT_EXIST,
EMobileAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN,
EMobileAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN,
EMobileAuthErrorCodes.INVALID_EMAIL_SIGN_IN,
EMobileAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
EMobileAuthErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED,
EMobileAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN,
EMobileAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_UP,
EMobileAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN,
EMobileAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP,
EMobileAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN,
EMobileAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP,
EMobileAuthErrorCodes.OAUTH_NOT_CONFIGURED,
EMobileAuthErrorCodes.GOOGLE_NOT_CONFIGURED,
EMobileAuthErrorCodes.GITHUB_NOT_CONFIGURED,
EMobileAuthErrorCodes.GITLAB_NOT_CONFIGURED,
EMobileAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR,
EMobileAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR,
EMobileAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR,
EMobileAuthErrorCodes.INVALID_PASSWORD_TOKEN,
EMobileAuthErrorCodes.EXPIRED_PASSWORD_TOKEN,
EMobileAuthErrorCodes.INCORRECT_OLD_PASSWORD,
EMobileAuthErrorCodes.MISSING_PASSWORD,
EMobileAuthErrorCodes.INVALID_NEW_PASSWORD,
EMobileAuthErrorCodes.PASSWORD_ALREADY_SET,
EMobileAuthErrorCodes.ADMIN_ALREADY_EXIST,
EMobileAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME,
EMobileAuthErrorCodes.INVALID_ADMIN_EMAIL,
EMobileAuthErrorCodes.INVALID_ADMIN_PASSWORD,
EMobileAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD,
EMobileAuthErrorCodes.ADMIN_AUTHENTICATION_FAILED,
EMobileAuthErrorCodes.ADMIN_USER_ALREADY_EXIST,
EMobileAuthErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
EMobileAuthErrorCodes.ADMIN_USER_DEACTIVATED,
EMobileAuthErrorCodes.RATE_LIMIT_EXCEEDED,
EMobileAuthErrorCodes.USER_NOT_ONBOARDED,
EMobileAuthErrorCodes.TOKEN_NOT_SET,
EMobileAuthErrorCodes.MOBILE_SIGNUP_DISABLED,
];
if (bannerAlertErrorCodes.includes(errorCode))
return {
type: EMobileErrorAlertType.BANNER_ALERT,
code: errorCode,
title: mobileAuthErrorCodeMessages[errorCode]?.title || "Error",
message: mobileAuthErrorCodeMessages[errorCode]?.message(email) || "Something went wrong. Please try again.",
};
return undefined;
};

View File

@@ -0,0 +1 @@
export * from "./auth";

View File

@@ -0,0 +1,38 @@
import { FC } from "react";
import { Info, X } from "lucide-react";
import { TMobileAuthErrorInfo } from "@plane/constants";
// plane imports
import { useTranslation } from "@plane/i18n";
type TMobileAuthBanner = {
bannerData: TMobileAuthErrorInfo | undefined;
handleBannerData?: (bannerData: TMobileAuthErrorInfo | undefined) => void;
};
export const MobileAuthBanner: FC<TMobileAuthBanner> = (props) => {
const { bannerData, handleBannerData } = props;
// translation
const { t } = useTranslation();
if (!bannerData) return <></>;
return (
<div
role="alert"
className="relative flex items-center p-2 rounded-md gap-2 border border-custom-primary-100/50 bg-custom-primary-100/10"
>
<div className="size-4 flex-shrink-0 grid place-items-center">
<Info size={16} className="text-custom-primary-100" />
</div>
<p className="w-full text-sm font-medium text-custom-primary-100">{bannerData?.message}</p>
<button
type="button"
className="relative ml-auto size-6 rounded-sm grid place-items-center transition-all hover:bg-custom-primary-100/20 text-custom-primary-100/80"
onClick={() => handleBannerData?.(undefined)}
aria-label={t("aria_labels.auth_forms.close_alert")}
>
<X className="size-4" />
</button>
</div>
);
};

View File

@@ -2,10 +2,17 @@
import { FC, FormEvent, useMemo, useRef, useState } from "react";
import { CircleAlert, XCircle } from "lucide-react";
import {
EMobileAuthSteps,
EMobileAuthModes,
TMobileAuthSteps,
TMobileAuthModes,
TMobileAuthErrorInfo,
} from "@plane/constants";
import { IEmailCheckData } from "@plane/types";
import { Button, Input, Spinner } from "@plane/ui";
// helpers
import { authErrorHandler, EAuthModes, EAuthSteps, TAuthErrorInfo } from "@/helpers/authentication.helper";
import { authErrorHandler } from "@/helpers/authentication.helper";
import { cn } from "@/helpers/common.helper";
import { checkEmailValidity } from "@/helpers/string.helper";
// plane web services
@@ -14,9 +21,9 @@ import mobileAuthService from "@/plane-web/services/mobile.service";
type TMobileAuthEmailValidationForm = {
email: string;
handleEmail: (value: string) => void;
handleAuthStep: (value: EAuthSteps) => void;
handleAuthMode: (value: EAuthModes) => void;
handleErrorInfo: (value: TAuthErrorInfo | undefined) => void;
handleAuthStep: (value: TMobileAuthSteps) => void;
handleAuthMode: (value: TMobileAuthModes) => void;
handleErrorInfo: (value: TMobileAuthErrorInfo | undefined) => void;
generateEmailUniqueCode: (email: string) => Promise<{ code: string } | undefined>;
};
@@ -83,18 +90,18 @@ export const MobileAuthEmailValidationForm: FC<TMobileAuthEmailValidationForm> =
.then(async (response) => {
// setting auth mode
if (response.existing) {
handleAuthMode(EAuthModes.SIGN_IN);
handleAuthMode(EMobileAuthModes.SIGN_IN);
} else {
handleAuthMode(EAuthModes.SIGN_UP);
handleAuthMode(EMobileAuthModes.SIGN_UP);
}
// setting auth step
if (response.status === "MAGIC_CODE") {
handleAuthStep(EAuthSteps.UNIQUE_CODE);
handleAuthStep(EMobileAuthSteps.UNIQUE_CODE);
// generating unique code
generateEmailUniqueCode(email);
} else if (response.status === "CREDENTIAL") {
handleAuthStep(EAuthSteps.PASSWORD);
handleAuthStep(EMobileAuthSteps.PASSWORD);
}
})
.catch((error) => {

View File

@@ -2,20 +2,20 @@
import { FC, useEffect, useRef, useState } from "react";
import { Eye, EyeOff, XCircle } from "lucide-react";
import { EMobileAuthSteps, EMobileAuthModes, TMobileAuthSteps, TMobileAuthModes } from "@plane/constants";
import { TMobileCSRFToken } from "@plane/types";
import { Button, Input, Spinner } from "@plane/ui";
// helpers
import { EAuthSteps, EAuthModes } from "@/helpers/authentication.helper";
import { API_BASE_URL } from "@/helpers/common.helper";
// services
import mobileAuthService from "@/plane-web/services/mobile.service";
type TMobileAuthPasswordForm = {
authMode: EAuthModes;
authMode: TMobileAuthModes;
invitationId: string | undefined;
email: string;
handleEmail: (value: string) => void;
handleAuthStep: (value: EAuthSteps) => void;
handleAuthStep: (value: TMobileAuthSteps) => void;
generateEmailUniqueCode: (email: string) => Promise<{ code: string } | undefined>;
isSMTPConfigured: boolean;
};
@@ -65,11 +65,11 @@ export const MobileAuthPasswordForm: FC<TMobileAuthPasswordForm> = (props) => {
const handleEmailClear = () => {
handleEmail("");
handleAuthStep(EAuthSteps.EMAIL);
handleAuthStep(EMobileAuthSteps.EMAIL);
};
const redirectToUniqueCodeSignIn = () => {
handleAuthStep(EAuthSteps.UNIQUE_CODE);
handleAuthStep(EMobileAuthSteps.UNIQUE_CODE);
// generate unique code
generateEmailUniqueCode(email);
};
@@ -79,7 +79,7 @@ export const MobileAuthPasswordForm: FC<TMobileAuthPasswordForm> = (props) => {
ref={authFormRef}
className="mt-5 space-y-4"
method="POST"
action={`${API_BASE_URL}/auth/mobile/${authMode === EAuthModes.SIGN_UP ? "sign-up" : "sign-in"}/`}
action={`${API_BASE_URL}/auth/mobile/${authMode === EMobileAuthModes.SIGN_UP ? "sign-up" : "sign-in"}/`}
onSubmit={async (event) => {
event.preventDefault(); // Prevent form from submitting by default
setIsSubmitting(true);

View File

@@ -2,9 +2,9 @@
import { FC, useEffect, useRef, useState } from "react";
import { CircleCheck, XCircle } from "lucide-react";
import { EMobileAuthSteps, EMobileAuthModes, TMobileAuthSteps, TMobileAuthModes } from "@plane/constants";
import { Button, Input, Spinner } from "@plane/ui";
// helpers
import { EAuthSteps, EAuthModes } from "@/helpers/authentication.helper";
import { API_BASE_URL } from "@/helpers/common.helper";
// hooks
import useTimer from "@/hooks/use-timer";
@@ -12,11 +12,11 @@ import useTimer from "@/hooks/use-timer";
import mobileAuthService from "@/plane-web/services/mobile.service";
type TMobileAuthUniqueCodeForm = {
authMode: EAuthModes;
authMode: TMobileAuthModes;
invitationId: string | undefined;
email: string;
handleEmail: (value: string) => void;
handleAuthStep: (value: EAuthSteps) => void;
handleAuthStep: (value: TMobileAuthSteps) => void;
generateEmailUniqueCode: (email: string) => Promise<{ code: string } | undefined>;
};
@@ -82,7 +82,7 @@ export const MobileAuthUniqueCodeForm: FC<TMobileAuthUniqueCodeForm> = (props) =
const handleEmailClear = () => {
handleEmail("");
handleAuthStep(EAuthSteps.EMAIL);
handleAuthStep(EMobileAuthSteps.EMAIL);
};
return (
@@ -90,7 +90,7 @@ export const MobileAuthUniqueCodeForm: FC<TMobileAuthUniqueCodeForm> = (props) =
ref={authFormRef}
className="mt-5 space-y-4"
method="POST"
action={`${API_BASE_URL}/auth/mobile/${authMode === EAuthModes.SIGN_UP ? "magic-sign-up" : "magic-sign-in"}/`}
action={`${API_BASE_URL}/auth/mobile/${authMode === EMobileAuthModes.SIGN_UP ? "magic-sign-up" : "magic-sign-in"}/`}
onSubmit={async (event) => {
event.preventDefault(); // Prevent form from submitting by default
setIsSubmitting(true);

View File

@@ -2,45 +2,44 @@
import { FC } from "react";
import Image from "next/image";
import { EMobileAuthModes, EMobileAuthSteps, TMobileAuthModes, TMobileAuthSteps } from "@plane/constants";
import { TMobileWorkspaceInvitation } from "@plane/types";
// helpers
import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper";
// assets
import planeLogo from "@/public/plane-logos/blue-without-text.png";
const AUTH_SIGNUP_HEADER_CONTENT_OPTIONS = {
[EAuthSteps.EMAIL]: {
[EMobileAuthSteps.EMAIL]: {
title: "sign up",
description: "",
},
[EAuthSteps.UNIQUE_CODE]: {
[EMobileAuthSteps.UNIQUE_CODE]: {
title: "Sign up",
description: "Sign up using a unique code sent to the email address above.",
},
[EAuthSteps.PASSWORD]: {
[EMobileAuthSteps.PASSWORD]: {
title: "Sign up",
description: "Sign up using an email-password combination.",
},
};
const AUTH_LOGIN_HEADER_CONTENT_OPTIONS = {
[EAuthSteps.EMAIL]: {
[EMobileAuthSteps.EMAIL]: {
title: "Log in or sign up",
description: "",
},
[EAuthSteps.UNIQUE_CODE]: {
[EMobileAuthSteps.UNIQUE_CODE]: {
title: "Log in or sign up",
description: "Log in using a unique code sent to the email address above.",
},
[EAuthSteps.PASSWORD]: {
[EMobileAuthSteps.PASSWORD]: {
title: "Log in or sign up",
description: "Use your email-password combination to log in.",
},
};
type TMobileAuthHeader = {
authMode: EAuthModes;
authStep: EAuthSteps;
authMode: TMobileAuthModes;
authStep: TMobileAuthSteps;
invitationDetails: TMobileWorkspaceInvitation | undefined;
};
@@ -50,7 +49,7 @@ export const MobileAuthHeader: FC<TMobileAuthHeader> = (props) => {
// derived values
const content =
authMode === EAuthModes.SIGN_UP
authMode === EMobileAuthModes.SIGN_UP
? AUTH_SIGNUP_HEADER_CONTENT_OPTIONS[authStep]
: AUTH_LOGIN_HEADER_CONTENT_OPTIONS[authStep];
const isInvitation = invitationDetails?.id || undefined;

View File

@@ -8,4 +8,6 @@ export * from "./terms-and-conditions";
export * from "./header";
export * from "./banner";
export * from "./wrappers";

View File

@@ -2,20 +2,21 @@
import { FC, useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import { TInstanceConfig, TMobileWorkspaceInvitation } from "@plane/types";
// components
import { AuthBanner } from "@/components/account";
// helpers
import {
authErrorHandler,
EAuthenticationErrorCodes,
EAuthSteps,
EAuthModes,
EErrorAlertType,
TAuthErrorInfo,
} from "@/helpers/authentication.helper";
EMobileAuthSteps,
EMobileAuthModes,
EMobileErrorAlertType,
TMobileAuthSteps,
TMobileAuthModes,
TMobileAuthErrorInfo,
EMobileAuthErrorCodes,
TMobileAuthErrorCodes,
} from "@plane/constants";
import { TInstanceConfig, TMobileWorkspaceInvitation } from "@plane/types";
import { mobileAuthErrorHandler } from "@plane/utils";
// plane web components
import {
MobileAuthBanner,
MobileTermsAndConditions,
MobileAuthEmailValidationForm,
MobileAuthUniqueCodeForm,
@@ -28,23 +29,23 @@ import {
import mobileAuthService from "@/plane-web/services/mobile.service";
const UNIQUE_CODE_ERROR_CODES = [
EAuthenticationErrorCodes.INVALID_MAGIC_CODE_SIGN_IN,
EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN,
EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN,
EMobileAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN,
EMobileAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
EMobileAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN,
EMobileAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN,
];
const PASSWORD_ERROR_CODES = [EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN];
const PASSWORD_ERROR_CODES = [EMobileAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN];
// oauth error codes
const OAUTH_ERROR_CODES = [
EAuthenticationErrorCodes.OAUTH_NOT_CONFIGURED,
EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED,
EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED,
EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR,
EAuthenticationErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR,
EAuthenticationErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR,
EAuthenticationErrorCodes.MOBILE_SIGNUP_DISABLED,
EMobileAuthErrorCodes.OAUTH_NOT_CONFIGURED,
EMobileAuthErrorCodes.GOOGLE_NOT_CONFIGURED,
EMobileAuthErrorCodes.GITHUB_NOT_CONFIGURED,
EMobileAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR,
EMobileAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR,
EMobileAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR,
EMobileAuthErrorCodes.MOBILE_SIGNUP_DISABLED,
];
type TAuthRoot = {
@@ -62,13 +63,13 @@ export const AuthRoot: FC<TAuthRoot> = (props) => {
const errorMessageParam = searchParams.get("error_message");
const sessionToken = searchParams.get("token");
// states
const [authMode, setAuthMode] = useState<EAuthModes>(EAuthModes.SIGN_IN);
const [authMode, setAuthMode] = useState<TMobileAuthModes>(EMobileAuthModes.SIGN_IN);
const [email, setEmail] = useState(emailParam ? emailParam.toString() : "");
const [authStep, setAuthStep] = useState<EAuthSteps>(EAuthSteps.EMAIL);
const [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined);
const [authStep, setAuthStep] = useState<TMobileAuthSteps>(EMobileAuthSteps.EMAIL);
const [errorInfo, setErrorInfo] = useState<TMobileAuthErrorInfo | undefined>(undefined);
const [invitationDetails, setInvitationDetails] = useState<TMobileWorkspaceInvitation | undefined>(undefined);
const handleErrorInfo = (value: TAuthErrorInfo | undefined) => {
const handleErrorInfo = (value: TMobileAuthErrorInfo | undefined) => {
setErrorInfo(value);
};
@@ -83,7 +84,7 @@ export const AuthRoot: FC<TAuthRoot> = (props) => {
.generateUniqueCode(payload)
.then(() => ({ code: "" }))
.catch((error) => {
const errorhandler = authErrorHandler(error?.error_code.toString());
const errorhandler = mobileAuthErrorHandler(error?.error_code.toString());
if (errorhandler?.type) setErrorInfo(errorhandler);
throw error;
});
@@ -92,12 +93,12 @@ export const AuthRoot: FC<TAuthRoot> = (props) => {
// validating and defining the errors
useEffect(() => {
if (!errorCodeParam) return;
const errorhandler = authErrorHandler(errorCodeParam?.toString() as EAuthenticationErrorCodes);
const errorhandler = mobileAuthErrorHandler(errorCodeParam?.toString() as TMobileAuthErrorCodes);
if (!errorhandler) return;
// password handler
if (PASSWORD_ERROR_CODES.includes(errorhandler.code)) setAuthStep(EAuthSteps.PASSWORD);
if (PASSWORD_ERROR_CODES.includes(errorhandler.code)) setAuthStep(EMobileAuthSteps.PASSWORD);
// unique code handler
if (UNIQUE_CODE_ERROR_CODES.includes(errorhandler.code)) setAuthStep(EAuthSteps.UNIQUE_CODE);
if (UNIQUE_CODE_ERROR_CODES.includes(errorhandler.code)) setAuthStep(EMobileAuthSteps.UNIQUE_CODE);
// oauth signup handler
if (OAUTH_ERROR_CODES.includes(errorhandler.code)) setErrorInfo(errorhandler);
setErrorInfo(errorhandler);
@@ -120,13 +121,13 @@ export const AuthRoot: FC<TAuthRoot> = (props) => {
<MobileAuthHeader invitationDetails={invitationDetails} authMode={authMode} authStep={authStep} />
{/* alert banner */}
{errorInfo && errorInfo?.type === EErrorAlertType.BANNER_ALERT && (
<AuthBanner bannerData={errorInfo} handleBannerData={handleErrorInfo} />
{errorInfo && errorInfo?.type === EMobileErrorAlertType.BANNER_ALERT && (
<MobileAuthBanner bannerData={errorInfo} handleBannerData={handleErrorInfo} />
)}
{/* auth content */}
<div>
{authStep === EAuthSteps.EMAIL && (
{authStep === EMobileAuthSteps.EMAIL && (
<MobileAuthEmailValidationForm
email={email}
handleEmail={(value) => setEmail(value)}
@@ -136,7 +137,7 @@ export const AuthRoot: FC<TAuthRoot> = (props) => {
generateEmailUniqueCode={generateEmailUniqueCode}
/>
)}
{authStep === EAuthSteps.UNIQUE_CODE && (
{authStep === EMobileAuthSteps.UNIQUE_CODE && (
<MobileAuthUniqueCodeForm
authMode={authMode}
invitationId={invitationIdParam}
@@ -146,7 +147,7 @@ export const AuthRoot: FC<TAuthRoot> = (props) => {
generateEmailUniqueCode={generateEmailUniqueCode}
/>
)}
{authStep === EAuthSteps.PASSWORD && (
{authStep === EMobileAuthSteps.PASSWORD && (
<MobileAuthPasswordForm
authMode={authMode}
invitationId={invitationIdParam}