diff --git a/src/layouts/app/pages/SignUp/images/facebook-icon.svg b/src/layouts/app/pages/SignUp/images/facebook-icon.svg new file mode 100644 index 00000000..6681697f --- /dev/null +++ b/src/layouts/app/pages/SignUp/images/facebook-icon.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/layouts/app/pages/SignUp/images/google-icon.svg b/src/layouts/app/pages/SignUp/images/google-icon.svg new file mode 100644 index 00000000..b26d4a45 --- /dev/null +++ b/src/layouts/app/pages/SignUp/images/google-icon.svg @@ -0,0 +1,28 @@ + + + + + Google-color + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/layouts/app/pages/SignUp/index.js b/src/layouts/app/pages/SignUp/index.js new file mode 100644 index 00000000..5289868a --- /dev/null +++ b/src/layouts/app/pages/SignUp/index.js @@ -0,0 +1,270 @@ +import { Component } from 'pet-dex-utilities'; + +import './index.scss'; + +import TextInput from '../../../../components/TextInput'; +import Button from '../../../../components/Button'; +import googleIcon from './images/google-icon.svg'; +import facebookIcon from './images/facebook-icon.svg'; + +const events = ['signUp']; + +const html = ` +
+
+ + + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+ +
+
+`; + +export default function SignUp() { + Component.call(this, { html, events }); + + const $nameInputContainer = this.selected.get('name-input'); + const $lastNameInputContainer = this.selected.get('last-name-input'); + const $birthDateInputContainer = this.selected.get('birth-date-input'); + const $localInputContainer = this.selected.get('local-input'); + const $emailInputContainer = this.selected.get('email-input'); + const $phoneInputContainer = this.selected.get('phone-input'); + const $passwordInputContainer = this.selected.get('password-input'); + const $confirmPasswordInputContainer = this.selected.get( + 'confirm-password-input', + ); + const $submitButton = this.selected.get('submit-button'); + const $emailErrorMessage = this.selected.get('email-input-error'); + const $passwordErrorMessage = this.selected.get('password-input-error'); + const $confirmPasswordErrorMessage = this.selected.get( + 'confirm-password-input-error', + ); + + const nameInput = new TextInput({ + placeholder: 'Devhat', + }); + const lastNameInput = new TextInput({ + placeholder: 'Devhat', + }); + const birthDateInput = new TextInput({ + placeholder: '13/12/1995', + type: 'date', + }); + const localInput = new TextInput({ + placeholder: 'São Paulo, SP', + }); + const emailInput = new TextInput({ + placeholder: 'dev@devhat.com.br', + type: 'email', + }); + const phoneInput = new TextInput({ + placeholder: '(11) 92875-3356', + }); + const passwordInput = new TextInput({ + placeholder: 'Senha', + assetPosition: 'suffix', + type: 'password', + }); + const confirmPasswordInput = new TextInput({ + placeholder: 'Confirmar senha', + assetPosition: 'suffix', + type: 'password', + }); + const submitButton = new Button({ + text: 'Cadastrar', + isFullWidth: true, + isDisabled: true, + }); + + nameInput.mount($nameInputContainer); + lastNameInput.mount($lastNameInputContainer); + birthDateInput.mount($birthDateInputContainer); + localInput.mount($localInputContainer); + emailInput.mount($emailInputContainer); + phoneInput.mount($phoneInputContainer); + passwordInput.mount($passwordInputContainer); + confirmPasswordInput.mount($confirmPasswordInputContainer); + submitButton.mount($submitButton); + + const validateFields = () => { + const name = nameInput.getValue().trim(); + const lastName = lastNameInput.getValue().trim(); + const birthDate = birthDateInput.getValue().trim(); + const local = localInput.getValue().trim(); + const email = emailInput.getValue().trim(); + const phone = phoneInput.getValue().trim(); + const password = passwordInput.getValue().trim(); + const confirmPassword = confirmPasswordInput.getValue().trim(); + + const allFieldsFilled = + name && + lastName && + birthDate && + local && + email && + phone && + password && + confirmPassword; + + if (allFieldsFilled) { + submitButton.enable(); + } else { + submitButton.disable(); + } + }; + + nameInput.selected + .get('input-text') + .addEventListener('input', validateFields); + lastNameInput.selected + .get('input-text') + .addEventListener('input', validateFields); + birthDateInput.selected + .get('input-text') + .addEventListener('input', validateFields); + localInput.selected + .get('input-text') + .addEventListener('input', validateFields); + emailInput.selected + .get('input-text') + .addEventListener('input', validateFields); + phoneInput.selected + .get('input-text') + .addEventListener('input', validateFields); + passwordInput.selected + .get('input-text') + .addEventListener('input', validateFields); + confirmPasswordInput.selected + .get('input-text') + .addEventListener('input', validateFields); + + submitButton.listen('click', () => { + const email = emailInput.getValue(); + const password = passwordInput.getValue(); + const confirmPassword = confirmPasswordInput.getValue(); + let validEmail = true; + let validPassword = true; + let validConfirmPassword = true; + + if (!this.validateEmail(email)) { + validEmail = false; + $emailErrorMessage.classList.add('signUp-page__form-input--show-error'); + $emailErrorMessage.innerText = 'E-mail inválido'; + emailInput.inputError(); + } + + if (!this.validatePassword(password)) { + validPassword = false; + $passwordErrorMessage.classList.add( + 'signUp-page__form-input--show-error', + ); + $passwordErrorMessage.innerText = + 'Senha inválida. Sua senha deve conter no mínimo 10 caracteres, incluindo pelo menos um caractere especial e uma letra maiúscula.'; + passwordInput.inputError(); + } + + if (!this.validateConfirmPassword(password, confirmPassword)) { + validConfirmPassword = false; + $confirmPasswordErrorMessage.classList.add( + 'signUp-page__form-input--show-error', + ); + $confirmPasswordErrorMessage.innerText = 'As senhas não coincidem.'; + confirmPasswordInput.inputError(); + } + + if (validEmail) + $emailErrorMessage.classList.remove( + 'signUp-page__form-input--show-error', + ); + if (validPassword) + $passwordErrorMessage.classList.remove( + 'signUp-page__form-input--show-error', + ); + + if (validConfirmPassword) + $confirmPasswordErrorMessage.classList.remove( + 'signUp-page__form-input--show-error', + ); + + if (validEmail && validPassword && validConfirmPassword) { + this.signUp(); + } + }); +} + +SignUp.prototype = Object.assign(SignUp.prototype, Component.prototype, { + signUp() { + this.emit('signUp'); + }, + validateEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; + + return emailRegex.test(email); + }, + validatePassword(password) { + const hasMinLength = password.length >= 10; + const hasUppercase = /[A-Z]/g.test(password); + const hasNumber = /[0-9]/g.test(password); + const hasSpecialCharacter = /[!@#$%^&*(),.?":{}|<>]/g.test(password); + + return hasMinLength && hasUppercase && hasNumber && hasSpecialCharacter; + }, + + validateConfirmPassword(password, confirmpassword) { + return password === confirmpassword; + }, +}); diff --git a/src/layouts/app/pages/SignUp/index.scss b/src/layouts/app/pages/SignUp/index.scss new file mode 100644 index 00000000..b732956c --- /dev/null +++ b/src/layouts/app/pages/SignUp/index.scss @@ -0,0 +1,151 @@ +@use '~styles/colors.scss' as colors; +@use '~styles/fonts.scss' as fonts; +@use '~styles/breakpoints.scss' as breakpoints; + +.signup-page { + &__title { + font-family: fonts.$primaryFont; + color: colors.$gray800; + font-size: fonts.$xl2; + font-weight: 700; + line-height: 1.6; + + margin-bottom: 3.2rem; + } + + &__provider { + max-width: 45rem; + + display: grid; + grid-template-columns: 1fr; + gap: 1.6rem; + + margin-bottom: 3.2rem; + } + + &__provider-button { + width: 100%; + + display: flex; + gap: 1.6rem; + + align-items: center; + justify-content: center; + + font-family: fonts.$fifthFont; + + font-size: 1.6rem; + font-weight: fonts.$medium; + + padding: 1.6rem; + + border: unset; + + background-color: colors.$secondary100; + box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.084); + border-radius: 1.4rem; + + transition: 0.3s ease-in-out; + + cursor: pointer; + + &:hover:not(:disabled) { + background-color: colors.$gray200; + } + } + + &__provider-icon { + max-width: 2.4rem; + } + + &__separator { + max-width: 45rem; + + display: flex; + + margin-bottom: 2.4rem; + } + + &__divisor { + width: 100%; + + border: unset; + border-top: 0.1rem solid colors.$gray200; + } + + &__separator-text { + font-family: fonts.$fifthFont; + + margin: 0 2.8rem; + } + + &__form { + display: grid; + grid-template-columns: 1fr; + gap: 2.8rem; + } + + &__form-input { + position: relative; + + &--error { + display: none; + + font-family: fonts.$fifthFont; + color: colors.$error100; + font-size: 1.4rem; + + margin-top: 0.8rem; + } + + &--show-error { + display: block; + } + + :has(&--error) .input-text-container, + :has(&--error) .input-text-container__input.standard.input-error { + background-color: transparent !important; + } + + .input-text-container__input { + font-family: fonts.$fifthFont; + } + } + + &__form-label { + width: max-content; + + font-family: fonts.$primaryFont; + font-size: 1.4rem; + + padding: 0 0.8rem; + + position: absolute; + bottom: 4.8rem; + left: 3rem; + z-index: 1; + + background-color: colors.$shade50; + } + + &__submit-button { + max-width: 45rem; + } +} + +@include breakpoints.from667 { + .signup-page { + &__provider { + grid-template-columns: 1fr 1fr; + } + + &__form { + display: grid; + grid-template-columns: 1fr 1fr; + } + + &__submit-button { + grid-column: span 2; + } + } +} diff --git a/src/stories/SignUpPage.stories.js b/src/stories/SignUpPage.stories.js new file mode 100644 index 00000000..0e3d5547 --- /dev/null +++ b/src/stories/SignUpPage.stories.js @@ -0,0 +1,15 @@ +import SignUp from '../layouts/app/pages/SignUp'; + +export default { + title: 'Pages/SignUp', + render: () => { + const signUp = new SignUp(); + const $container = document.createElement('div'); + + signUp.mount($container); + + return $container; + }, +}; + +export const SignUpPageStory = {};