mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: authentication views updated with new workflow (#4547)
* dev: update email check endpoint * fix: auth magic login check * chore: updated the error code handler and handled authentication workflow * dev: add magic link login --------- Co-authored-by: pablohashescobar <nikhilschacko@gmail.com> Co-authored-by: guru_sainath <gurusainath007@gmail.com>
This commit is contained in:
parent
509d5fe554
commit
9013497a5a
@ -2,13 +2,12 @@ from django.urls import path
|
|||||||
|
|
||||||
from .views import (
|
from .views import (
|
||||||
CSRFTokenEndpoint,
|
CSRFTokenEndpoint,
|
||||||
EmailCheckSignInEndpoint,
|
|
||||||
EmailCheckSignUpEndpoint,
|
|
||||||
ForgotPasswordEndpoint,
|
ForgotPasswordEndpoint,
|
||||||
SetUserPasswordEndpoint,
|
SetUserPasswordEndpoint,
|
||||||
ResetPasswordEndpoint,
|
ResetPasswordEndpoint,
|
||||||
ChangePasswordEndpoint,
|
ChangePasswordEndpoint,
|
||||||
# App
|
# App
|
||||||
|
EmailCheckEndpoint,
|
||||||
GitHubCallbackEndpoint,
|
GitHubCallbackEndpoint,
|
||||||
GitHubOauthInitiateEndpoint,
|
GitHubOauthInitiateEndpoint,
|
||||||
GoogleCallbackEndpoint,
|
GoogleCallbackEndpoint,
|
||||||
@ -22,7 +21,7 @@ from .views import (
|
|||||||
ForgotPasswordSpaceEndpoint,
|
ForgotPasswordSpaceEndpoint,
|
||||||
ResetPasswordSpaceEndpoint,
|
ResetPasswordSpaceEndpoint,
|
||||||
# Space
|
# Space
|
||||||
EmailCheckEndpoint,
|
EmailCheckSpaceEndpoint,
|
||||||
GitHubCallbackSpaceEndpoint,
|
GitHubCallbackSpaceEndpoint,
|
||||||
GitHubOauthInitiateSpaceEndpoint,
|
GitHubOauthInitiateSpaceEndpoint,
|
||||||
GoogleCallbackSpaceEndpoint,
|
GoogleCallbackSpaceEndpoint,
|
||||||
@ -154,18 +153,13 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
# Email Check
|
# Email Check
|
||||||
path(
|
path(
|
||||||
"sign-up/email-check/",
|
"email-check/",
|
||||||
EmailCheckSignUpEndpoint.as_view(),
|
EmailCheckEndpoint.as_view(),
|
||||||
name="email-check-sign-up",
|
name="email-check",
|
||||||
),
|
|
||||||
path(
|
|
||||||
"sign-in/email-check/",
|
|
||||||
EmailCheckSignInEndpoint.as_view(),
|
|
||||||
name="email-check-sign-in",
|
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"spaces/email-check/",
|
"spaces/email-check/",
|
||||||
EmailCheckEndpoint.as_view(),
|
EmailCheckSpaceEndpoint.as_view(),
|
||||||
name="email-check",
|
name="email-check",
|
||||||
),
|
),
|
||||||
# Password
|
# Password
|
||||||
|
@ -4,7 +4,7 @@ from .common import (
|
|||||||
SetUserPasswordEndpoint,
|
SetUserPasswordEndpoint,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .app.check import EmailCheckSignInEndpoint, EmailCheckSignUpEndpoint
|
from .app.check import EmailCheckEndpoint
|
||||||
|
|
||||||
from .app.email import (
|
from .app.email import (
|
||||||
SignInAuthEndpoint,
|
SignInAuthEndpoint,
|
||||||
@ -47,7 +47,7 @@ from .space.magic import (
|
|||||||
|
|
||||||
from .space.signout import SignOutAuthSpaceEndpoint
|
from .space.signout import SignOutAuthSpaceEndpoint
|
||||||
|
|
||||||
from .space.check import EmailCheckEndpoint
|
from .space.check import EmailCheckSpaceEndpoint
|
||||||
|
|
||||||
from .space.password_management import (
|
from .space.password_management import (
|
||||||
ForgotPasswordSpaceEndpoint,
|
ForgotPasswordSpaceEndpoint,
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
|
||||||
# Django imports
|
# Django imports
|
||||||
from django.core.validators import validate_email
|
from django.core.validators import validate_email
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@ -16,8 +19,12 @@ from plane.authentication.adapter.error import (
|
|||||||
AUTHENTICATION_ERROR_CODES,
|
AUTHENTICATION_ERROR_CODES,
|
||||||
)
|
)
|
||||||
from plane.authentication.rate_limit import AuthenticationThrottle
|
from plane.authentication.rate_limit import AuthenticationThrottle
|
||||||
|
from plane.license.utils.instance_value import (
|
||||||
|
get_configuration_value,
|
||||||
|
)
|
||||||
|
|
||||||
class EmailCheckSignUpEndpoint(APIView):
|
|
||||||
|
class EmailCheckEndpoint(APIView):
|
||||||
|
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
AllowAny,
|
AllowAny,
|
||||||
@ -28,128 +35,99 @@ class EmailCheckSignUpEndpoint(APIView):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
try:
|
|
||||||
# Check instance configuration
|
# Check instance configuration
|
||||||
instance = Instance.objects.first()
|
instance = Instance.objects.first()
|
||||||
if instance is None or not instance.is_setup_done:
|
if instance is None or not instance.is_setup_done:
|
||||||
raise AuthenticationException(
|
exc = AuthenticationException(
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[
|
error_code=AUTHENTICATION_ERROR_CODES[
|
||||||
"INSTANCE_NOT_CONFIGURED"
|
"INSTANCE_NOT_CONFIGURED"
|
||||||
],
|
],
|
||||||
error_message="INSTANCE_NOT_CONFIGURED",
|
error_message="INSTANCE_NOT_CONFIGURED",
|
||||||
)
|
)
|
||||||
|
return Response(
|
||||||
|
exc.get_error_dict(),
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
(EMAIL_HOST, ENABLE_MAGIC_LINK_LOGIN) = get_configuration_value(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "EMAIL_HOST",
|
||||||
|
"default": os.environ.get("EMAIL_HOST", ""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "ENABLE_MAGIC_LINK_LOGIN",
|
||||||
|
"default": os.environ.get("ENABLE_MAGIC_LINK_LOGIN", "1"),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
smtp_configured = bool(EMAIL_HOST)
|
||||||
|
is_magic_login_enabled = ENABLE_MAGIC_LINK_LOGIN == "1"
|
||||||
|
|
||||||
email = request.data.get("email", False)
|
email = request.data.get("email", False)
|
||||||
|
|
||||||
# Return error if email is not present
|
# Return error if email is not present
|
||||||
if not email:
|
if not email:
|
||||||
raise AuthenticationException(
|
exc = AuthenticationException(
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
|
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
|
||||||
error_message="EMAIL_REQUIRED",
|
error_message="EMAIL_REQUIRED",
|
||||||
)
|
)
|
||||||
|
return Response(
|
||||||
|
exc.get_error_dict(),
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
# Validate email
|
# Validate email
|
||||||
|
try:
|
||||||
validate_email(email)
|
validate_email(email)
|
||||||
|
|
||||||
existing_user = User.objects.filter(email=email).first()
|
|
||||||
|
|
||||||
if existing_user:
|
|
||||||
# check if the account is the deactivated
|
|
||||||
if not existing_user.is_active:
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[
|
|
||||||
"USER_ACCOUNT_DEACTIVATED"
|
|
||||||
],
|
|
||||||
error_message="USER_ACCOUNT_DEACTIVATED",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Raise user already exist
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[
|
|
||||||
"USER_ALREADY_EXIST"
|
|
||||||
],
|
|
||||||
error_message="USER_ALREADY_EXIST",
|
|
||||||
)
|
|
||||||
return Response(
|
|
||||||
{"status": True},
|
|
||||||
status=status.HTTP_200_OK,
|
|
||||||
)
|
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
raise AuthenticationException(
|
exc = AuthenticationException(
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
|
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
|
||||||
error_message="INVALID_EMAIL",
|
error_message="INVALID_EMAIL",
|
||||||
)
|
)
|
||||||
except AuthenticationException as e:
|
|
||||||
return Response(
|
return Response(
|
||||||
e.get_error_dict(), status=status.HTTP_400_BAD_REQUEST
|
exc.get_error_dict(),
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
)
|
)
|
||||||
|
# Check if a user already exists with the given email
|
||||||
|
|
||||||
class EmailCheckSignInEndpoint(APIView):
|
|
||||||
|
|
||||||
permission_classes = [
|
|
||||||
AllowAny,
|
|
||||||
]
|
|
||||||
|
|
||||||
throttle_classes = [
|
|
||||||
AuthenticationThrottle,
|
|
||||||
]
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
try:
|
|
||||||
# Check instance configuration
|
|
||||||
instance = Instance.objects.first()
|
|
||||||
if instance is None or not instance.is_setup_done:
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[
|
|
||||||
"INSTANCE_NOT_CONFIGURED"
|
|
||||||
],
|
|
||||||
error_message="INSTANCE_NOT_CONFIGURED",
|
|
||||||
)
|
|
||||||
|
|
||||||
email = request.data.get("email", False)
|
|
||||||
|
|
||||||
# Return error if email is not present
|
|
||||||
if not email:
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["EMAIL_REQUIRED"],
|
|
||||||
error_message="EMAIL_REQUIRED",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Validate email
|
|
||||||
validate_email(email)
|
|
||||||
|
|
||||||
existing_user = User.objects.filter(email=email).first()
|
existing_user = User.objects.filter(email=email).first()
|
||||||
|
|
||||||
# If existing user
|
# If existing user
|
||||||
if existing_user:
|
if existing_user:
|
||||||
# Raise different exception when user is not active
|
|
||||||
if not existing_user.is_active:
|
if not existing_user.is_active:
|
||||||
raise AuthenticationException(
|
exc = AuthenticationException(
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[
|
error_code=AUTHENTICATION_ERROR_CODES[
|
||||||
"USER_ACCOUNT_DEACTIVATED"
|
"USER_ACCOUNT_DEACTIVATED"
|
||||||
],
|
],
|
||||||
error_message="USER_ACCOUNT_DEACTIVATED",
|
error_message="USER_ACCOUNT_DEACTIVATED",
|
||||||
)
|
)
|
||||||
# Return true
|
return Response(
|
||||||
|
exc.get_error_dict(), status=status.HTTP_400_BAD_REQUEST
|
||||||
|
)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
"status": True,
|
"existing": True,
|
||||||
"is_password_autoset": existing_user.is_password_autoset,
|
"status": (
|
||||||
|
"MAGIC_CODE"
|
||||||
|
if existing_user.is_password_autoset
|
||||||
|
and smtp_configured
|
||||||
|
and is_magic_login_enabled
|
||||||
|
else "CREDENTIAL"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
|
# Else return response
|
||||||
# Raise error
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["USER_DOES_NOT_EXIST"],
|
|
||||||
error_message="USER_DOES_NOT_EXIST",
|
|
||||||
)
|
|
||||||
except ValidationError:
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
|
|
||||||
error_message="INVALID_EMAIL",
|
|
||||||
)
|
|
||||||
except AuthenticationException as e:
|
|
||||||
return Response(
|
return Response(
|
||||||
e.get_error_dict(), status=status.HTTP_400_BAD_REQUEST
|
{
|
||||||
|
"existing": False,
|
||||||
|
"status": (
|
||||||
|
"MAGIC_CODE"
|
||||||
|
if smtp_configured and is_magic_login_enabled
|
||||||
|
else "CREDENTIAL"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
|
||||||
# Django imports
|
# Django imports
|
||||||
from django.core.validators import validate_email
|
from django.core.validators import validate_email
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@ -16,8 +19,10 @@ from plane.authentication.adapter.error import (
|
|||||||
AuthenticationException,
|
AuthenticationException,
|
||||||
)
|
)
|
||||||
from plane.authentication.rate_limit import AuthenticationThrottle
|
from plane.authentication.rate_limit import AuthenticationThrottle
|
||||||
|
from plane.license.utils.instance_value import get_configuration_value
|
||||||
|
|
||||||
class EmailCheckEndpoint(APIView):
|
|
||||||
|
class EmailCheckSpaceEndpoint(APIView):
|
||||||
|
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
AllowAny,
|
AllowAny,
|
||||||
@ -42,6 +47,22 @@ class EmailCheckEndpoint(APIView):
|
|||||||
status=status.HTTP_400_BAD_REQUEST,
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(EMAIL_HOST, ENABLE_MAGIC_LINK_LOGIN) = get_configuration_value(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "EMAIL_HOST",
|
||||||
|
"default": os.environ.get("EMAIL_HOST", ""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "ENABLE_MAGIC_LINK_LOGIN",
|
||||||
|
"default": os.environ.get("ENABLE_MAGIC_LINK_LOGIN", "1"),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
smtp_configured = bool(EMAIL_HOST)
|
||||||
|
is_magic_login_enabled = ENABLE_MAGIC_LINK_LOGIN == "1"
|
||||||
|
|
||||||
email = request.data.get("email", False)
|
email = request.data.get("email", False)
|
||||||
|
|
||||||
# Return error if email is not present
|
# Return error if email is not present
|
||||||
@ -86,12 +107,25 @@ class EmailCheckEndpoint(APIView):
|
|||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
"existing": True,
|
"existing": True,
|
||||||
"is_password_autoset": existing_user.is_password_autoset,
|
"status": (
|
||||||
|
"MAGIC_CODE"
|
||||||
|
if existing_user.is_password_autoset
|
||||||
|
and smtp_configured
|
||||||
|
and is_magic_login_enabled
|
||||||
|
else "CREDENTIAL"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
# Else return response
|
# Else return response
|
||||||
return Response(
|
return Response(
|
||||||
{"existing": False, "is_password_autoset": False},
|
{
|
||||||
|
"existing": False,
|
||||||
|
"status": (
|
||||||
|
"MAGIC_CODE"
|
||||||
|
if smtp_configured and is_magic_login_enabled
|
||||||
|
else "CREDENTIAL"
|
||||||
|
),
|
||||||
|
},
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
|
3
packages/types/src/auth.d.ts
vendored
3
packages/types/src/auth.d.ts
vendored
@ -5,8 +5,7 @@ export interface IEmailCheckData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IEmailCheckResponse {
|
export interface IEmailCheckResponse {
|
||||||
is_password_autoset: boolean;
|
status: "MAGIC_CODE" | "CREDENTIAL";
|
||||||
status: boolean;
|
|
||||||
existing: boolean;
|
existing: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,30 +21,30 @@ type TAuthHeader = {
|
|||||||
const Titles = {
|
const Titles = {
|
||||||
[EAuthModes.SIGN_IN]: {
|
[EAuthModes.SIGN_IN]: {
|
||||||
[EAuthSteps.EMAIL]: {
|
[EAuthSteps.EMAIL]: {
|
||||||
header: "Sign in to Plane",
|
header: "Log in or sign up",
|
||||||
subHeader: "Get back to your projects and make progress",
|
subHeader: "",
|
||||||
},
|
},
|
||||||
[EAuthSteps.PASSWORD]: {
|
[EAuthSteps.PASSWORD]: {
|
||||||
header: "Sign in to Plane",
|
header: "Log in or sign up",
|
||||||
subHeader: "Get back to your projects and make progress",
|
subHeader: "Log in using your password.",
|
||||||
},
|
},
|
||||||
[EAuthSteps.UNIQUE_CODE]: {
|
[EAuthSteps.UNIQUE_CODE]: {
|
||||||
header: "Sign in to Plane",
|
header: "Log in or sign up",
|
||||||
subHeader: "Get back to your projects and make progress",
|
subHeader: "Log in using your unique code.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[EAuthModes.SIGN_UP]: {
|
[EAuthModes.SIGN_UP]: {
|
||||||
[EAuthSteps.EMAIL]: {
|
[EAuthSteps.EMAIL]: {
|
||||||
header: "Create your account",
|
header: "Sign up or log in",
|
||||||
subHeader: "Start tracking your projects with Plane",
|
subHeader: "",
|
||||||
},
|
},
|
||||||
[EAuthSteps.PASSWORD]: {
|
[EAuthSteps.PASSWORD]: {
|
||||||
header: "Create your account",
|
header: "Sign up or log in",
|
||||||
subHeader: "Progress, visualize, and measure work how it works best for you.",
|
subHeader: "Sign up using your password",
|
||||||
},
|
},
|
||||||
[EAuthSteps.UNIQUE_CODE]: {
|
[EAuthSteps.UNIQUE_CODE]: {
|
||||||
header: "Create your account",
|
header: "Sign up or log in",
|
||||||
subHeader: "Progress, visualize, and measure work how it works best for you.",
|
subHeader: "Sign up using your unique code",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -37,67 +37,83 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { email: emailParam, invitation_id, slug: workspaceSlug, error_code } = router.query;
|
const { email: emailParam, invitation_id, slug: workspaceSlug, error_code } = router.query;
|
||||||
// props
|
// props
|
||||||
const { authMode } = props;
|
const { authMode: currentAuthMode } = props;
|
||||||
// states
|
// states
|
||||||
|
const [authMode, setAuthMode] = useState<EAuthModes | undefined>(undefined);
|
||||||
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 [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined);
|
const [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined);
|
||||||
const [isPasswordAutoset, setIsPasswordAutoset] = useState(true);
|
|
||||||
// hooks
|
// hooks
|
||||||
const { config } = useInstance();
|
const { config } = useInstance();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (error_code) {
|
if (!authMode && currentAuthMode) setAuthMode(currentAuthMode);
|
||||||
|
}, [currentAuthMode, authMode]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (error_code && authMode) {
|
||||||
const errorhandler = authErrorHandler(error_code?.toString() as EAuthenticationErrorCodes);
|
const errorhandler = authErrorHandler(error_code?.toString() as EAuthenticationErrorCodes);
|
||||||
if (errorhandler) {
|
if (errorhandler) {
|
||||||
if (
|
// password error handler
|
||||||
[
|
if ([EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP].includes(errorhandler.code)) {
|
||||||
EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN,
|
setAuthMode(EAuthModes.SIGN_UP);
|
||||||
EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP,
|
|
||||||
].includes(errorhandler.code)
|
|
||||||
)
|
|
||||||
setAuthStep(EAuthSteps.PASSWORD);
|
setAuthStep(EAuthSteps.PASSWORD);
|
||||||
|
}
|
||||||
|
if ([EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN].includes(errorhandler.code)) {
|
||||||
|
setAuthMode(EAuthModes.SIGN_IN);
|
||||||
|
setAuthStep(EAuthSteps.PASSWORD);
|
||||||
|
}
|
||||||
|
// magic_code error handler
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
|
EAuthenticationErrorCodes.INVALID_MAGIC_CODE_SIGN_UP,
|
||||||
EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP,
|
EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP,
|
||||||
EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN,
|
|
||||||
EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP,
|
EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP,
|
||||||
EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN,
|
|
||||||
EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP,
|
EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP,
|
||||||
].includes(errorhandler.code)
|
].includes(errorhandler.code)
|
||||||
)
|
) {
|
||||||
|
setAuthMode(EAuthModes.SIGN_UP);
|
||||||
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
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,
|
||||||
|
].includes(errorhandler.code)
|
||||||
|
) {
|
||||||
|
setAuthMode(EAuthModes.SIGN_IN);
|
||||||
|
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
setErrorInfo(errorhandler);
|
setErrorInfo(errorhandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [error_code, authMode]);
|
}, [error_code, authMode]);
|
||||||
|
|
||||||
const isSMTPConfigured = config?.is_smtp_configured || false;
|
const isSMTPConfigured = config?.is_smtp_configured || false;
|
||||||
const isMagicLoginEnabled = config?.is_magic_login_enabled || false;
|
|
||||||
const isEmailPasswordEnabled = config?.is_email_password_enabled || false;
|
|
||||||
|
|
||||||
// submit handler- email verification
|
// submit handler- email verification
|
||||||
const handleEmailVerification = async (data: IEmailCheckData) => {
|
const handleEmailVerification = async (data: IEmailCheckData) => {
|
||||||
setEmail(data.email);
|
setEmail(data.email);
|
||||||
const emailCheckRequest =
|
await authService
|
||||||
authMode === EAuthModes.SIGN_IN ? authService.signInEmailCheck(data) : authService.signUpEmailCheck(data);
|
.emailCheck(data)
|
||||||
|
|
||||||
await emailCheckRequest
|
|
||||||
.then(async (response) => {
|
.then(async (response) => {
|
||||||
if (authMode === EAuthModes.SIGN_IN) {
|
if (response.existing) {
|
||||||
if (response.is_password_autoset) {
|
if (currentAuthMode === EAuthModes.SIGN_UP) setAuthMode(EAuthModes.SIGN_IN);
|
||||||
|
if (response.status === "MAGIC_CODE") {
|
||||||
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||||
generateEmailUniqueCode(data.email);
|
generateEmailUniqueCode(data.email);
|
||||||
} else if (isEmailPasswordEnabled) {
|
} else if (response.status === "CREDENTIAL") {
|
||||||
setIsPasswordAutoset(false);
|
|
||||||
setAuthStep(EAuthSteps.PASSWORD);
|
setAuthStep(EAuthSteps.PASSWORD);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isSMTPConfigured && isMagicLoginEnabled) {
|
if (currentAuthMode === EAuthModes.SIGN_IN) setAuthMode(EAuthModes.SIGN_UP);
|
||||||
|
if (response.status === "MAGIC_CODE") {
|
||||||
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
setAuthStep(EAuthSteps.UNIQUE_CODE);
|
||||||
generateEmailUniqueCode(data.email);
|
generateEmailUniqueCode(data.email);
|
||||||
} else if (isEmailPasswordEnabled) {
|
} else if (response.status === "CREDENTIAL") {
|
||||||
setAuthStep(EAuthSteps.PASSWORD);
|
setAuthStep(EAuthSteps.PASSWORD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,8 +124,17 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEmailClear = () => {
|
||||||
|
setAuthMode(currentAuthMode);
|
||||||
|
setErrorInfo(undefined);
|
||||||
|
setEmail("");
|
||||||
|
setAuthStep(EAuthSteps.EMAIL);
|
||||||
|
router.push(currentAuthMode === EAuthModes.SIGN_IN ? `/` : "/sign-up", undefined, { shallow: true });
|
||||||
|
};
|
||||||
|
|
||||||
// generating the unique code
|
// generating the unique code
|
||||||
const generateEmailUniqueCode = async (email: string): Promise<{ code: string } | undefined> => {
|
const generateEmailUniqueCode = async (email: string): Promise<{ code: string } | undefined> => {
|
||||||
|
if (!isSMTPConfigured) return;
|
||||||
const payload = { email: email };
|
const payload = { email: email };
|
||||||
return await authService
|
return await authService
|
||||||
.generateUniqueCode(payload)
|
.generateUniqueCode(payload)
|
||||||
@ -121,6 +146,7 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!authMode) return <></>;
|
||||||
return (
|
return (
|
||||||
<div className="relative flex flex-col space-y-6">
|
<div className="relative flex flex-col space-y-6">
|
||||||
<AuthHeader
|
<AuthHeader
|
||||||
@ -138,23 +164,16 @@ export const AuthRoot: FC<TAuthRoot> = observer((props) => {
|
|||||||
<AuthUniqueCodeForm
|
<AuthUniqueCodeForm
|
||||||
mode={authMode}
|
mode={authMode}
|
||||||
email={email}
|
email={email}
|
||||||
handleEmailClear={() => {
|
handleEmailClear={handleEmailClear}
|
||||||
setEmail("");
|
|
||||||
setAuthStep(EAuthSteps.EMAIL);
|
|
||||||
}}
|
|
||||||
generateEmailUniqueCode={generateEmailUniqueCode}
|
generateEmailUniqueCode={generateEmailUniqueCode}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{authStep === EAuthSteps.PASSWORD && (
|
{authStep === EAuthSteps.PASSWORD && (
|
||||||
<AuthPasswordForm
|
<AuthPasswordForm
|
||||||
mode={authMode}
|
mode={authMode}
|
||||||
isPasswordAutoset={isPasswordAutoset}
|
|
||||||
isSMTPConfigured={isSMTPConfigured}
|
isSMTPConfigured={isSMTPConfigured}
|
||||||
email={email}
|
email={email}
|
||||||
handleEmailClear={() => {
|
handleEmailClear={handleEmailClear}
|
||||||
setEmail("");
|
|
||||||
setAuthStep(EAuthSteps.EMAIL);
|
|
||||||
}}
|
|
||||||
handleAuthStep={(step: EAuthSteps) => {
|
handleAuthStep={(step: EAuthSteps) => {
|
||||||
if (step === EAuthSteps.UNIQUE_CODE) generateEmailUniqueCode(email);
|
if (step === EAuthSteps.UNIQUE_CODE) generateEmailUniqueCode(email);
|
||||||
setAuthStep(step);
|
setAuthStep(step);
|
||||||
|
@ -57,7 +57,7 @@ export const AuthEmailForm: FC<TAuthEmailForm> = observer((props) => {
|
|||||||
type="email"
|
type="email"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder="name@company.com"
|
placeholder="name@example.com"
|
||||||
className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 autofill:bg-red-500 border-0 focus:bg-none active:bg-transparent`}
|
className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 autofill:bg-red-500 border-0 focus:bg-none active:bg-transparent`}
|
||||||
onFocus={() => setFocused(true)}
|
onFocus={() => setFocused(true)}
|
||||||
onBlur={() => setFocused(false)}
|
onBlur={() => setFocused(false)}
|
||||||
|
@ -20,7 +20,6 @@ import { AuthService } from "@/services/auth.service";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
email: string;
|
email: string;
|
||||||
isPasswordAutoset: boolean;
|
|
||||||
isSMTPConfigured: boolean;
|
isSMTPConfigured: boolean;
|
||||||
mode: EAuthModes;
|
mode: EAuthModes;
|
||||||
handleEmailClear: () => void;
|
handleEmailClear: () => void;
|
||||||
|
@ -8,8 +8,7 @@ type TOAuthOptionProps = {
|
|||||||
isSignUp?: boolean;
|
isSignUp?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OAuthOptions: React.FC<TOAuthOptionProps> = observer((props) => {
|
export const OAuthOptions: React.FC<TOAuthOptionProps> = observer(() => {
|
||||||
const { isSignUp = false } = props;
|
|
||||||
// hooks
|
// hooks
|
||||||
const { config } = useInstance();
|
const { config } = useInstance();
|
||||||
|
|
||||||
@ -17,8 +16,6 @@ export const OAuthOptions: React.FC<TOAuthOptionProps> = observer((props) => {
|
|||||||
|
|
||||||
if (!isOAuthEnabled) return null;
|
if (!isOAuthEnabled) return null;
|
||||||
|
|
||||||
const oauthProviderButtonText = `Sign ${isSignUp ? "up" : "in"} with`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mt-4 flex items-center">
|
<div className="mt-4 flex items-center">
|
||||||
@ -29,10 +26,10 @@ export const OAuthOptions: React.FC<TOAuthOptionProps> = observer((props) => {
|
|||||||
<div className={`mt-7 grid gap-4 overflow-hidden`}>
|
<div className={`mt-7 grid gap-4 overflow-hidden`}>
|
||||||
{config?.is_google_enabled && (
|
{config?.is_google_enabled && (
|
||||||
<div className="flex h-[42px] items-center !overflow-hidden">
|
<div className="flex h-[42px] items-center !overflow-hidden">
|
||||||
<GoogleOAuthButton text={`${oauthProviderButtonText} Google`} />
|
<GoogleOAuthButton text="Continue with Google" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{config?.is_github_enabled && <GithubOAuthButton text={`${oauthProviderButtonText} Github`} />}
|
{config?.is_github_enabled && <GithubOAuthButton text="Continue with Github" />}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -34,6 +34,9 @@ export enum EAuthenticationErrorCodes {
|
|||||||
INVALID_EMAIL = "5005",
|
INVALID_EMAIL = "5005",
|
||||||
EMAIL_REQUIRED = "5010",
|
EMAIL_REQUIRED = "5010",
|
||||||
SIGNUP_DISABLED = "5015",
|
SIGNUP_DISABLED = "5015",
|
||||||
|
MAGIC_LINK_LOGIN_DISABLED = "5016",
|
||||||
|
PASSWORD_LOGIN_DISABLED = "5018",
|
||||||
|
USER_ACCOUNT_DEACTIVATED = "5019",
|
||||||
// Password strength
|
// Password strength
|
||||||
INVALID_PASSWORD = "5020",
|
INVALID_PASSWORD = "5020",
|
||||||
SMTP_NOT_CONFIGURED = "5025",
|
SMTP_NOT_CONFIGURED = "5025",
|
||||||
@ -45,7 +48,6 @@ export enum EAuthenticationErrorCodes {
|
|||||||
INVALID_EMAIL_MAGIC_SIGN_UP = "5050",
|
INVALID_EMAIL_MAGIC_SIGN_UP = "5050",
|
||||||
MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED = "5055",
|
MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED = "5055",
|
||||||
// Sign In
|
// Sign In
|
||||||
USER_ACCOUNT_DEACTIVATED = "5019",
|
|
||||||
USER_DOES_NOT_EXIST = "5060",
|
USER_DOES_NOT_EXIST = "5060",
|
||||||
AUTHENTICATION_FAILED_SIGN_IN = "5065",
|
AUTHENTICATION_FAILED_SIGN_IN = "5065",
|
||||||
REQUIRED_EMAIL_PASSWORD_SIGN_IN = "5070",
|
REQUIRED_EMAIL_PASSWORD_SIGN_IN = "5070",
|
||||||
@ -82,6 +84,9 @@ export enum EAuthenticationErrorCodes {
|
|||||||
ADMIN_AUTHENTICATION_FAILED = "5175",
|
ADMIN_AUTHENTICATION_FAILED = "5175",
|
||||||
ADMIN_USER_ALREADY_EXIST = "5180",
|
ADMIN_USER_ALREADY_EXIST = "5180",
|
||||||
ADMIN_USER_DOES_NOT_EXIST = "5185",
|
ADMIN_USER_DOES_NOT_EXIST = "5185",
|
||||||
|
ADMIN_USER_DEACTIVATED = "5190",
|
||||||
|
// Rate limit
|
||||||
|
RATE_LIMIT_EXCEEDED = "5900",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TAuthErrorInfo = {
|
export type TAuthErrorInfo = {
|
||||||
@ -99,10 +104,30 @@ const errorCodeMessages: {
|
|||||||
title: `Instance not configured`,
|
title: `Instance not configured`,
|
||||||
message: () => `Instance not configured. Please contact your administrator.`,
|
message: () => `Instance not configured. Please contact your administrator.`,
|
||||||
},
|
},
|
||||||
|
[EAuthenticationErrorCodes.INVALID_EMAIL]: {
|
||||||
|
title: `Invalid email`,
|
||||||
|
message: () => `Invalid email. Please try again.`,
|
||||||
|
},
|
||||||
|
[EAuthenticationErrorCodes.EMAIL_REQUIRED]: {
|
||||||
|
title: `Email required`,
|
||||||
|
message: () => `Email required. Please try again.`,
|
||||||
|
},
|
||||||
[EAuthenticationErrorCodes.SIGNUP_DISABLED]: {
|
[EAuthenticationErrorCodes.SIGNUP_DISABLED]: {
|
||||||
title: `Sign up disabled`,
|
title: `Sign up disabled`,
|
||||||
message: () => `Sign up disabled. Please contact your administrator.`,
|
message: () => `Sign up disabled. Please contact your administrator.`,
|
||||||
},
|
},
|
||||||
|
[EAuthenticationErrorCodes.MAGIC_LINK_LOGIN_DISABLED]: {
|
||||||
|
title: `Magic link login disabled`,
|
||||||
|
message: () => `Magic link login disabled. Please contact your administrator.`,
|
||||||
|
},
|
||||||
|
[EAuthenticationErrorCodes.PASSWORD_LOGIN_DISABLED]: {
|
||||||
|
title: `Password login disabled`,
|
||||||
|
message: () => `Password login disabled. Please contact your administrator.`,
|
||||||
|
},
|
||||||
|
[EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
|
||||||
|
title: `User account deactivated`,
|
||||||
|
message: () => `User account deactivated. Please contact your administrator.`,
|
||||||
|
},
|
||||||
[EAuthenticationErrorCodes.INVALID_PASSWORD]: {
|
[EAuthenticationErrorCodes.INVALID_PASSWORD]: {
|
||||||
title: `Invalid password`,
|
title: `Invalid password`,
|
||||||
message: () => `Invalid password. Please try again.`,
|
message: () => `Invalid password. Please try again.`,
|
||||||
@ -112,16 +137,6 @@ const errorCodeMessages: {
|
|||||||
message: () => `SMTP not configured. Please contact your administrator.`,
|
message: () => `SMTP not configured. Please contact your administrator.`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// email check in both sign up and sign in
|
|
||||||
[EAuthenticationErrorCodes.INVALID_EMAIL]: {
|
|
||||||
title: `Invalid email`,
|
|
||||||
message: () => `Invalid email. Please try again.`,
|
|
||||||
},
|
|
||||||
[EAuthenticationErrorCodes.EMAIL_REQUIRED]: {
|
|
||||||
title: `Email required`,
|
|
||||||
message: () => `Email required. Please try again.`,
|
|
||||||
},
|
|
||||||
|
|
||||||
// sign up
|
// sign up
|
||||||
[EAuthenticationErrorCodes.USER_ALREADY_EXIST]: {
|
[EAuthenticationErrorCodes.USER_ALREADY_EXIST]: {
|
||||||
title: `User already exists`,
|
title: `User already exists`,
|
||||||
@ -159,12 +174,6 @@ const errorCodeMessages: {
|
|||||||
message: () => `Invalid email. Please try again.`,
|
message: () => `Invalid email. Please try again.`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// sign in
|
|
||||||
[EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
|
|
||||||
title: `User account deactivated`,
|
|
||||||
message: () => <div>Your account is deactivated. Contact support@plane.so.</div>,
|
|
||||||
},
|
|
||||||
|
|
||||||
[EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: {
|
[EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: {
|
||||||
title: `User does not exist`,
|
title: `User does not exist`,
|
||||||
message: (email = undefined) => (
|
message: (email = undefined) => (
|
||||||
@ -324,6 +333,14 @@ const errorCodeMessages: {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
[EAuthenticationErrorCodes.ADMIN_USER_DEACTIVATED]: {
|
||||||
|
title: `Admin user deactivated`,
|
||||||
|
message: () => <div>Your account is deactivated</div>,
|
||||||
|
},
|
||||||
|
[EAuthenticationErrorCodes.RATE_LIMIT_EXCEEDED]: {
|
||||||
|
title: "",
|
||||||
|
message: () => `Rate limit exceeded. Please try again later.`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const authErrorHandler = (
|
export const authErrorHandler = (
|
||||||
@ -335,6 +352,9 @@ export const authErrorHandler = (
|
|||||||
EAuthenticationErrorCodes.INVALID_EMAIL,
|
EAuthenticationErrorCodes.INVALID_EMAIL,
|
||||||
EAuthenticationErrorCodes.EMAIL_REQUIRED,
|
EAuthenticationErrorCodes.EMAIL_REQUIRED,
|
||||||
EAuthenticationErrorCodes.SIGNUP_DISABLED,
|
EAuthenticationErrorCodes.SIGNUP_DISABLED,
|
||||||
|
EAuthenticationErrorCodes.MAGIC_LINK_LOGIN_DISABLED,
|
||||||
|
EAuthenticationErrorCodes.PASSWORD_LOGIN_DISABLED,
|
||||||
|
EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED,
|
||||||
EAuthenticationErrorCodes.INVALID_PASSWORD,
|
EAuthenticationErrorCodes.INVALID_PASSWORD,
|
||||||
EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED,
|
EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED,
|
||||||
EAuthenticationErrorCodes.USER_ALREADY_EXIST,
|
EAuthenticationErrorCodes.USER_ALREADY_EXIST,
|
||||||
@ -362,6 +382,7 @@ export const authErrorHandler = (
|
|||||||
EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN,
|
EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN,
|
||||||
EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN,
|
EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN,
|
||||||
EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD,
|
EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD,
|
||||||
|
EAuthenticationErrorCodes.MISSING_PASSWORD,
|
||||||
EAuthenticationErrorCodes.INVALID_NEW_PASSWORD,
|
EAuthenticationErrorCodes.INVALID_NEW_PASSWORD,
|
||||||
EAuthenticationErrorCodes.PASSWORD_ALREADY_SET,
|
EAuthenticationErrorCodes.PASSWORD_ALREADY_SET,
|
||||||
EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST,
|
EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST,
|
||||||
@ -372,7 +393,8 @@ export const authErrorHandler = (
|
|||||||
EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED,
|
EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED,
|
||||||
EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST,
|
EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST,
|
||||||
EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
|
EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
|
||||||
EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED,
|
EAuthenticationErrorCodes.ADMIN_USER_DEACTIVATED,
|
||||||
|
EAuthenticationErrorCodes.RATE_LIMIT_EXCEEDED,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (bannerAlertErrorCodes.includes(errorCode))
|
if (bannerAlertErrorCodes.includes(errorCode))
|
||||||
|
@ -34,6 +34,11 @@ const nextConfig = {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
source: "/accounts/sign-up",
|
source: "/accounts/sign-up",
|
||||||
|
destination: "/sign-up",
|
||||||
|
permanent: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: "/sign-in",
|
||||||
destination: "/",
|
destination: "/",
|
||||||
permanent: true
|
permanent: true
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { useTheme } from "next-themes";
|
|||||||
import { AuthRoot } from "@/components/account";
|
import { AuthRoot } from "@/components/account";
|
||||||
import { PageHead } from "@/components/core";
|
import { PageHead } from "@/components/core";
|
||||||
// constants
|
// constants
|
||||||
import { NAVIGATE_TO_SIGNIN } from "@/constants/event-tracker";
|
import { NAVIGATE_TO_SIGNUP } from "@/constants/event-tracker";
|
||||||
// helpers
|
// helpers
|
||||||
import { EAuthModes, EPageTypes } from "@/helpers/authentication.helper";
|
import { EAuthModes, EPageTypes } from "@/helpers/authentication.helper";
|
||||||
// hooks
|
// hooks
|
||||||
@ -31,7 +31,7 @@ const HomePage: NextPageWithLayout = observer(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-screen h-screen overflow-hidden">
|
<div className="relative w-screen h-screen overflow-hidden">
|
||||||
<PageHead title="Sign Up" />
|
<PageHead title="Log in to continue" />
|
||||||
<div className="absolute inset-0 z-0">
|
<div className="absolute inset-0 z-0">
|
||||||
<Image
|
<Image
|
||||||
src={resolvedTheme === "dark" ? PlaneBackgroundPatternDark : PlaneBackgroundPattern}
|
src={resolvedTheme === "dark" ? PlaneBackgroundPatternDark : PlaneBackgroundPattern}
|
||||||
@ -46,18 +46,18 @@ const HomePage: NextPageWithLayout = observer(() => {
|
|||||||
<span className="text-2xl font-semibold sm:text-3xl">Plane</span>
|
<span className="text-2xl font-semibold sm:text-3xl">Plane</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-end sm:items-center sm:gap-2 sm:flex-row text-center text-sm font-medium text-onboarding-text-300">
|
<div className="flex flex-col items-end sm:items-center sm:gap-2 sm:flex-row text-center text-sm font-medium text-onboarding-text-300">
|
||||||
Already have an account?{" "}
|
New to Plane?{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/sign-in"
|
href="/sign-up"
|
||||||
onClick={() => captureEvent(NAVIGATE_TO_SIGNIN, {})}
|
onClick={() => captureEvent(NAVIGATE_TO_SIGNUP, {})}
|
||||||
className="font-semibold text-custom-primary-100 hover:underline"
|
className="font-semibold text-custom-primary-100 hover:underline"
|
||||||
>
|
>
|
||||||
Sign In
|
Create an account
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow container mx-auto max-w-lg px-10 lg:max-w-md lg:px-5 py-10 lg:pt-28 transition-all">
|
<div className="flex-grow container mx-auto max-w-lg px-10 lg:max-w-md lg:px-5 py-10 lg:pt-28 transition-all">
|
||||||
<AuthRoot authMode={EAuthModes.SIGN_UP} />
|
<AuthRoot authMode={EAuthModes.SIGN_IN} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@ import { useTheme } from "next-themes";
|
|||||||
import { AuthRoot } from "@/components/account";
|
import { AuthRoot } from "@/components/account";
|
||||||
import { PageHead } from "@/components/core";
|
import { PageHead } from "@/components/core";
|
||||||
// constants
|
// constants
|
||||||
import { NAVIGATE_TO_SIGNUP } from "@/constants/event-tracker";
|
import { NAVIGATE_TO_SIGNIN } from "@/constants/event-tracker";
|
||||||
// helpers
|
// helpers
|
||||||
import { EAuthModes, EPageTypes } from "@/helpers/authentication.helper";
|
import { EAuthModes, EPageTypes } from "@/helpers/authentication.helper";
|
||||||
// hooks
|
// hooks
|
||||||
@ -48,18 +48,18 @@ const SignInPage: NextPageWithLayout = observer(() => {
|
|||||||
<span className="text-2xl font-semibold sm:text-3xl">Plane</span>
|
<span className="text-2xl font-semibold sm:text-3xl">Plane</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-end sm:items-center sm:gap-2 sm:flex-row text-center text-sm font-medium text-onboarding-text-300">
|
<div className="flex flex-col items-end sm:items-center sm:gap-2 sm:flex-row text-center text-sm font-medium text-onboarding-text-300">
|
||||||
New to Plane?{" "}
|
Already have an account?{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
onClick={() => captureEvent(NAVIGATE_TO_SIGNUP, {})}
|
onClick={() => captureEvent(NAVIGATE_TO_SIGNIN, {})}
|
||||||
className="font-semibold text-custom-primary-100 hover:underline"
|
className="font-semibold text-custom-primary-100 hover:underline"
|
||||||
>
|
>
|
||||||
Create an account
|
Log in
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow container mx-auto max-w-lg px-10 lg:max-w-md lg:px-5 py-10 lg:pt-28 transition-all">
|
<div className="flex-grow container mx-auto max-w-lg px-10 lg:max-w-md lg:px-5 py-10 lg:pt-28 transition-all">
|
||||||
<AuthRoot authMode={EAuthModes.SIGN_IN} />
|
<AuthRoot authMode={EAuthModes.SIGN_UP} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -18,15 +18,8 @@ export class AuthService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
signUpEmailCheck = async (data: IEmailCheckData): Promise<IEmailCheckResponse> =>
|
emailCheck = async (data: IEmailCheckData): Promise<IEmailCheckResponse> =>
|
||||||
this.post("/auth/sign-up/email-check/", data, { headers: {} })
|
this.post("/auth/email-check/", data, { headers: {} })
|
||||||
.then((response) => response?.data)
|
|
||||||
.catch((error) => {
|
|
||||||
throw error?.response?.data;
|
|
||||||
});
|
|
||||||
|
|
||||||
signInEmailCheck = async (data: IEmailCheckData): Promise<IEmailCheckResponse> =>
|
|
||||||
this.post("/auth/sign-in/email-check/", data, { headers: {} })
|
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
|
Loading…
Reference in New Issue
Block a user