mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: handled signin workflow
This commit is contained in:
parent
e8711dc4cc
commit
6c84b4f490
@ -240,13 +240,15 @@ export const InstanceSignUpForm: FC = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative flex items-center pt-2 gap-2">
|
<div className="relative flex items-center pt-2 gap-2">
|
||||||
<Checkbox
|
<div>
|
||||||
id="is_telemetry_enabled"
|
<Checkbox
|
||||||
name="is_telemetry_enabled"
|
id="is_telemetry_enabled"
|
||||||
value={formData.is_telemetry_enabled ? "True" : "False"}
|
name="is_telemetry_enabled"
|
||||||
onChange={() => handleFormChange("is_telemetry_enabled", !formData.is_telemetry_enabled)}
|
value={formData.is_telemetry_enabled ? "True" : "False"}
|
||||||
checked={formData.is_telemetry_enabled}
|
onChange={() => handleFormChange("is_telemetry_enabled", !formData.is_telemetry_enabled)}
|
||||||
/>
|
checked={formData.is_telemetry_enabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<label className="text-sm text-custom-text-300 font-medium cursor-pointer" htmlFor="is_telemetry_enabled">
|
<label className="text-sm text-custom-text-300 font-medium cursor-pointer" htmlFor="is_telemetry_enabled">
|
||||||
Allow Plane to anonymously collect usage events.
|
Allow Plane to anonymously collect usage events.
|
||||||
</label>
|
</label>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import { FC, ReactNode } from "react";
|
import { FC, ReactNode } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { usePathname } from "next/navigation";
|
|
||||||
// logo
|
// logo
|
||||||
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
|
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
|
||||||
|
|
||||||
@ -12,9 +11,6 @@ type TDefaultLayout = {
|
|||||||
|
|
||||||
export const DefaultLayout: FC<TDefaultLayout> = (props) => {
|
export const DefaultLayout: FC<TDefaultLayout> = (props) => {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
const pathname = usePathname();
|
|
||||||
|
|
||||||
console.log("pathname", pathname);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-screen max-h-max w-full overflow-hidden overflow-y-auto flex flex-col">
|
<div className="relative h-screen max-h-max w-full overflow-hidden overflow-y-auto flex flex-col">
|
||||||
|
@ -13,8 +13,10 @@ export const AuthBanner: FC<TAuthBanner> = (props) => {
|
|||||||
|
|
||||||
if (!bannerData) return <></>;
|
if (!bannerData) return <></>;
|
||||||
return (
|
return (
|
||||||
<div className="relative inline-flex items-center p-3 rounded-md gap-3 border border-custom-primary-100/50 bg-custom-primary-100/10">
|
<div className="relative inline-flex items-center p-2 rounded-md gap-2 border border-custom-primary-100/50 bg-custom-primary-100/10">
|
||||||
<Info className="w-5 h-5 flex-shrink-0 text-custom-primary-100" />
|
<div className="w-4 h-4 flex-shrink-0 relative flex justify-center items-center">
|
||||||
|
<Info size={16} className="text-custom-primary-100" />
|
||||||
|
</div>
|
||||||
<div className="w-full text-sm font-medium text-custom-primary-100">{bannerData?.message}</div>
|
<div className="w-full text-sm font-medium text-custom-primary-100">{bannerData?.message}</div>
|
||||||
<div
|
<div
|
||||||
className="relative ml-auto w-6 h-6 rounded-sm flex justify-center items-center transition-all cursor-pointer hover:bg-custom-primary-100/20 text-custom-primary-100/80"
|
className="relative ml-auto w-6 h-6 rounded-sm flex justify-center items-center transition-all cursor-pointer hover:bg-custom-primary-100/20 text-custom-primary-100/80"
|
||||||
|
@ -6,10 +6,11 @@ import { Eye, EyeOff, XCircle } from "lucide-react";
|
|||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { EAuthModes, EAuthSteps, ForgotPasswordPopover, PasswordStrengthMeter } from "@/components/account";
|
import { ForgotPasswordPopover, PasswordStrengthMeter } from "@/components/account";
|
||||||
// constants
|
// constants
|
||||||
import { FORGOT_PASSWORD } from "@/constants/event-tracker";
|
import { FORGOT_PASSWORD } from "@/constants/event-tracker";
|
||||||
// helpers
|
// helpers
|
||||||
|
import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper";
|
||||||
import { API_BASE_URL } from "@/helpers/common.helper";
|
import { API_BASE_URL } from "@/helpers/common.helper";
|
||||||
import { getPasswordStrength } from "@/helpers/password.helper";
|
import { getPasswordStrength } from "@/helpers/password.helper";
|
||||||
// hooks
|
// hooks
|
||||||
@ -94,51 +95,78 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form
|
||||||
<form
|
className="mx-auto mt-5 space-y-4 w-5/6 sm:w-96"
|
||||||
className="mx-auto mt-5 space-y-4 w-5/6 sm:w-96"
|
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"}/`}
|
>
|
||||||
>
|
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
||||||
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
<div className="space-y-1">
|
||||||
<div className="space-y-1">
|
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="email">
|
||||||
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="email">
|
Email
|
||||||
Email
|
</label>
|
||||||
</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">
|
<Input
|
||||||
<Input
|
id="email"
|
||||||
id="email"
|
name="email"
|
||||||
name="email"
|
type="email"
|
||||||
type="email"
|
value={passwordFormData.email}
|
||||||
value={passwordFormData.email}
|
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
// hasError={Boolean(errors.email)}
|
||||||
// hasError={Boolean(errors.email)}
|
placeholder="name@company.com"
|
||||||
placeholder="name@company.com"
|
className="h-[46px] w-full border border-onboarding-border-100 pr-12 placeholder:text-onboarding-text-400"
|
||||||
className="h-[46px] w-full border border-onboarding-border-100 pr-12 placeholder:text-onboarding-text-400"
|
/>
|
||||||
|
{passwordFormData.email.length > 0 && (
|
||||||
|
<XCircle
|
||||||
|
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
||||||
|
onClick={handleEmailClear}
|
||||||
/>
|
/>
|
||||||
{passwordFormData.email.length > 0 && (
|
)}
|
||||||
<XCircle
|
|
||||||
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
|
||||||
onClick={handleEmailClear}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="password">
|
||||||
|
{mode === EAuthModes.SIGN_IN ? "Password" : "Set a password"}
|
||||||
|
</label>
|
||||||
|
<div className="relative flex items-center rounded-md bg-onboarding-background-200">
|
||||||
|
<Input
|
||||||
|
type={showPassword ? "text" : "password"}
|
||||||
|
name="password"
|
||||||
|
value={passwordFormData.password}
|
||||||
|
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||||
|
placeholder="Enter password"
|
||||||
|
className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400"
|
||||||
|
onFocus={() => setIsPasswordInputFocused(true)}
|
||||||
|
onBlur={() => setIsPasswordInputFocused(false)}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
{showPassword ? (
|
||||||
|
<EyeOff
|
||||||
|
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
||||||
|
onClick={() => setShowPassword(false)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Eye
|
||||||
|
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
||||||
|
onClick={() => setShowPassword(true)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{passwordSupport}
|
||||||
|
</div>
|
||||||
|
{mode === EAuthModes.SIGN_UP && (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="password">
|
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="confirm_password">
|
||||||
{mode === EAuthModes.SIGN_IN ? "Password" : "Set a password"}
|
Confirm password
|
||||||
</label>
|
</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">
|
||||||
<Input
|
<Input
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
name="password"
|
name="confirm_password"
|
||||||
value={passwordFormData.password}
|
value={passwordFormData.confirm_password}
|
||||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
||||||
placeholder="Enter password"
|
placeholder="Confirm password"
|
||||||
className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400"
|
className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400"
|
||||||
onFocus={() => setIsPasswordInputFocused(true)}
|
|
||||||
onBlur={() => setIsPasswordInputFocused(false)}
|
|
||||||
autoFocus
|
|
||||||
/>
|
/>
|
||||||
{showPassword ? (
|
{showPassword ? (
|
||||||
<EyeOff
|
<EyeOff
|
||||||
@ -152,64 +180,35 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{passwordSupport}
|
{!!passwordFormData.confirm_password && passwordFormData.password !== passwordFormData.confirm_password && (
|
||||||
</div>
|
<span className="text-sm text-red-500">Passwords don{"'"}t match</span>
|
||||||
{mode === EAuthModes.SIGN_UP && (
|
|
||||||
<div className="space-y-1">
|
|
||||||
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="confirm_password">
|
|
||||||
Confirm password
|
|
||||||
</label>
|
|
||||||
<div className="relative flex items-center rounded-md bg-onboarding-background-200">
|
|
||||||
<Input
|
|
||||||
type={showPassword ? "text" : "password"}
|
|
||||||
name="confirm_password"
|
|
||||||
value={passwordFormData.confirm_password}
|
|
||||||
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
|
||||||
placeholder="Confirm password"
|
|
||||||
className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400"
|
|
||||||
/>
|
|
||||||
{showPassword ? (
|
|
||||||
<EyeOff
|
|
||||||
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
|
||||||
onClick={() => setShowPassword(false)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Eye
|
|
||||||
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
|
|
||||||
onClick={() => setShowPassword(true)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{!!passwordFormData.confirm_password && passwordFormData.password !== passwordFormData.confirm_password && (
|
|
||||||
<span className="text-sm text-red-500">Passwords don{"'"}t match</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="space-y-2.5">
|
|
||||||
{mode === EAuthModes.SIGN_IN ? (
|
|
||||||
<>
|
|
||||||
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
|
|
||||||
{isSmtpConfigured ? "Continue" : "Go to workspace"}
|
|
||||||
</Button>
|
|
||||||
{instance && isSmtpConfigured && (
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
onClick={redirectToUniqueCodeLogin}
|
|
||||||
variant="outline-primary"
|
|
||||||
className="w-full"
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
Sign in with unique code
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
|
|
||||||
Create account
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
)}
|
||||||
</>
|
<div className="space-y-2.5">
|
||||||
|
{mode === EAuthModes.SIGN_IN ? (
|
||||||
|
<>
|
||||||
|
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
|
||||||
|
{isSmtpConfigured ? "Continue" : "Go to workspace"}
|
||||||
|
</Button>
|
||||||
|
{instance && isSmtpConfigured && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={redirectToUniqueCodeLogin}
|
||||||
|
variant="outline-primary"
|
||||||
|
className="w-full"
|
||||||
|
size="lg"
|
||||||
|
>
|
||||||
|
Sign in with unique code
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
|
||||||
|
Create account
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,175 +1,68 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import isEmpty from "lodash/isEmpty";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// types
|
import { IEmailCheckData } from "@plane/types";
|
||||||
import { IEmailCheckData, IWorkspaceMemberInvitation } from "@plane/types";
|
|
||||||
// ui
|
|
||||||
import { Spinner, TOAST_TYPE, setToast } from "@plane/ui";
|
import { Spinner, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
|
AuthHeader,
|
||||||
|
AuthBanner,
|
||||||
AuthEmailForm,
|
AuthEmailForm,
|
||||||
AuthPasswordForm,
|
AuthPasswordForm,
|
||||||
OAuthOptions,
|
OAuthOptions,
|
||||||
TermsAndConditions,
|
TermsAndConditions,
|
||||||
UniqueCodeForm,
|
UniqueCodeForm,
|
||||||
} from "@/components/account";
|
} from "@/components/account";
|
||||||
import { WorkspaceLogo } from "@/components/workspace/logo";
|
// helpers
|
||||||
|
import {
|
||||||
|
EAuthModes,
|
||||||
|
EAuthSteps,
|
||||||
|
EAuthenticationErrorCodes,
|
||||||
|
EErrorAlertType,
|
||||||
|
TAuthErrorInfo,
|
||||||
|
authErrorHandler,
|
||||||
|
} from "@/helpers/authentication.helper";
|
||||||
|
// hooks
|
||||||
import { useInstance } from "@/hooks/store";
|
import { useInstance } from "@/hooks/store";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "@/services/auth.service";
|
import { AuthService } from "@/services/auth.service";
|
||||||
import { WorkspaceService } from "@/services/workspace.service";
|
|
||||||
|
|
||||||
const authService = new AuthService();
|
const authService = new AuthService();
|
||||||
const workSpaceService = new WorkspaceService();
|
|
||||||
|
|
||||||
export enum EAuthModes {
|
export const SignInAuthRoot = observer(() => {
|
||||||
SIGN_IN = "SIGN_IN",
|
|
||||||
SIGN_UP = "SIGN_UP",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum EAuthSteps {
|
|
||||||
EMAIL = "EMAIL",
|
|
||||||
PASSWORD = "PASSWORD",
|
|
||||||
UNIQUE_CODE = "UNIQUE_CODE",
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
mode: EAuthModes;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Titles = {
|
|
||||||
[EAuthModes.SIGN_IN]: {
|
|
||||||
[EAuthSteps.EMAIL]: {
|
|
||||||
header: "Sign in to Plane",
|
|
||||||
subHeader: "Get back to your projects and make progress",
|
|
||||||
},
|
|
||||||
[EAuthSteps.PASSWORD]: {
|
|
||||||
header: "Sign in to Plane",
|
|
||||||
subHeader: "Get back to your projects and make progress",
|
|
||||||
},
|
|
||||||
[EAuthSteps.UNIQUE_CODE]: {
|
|
||||||
header: "Sign in to Plane",
|
|
||||||
subHeader: "Get back to your projects and make progress",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[EAuthModes.SIGN_UP]: {
|
|
||||||
[EAuthSteps.EMAIL]: {
|
|
||||||
header: "Create your account",
|
|
||||||
subHeader: "Start tracking your projects with Plane",
|
|
||||||
},
|
|
||||||
[EAuthSteps.PASSWORD]: {
|
|
||||||
header: "Create your account",
|
|
||||||
subHeader: "Progress, visualize, and measure work how it works best for you.",
|
|
||||||
},
|
|
||||||
[EAuthSteps.UNIQUE_CODE]: {
|
|
||||||
header: "Create your account",
|
|
||||||
subHeader: "Progress, visualize, and measure work how it works best for you.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const getHeaderSubHeader = (
|
|
||||||
step: EAuthSteps,
|
|
||||||
mode: EAuthModes,
|
|
||||||
invitation?: IWorkspaceMemberInvitation | undefined,
|
|
||||||
email?: string
|
|
||||||
) => {
|
|
||||||
if (invitation && email && invitation.email === email && invitation.workspace) {
|
|
||||||
const workspace = invitation.workspace;
|
|
||||||
return {
|
|
||||||
header: (
|
|
||||||
<>
|
|
||||||
Join <WorkspaceLogo logo={workspace?.logo} name={workspace?.name} classNames="w-8 h-9" /> {workspace.name}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
subHeader: `${
|
|
||||||
mode == EAuthModes.SIGN_UP ? "Create an account" : "Sign in"
|
|
||||||
} to start managing work with your team.`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return Titles[mode][step];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SignInAuthRoot = observer((props: Props) => {
|
|
||||||
const { mode } = props;
|
|
||||||
//router
|
//router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { email: emailParam, invitation_id, slug: workspaceSlug } = router.query;
|
const { email: emailParam, invitation_id, slug: workspaceSlug, error_code, error_message } = router.query;
|
||||||
// states
|
// states
|
||||||
const [authStep, setAuthStep] = useState<EAuthSteps>(EAuthSteps.EMAIL);
|
const [authStep, setAuthStep] = useState<EAuthSteps>(EAuthSteps.EMAIL);
|
||||||
const [email, setEmail] = useState(emailParam ? emailParam.toString() : "");
|
const [email, setEmail] = useState(emailParam ? emailParam.toString() : "");
|
||||||
const [invitation, setInvitation] = useState<IWorkspaceMemberInvitation | undefined>(undefined);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined);
|
||||||
// hooks
|
// hooks
|
||||||
const { instance } = useInstance();
|
const { instance } = useInstance();
|
||||||
// derived values
|
// derived values
|
||||||
const isSmtpConfigured = instance?.config?.is_smtp_configured;
|
const authMode = EAuthModes.SIGN_IN;
|
||||||
|
|
||||||
const redirectToSignUp = (email: string) => {
|
|
||||||
if (isEmpty(email)) router.push({ pathname: "/", query: router.query });
|
|
||||||
else router.push({ pathname: "/", query: { ...router.query, email: email } });
|
|
||||||
};
|
|
||||||
|
|
||||||
const redirectToSignIn = (email: string) => {
|
|
||||||
if (isEmpty(email)) router.push({ pathname: "/accounts/sign-in", query: router.query });
|
|
||||||
else router.push({ pathname: "/accounts/sign-in", query: { ...router.query, email: email } });
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (invitation_id && workspaceSlug) {
|
if (error_code && error_message) {
|
||||||
setIsLoading(true);
|
const errorhandler = authErrorHandler(
|
||||||
workSpaceService
|
error_code?.toString() as EAuthenticationErrorCodes,
|
||||||
.getWorkspaceInvitation(workspaceSlug.toString(), invitation_id.toString())
|
error_message?.toString()
|
||||||
.then((res) => {
|
);
|
||||||
setInvitation(res);
|
if (errorhandler) setErrorInfo(errorhandler);
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setInvitation(undefined);
|
|
||||||
})
|
|
||||||
.finally(() => setIsLoading(false));
|
|
||||||
} else {
|
|
||||||
setInvitation(undefined);
|
|
||||||
}
|
}
|
||||||
}, [invitation_id, workspaceSlug]);
|
}, [error_code, error_message]);
|
||||||
|
|
||||||
const { header, subHeader } = getHeaderSubHeader(authStep, mode, invitation, email);
|
|
||||||
|
|
||||||
// step 1 submit handler- email verification
|
// step 1 submit handler- email verification
|
||||||
const handleEmailVerification = async (data: IEmailCheckData) => {
|
const handleEmailVerification = async (data: IEmailCheckData) => {
|
||||||
setEmail(data.email);
|
setEmail(data.email);
|
||||||
|
|
||||||
const emailCheck = mode === EAuthModes.SIGN_UP ? authService.signUpEmailCheck : authService.signInEmailCheck;
|
await authService
|
||||||
|
.signInEmailCheck(data)
|
||||||
await emailCheck(data)
|
.then(() => {
|
||||||
.then((res) => {
|
setAuthStep(EAuthSteps.PASSWORD);
|
||||||
if (mode === EAuthModes.SIGN_IN && !res.is_password_autoset) {
|
|
||||||
setAuthStep(EAuthSteps.PASSWORD);
|
|
||||||
} else {
|
|
||||||
if (isSmtpConfigured) {
|
|
||||||
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
|
||||||
} else {
|
|
||||||
if (mode === EAuthModes.SIGN_IN) {
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Error!",
|
|
||||||
message: "Unable to process request please contact Administrator to reset password",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setAuthStep(EAuthSteps.PASSWORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err?.error_code === "USER_DOES_NOT_EXIST") {
|
|
||||||
redirectToSignUp(data.email);
|
|
||||||
return;
|
|
||||||
} else if (err?.error_code === "USER_ALREADY_EXIST") {
|
|
||||||
redirectToSignIn(data.email);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
@ -190,13 +83,19 @@ export const SignInAuthRoot = observer((props: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mx-auto flex flex-col">
|
<div className="relative max-w-lg mx-auto flex flex-col space-y-6">
|
||||||
<div className="text-center space-y-1 py-4 mx-auto sm:w-96">
|
<AuthHeader
|
||||||
<h3 className="flex gap-4 justify-center text-3xl font-bold text-onboarding-text-100">{header}</h3>
|
workspaceSlug={workspaceSlug?.toString() || undefined}
|
||||||
<p className="font-medium text-onboarding-text-400">{subHeader}</p>
|
invitationId={invitation_id?.toString() || undefined}
|
||||||
</div>
|
invitationEmail={email || undefined}
|
||||||
|
authMode={EAuthModes.SIGN_IN}
|
||||||
|
currentAuthStep={authStep}
|
||||||
|
handleLoader={setIsLoading}
|
||||||
|
/>
|
||||||
|
{errorInfo && errorInfo?.type === EErrorAlertType.BANNER_ALERT && (
|
||||||
|
<AuthBanner bannerData={errorInfo} handleBannerData={(value) => setErrorInfo(value)} />
|
||||||
|
)}
|
||||||
{authStep === EAuthSteps.EMAIL && <AuthEmailForm defaultEmail={email} onSubmit={handleEmailVerification} />}
|
{authStep === EAuthSteps.EMAIL && <AuthEmailForm defaultEmail={email} onSubmit={handleEmailVerification} />}
|
||||||
|
|
||||||
{authStep === EAuthSteps.UNIQUE_CODE && (
|
{authStep === EAuthSteps.UNIQUE_CODE && (
|
||||||
<UniqueCodeForm
|
<UniqueCodeForm
|
||||||
email={email}
|
email={email}
|
||||||
@ -205,10 +104,9 @@ export const SignInAuthRoot = observer((props: Props) => {
|
|||||||
setAuthStep(EAuthSteps.EMAIL);
|
setAuthStep(EAuthSteps.EMAIL);
|
||||||
}}
|
}}
|
||||||
submitButtonText="Continue"
|
submitButtonText="Continue"
|
||||||
mode={mode}
|
mode={authMode}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{authStep === EAuthSteps.PASSWORD && (
|
{authStep === EAuthSteps.PASSWORD && (
|
||||||
<AuthPasswordForm
|
<AuthPasswordForm
|
||||||
email={email}
|
email={email}
|
||||||
@ -217,12 +115,12 @@ export const SignInAuthRoot = observer((props: Props) => {
|
|||||||
setAuthStep(EAuthSteps.EMAIL);
|
setAuthStep(EAuthSteps.EMAIL);
|
||||||
}}
|
}}
|
||||||
handleStepChange={(step) => setAuthStep(step)}
|
handleStepChange={(step) => setAuthStep(step)}
|
||||||
mode={mode}
|
mode={authMode}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{isOAuthEnabled && <OAuthOptions />}
|
||||||
|
<TermsAndConditions isSignUp={false} />
|
||||||
</div>
|
</div>
|
||||||
{isOAuthEnabled && <OAuthOptions />}
|
|
||||||
<TermsAndConditions isSignUp={mode === EAuthModes.SIGN_UP} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useEffect, useState } from "react";
|
||||||
import isEmpty from "lodash/isEmpty";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// types
|
// types
|
||||||
@ -17,7 +16,14 @@ import {
|
|||||||
UniqueCodeForm,
|
UniqueCodeForm,
|
||||||
} from "@/components/account";
|
} from "@/components/account";
|
||||||
// helpers
|
// helpers
|
||||||
import { EAuthModes, EAuthSteps, EErrorAlertType, TAuthErrorInfo } from "@/helpers/authentication.helper";
|
import {
|
||||||
|
EAuthModes,
|
||||||
|
EAuthSteps,
|
||||||
|
EAuthenticationErrorCodes,
|
||||||
|
EErrorAlertType,
|
||||||
|
TAuthErrorInfo,
|
||||||
|
authErrorHandler,
|
||||||
|
} from "@/helpers/authentication.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useInstance } from "@/hooks/store";
|
import { useInstance } from "@/hooks/store";
|
||||||
// services
|
// services
|
||||||
@ -29,7 +35,7 @@ const authService = new AuthService();
|
|||||||
export const SignUpAuthRoot: FC = observer(() => {
|
export const SignUpAuthRoot: FC = observer(() => {
|
||||||
//router
|
//router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { email: emailParam, invitation_id, slug: workspaceSlug } = router.query;
|
const { email: emailParam, invitation_id, slug: workspaceSlug, error_code, error_message } = router.query;
|
||||||
// states
|
// states
|
||||||
const [authStep, setAuthStep] = useState<EAuthSteps>(EAuthSteps.EMAIL);
|
const [authStep, setAuthStep] = useState<EAuthSteps>(EAuthSteps.EMAIL);
|
||||||
const [email, setEmail] = useState(emailParam ? emailParam.toString() : "");
|
const [email, setEmail] = useState(emailParam ? emailParam.toString() : "");
|
||||||
@ -41,12 +47,17 @@ export const SignUpAuthRoot: FC = observer(() => {
|
|||||||
const authMode = EAuthModes.SIGN_UP;
|
const authMode = EAuthModes.SIGN_UP;
|
||||||
const isSmtpConfigured = instance?.config?.is_smtp_configured;
|
const isSmtpConfigured = instance?.config?.is_smtp_configured;
|
||||||
|
|
||||||
// const redirectToSignUp = (email: string) => {
|
useEffect(() => {
|
||||||
// if (isEmpty(email)) router.push({ pathname: "/", query: router.query });
|
if (error_code && error_message) {
|
||||||
// else router.push({ pathname: "/", query: { ...router.query, email: email } });
|
const errorhandler = authErrorHandler(
|
||||||
// };
|
error_code?.toString() as EAuthenticationErrorCodes,
|
||||||
|
error_message?.toString()
|
||||||
|
);
|
||||||
|
if (errorhandler) setErrorInfo(errorhandler);
|
||||||
|
}
|
||||||
|
}, [error_code, error_message]);
|
||||||
|
|
||||||
// step 1 - email verification
|
// email verification
|
||||||
const handleEmailVerification = async (data: IEmailCheckData) => {
|
const handleEmailVerification = async (data: IEmailCheckData) => {
|
||||||
setEmail(data.email);
|
setEmail(data.email);
|
||||||
await authService
|
await authService
|
||||||
@ -55,12 +66,16 @@ export const SignUpAuthRoot: FC = observer(() => {
|
|||||||
if (isSmtpConfigured) setAuthStep(EAuthSteps.UNIQUE_CODE);
|
if (isSmtpConfigured) setAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||||
else setAuthStep(EAuthSteps.PASSWORD);
|
else setAuthStep(EAuthSteps.PASSWORD);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((error) => {
|
||||||
console.log("error", err);
|
const errorhandler = authErrorHandler(error?.error_code, error?.error_message);
|
||||||
|
if (errorhandler) {
|
||||||
|
setErrorInfo(errorhandler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error_message ?? "Something went wrong. Please try again.",
|
message: error?.error_message ?? "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -76,50 +91,43 @@ export const SignUpAuthRoot: FC = observer(() => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="relative max-w-lg mx-auto flex flex-col space-y-6">
|
||||||
<div className="relative max-w-lg mx-auto flex flex-col space-y-6">
|
<AuthHeader
|
||||||
<AuthHeader
|
workspaceSlug={workspaceSlug?.toString() || undefined}
|
||||||
workspaceSlug={workspaceSlug?.toString() || undefined}
|
invitationId={invitation_id?.toString() || undefined}
|
||||||
invitationId={invitation_id?.toString() || undefined}
|
invitationEmail={email || undefined}
|
||||||
invitationEmail={emailParam?.toString() || undefined}
|
authMode={EAuthModes.SIGN_UP}
|
||||||
authMode={EAuthModes.SIGN_UP}
|
currentAuthStep={authStep}
|
||||||
currentAuthStep={authStep}
|
handleLoader={setIsLoading}
|
||||||
handleLoader={setIsLoading}
|
/>
|
||||||
|
{errorInfo && errorInfo?.type === EErrorAlertType.BANNER_ALERT && (
|
||||||
|
<AuthBanner bannerData={errorInfo} handleBannerData={(value) => setErrorInfo(value)} />
|
||||||
|
)}
|
||||||
|
{authStep === EAuthSteps.EMAIL && <AuthEmailForm defaultEmail={email} onSubmit={handleEmailVerification} />}
|
||||||
|
{authStep === EAuthSteps.UNIQUE_CODE && (
|
||||||
|
<UniqueCodeForm
|
||||||
|
email={email}
|
||||||
|
handleEmailClear={() => {
|
||||||
|
setEmail("");
|
||||||
|
setAuthStep(EAuthSteps.EMAIL);
|
||||||
|
}}
|
||||||
|
submitButtonText="Continue"
|
||||||
|
mode={authMode}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{errorInfo && errorInfo?.type === EErrorAlertType.BANNER_ALERT && (
|
{authStep === EAuthSteps.PASSWORD && (
|
||||||
<AuthBanner bannerData={errorInfo} handleBannerData={(value) => setErrorInfo(value)} />
|
<AuthPasswordForm
|
||||||
)}
|
email={email}
|
||||||
|
handleEmailClear={() => {
|
||||||
{authStep === EAuthSteps.EMAIL && <AuthEmailForm defaultEmail={email} onSubmit={handleEmailVerification} />}
|
setEmail("");
|
||||||
|
setAuthStep(EAuthSteps.EMAIL);
|
||||||
{authStep === EAuthSteps.UNIQUE_CODE && (
|
}}
|
||||||
<UniqueCodeForm
|
handleStepChange={(step) => setAuthStep(step)}
|
||||||
email={email}
|
mode={authMode}
|
||||||
handleEmailClear={() => {
|
/>
|
||||||
setEmail("");
|
)}
|
||||||
setAuthStep(EAuthSteps.EMAIL);
|
{isOAuthEnabled && <OAuthOptions />}
|
||||||
}}
|
<TermsAndConditions isSignUp={authMode === EAuthModes.SIGN_UP} />
|
||||||
submitButtonText="Continue"
|
</div>
|
||||||
mode={authMode}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{authStep === EAuthSteps.PASSWORD && (
|
|
||||||
<AuthPasswordForm
|
|
||||||
email={email}
|
|
||||||
handleEmailClear={() => {
|
|
||||||
setEmail("");
|
|
||||||
setAuthStep(EAuthSteps.EMAIL);
|
|
||||||
}}
|
|
||||||
handleStepChange={(step) => setAuthStep(step)}
|
|
||||||
mode={authMode}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isOAuthEnabled && <OAuthOptions />}
|
|
||||||
<TermsAndConditions isSignUp={authMode === EAuthModes.SIGN_UP} />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { CircleCheck, XCircle } from "lucide-react";
|
import { CircleCheck, XCircle } from "lucide-react";
|
||||||
// types
|
|
||||||
import { IEmailCheckData } from "@plane/types";
|
import { IEmailCheckData } from "@plane/types";
|
||||||
// ui
|
|
||||||
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// constants
|
|
||||||
// helpers
|
// helpers
|
||||||
|
import { EAuthModes } from "@/helpers/authentication.helper";
|
||||||
import { API_BASE_URL } from "@/helpers/common.helper";
|
import { API_BASE_URL } from "@/helpers/common.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import useTimer from "@/hooks/use-timer";
|
import useTimer from "@/hooks/use-timer";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "@/services/auth.service";
|
import { AuthService } from "@/services/auth.service";
|
||||||
import { EAuthModes } from "./sign-up-root";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
email: string;
|
email: string;
|
||||||
|
@ -1,45 +1,43 @@
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// icons
|
import { Button } from "@plane/ui";
|
||||||
import { UserCog2 } from "lucide-react";
|
|
||||||
// ui
|
|
||||||
import { getButtonStyling } from "@plane/ui";
|
|
||||||
// images
|
// images
|
||||||
import instanceNotReady from "public/instance/plane-instance-not-ready.webp";
|
import PlaneBlackLogo from "@/public/plane-logos/black-horizontal-with-blue-logo.svg";
|
||||||
import PlaneBlackLogo from "public/plane-logos/black-horizontal-with-blue-logo.svg";
|
import PlaneWhiteLogo from "@/public/plane-logos/white-horizontal-with-blue-logo.svg";
|
||||||
import PlaneWhiteLogo from "public/plane-logos/white-horizontal-with-blue-logo.svg";
|
import PlaneTakeOffImage from "@/public/plane-takeoff.png";
|
||||||
|
|
||||||
type TInstanceNotReady = {
|
|
||||||
isGodModeEnabled: boolean;
|
|
||||||
handleGodModeStateChange?: (state: boolean) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InstanceNotReady: FC<TInstanceNotReady> = () => {
|
|
||||||
// const { isGodModeEnabled, handleGodModeStateChange } = props;
|
|
||||||
|
|
||||||
|
export const InstanceNotReady: FC = () => {
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
const planeLogo = resolvedTheme === "dark" ? PlaneWhiteLogo : PlaneBlackLogo;
|
const planeLogo = resolvedTheme === "dark" ? PlaneWhiteLogo : PlaneBlackLogo;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen w-full overflow-y-auto bg-onboarding-gradient-100">
|
<div className="relative h-screen max-h-max w-full overflow-hidden overflow-y-auto flex flex-col">
|
||||||
<div className="h-full w-full pt-24">
|
<div className="flex-shrink-0 h-[120px]">
|
||||||
<div className="mx-auto h-full rounded-t-md border-x border-t border-custom-border-100 bg-onboarding-gradient-100 px-4 pt-4 shadow-sm sm:w-4/5 md:w-2/3">
|
<div className="relative h-full container mx-auto px-5 lg:px-0 flex items-center justify-between gap-5 z-50">
|
||||||
<div className="relative h-full rounded-t-md bg-onboarding-gradient-200 px-7 sm:px-0">
|
<div className="flex items-center gap-x-2">
|
||||||
<div className="flex items-center justify-center py-10">
|
<Image src={planeLogo} className="h-[24px] w-full" alt="Plane logo" />
|
||||||
<Image src={planeLogo} className="h-[44px] w-full" alt="Plane logo" />
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex-grow">
|
||||||
|
<div className="h-full w-full relative container px-5 mx-auto flex justify-center items-center">
|
||||||
|
<div className="w-auto max-w-2xl relative space-y-8 py-10">
|
||||||
|
<div className="relative flex flex-col justify-center items-center space-y-4">
|
||||||
|
<h1 className="text-3xl font-bold pb-3">Welcome aboard Plane!</h1>
|
||||||
|
<Image src={PlaneTakeOffImage} alt="Plane Logo" />
|
||||||
|
<p className="font-medium text-base text-custom-text-400">
|
||||||
|
Get started by setting up your instance and workspace
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-20">
|
<div>
|
||||||
<Image src={instanceNotReady} className="w-full" alt="Instance not ready" />
|
<Link href={"/god-mode/"}>
|
||||||
</div>
|
<Button size="lg" className="w-full">
|
||||||
<div className="flex w-full flex-col items-center gap-5 py-12 pb-20">
|
Get started
|
||||||
<h3 className="text-2xl font-medium">Your Plane instance isn{"'"}t ready yet</h3>
|
</Button>
|
||||||
<p className="text-sm">Ask your Instance Admin to complete set-up first.</p>
|
</Link>
|
||||||
<a href="/god-mode" className={`${getButtonStyling("primary", "md")} mt-4`}>
|
|
||||||
<UserCog2 className="h-3.5 w-3.5" />
|
|
||||||
Get started
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,7 +46,10 @@ export enum EErrorAlertType {
|
|||||||
|
|
||||||
export type TAuthErrorInfo = { type: EErrorAlertType; message: string };
|
export type TAuthErrorInfo = { type: EErrorAlertType; message: string };
|
||||||
|
|
||||||
export const errorHandler = (errorType: EAuthenticationErrorCodes, errorMessage: string | undefined) => {
|
export const authErrorHandler = (
|
||||||
|
errorCode: EAuthenticationErrorCodes,
|
||||||
|
errorMessage: string | undefined
|
||||||
|
): TAuthErrorInfo | undefined => {
|
||||||
const toastAlertErrorCodes = [
|
const toastAlertErrorCodes = [
|
||||||
EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED,
|
EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED,
|
||||||
EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED,
|
EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED,
|
||||||
@ -66,43 +69,41 @@ export const errorHandler = (errorType: EAuthenticationErrorCodes, errorMessage:
|
|||||||
const inlineEmailCodeErrorCodes = [EAuthenticationErrorCodes.INLINE_EMAIL_CODE];
|
const inlineEmailCodeErrorCodes = [EAuthenticationErrorCodes.INLINE_EMAIL_CODE];
|
||||||
const inlinePasswordErrorCodes = [EAuthenticationErrorCodes.INLINE_PASSWORD];
|
const inlinePasswordErrorCodes = [EAuthenticationErrorCodes.INLINE_PASSWORD];
|
||||||
|
|
||||||
let errorPayload: TAuthErrorInfo | undefined = undefined;
|
if (toastAlertErrorCodes.includes(errorCode))
|
||||||
|
return {
|
||||||
if (toastAlertErrorCodes.includes(errorType))
|
|
||||||
errorPayload = {
|
|
||||||
type: EErrorAlertType.TOAST_ALERT,
|
type: EErrorAlertType.TOAST_ALERT,
|
||||||
message: errorMessage || "Something went wrong",
|
message: errorMessage || "Something went wrong. Please try again.",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (bannerAlertErrorCodes.includes(errorType))
|
if (bannerAlertErrorCodes.includes(errorCode))
|
||||||
errorPayload = {
|
return {
|
||||||
type: EErrorAlertType.BANNER_ALERT,
|
type: EErrorAlertType.BANNER_ALERT,
|
||||||
message: errorMessage || "Something went wrong",
|
message: errorMessage || "Something went wrong. Please try again.",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (inlineFirstNameErrorCodes.includes(errorType))
|
if (inlineFirstNameErrorCodes.includes(errorCode))
|
||||||
errorPayload = {
|
return {
|
||||||
type: EErrorAlertType.INLINE_FIRST_NAME,
|
type: EErrorAlertType.INLINE_FIRST_NAME,
|
||||||
message: errorMessage || "Something went wrong",
|
message: errorMessage || "Something went wrong. Please try again.",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (inlineEmailErrorCodes.includes(errorType))
|
if (inlineEmailErrorCodes.includes(errorCode))
|
||||||
errorPayload = {
|
return {
|
||||||
type: EErrorAlertType.INLINE_EMAIL,
|
type: EErrorAlertType.INLINE_EMAIL,
|
||||||
message: errorMessage || "Something went wrong",
|
message: errorMessage || "Something went wrong. Please try again.",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (inlinePasswordErrorCodes.includes(errorType))
|
if (inlinePasswordErrorCodes.includes(errorCode))
|
||||||
errorPayload = {
|
return {
|
||||||
type: EErrorAlertType.INLINE_PASSWORD,
|
type: EErrorAlertType.INLINE_PASSWORD,
|
||||||
message: errorMessage || "Something went wrong",
|
message: errorMessage || "Something went wrong. Please try again.",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (inlineEmailCodeErrorCodes.includes(errorType))
|
if (inlineEmailCodeErrorCodes.includes(errorCode))
|
||||||
errorPayload = {
|
return {
|
||||||
type: EErrorAlertType.INLINE_EMAIL_CODE,
|
type: EErrorAlertType.INLINE_EMAIL_CODE,
|
||||||
message: errorMessage || "Something went wrong",
|
message: errorMessage || "Something went wrong. Please try again.",
|
||||||
};
|
};
|
||||||
|
|
||||||
return errorPayload;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
@ -37,11 +37,8 @@ const InstanceWrapper: FC<TInstanceWrapper> = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
// checking if the instance is activated or not
|
|
||||||
if (error && !error?.data?.is_activated) return <InstanceNotReady isGodModeEnabled={false} />;
|
|
||||||
|
|
||||||
// instance is not ready and setup is not done
|
// instance is not ready and setup is not done
|
||||||
if (instance?.instance?.is_setup_done === false) return <InstanceNotReady isGodModeEnabled />;
|
if (instance?.instance?.is_setup_done === false) return <InstanceNotReady />;
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
});
|
});
|
||||||
|
BIN
web/public/plane-takeoff.png
Normal file
BIN
web/public/plane-takeoff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
@ -16,7 +16,6 @@ type TError = {
|
|||||||
export interface IInstanceStore {
|
export interface IInstanceStore {
|
||||||
// issues
|
// issues
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
instanceNotReady: any | undefined;
|
|
||||||
instance: IInstance | undefined;
|
instance: IInstance | undefined;
|
||||||
error: TError | undefined;
|
error: TError | undefined;
|
||||||
// action
|
// action
|
||||||
@ -25,7 +24,6 @@ export interface IInstanceStore {
|
|||||||
|
|
||||||
export class InstanceStore implements IInstanceStore {
|
export class InstanceStore implements IInstanceStore {
|
||||||
isLoading: boolean = true;
|
isLoading: boolean = true;
|
||||||
instanceNotReady: any | undefined = undefined;
|
|
||||||
instance: IInstance | undefined = undefined;
|
instance: IInstance | undefined = undefined;
|
||||||
error: TError | undefined = undefined;
|
error: TError | undefined = undefined;
|
||||||
// services
|
// services
|
||||||
@ -49,33 +47,13 @@ export class InstanceStore implements IInstanceStore {
|
|||||||
*/
|
*/
|
||||||
fetchInstanceInfo = async () => {
|
fetchInstanceInfo = async () => {
|
||||||
try {
|
try {
|
||||||
runInAction(() => {
|
this.isLoading = true;
|
||||||
this.isLoading = true;
|
this.error = undefined;
|
||||||
this.error = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
const instance = await this.instanceService.getInstanceInfo();
|
const instance = await this.instanceService.getInstanceInfo();
|
||||||
|
runInAction(() => {
|
||||||
const isInstanceNotSetup = (instance: IInstance) => "is_activated" in instance && "is_setup_done" in instance;
|
this.isLoading = false;
|
||||||
|
this.instance = instance;
|
||||||
if (isInstanceNotSetup(instance)) {
|
});
|
||||||
runInAction(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
this.error = {
|
|
||||||
status: "success",
|
|
||||||
message: "Instance is not created in the backend",
|
|
||||||
data: {
|
|
||||||
is_activated: instance?.instance?.is_activated,
|
|
||||||
is_setup_done: instance?.instance?.is_setup_done,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
runInAction(() => {
|
|
||||||
this.isLoading = false;
|
|
||||||
this.instance = instance;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user