diff --git a/src/app/i18n/locales/de.json b/src/app/i18n/locales/de.json index b22ba8deaa..a24474fdb4 100644 --- a/src/app/i18n/locales/de.json +++ b/src/app/i18n/locales/de.json @@ -83,15 +83,20 @@ "title": "Anmelden", "forgotPwd": "Haben Sie Ihr Passwort vergessen?", "dontHaveAccount": "Sie haben kein Konto?", + "dontHaveAccountMobile": "Sie haben kein Internxt-Konto?", "createAccount": "Konto erstellen", "2FA": "Zwei-Faktor-Code", "twoFactorAuthenticationCode": "Zwei-Faktor-Authentifizierungscode", "wrongLogin": "Ungültiger Benutzername oder Passwort", "failedToSendAuthData": "Fehler beim Senden der Authentifizierungsdaten. Bitte versuchen Sie es erneut." }, + "button": { + "loginAction": "Anmelden" + }, "signup": { "title": "Konto erstellen", "haveAccount": "Haben Sie bereits ein Konto?", + "haveAccountMobile": "Haben Sie bereits ein Internxt-Konto?", "login": "Anmelden", "encrypting": "Verschlüsselung im Gange", "info": { diff --git a/src/app/i18n/locales/en.json b/src/app/i18n/locales/en.json index 10465c8282..a76f386ebe 100644 --- a/src/app/i18n/locales/en.json +++ b/src/app/i18n/locales/en.json @@ -101,19 +101,24 @@ "terms2": "you accept the terms & conditions", "decrypting": "Decrypting...", "login": { - "title": "Log in", + "title": "Login", "forgotPwd": "Forgot your password?", - "dontHaveAccount": "Don’t have an account?", + "dontHaveAccount": "Don't have an account?", + "dontHaveAccountMobile": "Don't have an Internxt account?", "createAccount": "Create account", "2FA": "Two factor code", "twoFactorAuthenticationCode": "Two factor authentication code", "wrongLogin": "Invalid username or password", "failedToSendAuthData": "Failed to send authentication data. Please try again." }, + "button": { + "loginAction": "Log in" + }, "signup": { "title": "Create account", "haveAccount": "Already have an account?", - "login": "Log in", + "haveAccountMobile": "Already have an Internxt account?", + "login": "Login", "encrypting": "Encrypting", "info": { "normalText": "Internxt doesn’t store passwords.", @@ -244,7 +249,7 @@ }, "title": { "signUp": "Create an account", - "signIn": "Log in", + "signIn": "Login", "userIsSignedIn": "User signed in as" }, "emailMustNotBeEmpty": "Email must not be empty", diff --git a/src/app/i18n/locales/es.json b/src/app/i18n/locales/es.json index ca0c96ed54..3d38f03105 100644 --- a/src/app/i18n/locales/es.json +++ b/src/app/i18n/locales/es.json @@ -83,15 +83,20 @@ "title": "Iniciar Sesión", "forgotPwd": "¿Olvidaste tu contraseña?", "dontHaveAccount": "¿No tienes cuenta?", + "dontHaveAccountMobile": "¿No tienes cuenta de Internxt?", "createAccount": "Crear cuenta", "2FA": "Código de dos factores", "twoFactorAuthenticationCode": "Código de autenticación de dos factores", "wrongLogin": "Nombre de usuario o contraseña no válidos", "failedToSendAuthData": "Error al enviar datos de autenticación. Por favor, inténtalo de nuevo." }, + "button": { + "loginAction": "Iniciar sesión" + }, "signup": { "title": "Crear cuenta", "haveAccount": "¿Ya tienes una cuenta?", + "haveAccountMobile": "¿Ya tienes una cuenta de Internxt?", "login": "Iniciar sesión", "encrypting": "Cifrando", "info": { diff --git a/src/app/i18n/locales/fr.json b/src/app/i18n/locales/fr.json index 26faa6331a..4c05922941 100644 --- a/src/app/i18n/locales/fr.json +++ b/src/app/i18n/locales/fr.json @@ -83,15 +83,20 @@ "title": " Connexion ", "forgotPwd": "Mot de passe oublié?", "dontHaveAccount": "Vous n'avez pas de compte ?", + "dontHaveAccountMobile": "Vous n'avez pas de compte Internxt ?", "createAccount": "Créer un compte", "2FA": "Code à deux facteurs", "twoFactorAuthenticationCode": "Code d'authentification à deux facteurs", "wrongLogin": "Nom d'utilisateur ou mot de passe invalide", "failedToSendAuthData": "Échec de l'envoi des données d'authentification. Veuillez réessayer." }, + "button": { + "loginAction": "Se connecter" + }, "signup": { "title": "Créer un compte", "haveAccount": "Vous avez déjà un compte ?", + "haveAccountMobile": "Vous avez déjà un compte Internxt ?", "login": " Connexion ", "encrypting": "Encryptant", "info": { diff --git a/src/app/i18n/locales/it.json b/src/app/i18n/locales/it.json index 40ad67861e..2aaa139db4 100644 --- a/src/app/i18n/locales/it.json +++ b/src/app/i18n/locales/it.json @@ -104,15 +104,20 @@ "title": "Accedere", "forgotPwd": "Hai dimenticato la password?", "dontHaveAccount": "Non hai un account?", + "dontHaveAccountMobile": "Non hai un account Internxt?", "createAccount": "Creare un account", "2FA": "Codice a due fattori", "twoFactorAuthenticationCode": "Codice di autenticazione a due fattori", "wrongLogin": "Nome utente o password non validi", "failedToSendAuthData": "Impossibile inviare i dati di autenticazione. Riprova." }, + "button": { + "loginAction": "Accedi" + }, "signup": { "title": "Creare un account", "haveAccount": "Hai già un account?", + "haveAccountMobile": "Hai già un account Internxt?", "login": "Accedi", "encrypting": "Crittografia in corso", "info": { diff --git a/src/app/i18n/locales/ru.json b/src/app/i18n/locales/ru.json index a15c66cf0b..b5197f3087 100644 --- a/src/app/i18n/locales/ru.json +++ b/src/app/i18n/locales/ru.json @@ -83,15 +83,20 @@ "title": "Войти", "forgotPwd": "Забыли пароль?", "dontHaveAccount": "У вас нет учетной записи?", + "dontHaveAccountMobile": "У вас нет учетной записи Internxt?", "createAccount": "Создать учетную запись", "2FA": "Двухфакторный код", "twoFactorAuthenticationCode": "Код двухфакторной аутентификации", "wrongLogin": "Неверное имя пользователя или пароль", "failedToSendAuthData": "Не удалось отправить данные аутентификации. Пожалуйста, попробуйте еще раз." }, + "button": { + "loginAction": "Войти" + }, "signup": { "title": "Создать учетную запись", "haveAccount": "Уже есть аккаунт?", + "haveAccountMobile": "Уже есть аккаунт Internxt?", "login": "Войти", "encrypting": "Идет шифрование", "info": { diff --git a/src/app/i18n/locales/tw.json b/src/app/i18n/locales/tw.json index e65d08a474..41d3201328 100644 --- a/src/app/i18n/locales/tw.json +++ b/src/app/i18n/locales/tw.json @@ -103,15 +103,20 @@ "title": "登錄", "forgotPwd": "忘記密碼?", "dontHaveAccount": "沒有帳戶?", + "dontHaveAccountMobile": "沒有 Internxt 帳戶?", "createAccount": "創建帳戶", "2FA": "雙重身份驗證代碼", "twoFactorAuthenticationCode": "雙重身份驗證代碼", "wrongLogin": "使用者名稱或密碼無效", "failedToSendAuthData": "無法發送身份驗證數據。請重試。" }, + "button": { + "loginAction": "登錄" + }, "signup": { "title": "創建帳戶", "haveAccount": "已有帳戶?", + "haveAccountMobile": "已有 Internxt 帳戶?", "login": "登錄", "encrypting": "加密中", "info": { diff --git a/src/app/i18n/locales/zh.json b/src/app/i18n/locales/zh.json index e3cb6af9b9..e6cc7677eb 100644 --- a/src/app/i18n/locales/zh.json +++ b/src/app/i18n/locales/zh.json @@ -101,15 +101,20 @@ "title": "登录", "forgotPwd": "忘记密码了?", "dontHaveAccount": "没有账户?", + "dontHaveAccountMobile": "没有 Internxt 账户?", "createAccount": "创建账户", "2FA": "双因素代码", "twoFactorAuthenticationCode": "双因素验证码", "wrongLogin": "用户名或密码无效", "failedToSendAuthData": "发送身份验证数据失败。请重试。" }, + "button": { + "loginAction": "登录" + }, "signup": { "title": "创建账户", "haveAccount": "已有账户?", + "haveAccountMobile": "已有 Internxt 账户?", "login": "登录", "encrypting": "加密中", "info": { diff --git a/src/index.scss b/src/index.scss index 65a3b40fff..ac63ca8fd0 100644 --- a/src/index.scss +++ b/src/index.scss @@ -393,3 +393,21 @@ abbr[title] { .text-ellipsis { text-overflow: ellipsis; } + +@media (width <= 639px) { + .bg-login-gradient { + background: linear-gradient(180deg, rgb(249 249 252 / 0%) 0%, #f9f9fc 100%); + } + + .dark .bg-login-gradient { + background: linear-gradient(180deg, #1c1c1c 0%, #031632 100%); + } +} + +.auth-footer-link { + @apply font-medium text-base no-underline text-primary hover:text-primary-dark; + + @media (width >= 640px) { + @apply text-gray-80 hover:text-gray-100; + } +} diff --git a/src/views/Login/RecoveryLinkView.tsx b/src/views/Login/RecoveryLinkView.tsx index dc331fcba8..8acf1407b7 100644 --- a/src/views/Login/RecoveryLinkView.tsx +++ b/src/views/Login/RecoveryLinkView.tsx @@ -5,7 +5,7 @@ import { RecoveryLink } from './components'; function RecoveryLinkView(): JSX.Element { const { translate } = useTranslationContext(); return ( -
+
@@ -14,11 +14,11 @@ function RecoveryLinkView(): JSX.Element {
-
- +
+ {translate('general.terms')} - + {translate('general.help')}
diff --git a/src/views/Login/SignInView.tsx b/src/views/Login/SignInView.tsx index 7ea49a85da..f6107da983 100644 --- a/src/views/Login/SignInView.tsx +++ b/src/views/Login/SignInView.tsx @@ -8,10 +8,9 @@ interface SignInProps { export default function SignInView(props: Readonly): JSX.Element { const { translate } = useTranslationContext(); + return ( -
+
{!props.displayIframe && (
@@ -23,19 +22,11 @@ export default function SignInView(props: Readonly): JSX.Element {
{!props.displayIframe && ( -
- + diff --git a/src/views/Login/components/LogIn.tsx b/src/views/Login/components/LogIn.tsx index 768f46ee16..3b949aba56 100644 --- a/src/views/Login/components/LogIn.tsx +++ b/src/views/Login/components/LogIn.tsx @@ -6,26 +6,26 @@ import { SubmitHandler, useForm, useWatch } from 'react-hook-form'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; -import localStorageService from 'services/local-storage.service'; -import { twoFactorRegexPattern } from 'services/validation.service'; import { RootState } from 'app/store'; import { useAppDispatch } from 'app/store/hooks'; import { userActions } from 'app/store/slices/user'; import authService, { authenticateUser, is2FANeeded } from 'services/auth.service'; +import localStorageService from 'services/local-storage.service'; +import { twoFactorRegexPattern } from 'services/validation.service'; import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings'; import { Button } from '@internxt/ui'; import { WarningCircle } from '@phosphor-icons/react'; -import { useOAuthFlow } from 'views/Login/hooks/useOAuthFlow'; -import { errorService, navigationService, workspacesService, envService, vpnAuthService } from 'services'; import AppError, { AppView, IFormValues } from 'app/core/types'; import { useTranslationContext } from 'app/i18n/provider/TranslationProvider'; import notificationsService, { ToastType } from 'app/notifications/services/notifications.service'; -import useLoginRedirections from '../hooks/useLoginRedirections'; import shareService from 'app/share/services/share.service'; import PasswordInput from 'components/PasswordInput'; import TextInput from 'components/TextInput'; +import { envService, errorService, navigationService, vpnAuthService, workspacesService } from 'services'; import { AuthMethodTypes } from 'views/Checkout/types'; +import { useOAuthFlow } from 'views/Login/hooks/useOAuthFlow'; +import useLoginRedirections from '../hooks/useLoginRedirections'; const showNotification = ({ text, isError }: { text: string; isError: boolean }) => { notificationsService.show({ @@ -272,7 +272,7 @@ export default function LogIn(): JSX.Element { variant="primary" disabled={isLoggingIn} > - {isLoggingIn && isValid ? translate('auth.decrypting') : translate('auth.login.title')} + {isLoggingIn && isValid ? translate('auth.decrypting') : translate('auth.button.loginAction')} @@ -288,7 +288,8 @@ export default function LogIn(): JSX.Element {
-
+ {/* Desktop: link style */} +
{translate('auth.login.dontHaveAccount')}
+ + {/* Mobile: button style */} +
+

{translate('auth.login.dontHaveAccountMobile')}

+ + + +
); diff --git a/src/views/Signup/SignupView.tsx b/src/views/Signup/SignupView.tsx index c199626de1..07f248608b 100644 --- a/src/views/Signup/SignupView.tsx +++ b/src/views/Signup/SignupView.tsx @@ -20,9 +20,7 @@ export default function SignUpView(props: Readonly): JSX.Elemen const isRegularSignup = !props.displayIframe && !autoSubmit.enabled; return ( -
+
{isRegularSignup && (
@@ -34,15 +32,11 @@ export default function SignUpView(props: Readonly): JSX.Elemen
{isRegularSignup && ( -
- + diff --git a/src/views/Signup/components/SignupForm.tsx b/src/views/Signup/components/SignupForm.tsx index cd4e7a6d67..f9b11a3bf2 100644 --- a/src/views/Signup/components/SignupForm.tsx +++ b/src/views/Signup/components/SignupForm.tsx @@ -6,22 +6,22 @@ import { SubmitHandler, useForm, useWatch } from 'react-hook-form'; import { Link } from 'react-router-dom'; import PasswordFieldWithInfo from './PasswordFieldWithInfo'; +import testPasswordStrength from '@internxt/lib/dist/src/auth/testPasswordStrength'; +import { Button } from '@internxt/ui'; +import { AppView, IFormValues } from 'app/core/types'; +import { useTranslationContext } from 'app/i18n/provider/TranslationProvider'; import { useAppDispatch } from 'app/store/hooks'; import { planThunks } from 'app/store/slices/plan'; -import { errorService, navigationService, envService, localStorageService } from 'services'; -import { AppView, IFormValues } from 'app/core/types'; import TextInput from 'components/TextInput'; -import testPasswordStrength from '@internxt/lib/dist/src/auth/testPasswordStrength'; -import { useSignUp } from '../hooks/useSignup'; -import { useTranslationContext } from 'app/i18n/provider/TranslationProvider'; +import { MAX_PASSWORD_LENGTH } from 'components/ValidPassword'; +import { envService, errorService, localStorageService, navigationService } from 'services'; import authService, { authenticateUser } from 'services/auth.service'; -import PreparingWorkspaceAnimation from '../../../components/PreparingWorkspaceAnimation'; +import vpnAuthService from 'services/vpnAuth.service'; import { paymentService } from 'views/Checkout/services'; -import { MAX_PASSWORD_LENGTH } from 'components/ValidPassword'; -import { Button } from '@internxt/ui'; import { AuthMethodTypes } from 'views/Checkout/types'; -import vpnAuthService from 'services/vpnAuth.service'; import { useOAuthFlow } from 'views/Login/hooks/useOAuthFlow'; +import PreparingWorkspaceAnimation from '../../../components/PreparingWorkspaceAnimation'; +import { useSignUp } from '../hooks/useSignup'; export interface SignUpProps { location: { @@ -291,13 +291,27 @@ function SignUpForm(): JSX.Element {
-
+ {/* Desktop: link style */} +
{translate('auth.signup.haveAccount')} - {translate('auth.signup.login')} + {translate('auth.button.loginAction')} + +
+ + {/* Mobile: button style */} +
+

{translate('auth.signup.haveAccountMobile')}

+ +
diff --git a/test/e2e/tests/helper/staticData.ts b/test/e2e/tests/helper/staticData.ts index d8eb8a0056..9f46d4be0f 100644 --- a/test/e2e/tests/helper/staticData.ts +++ b/test/e2e/tests/helper/staticData.ts @@ -23,12 +23,13 @@ export const staticData = { termsOfServiceTitle: 'Terms of Service', needHelpTitle: 'How can we help you?', howToCreateBackUpKeyPageTitle: 'How do I create a backup key?', - logInPageTitle: 'Log in', + logInPageTitle: 'Login', + logInButtonText: 'Log in', userAlreadyRegistered: 'already registered', accountRecovery: 'Account recovery', wrongLoginWarning: 'Wrong login credentials', - dontHaveAccountText: 'Don’t have an account?', + dontHaveAccountText: "Don't have an account?", createAccountText: 'Create account', termsAndConditionsLinkText: 'Terms and conditions', youAcceptTermsLinkText: 'you accept the terms & conditions', diff --git a/test/e2e/tests/pages/loginPage.ts b/test/e2e/tests/pages/loginPage.ts index a1944b5679..7e6d054346 100644 --- a/test/e2e/tests/pages/loginPage.ts +++ b/test/e2e/tests/pages/loginPage.ts @@ -23,14 +23,14 @@ export class LoginPage { constructor(page: Page) { this.page = page; - this.loginTitle = this.page.getByRole('heading', { name: 'Log in' }); + this.loginTitle = this.page.getByRole('heading', { name: 'Login' }); this.emailInput = this.page.getByPlaceholder('Email', { exact: true }); this.passwordInput = this.page.getByPlaceholder('Password', { exact: true }); this.loginButton = this.page.getByRole('button', { name: 'Log in' }); this.loginButtonText = this.page.locator('[data-cy="loginButton"] div'); this.forgotPassword = this.page.getByText('Forgot your password?'); - this.dontHaveAccountText = this.page.getByText('Don’t have an account?'); - this.createAccount = this.page.getByText('Create account'); + this.dontHaveAccountText = this.page.getByText(/Don.t have an account\?/).first(); + this.createAccount = this.page.getByRole('link', { name: 'Create account' }); this.termsAndConditions = this.page.getByRole('link', { name: 'Terms and conditions' }); this.needHelp = this.page.getByRole('link', { name: 'Need help?' }); this.wrongCredentials = this.page.locator('[class="flex flex-row items-start pt-1"] span'); @@ -94,7 +94,7 @@ export class LoginPage { const createAccountText = await this.createAccount.textContent({ timeout: 10000, }); - expect(dontHaveAccountText).toEqual('Don’t have an account?'); + expect(dontHaveAccountText).toEqual("Don't have an account?"); expect(createAccountText).toEqual('Create account'); await expect(this.createAccount).toBeEnabled(); await this.createAccount.click(); diff --git a/test/e2e/tests/pages/signUpPage.ts b/test/e2e/tests/pages/signUpPage.ts index de69e63feb..f45b018dc7 100644 --- a/test/e2e/tests/pages/signUpPage.ts +++ b/test/e2e/tests/pages/signUpPage.ts @@ -30,10 +30,10 @@ export class SignUpPage { this.passwordWarning = this.page.locator('[class="pt-1"] p'); this.disclaimer = this.page.locator('[class$="pr-4 dark:bg-primary/20"] p'); this.learnMoreLinkText = this.page.getByRole('link', { name: 'Learn more' }); - this.createAccountButton = this.page.getByRole('button', { name: 'Create account' }); - this.createAccountButtonText = this.page.locator('[class$="justify-center space-x-2"]'); + this.createAccountButton = this.page.getByRole('button', { name: 'Create account' }).first(); + this.createAccountButtonText = this.page.getByRole('button', { name: 'Create account' }).first().locator('div'); this.byCreatingYourAccountText = this.page.locator('[class="mt-2 w-full text-xs text-gray-50"]'); - this.alreadyHaveAccountText = this.page.locator('[class$="space-x-1.5 font-medium"] span'); + this.alreadyHaveAccountText = this.page.getByText('Already have an account?').first(); this.logIn = this.page.getByRole('link', { name: 'Log in' }); this.termsAndConditions = this.page.getByRole('link', { name: 'you accept the terms & conditions' }); this.needHelp = this.page.getByRole('link', { name: 'Need help?' }); diff --git a/test/e2e/tests/specs/internxt-signup.spec.ts b/test/e2e/tests/specs/internxt-signup.spec.ts index 8a17fca331..4917278ce9 100644 --- a/test/e2e/tests/specs/internxt-signup.spec.ts +++ b/test/e2e/tests/specs/internxt-signup.spec.ts @@ -1,8 +1,8 @@ import { faker } from '@faker-js/faker'; import { expect, Request, Route, test } from '@playwright/test'; +import { getUser, getUserCredentials } from '../helper/getUser'; import { staticData } from '../helper/staticData'; import { SignUpPage } from '../pages/signUpPage'; -import { getUser, getUserCredentials } from '../helper/getUser'; const BASE_API_URL = process.env.REACT_APP_DRIVE_NEW_API_URL; const credentialsFile = getUserCredentials(); @@ -97,13 +97,11 @@ test.describe('Internxt SignUp', async () => { expect(termsOfServiceTitle).toEqual(staticData.termsOfServiceTitle); }); - test('TC7: Validate that the user is redirected to the “Log in” page after clicking on “Log in”', async ({ - page, - }) => { + test('TC7: Validate that the user is redirected to the “Login” page after clicking on “Log in”', async ({ page }) => { const SignupPage = new SignUpPage(page); const { logInText, logInTitle } = await SignupPage.clickOnLogIn(); - expect(logInText).toEqual(staticData.logInPageTitle); + expect(logInText).toEqual(staticData.logInButtonText); expect(logInTitle).toEqual(staticData.logInPageTitle); });