Merge pull request #35 from Quantum-P3/feature/US-08

Feature/us 08
This commit is contained in:
Eduardo Quiros 2021-07-16 15:50:22 +00:00 committed by GitHub
commit 8918cf8d65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 222 additions and 27442 deletions

27406
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -180,7 +180,7 @@
</div>
</div>
<!-- Form -->
<!-- Form de info usuario -->
<form
autocomplete="off"
class="ds-form col-lg ml-lg-5 mr-lg-5 pr-lg-5"
@ -191,6 +191,20 @@
[formGroup]="editForm"
>
<div class="row mb-2">
<div
class="alert alert-danger"
*ngIf="error"
jhiTranslate="global.messages.info.authenticated.updateForm"
data-cy="loginError"
></div>
<div *ngIf="success" class="alert alert-success alert-dismissible fade show" role="alert">
Sus datos fueron actualizados de manera exitosa
<!--<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>-->
</div>
<div class="form-group w-100">
<label class="form-control-label" for="field_email">Correo electrónico</label>
<input type="text" class="form-control" name="email" id="field_email" data-cy="email" formControlName="email" [readonly]="true" />
@ -221,7 +235,7 @@
<input
id="field_fechaNacimiento"
data-cy="fechaNacimiento"
type="datetime-local"
type="date"
class="form-control"
name="fechaNacimiento"
formControlName="fechaNacimiento"
@ -273,33 +287,59 @@
Utilice una contraseña segura al realizar el cambio, este dato debe ser secreto ya que provee acceso a su cuenta.
</p>
</div>
<div class="alert alert-danger" *ngIf="isGoogle" jhiTranslate="login.messages.error.isGoogle" data-cy="loginError"></div>
</div>
</div>
<!-- Form -->
<!-- Form de password-->
<form
autocomplete="off"
class="ds-form col-lg ml-lg-5 mr-lg-5 pr-lg-5"
name="passwordForm"
role="form"
novalidate
(ngSubmit)="save()"
(ngSubmit)="savePassword()"
[formGroup]="passwordForm"
>
<div class="row mb-3 pb-3" style="border-bottom: 1px solid #e7ebf3">
<div
class="alert alert-danger"
*ngIf="errorPassword && !doNotMatch && !successPassword"
jhiTranslate="global.messages.info.authenticated.passwordForm"
data-cy="loginError"
></div>
<div *ngIf="successPassword" class="alert alert-success alert-dismissible fade show" role="alert">
Sus contraseña fue actualizada de manera exitosa
<!-- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>-->
</div>
<div class="alert alert-danger" *ngIf="doNotMatch && !successPassword" jhiTranslate="global.messages.error.dontmatch">
The password and its confirmation do not match!
</div>
<div class="form-group w-100">
<label class="form-control-label" for="field_password">Contraseña actual</label>
<input
type="text"
type="password"
class="form-control"
name="password"
id="field_password"
data-cy="password"
formControlName="password"
placeholder="Su contraseña actual"
[readOnly]="isGoogle"
/>
<div
*ngIf="passwordForm.get('password')!.invalid && (passwordForm.get('password')!.dirty || passwordForm.get('password')!.touched)"
*ngIf="
passwordForm.get('password')!.invalid &&
(passwordForm.get('password')!.dirty || passwordForm.get('password')!.touched) &&
!isGoogle
"
>
<small
class="form-text text-danger"
@ -308,6 +348,22 @@
>
This field is required.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('password')?.errors?.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength"
>
Your password is required to be at least 4 characters.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('password')?.errors?.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength"
>
Your password cannot be longer than 50 characters.
</small>
</div>
</div>
</div>
@ -315,18 +371,20 @@
<div class="form-group w-100">
<label class="form-control-label" for="field_passwordNew">Contraseña nueva</label>
<input
type="text"
type="password"
class="form-control"
name="passwordNew"
id="field_passwordNew"
data-cy="passwordNew"
formControlName="passwordNew"
placeholder="Contraseña nueva"
[readOnly]="isGoogle"
/>
<div
*ngIf="
passwordForm.get('passwordNew')!.invalid &&
(passwordForm.get('passwordNew')!.dirty || passwordForm.get('passwordNew')!.touched)
(passwordForm.get('passwordNew')!.dirty || passwordForm.get('passwordNew')!.touched) &&
!isGoogle
"
>
<small
@ -336,6 +394,22 @@
>
This field is required.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNew')?.errors?.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength"
>
Your password is required to be at least 4 characters.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNew')?.errors?.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength"
>
Your password cannot be longer than 50 characters.
</small>
</div>
</div>
</div>
@ -344,18 +418,20 @@
<div class="form-group w-100">
<label class="form-control-label" for="field_passwordNewConfirm">Confirmar contraseña nueva</label>
<input
type="text"
type="password"
class="form-control"
name="passwordNewConfirm"
id="field_passwordNewConfirm"
data-cy="passwordNewConfirm"
formControlName="passwordNewConfirm"
placeholder="Contraseña nueva"
[readOnly]="isGoogle"
/>
<div
*ngIf="
passwordForm.get('passwordNewConfirm')!.invalid &&
(passwordForm.get('passwordNewConfirm')!.dirty || passwordForm.get('passwordNewConfirm')!.touched)
(passwordForm.get('passwordNewConfirm')!.dirty || passwordForm.get('passwordNewConfirm')!.touched) &&
!isGoogle
"
>
<small
@ -365,12 +441,28 @@
>
This field is required.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNewConfirm')?.errors?.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength"
>
Your password is required to be at least 4 characters.
</small>
<small
class="form-text text-danger"
*ngIf="passwordForm.get('passwordNewConfirm')?.errors?.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength"
>
Your password cannot be longer than 50 characters.
</small>
</div>
</div>
</div>
<div class="row">
<button
*ngIf="!isGoogle"
type="button"
id="cancel-save"
data-cy="entityCreateCancelButton"
@ -381,10 +473,11 @@
</button>
<button
*ngIf="!isGoogle"
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
[disabled]="passwordForm.invalid || isSaving"
[disabled]="isSaving"
class="ds-btn ds-btn--primary"
>
<span jhiTranslate="entity.action.save">Save</span>

