Skip to content

Commit

Permalink
Merge branch 'main' into issue-242
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasfreitas-dev committed Jul 29, 2024
2 parents daec562 + a1d9893 commit 664d628
Show file tree
Hide file tree
Showing 10 changed files with 467 additions and 0 deletions.
5 changes: 5 additions & 0 deletions db.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"login": [
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Ijc3OTFkZmMwLWY3YzEtNDAyMy05ZDUxLTFlYTQ3OWQ2ZjgyYiIsIm5hbWUiOiJqb2huZG9lQGV4YW1wbGUuY29tIiwiZW1haWwiOiJqb2huZG9lQGV4YW1wbGUuY29tIiwiZXhwIjoxNzIxODI4MDA3fQ.Agk6Yz2E6TpoqI6mVYeClKx1zOxSsp TyIhtJEvFvG-E"
}
],
"user": [
{
"id": "1",
Expand Down
163 changes: 163 additions & 0 deletions src/components/ChangePassword/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { Component } from 'pet-dex-utilities';
import TextInput from '../TextInput';
import Button from '../Button';
import './index.scss';

const events = ['password:change'];

const html = `
<form
data-select="change-password"
class="change-password"
action="submit"
>
<h3 class="change-password__title">
Senha antiga
</h3>
<div data-select="password" class="change-password__input"></div>
<span data-select="password-error" class="change-password__error">Senha inválida</span>
<hr class="change-password__separator"/>
<h3 class="change-password__title">Nova senha</h3>
<div data-select="new-password" class="change-password__input"></div>
<span data-select="new-password-error" class="change-password__error">Senha inválida</span>
<span data-select="new-password-error-match" class="change-password__error">As senhas não coincidem</span>
<div data-select="confirm-password" class="change-password__input"></div>
<span data-select="confirm-password-error" class="change-password__error">Senha inválida</span>
<span data-select="confirm-password-error-match" class="change-password__error">As senhas não coincidem</span>
<ul class="change-password__tips">
<li>Insira no mínimo 6 caracteres</li>
<li>A senha deve conter uma letra maiúscula</li>
<li>Deve conter um caractere especial</li>
</ul>
</form>
`;

const 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;
};

export default function ChangePassword() {
Component.call(this, { html, events });
const $changePasswordForm = this.selected.get('change-password');
const $passwordInputContainer = this.selected.get('password');
const $currentPasswordErrorMessage = this.selected.get('password-error');
const $newPasswordInputContainer = this.selected.get('new-password');
const $newPasswordErrorMessage = this.selected.get('new-password-error');
const $newPasswordErrorMatch = this.selected.get('new-password-error-match');
const $confirmPasswordInputContainer = this.selected.get('confirm-password');
const $confirmPasswordErrorMessage = this.selected.get(
'confirm-password-error',
);
const $confirmPasswordErrorMatch = this.selected.get(
'confirm-password-error-match',
);

const currentPasswordInput = new TextInput({
placeholder: 'Senha',
assetPosition: 'suffix',
type: 'password',
});
const newPasswordInput = new TextInput({
placeholder: 'Nova senha',
assetPosition: 'suffix',
type: 'password',
});
const confirmPasswordInput = new TextInput({
placeholder: ' Confirmar senha',
assetPosition: 'suffix',
type: 'password',
});
const submitButton = new Button({
text: 'Salvar',
isFullWidth: true,
isDisabled: true,
});

currentPasswordInput.mount($passwordInputContainer);
newPasswordInput.mount($newPasswordInputContainer);
confirmPasswordInput.mount($confirmPasswordInputContainer);
submitButton.mount($changePasswordForm);

const validateSubmit = () => {
if (
currentPasswordInput.getValue() &&
newPasswordInput.getValue() &&
confirmPasswordInput.getValue()
) {
submitButton.enable();
} else {
submitButton.disable();
}
};

submitButton.selected.get('button').classList.add('change-password__button');
currentPasswordInput.selected
.get('input-text')
.addEventListener('input', () => {
$currentPasswordErrorMessage.classList.remove('show-error');
validateSubmit();
});
newPasswordInput.selected.get('input-text').addEventListener('input', () => {
$newPasswordErrorMessage.classList.remove('show-error');
validateSubmit();
});
confirmPasswordInput.selected
.get('input-text')
.addEventListener('input', () => {
$confirmPasswordErrorMessage.classList.remove('show-error');
validateSubmit();
});

submitButton.listen('click', () => {
let validPasswords = true;
const newPassword = newPasswordInput.selected.get('input-text').value;
const confirmPassword =
confirmPasswordInput.selected.get('input-text').value;

const showErrorMessage = (field, error) => {
const fieldValue = field.selected.get('input-text').value;
if (!validatePassword(fieldValue)) {
validPasswords = false;
error.classList.add('show-error');
field.inputError();
}
};

showErrorMessage(currentPasswordInput, $currentPasswordErrorMessage);
showErrorMessage(newPasswordInput, $newPasswordErrorMessage);
showErrorMessage(confirmPasswordInput, $confirmPasswordErrorMessage);

if (confirmPassword !== newPassword) {
validPasswords = false;
$newPasswordErrorMatch.classList.add('show-error');
$confirmPasswordErrorMatch.classList.add('show-error');
newPasswordInput.inputError();
confirmPasswordInput.inputError();
}

const removeErrors = (div) => {
div.classList.remove('show-error');
};

if (validPasswords) {
removeErrors($currentPasswordErrorMessage);
removeErrors($newPasswordErrorMessage);
removeErrors($confirmPasswordErrorMessage);
removeErrors($newPasswordErrorMatch);
removeErrors($confirmPasswordErrorMatch);
this.emit('password:change');
}
});
}
ChangePassword.prototype = Object.assign(
ChangePassword.prototype,
Component.prototype,
);
56 changes: 56 additions & 0 deletions src/components/ChangePassword/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@use '~styles/colors.scss' as colors;
@use '~styles/fonts.scss' as fonts;
@use '~styles/breakpoints.scss' as breakpoints;

.change-password {
height: 100%;

display: flex;
flex-direction: column;
gap: 2rem;

font-family: fonts.$primaryFont;
line-height: 1.5;

padding: 0 2rem;

background-color: colors.$secondary100;

&__title {
color: colors.$gray600;
font-size: fonts.$sm;
font-weight: fonts.$bold;
}

&__error {
display: none;

color: colors.$error100;

&.show-error {
display: block;
}
}

&__tips {
color: colors.$gray500;
font-weight: fonts.$regular;

list-style-type: disc;
padding-inline-start: 3rem;
}

&__button {
margin-top: auto;
margin-bottom: 1rem;
}

&__separator {
width: 100%;

display: flex;

border: 0;
border-top: 0.1rem solid colors.$gray200;
}
}
47 changes: 47 additions & 0 deletions src/components/PetAvatar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Component } from 'pet-dex-utilities';
import './index.scss';
import { routeLocation } from 'vanilla-routing';

