diff --git a/apps/admin/app/(all)/(home)/auth-helpers.tsx b/apps/admin/app/(all)/(home)/auth-helpers.tsx index ea18dc99599..692bc1de590 100644 --- a/apps/admin/app/(all)/(home)/auth-helpers.tsx +++ b/apps/admin/app/(all)/(home)/auth-helpers.tsx @@ -21,6 +21,15 @@ const errorCodeMessages: { [key in EAdminAuthErrorCodes]: { title: string; message: (email?: string) => React.ReactNode }; } = { // admin + [EAdminAuthErrorCodes.INSTANCE_NOT_CONFIGURED]: { + title: `Instance not configured`, + message: () => `This Plane instance is not configured. Please contact your administrator.`, + }, + [EAdminAuthErrorCodes.PASSWORD_TOO_WEAK]: { + title: `Password too weak`, + message: () => + `Your password is too weak. Please use a mix of uppercase, lowercase, numbers, and special characters.`, + }, [EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST]: { title: `Admin already exists`, message: () => `Admin already exists. Please try again.`, @@ -77,6 +86,8 @@ const errorCodeMessages: { export const authErrorHandler = (errorCode: EAdminAuthErrorCodes, email?: string): TAdminAuthErrorInfo | undefined => { const bannerAlertErrorCodes = [ + EAdminAuthErrorCodes.INSTANCE_NOT_CONFIGURED, + EAdminAuthErrorCodes.PASSWORD_TOO_WEAK, EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST, EAdminAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME, EAdminAuthErrorCodes.INVALID_ADMIN_EMAIL, diff --git a/apps/admin/components/instance/setup-form.tsx b/apps/admin/components/instance/setup-form.tsx index 74e80db45b6..9dcd0cd94ed 100644 --- a/apps/admin/components/instance/setup-form.tsx +++ b/apps/admin/components/instance/setup-form.tsx @@ -9,34 +9,21 @@ import { useSearchParams } from "next/navigation"; // icons import { Eye, EyeOff } from "lucide-react"; // plane internal packages -import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants"; +import { API_BASE_URL, E_PASSWORD_STRENGTH, EAdminAuthErrorCodes } from "@plane/constants"; +import type { TAdminAuthErrorInfo } from "@plane/constants"; import { Button } from "@plane/propel/button"; import { AuthService } from "@plane/services"; import { Checkbox, Input, PasswordStrengthIndicator, Spinner } from "@plane/ui"; import { getPasswordStrength, validatePersonName, validateCompanyName } from "@plane/utils"; // components +import { AuthBanner } from "@/app/(all)/(home)/auth-banner"; +import { authErrorHandler } from "@/app/(all)/(home)/auth-helpers"; import { AuthHeader } from "@/app/(all)/(home)/auth-header"; -import { Banner } from "../common/banner"; import { FormHeader } from "./form-header"; // service initialization const authService = new AuthService(); -// error codes -enum EErrorCodes { - INSTANCE_NOT_CONFIGURED = "INSTANCE_NOT_CONFIGURED", - ADMIN_ALREADY_EXIST = "ADMIN_ALREADY_EXIST", - REQUIRED_EMAIL_PASSWORD_FIRST_NAME = "REQUIRED_EMAIL_PASSWORD_FIRST_NAME", - INVALID_EMAIL = "INVALID_EMAIL", - INVALID_PASSWORD = "INVALID_PASSWORD", - USER_ALREADY_EXISTS = "USER_ALREADY_EXISTS", -} - -type TError = { - type: EErrorCodes | undefined; - message: string | undefined; -}; - // form data type TFormData = { first_name: string; @@ -64,9 +51,8 @@ export function InstanceSetupForm() { const lastNameParam = searchParams?.get("last_name") || undefined; const companyParam = searchParams?.get("company") || undefined; const emailParam = searchParams?.get("email") || undefined; - const isTelemetryEnabledParam = (searchParams?.get("is_telemetry_enabled") === "True" ? true : false) || true; + const isTelemetryEnabledParam = searchParams?.get("is_telemetry_enabled") === "True"; const errorCode = searchParams?.get("error_code") || undefined; - const errorMessage = searchParams?.get("error_message") || undefined; // state const [showPassword, setShowPassword] = useState({ password: false, @@ -77,6 +63,7 @@ export function InstanceSetupForm() { const [isPasswordInputFocused, setIsPasswordInputFocused] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [isRetryPasswordInputFocused, setIsRetryPasswordInputFocused] = useState(false); + const [errorInfo, setErrorInfo] = useState(undefined); const handleShowPassword = (key: keyof typeof showPassword) => setShowPassword((prev) => ({ ...prev, [key]: !prev[key] })); @@ -97,38 +84,21 @@ export function InstanceSetupForm() { if (isTelemetryEnabledParam) setFormData((prev) => ({ ...prev, is_telemetry_enabled: isTelemetryEnabledParam })); }, [firstNameParam, lastNameParam, companyParam, emailParam, isTelemetryEnabledParam]); - // derived values - const errorData: TError = useMemo(() => { - if (errorCode && errorMessage) { - switch (errorCode) { - case EErrorCodes.INSTANCE_NOT_CONFIGURED: - return { type: EErrorCodes.INSTANCE_NOT_CONFIGURED, message: errorMessage }; - case EErrorCodes.ADMIN_ALREADY_EXIST: - return { type: EErrorCodes.ADMIN_ALREADY_EXIST, message: errorMessage }; - case EErrorCodes.REQUIRED_EMAIL_PASSWORD_FIRST_NAME: - return { type: EErrorCodes.REQUIRED_EMAIL_PASSWORD_FIRST_NAME, message: errorMessage }; - case EErrorCodes.INVALID_EMAIL: - return { type: EErrorCodes.INVALID_EMAIL, message: errorMessage }; - case EErrorCodes.INVALID_PASSWORD: - return { type: EErrorCodes.INVALID_PASSWORD, message: errorMessage }; - case EErrorCodes.USER_ALREADY_EXISTS: - return { type: EErrorCodes.USER_ALREADY_EXISTS, message: errorMessage }; - default: - return { type: undefined, message: undefined }; - } - } else return { type: undefined, message: undefined }; - }, [errorCode, errorMessage]); + useEffect(() => { + if (errorCode) { + const errorDetail = authErrorHandler(errorCode as EAdminAuthErrorCodes); + if (errorDetail) setErrorInfo(errorDetail); + } + }, [errorCode]); const isButtonDisabled = useMemo( () => - !isSubmitting && - formData.first_name && - formData.email && - formData.password && - getPasswordStrength(formData.password) === E_PASSWORD_STRENGTH.STRENGTH_VALID && - formData.password === formData.confirm_password - ? false - : true, + isSubmitting || + !formData.first_name || + !formData.email || + !formData.password || + getPasswordStrength(formData.password) !== E_PASSWORD_STRENGTH.STRENGTH_VALID || + formData.password !== formData.confirm_password, [formData.confirm_password, formData.email, formData.first_name, formData.password, isSubmitting] ); @@ -145,11 +115,7 @@ export function InstanceSetupForm() { heading="Setup your Plane Instance" subHeading="Post setup you will be able to manage this Plane instance." /> - {errorData.type && - errorData?.message && - ![EErrorCodes.INVALID_EMAIL, EErrorCodes.INVALID_PASSWORD].includes(errorData.type) && ( - - )} + {errorInfo && setErrorInfo(v)} />}
@@ -221,12 +186,8 @@ export function InstanceSetupForm() { placeholder="name@company.com" value={formData.email} onChange={(e) => handleFormChange("email", e.target.value)} - hasError={errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL ? true : false} autoComplete="off" /> - {errorData.type && errorData.type === EErrorCodes.INVALID_EMAIL && errorData.message && ( -

{errorData.message}

- )}
@@ -265,7 +226,6 @@ export function InstanceSetupForm() { placeholder="New password" value={formData.password} onChange={(e) => handleFormChange("password", e.target.value)} - hasError={errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD ? true : false} onFocus={() => setIsPasswordInputFocused(true)} onBlur={() => setIsPasswordInputFocused(false)} autoComplete="new-password" @@ -290,9 +250,6 @@ export function InstanceSetupForm() { )}
- {errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD && errorData.message && ( -

{errorData.message}

- )} diff --git a/packages/constants/src/auth/index.ts b/packages/constants/src/auth/index.ts index 32a7d5eee64..531642602ed 100644 --- a/packages/constants/src/auth/index.ts +++ b/packages/constants/src/auth/index.ts @@ -85,6 +85,8 @@ export type TAuthErrorInfo = { export enum EAdminAuthErrorCodes { // Admin + INSTANCE_NOT_CONFIGURED = "5000", + PASSWORD_TOO_WEAK = "5021", ADMIN_ALREADY_EXIST = "5150", REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5155", INVALID_ADMIN_EMAIL = "5160",