View File

@ -1,3 +1,5 @@
import { LocalStorageService } from 'ngx-webstorage';
jest.mock('@ngx-translate/core');
jest.mock('app/core/auth/account.service');
@ -19,6 +21,7 @@ describe('Component Tests', () => {
let comp: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;
let mockAccountService: AccountService;
let localStorage: LocalStorageService;
const account: Account = {
id: 0,
firstName: 'John',
@ -36,17 +39,23 @@ describe('Component Tests', () => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, HttpClientTestingModule],
declarations: [SettingsComponent],
providers: [FormBuilder, TranslateService, AccountService],
providers: [FormBuilder, TranslateService, AccountService, LocalStorageService],
})
.overrideTemplate(SettingsComponent, '')
.compileComponents();
localStorage = TestBed.inject(LocalStorageService);
})
);
it('should be created', () => {
expect(localStorage).toBeTruthy();
});
beforeEach(() => {
fixture = TestBed.createComponent(SettingsComponent);
comp = fixture.componentInstance;
mockAccountService = TestBed.inject(AccountService);
localStorage = TestBed.inject(LocalStorageService);
mockAccountService.identity = jest.fn(() => of(account));
mockAccountService.getAuthenticationState = jest.fn(() => of(account));
});
@ -63,6 +72,10 @@ describe('Component Tests', () => {
// expect(comp.success).toBe(true);
});
it('should be created', () => {
expect(localStorage).toBeTruthy();
});
it('should notify of error upon failed save', () => {
// GIVEN
mockAccountService.save = jest.fn(() => throwError('ERROR'));

View File

@ -1,12 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { Component, ContentChild, OnInit } from '@angular/core';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { finalize, map } from 'rxjs/operators';
import * as dayjs from 'dayjs';
import { DATE_TIME_FORMAT } from 'app/config/input.constants';
import { DATE_FORMAT, DATE_TIME_FORMAT } from 'app/config/input.constants';
import { IUser } from 'app/entities/user/user.model';
import { UserService } from 'app/entities/user/user.service';
import { IPlantilla } from 'app/entities/plantilla/plantilla.model';
@ -14,17 +13,30 @@ import { PlantillaService } from 'app/entities/plantilla/service/plantilla.servi
import { IUsuarioExtra, UsuarioExtra } from 'app/entities/usuario-extra/usuario-extra.model';
import { UsuarioExtraService } from 'app/entities/usuario-extra/service/usuario-extra.service';
import { AccountService } from 'app/core/auth/account.service';
import { LocalStorageService } from 'ngx-webstorage';
import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from '../../config/error.constants';
import { PasswordService } from '../password/password.service';
@Component({
selector: 'jhi-settings',
templateUrl: './settings.component.html',
providers: [LocalStorageService],
})
export class SettingsComponent implements OnInit {
currentUrl = this.router.url;
isSaving = false;
success = false;
successPassword = false;
error = false;
errorPassword = false;
doNotMatch = false;
usersSharedCollection: IUser[] = [];
plantillasSharedCollection: IPlantilla[] = [];
showPassword = false;
isGoogle = this.localStorageService.retrieve('IsGoogle');
//Form info del usuario
editForm = this.fb.group({
email: [null, [Validators.required]],
id: [],
@ -36,10 +48,11 @@ export class SettingsComponent implements OnInit {
plantillas: [],
});
//form de la contraseña
passwordForm = this.fb.group({
password: [null, [Validators.required]],
passwordNew: [null, [Validators.required]],
passwordNewConfirm: [null, [Validators.required]],
password: [null, [Validators.required], Validators.minLength(8), Validators.maxLength(50)],
passwordNew: [null, [Validators.required], Validators.minLength(8), Validators.maxLength(50)],
passwordNewConfirm: [null, [Validators.required, Validators.minLength(8), Validators.maxLength(50)]],
});
usuarioExtra: UsuarioExtra | null = null;
@ -75,13 +88,18 @@ export class SettingsComponent implements OnInit {
{ name: 'C28' },
];
/* @ContentChild(IonInput) input: IonInput;*/
constructor(
protected usuarioExtraService: UsuarioExtraService,
protected userService: UserService,
protected plantillaService: PlantillaService,
protected activatedRoute: ActivatedRoute,
protected fb: FormBuilder,
protected accountService: AccountService
protected accountService: AccountService,
private localStorageService: LocalStorageService,
protected passwordService: PasswordService,
private router: Router
) {}
ngOnInit(): void {
@ -103,6 +121,8 @@ export class SettingsComponent implements OnInit {
}
});
console.log(this.isGoogle);
// this.activatedRoute.data.subscribe(({ usuarioExtra }) => {
// });
@ -112,13 +132,26 @@ export class SettingsComponent implements OnInit {
window.history.back();
}
//Se manda la info a guardar
save(): void {
this.isSaving = true;
const usuarioExtra = this.createFromForm();
if (usuarioExtra.id !== undefined) {
console.log(usuarioExtra.iconoPerfil);
console.log(usuarioExtra.fechaNacimiento);
this.subscribeToSaveResponse(this.usuarioExtraService.update(usuarioExtra));
}
savePassword(): void {
const passwordNew = this.passwordForm.get(['passwordNew'])!.value;
if (passwordNew !== this.passwordForm.get(['passwordNewConfirm'])!.value) {
this.doNotMatch = true;
} else {
this.subscribeToSaveResponse(this.usuarioExtraService.create(usuarioExtra));
this.passwordService.save(this.passwordForm.get(['passwordNew'])!.value, this.passwordForm.get(['password'])!.value).subscribe(
() => (this.successPassword = true),
() => (this.errorPassword = true)
);
}
}
@ -143,10 +176,20 @@ export class SettingsComponent implements OnInit {
protected subscribeToSaveResponse(result: Observable<HttpResponse<IUsuarioExtra>>): void {
result.pipe(finalize(() => this.onSaveFinalize())).subscribe(
() => this.onSaveSuccess(),
() => this.onSaveError()
() => (
(this.success = true),
this.router.navigate(['account/settings']).then(() => {
window.location.reload();
})
),
response => this.processError(response)
);
}
processError(response: HttpErrorResponse): void {
if (response.status === 400) {
this.error = true;
}
}
protected onSaveSuccess(): void {
this.previousState();
@ -160,20 +203,21 @@ export class SettingsComponent implements OnInit {
this.isSaving = false;
}
//Llena el formulario para que se vea en pantalla
protected updateForm(usuarioExtra: IUsuarioExtra): void {
this.editForm.patchValue({
email: usuarioExtra.user?.login,
id: usuarioExtra.id,
nombre: usuarioExtra.nombre,
iconoPerfil: usuarioExtra.iconoPerfil,
fechaNacimiento: usuarioExtra.fechaNacimiento ? usuarioExtra.fechaNacimiento.format(DATE_TIME_FORMAT) : null,
fechaNacimiento: usuarioExtra.fechaNacimiento ? usuarioExtra.fechaNacimiento.format(DATE_FORMAT) : null,
estado: usuarioExtra.estado,
user: usuarioExtra.user,
plantillas: usuarioExtra.plantillas,
});
// Update swiper
this.profileIcon = parseInt(usuarioExtra.iconoPerfil!);
this.profileIcon = usuarioExtra.iconoPerfil!;
this.profileIcons.forEach(icon => {
if (parseInt(icon.name.split('C')[1]) === this.profileIcon) {
icon.class = 'active';
@ -210,9 +254,9 @@ export class SettingsComponent implements OnInit {
...new UsuarioExtra(),
id: this.editForm.get(['id'])!.value,
nombre: this.editForm.get(['nombre'])!.value,
iconoPerfil: this.editForm.get(['iconoPerfil'])!.value,
iconoPerfil: this.profileIcon,
fechaNacimiento: this.editForm.get(['fechaNacimiento'])!.value
? dayjs(this.editForm.get(['fechaNacimiento'])!.value, DATE_TIME_FORMAT)
? dayjs(this.editForm.get(['fechaNacimiento'])!.value, DATE_FORMAT)
: undefined,
estado: this.editForm.get(['estado'])!.value,
user: this.editForm.get(['user'])!.value,
@ -225,6 +269,8 @@ export class SettingsComponent implements OnInit {
document.querySelectorAll('.active').forEach(e => e.classList.remove('active'));
event.target.classList.add('active');
this.profileIcon = +event.target.getAttribute('id')! + 1;
console.log(this.profileIcon);
}
}
}

View File

@ -9,7 +9,7 @@ import { TranslateModule, TranslateService, TranslateLoader, MissingTranslationH
import { NgxWebstorageModule, SessionStorageService } from 'ngx-webstorage';
import * as dayjs from 'dayjs';
import { NgbDateAdapter, NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap';
import { LocalStorageService } from 'ngx-webstorage';
import { SERVER_API_URL } from './app.constants';
import { ApplicationConfigService } from 'app/core/config/application-config.service';
import './config/dayjs';
@ -35,6 +35,7 @@ import { SidebarComponent } from './layouts/sidebar/sidebar.component';
@NgModule({
imports: [
NgxWebstorageModule.forRoot(),
BrowserModule,
SharedModule,
HomeModule,
@ -59,6 +60,7 @@ import { SidebarComponent } from './layouts/sidebar/sidebar.component';
}),
],
providers: [
LocalStorageService,
Title,
{ provide: LOCALE_ID, useValue: 'es' },
{ provide: NgbDateAdapter, useClass: NgbDateDayjsAdapter },

View File

@ -28,7 +28,7 @@ describe('Service Tests', () => {
elemDefault = {
id: 0,
nombre: 'AAAAAAA',
iconoPerfil: 'AAAAAAA',
iconoPerfil: 1,
fechaNacimiento: currentDate,
estado: EstadoUsuario.ACTIVE,
};

View File

@ -8,7 +8,7 @@ import { EstadoUsuario } from 'app/entities/enumerations/estado-usuario.model';
export interface IUsuarioExtra {
id?: number;
nombre?: string;
iconoPerfil?: string | null;
iconoPerfil?: number | null;
fechaNacimiento?: dayjs.Dayjs | null;
estado?: EstadoUsuario;
user?: IUser | null;
@ -21,7 +21,7 @@ export class UsuarioExtra implements IUsuarioExtra {
constructor(
public id?: number,
public nombre?: string,
public iconoPerfil?: string | null,
public iconoPerfil?: number | null,
public fechaNacimiento?: dayjs.Dayjs | null,
public estado?: EstadoUsuario,
public user?: IUser | null,

View File

@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { UsuarioGoogleLogInService } from './usuario-google-log-in.service';
describe('UsuarioGoogleLogInService', () => {
let service: UsuarioGoogleLogInService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UsuarioGoogleLogInService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -1,9 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class UsuarioGoogleLogInService {
constructor() {}
}

View File

@ -65,7 +65,9 @@
"authenticated": {
"prefix": "Si desea ",
"link": "iniciar sesión",
"suffix": ", puede intentar con las cuentas predeterminadas:<br/>- Administrador (usuario=\"admin\" y contraseña=\"admin\") <br/>- Usuario (usuario=\"user\" y contraseña=\"user\")."
"suffix": ", puede intentar con las cuentas predeterminadas:<br/>- Administrador (usuario=\"admin\" y contraseña=\"admin\") <br/>- Usuario (usuario=\"user\" y contraseña=\"user\").",
"updateForm": "Ocurrió un error al actualizar su información, favor revisar los campos e intentar de nuevo",
"passwordForm": "Ocurrió un error al actualizar su contraseña, favor revisar los campos e intentar de nuevo"
},
"register": {
"noaccount": "¿Aún no tienes una cuenta?",

View File

@ -9,7 +9,8 @@
},
"messages": {
"error": {
"authentication": "Revise las credenciales e intente de nuevo "
"authentication": "Revise las credenciales e intente de nuevo ",
"isGoogle": "Al haber ingresado por medio de Google no cuenta con los permisos para modificar su contraseña"
}
},
"password": {