const events = ['active'];

const html = `
<a class="pet-avatar" data-select="pet-avatar" href="/petperfil/">
<img class="pet-avatar__img" data-select="pet-image" src="" alt=""/>
<p class="pet-avatar__title" data-select="pet-title"></p>
</a>
`;

export default function PetAvatar({ id, title, imgSrc, imgAlt } = {}) {
Component.call(this, { html, events });

if (id) this.setHref(id);
if (title) this.setTitle(title);
if (imgSrc) this.setImgSrc(imgSrc);
if (imgAlt) this.setImgAlt(imgAlt);

if (routeLocation().pathname === `/petperfil/${id}`) {
this.activate();
}
}

PetAvatar.prototype = Object.assign(PetAvatar.prototype, Component.prototype, {
setTitle(text) {
this.selected.get('pet-title').textContent = text;
},
setImgSrc(src) {
this.selected.get('pet-image').src = src;
},
setImgAlt(alt) {
this.selected.get('pet-image').alt = alt;
},
setHref(id) {
this.selected.get('pet-avatar').href += id;
},
activate() {
const image = this.selected.get('pet-image');
const title = this.selected.get('pet-title');
image.classList.add('pet-avatar__img--active');
title.classList.add('pet-avatar__title--active');
this.emit('active');
},
});
54 changes: 54 additions & 0 deletions src/components/PetAvatar/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@use '~styles/colors' as colors;
@use '~styles/fonts' as fonts;

.pet-avatar {
display: flex;
flex-direction: column;
gap: 1rem;

align-items: center;

text-decoration: none;
aspect-ratio: 1/1;

opacity: 0.85;

transition: 0.3s ease-in-out;

&__img {
height: 100%;

outline: 0.15rem solid colors.$gray500;

border-radius: 50%;
object-fit: cover;
aspect-ratio: 1/1;

transition: 0.3s ease-in-out;

&--active {
outline: 0.3rem solid colors.$primary200;
}
}

&__title {
font-family: fonts.$fourthFont;

color: colors.$gray200;
text-align: center;
font-size: 1.4rem;
font-weight: fonts.$regular;

transition: 0.3s ease-in-out;

&--active {
color: colors.$primary200;
font-weight: fonts.$semiBold;
}
}

&:hover {
transform: scale(1.02);
opacity: 1;
}
}
Loading

0 comments on commit 664d628

Please sign in to comment.