diff --git a/src/app/form/form.component.html b/src/app/form/form.component.html index 5667595b75d88aba4578bc9473a513e2ddafbb05..dbfe52fe2232339cf8146754edcdd8c96cfee9e4 100644 --- a/src/app/form/form.component.html +++ b/src/app/form/form.component.html @@ -5,8 +5,13 @@ (closed)="hasRedirectionAccepted($event)" ></app-modal-confirmation> <div class="content" *ngIf="!isLoading" [ngClass]="{ editMode: isEditMode }"> - <div class="headerEditMode" *ngIf="isEditMode"> + <div class="headerEditMode" *ngIf="isEditMode" fxLayout="row" fxLayoutAlign="space-between center"> <h2>Modification de {{ editForm.get('structureName').value }}</h2> + <app-structure-options-modal + [structure]="structureWithOwners" + [isEditFormView]="true" + (closed)="structureDeleted()" + ></app-structure-options-modal> </div> <div class="returnBtnSection" *ngIf="isEditMode && currentPage != 0"> <button class="btn-primary previous" (click)="goToSpecificPage(0, false)"> @@ -959,27 +964,6 @@ </p> </div> </div> - <div *ngIf="false" class="page"> - <div class="title"> - <h3>Voulez-vous inviter d’autres personnes dans cette structure ?</h3> - <p class="notRequired">facultatif</p> - </div> - <div class="collapse" [ngClass]="{ notCollapsed: true }"> - <div fxLayout="column"> - <div class="collapseHeader" fxLayout="row" fxLayoutAlign=" center"> - <div class="titleCollapse">J’ajoute d'autres personnes dans cette structure</div> - <div class="logo"> - <svg class="show" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#show'"></use> - </svg> - <svg class="hide" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#hide'"></use> - </svg> - </div> - </div> - </div> - </div> - </div> </form> <div *ngIf="currentPage == pageTypeEnum.cgu" class="page"> <div class="title"> diff --git a/src/app/form/form.component.ts b/src/app/form/form.component.ts index 837866f335a312cd55e8821da9389cfcb04a24b6..dcc151211a8f72f9e0b65eb1e66852d31a7457a1 100644 --- a/src/app/form/form.component.ts +++ b/src/app/form/form.component.ts @@ -17,8 +17,8 @@ import { ActivatedRoute, Router } from '@angular/router'; import { AuthService } from '../services/auth.service'; import { first } from 'rxjs/operators'; import { PageTypeEnum } from './pageType.enum'; -import { TempUserService } from '../services/temp-user.service'; import { CustomRegExp } from '../utils/CustomRegExp'; +import { StructureWithOwners } from '../models/structureWithOwners.model'; const { DateTime } = require('luxon'); @Component({ selector: 'app-structureForm', @@ -28,7 +28,6 @@ const { DateTime } = require('luxon'); export class FormComponent implements OnInit { public profile: User; public createdStructure: Structure; - // Form var public structureForm: FormGroup; public accountForm: FormGroup; @@ -73,13 +72,13 @@ export class FormComponent implements OnInit { public isJoinMode = false; public isLoading = false; public isWifiChoosen = false; + public structureWithOwners: StructureWithOwners; constructor( private structureService: StructureService, private searchService: SearchService, private profileService: ProfileService, private authService: AuthService, - private tempUserService: TempUserService, private router: Router, private route: ActivatedRoute ) {} @@ -95,7 +94,11 @@ export class FormComponent implements OnInit { if (history.state.data) { this.isEditMode = true; this.isWifiChoosen = true; - this.initForm(new Structure(history.state.data)); + const editStructure = new Structure(history.state.data); + this.initForm(editStructure); + this.structureService.getStructureWithOwners(editStructure._id, this.profile).subscribe((s) => { + this.structureWithOwners = s; + }); } else if (history.state.newUser) { this.isClaimMode = true; // Handle join strucutre, the case is very similar to claim @@ -541,7 +544,6 @@ export class FormComponent implements OnInit { name: 'Informations spécifiques à la période COVID', }; this.pagesValidation[PageTypeEnum.cgu] = { valid: this.userAcceptSavedDate }; - //this.pagesValidation[PageTypeEnum.addUserToStructure] = { valid: true }; this.updatePageValid(); } } @@ -664,7 +666,6 @@ export class FormComponent implements OnInit { this.currentPage++; // page structureOtherAccompaniment skip and go to page structureWorkshop this.progressStatus += 100 / this.nbPagesForm; } - // Check if going to the last page to submit form and send email verification. if (this.currentPage == this.nbPagesForm - 1) { this.validateForm(); @@ -908,4 +909,8 @@ export class FormComponent implements OnInit { public displayClaimStructure(): boolean { return this.currentPage == this.pageTypeEnum.summary && !this.isEditMode && this.isClaimMode; } + + public structureDeleted(): void { + this.router.navigateByUrl('home'); + } } diff --git a/src/app/form/pageType.enum.ts b/src/app/form/pageType.enum.ts index 4742e76b28e9a418b5c628fde62bd60317871f27..3b3f5071add1c54b7940b04c4b7577aa94059c35 100644 --- a/src/app/form/pageType.enum.ts +++ b/src/app/form/pageType.enum.ts @@ -23,5 +23,4 @@ export enum PageTypeEnum { structureDescription = 21, structureCovidInfo = 22, cgu = 23, - addUserToStructure = 24, } diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html index 3ef2c4743dbc9983a2ca6d3adfc84b74f031bf6d..96e8c9734cebfada5385d50bc87ae868be47f2ae 100644 --- a/src/app/profile/profile.component.html +++ b/src/app/profile/profile.component.html @@ -13,26 +13,10 @@ <span>Identifiant</span> <div fxLayout="row" fxLayoutAlign="space-between center"> <p>{{ userProfile.email }}</p> - <nav aria-label="modalOption"> - <ul> - <li> - <button - [ngClass]="{ active: isModalOptsProfile }" - (click)="openModalOptsProfile()" - class="btn-primary transparent" - > - <app-svg-icon [type]="'ico'" [iconColor]="inherit" [icon]="'moreOpts'"></app-svg-icon> - </button> - <ul *ngIf="isModalOptsProfile" class="dropdown"> - <app-modal-options - [isModalProfileOpts]="true" - [hasOwners]="false" - (closed)="closeModalOpts($event)" - ></app-modal-options> - </ul> - </li> - </ul> - </nav> + <app-structure-options-modal + [userProfile]="userProfile" + (closed)="ngOnInit()" + ></app-structure-options-modal> </div> </div> </div> @@ -47,26 +31,7 @@ <a class="structureName" routerLink="/home" [state]="{ data: s.structure }">{{ s.structure.structureName }}</a> - <nav aria-label="modalOption"> - <ul> - <li> - <button - [ngClass]="{ active: modalOptsStructureIndex == i }" - (click)="openModalOptsStructure(i, s)" - class="btn-primary transparent" - > - <app-svg-icon [type]="'ico'" [iconColor]="inherit" [icon]="'moreOpts'"></app-svg-icon> - </button> - <ul *ngIf="modalOptsStructureIndex == i" class="dropdown"> - <app-modal-options - [isModalProfileOpts]="false" - [hasOwners]="currentStructureOwners.owners.length > 0" - (closed)="closeModalOpts($event)" - ></app-modal-options> - </ul> - </li> - </ul> - </nav> + <app-structure-options-modal [structure]="s" (closed)="ngOnInit()"></app-structure-options-modal> </div> <div fxLayout="column" fxLayoutGap="14px"> <p class="ownerName" *ngFor="let owner of s.owners">{{ owner.email }}</p> @@ -99,213 +64,3 @@ </div> </div> </div> -<div *ngIf="editModal" class="modalBackground"> - <div class="modal" (clickOutside)="closeModalOptsProfile()"> - <form - *ngIf="editModal == typeModalProfile.password" - [formGroup]="formPassword" - class="contentModal" - fxLayout="column" - fxLayoutAlign="center start" - fxLayoutGap="20px" - > - <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> - <h2>Changer de mot de passe</h2> - <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> - </div> - <div class="form-group" fxLayout="column" fxLayoutGap="4px"> - <label for="oldPassword">Ancien mot de passe</label> - <p *ngIf="passwordError" class="special invalid">Votre ancien mot de passe est incorrect.</p> - <div fxLayout="row" fxLayoutGap="13px"> - <input - [type]="isShowOldPassword ? 'text' : 'password'" - formControlName="oldPassword" - class="form-input password" - autocomplete="on" - /> - <app-svg-icon - (click)="showOldPassword()" - [type]="'form'" - [iconClass]="'grey'" - [icon]="'eyePassword'" - ></app-svg-icon> - <app-svg-icon *ngIf="passwordError" [type]="'form'" [icon]="'notValidate'"></app-svg-icon> - </div> - </div> - <div class="form-group" fxLayout="column"> - <label for="password">Nouveau mot de passe</label> - <p class="special" [ngClass]="{ invalid: fpass.password.invalid && fpass.password.value }"> - Le mot de passe doit contenir au minimum : 8 caractères dont un caractère spécial, un caractère en majuscule - et un chiffre. - </p> - <div fxLayout="row" fxLayoutGap="13px"> - <input - [type]="isShowPassword ? 'text' : 'password'" - formControlName="password" - class="form-input password" - autocomplete="on" - /> - <app-svg-icon - (click)="showPassword()" - [type]="'form'" - [iconClass]="'grey'" - [icon]="'eyePassword'" - ></app-svg-icon> - <app-svg-icon *ngIf="fpass.password.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon> - <app-svg-icon - *ngIf="fpass.password.invalid && fpass.password.value" - [type]="'form'" - [icon]="'notValidate'" - ></app-svg-icon> - </div> - </div> - <div class="form-group" fxLayout="column"> - <label for="confirmPassword">Confirmation du mot de passe</label> - <div fxLayout="row" fxLayoutGap="13px"> - <input - [type]="isShowConfirmPassword ? 'text' : 'password'" - formControlName="confirmPassword" - class="form-input password" - autocomplete="on" - /> - <app-svg-icon - (click)="showConfirmPassword()" - [type]="'form'" - [iconClass]="'grey'" - [icon]="'eyePassword'" - ></app-svg-icon> - <app-svg-icon - *ngIf="fpass.confirmPassword.valid && fpass.password.value" - [type]="'form'" - [icon]="'validate'" - ></app-svg-icon> - <app-svg-icon - *ngIf="fpass.confirmPassword.invalid && fpass.confirmPassword.value" - [type]="'form'" - [icon]="'notValidate'" - ></app-svg-icon> - </div> - </div> - <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> - <button - type="submit" - [ngClass]="{ invalid: formPassword.invalid }" - class="btn-primary small leave" - (click)="submitPassword()" - > - Valider - </button> - </div> - </form> - <form - *ngIf="editModal == typeModalProfile.email" - [formGroup]="formEmail" - class="contentModal" - fxLayout="column" - fxLayoutAlign="center start" - > - <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> - <h2>Changer de courriel</h2> - <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> - </div> - <div class="form-group" fxLayout="column"> - <label for="email">Nouveau courriel</label> - <p class="special invalid" *ngIf="this.fmail.email.hasError('alreadyExist')">L'email est déja utilisé.</p> - <div fxLayout="row" fxLayoutGap="13px"> - <input - type="text" - formControlName="email" - class="form-input" - autocomplete="on" - (keyup)="verifyEmailAlreadyUsed($event.target.value, this.fmail.email)" - /> - <app-svg-icon *ngIf="fmail.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon> - <app-svg-icon - *ngIf="fmail.email.invalid && fmail.email.value" - [type]="'form'" - [icon]="'notValidate'" - ></app-svg-icon> - </div> - </div> - <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> - <button - type="submit" - [ngClass]="{ invalid: formEmail.invalid }" - class="btn-primary small leave" - (click)="submitEmail()" - > - Valider - </button> - </div> - </form> - <div - *ngIf="editModal == typeModalProfile.deleteAccount" - class="contentModal" - fxLayout="column" - fxLayoutAlign="center start" - fxLayoutGap="30px" - > - <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> - <h2>Supprimer un compte</h2> - <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> - </div> - <div fxLayout="column" fxLayoutGap="16px"> - <div class="row removeOwner" *ngFor="let owner of currentStructureOwners.owners" fxLayoutGap="16px"> - <button class="btn-primary small" (click)="removeOwner(owner.id)">X</button> - <span> - {{ owner.email }} - </span> - </div> - </div> - <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> - <button type="button" class="btn-primary small leave" (click)="closeModalOptsProfile()">Terminer</button> - </div> - </div> - <form - *ngIf="editModal == typeModalProfile.addAccount" - [formGroup]="formAddAccount" - class="contentModal" - fxLayout="column" - fxLayoutAlign="center start" - fxLayoutGap="30px" - > - <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> - <h2>Ajouter un compte</h2> - <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> - </div> - <div class="form-group" fxLayout="column"> - <label for="email">Courriel du compte à ajouter</label> - <p *ngIf="ownerAlreadyLinked" class="special invalid">L'email est déjà rattaché à la structure.</p> - <div fxLayout="row" fxLayoutGap="13px"> - <input type="text" formControlName="email" class="form-input" autocomplete="on" /> - <app-svg-icon *ngIf="fAddAccount.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon> - <app-svg-icon - *ngIf="fAddAccount.email.invalid && fAddAccount.email.value" - [type]="'form'" - [icon]="'notValidate'" - ></app-svg-icon> - </div> - </div> - <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> - <button - type="submit" - [ngClass]="{ invalid: formAddAccount.invalid }" - class="btn-primary small leave" - (click)="addOwner()" - > - Envoyer - </button> - </div> - </form> - </div> -</div> -<app-modal-confirmation - [openned]="deleteModalStructureOpenned" - [content]="'Voulez-vous vraiment supprimer cette structure ?'" - (closed)="deleteStructure($event)" -></app-modal-confirmation> -<app-modal-confirmation - [openned]="deleteModalAccountOpenned" - [content]="'Voulez-vous vraiment supprimer votre compte ?'" - (closed)="deleteAccount($event)" -></app-modal-confirmation> diff --git a/src/app/profile/profile.component.scss b/src/app/profile/profile.component.scss index 090368df6c928fdd05662d52211a3f3f0b12b4db..50f831bd0b480351d3ba1edd610a51b51604c058 100644 --- a/src/app/profile/profile.component.scss +++ b/src/app/profile/profile.component.scss @@ -46,13 +46,6 @@ } } } -button { - &.transparent { - background: none; - border: 1px solid $grey-4; - border-radius: 6px; - } -} .structureSection { margin-bottom: 108px; .structureCard { @@ -88,79 +81,3 @@ button { color: $white; } } -.contentModal { - padding: 35px 34px 18px 54px !important; - .headerModal { - width: 100%; - } - p { - &.special { - margin: 8px 0; - @include cn-regular-14; - color: $grey-3; - &.invalid { - color: $orange-warning; - } - } - } - .removeOwner { - button { - width: 40px; - background-color: $red-default; - } - span { - @include cn-bold-18; - } - } - button { - &.invalid { - opacity: 0.4; - } - } - .form-group { - width: 100%; - padding-right: 40px; - input { - width: 100%; - } - } - .ico-close-details { - min-width: 40px; - } -} - -ul { - list-style: none; - margin: 0; - padding-left: 0; -} - -li { - fill: $secondary-color; - color: $black; - display: block; - float: left; - position: relative; - text-decoration: none; - button { - width: 40px; - fill: $secondary-color; - &.active { - background-color: $secondary-color; - fill: $white; - border-color: $secondary-color; - } - &:hover { - background-color: $secondary-color; - fill: $white; - border-color: $secondary-color; - } - } -} - -ul li ul { - position: absolute; - display: block; - margin-left: -268px; - margin-top: 7px; -} diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts index 67cb9257417d663de7f44e61de8c397327850f14..0b3b1d36c276ff97445d274268e12faa1ce09d7a 100644 --- a/src/app/profile/profile.component.ts +++ b/src/app/profile/profile.component.ts @@ -1,16 +1,9 @@ import { Component, OnInit } from '@angular/core'; -import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; -import { Structure } from '../models/structure.model'; import { StructureWithOwners } from '../models/structureWithOwners.model'; -import { TempUser } from '../models/temp-user.model'; import { User } from '../models/user.model'; import { AuthService } from '../services/auth.service'; import { StructureService } from '../services/structure.service'; -import { MustMatch } from '../shared/validator/form'; -import { CustomRegExp } from '../utils/CustomRegExp'; -import { FunctionTypeModalOptions } from './enum/functionTypeModalOptions.enum'; -import { TypeModalProfile } from './enum/TypeModalProfile.enum'; import { ProfileService } from './services/profile.service'; @Component({ @@ -19,42 +12,14 @@ import { ProfileService } from './services/profile.service'; styleUrls: ['./profile.component.scss'], }) export class ProfileComponent implements OnInit { - // Password profile - public formPassword: FormGroup; - public isShowOldPassword = false; - public isShowPassword = false; - public isShowConfirmPassword = false; - public changePassword = false; - public passwordError = false; - - // Email profile - public formEmail: FormGroup; - public changeEmail = false; - - // formAddAccount - public formAddAccount: FormGroup; - public ownerAlreadyLinked = false; - - // Global var public userProfile: User; - public loading = false; public structures: StructureWithOwners[] = []; - public editModal: TypeModalProfile; - public typeModalProfile = TypeModalProfile; - - // Modal options - public modalOptsStructureIndex: number; - public isModalOptsProfile = false; - public currentStructureOwners: StructureWithOwners; - public deleteModalStructureOpenned = false; - public deleteModalAccountOpenned = false; constructor( - private authService: AuthService, - private formBuilder: FormBuilder, private profileService: ProfileService, private structureService: StructureService, - private router: Router + private router: Router, + private authService: AuthService ) {} ngOnInit(): void { @@ -67,198 +32,13 @@ export class ProfileComponent implements OnInit { }); }); }); - this.initForm(); - } - public initForm(): void { - this.formPassword = this.formBuilder.group( - { - oldPassword: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]], - password: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]], - confirmPassword: [''], - }, - { validator: MustMatch('password', 'confirmPassword') } - ); - - this.formEmail = this.formBuilder.group({ - email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]], - }); - - this.formAddAccount = this.formBuilder.group({ - email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]], - }); - } - // getter for form fields - get fpass(): { [key: string]: AbstractControl } { - return this.formPassword.controls; - } - - // getter for form fields - get fmail(): { [key: string]: AbstractControl } { - return this.formEmail.controls; - } - - get fAddAccount(): { [key: string]: AbstractControl } { - return this.formAddAccount.controls; - } - - public closeModalOpts(functionType: number): void { - switch (functionType) { - case FunctionTypeModalOptions.changeEmail: - this.editModal = TypeModalProfile.email; - break; - case FunctionTypeModalOptions.changePassword: - this.editModal = TypeModalProfile.password; - break; - case FunctionTypeModalOptions.deleteAccount: - this.toggleDeleteAccountModal(); - break; - case FunctionTypeModalOptions.addUser: - this.editModal = TypeModalProfile.addAccount; - this.ownerAlreadyLinked = false; - break; - case FunctionTypeModalOptions.removeUser: - this.editModal = TypeModalProfile.deleteAccount; - break; - case FunctionTypeModalOptions.editStructure: - this.router.navigateByUrl('/create-structure', { state: { data: this.currentStructureOwners.structure } }); - break; - case FunctionTypeModalOptions.removeStructure: - this.toggleDeleteStructureModal(); - break; - default: - break; - } - this.isModalOptsProfile = false; - this.modalOptsStructureIndex = null; - } - - // Profile Section - public closeModalOptsProfile(): void { - this.editModal = null; - this.formAddAccount.reset(); - this.formEmail.reset(); - this.formPassword.reset(); - } - public submitEmail(): void { - // stop here if form is invalid - if (this.formEmail.invalid) { - return; - } - this.loading = true; - this.profileService.changeEmail(this.formEmail.value.email, this.userProfile.email).subscribe( - () => { - this.closeModalOptsProfile(); - this.formEmail.reset(); - this.loading = false; - }, - (err) => { - this.loading = false; - } - ); - } - public submitPassword(): void { - // stop here if form is invalid - if (this.formPassword.invalid) { - return; - } - this.loading = true; - - this.profileService.changePassword(this.formPassword.value.password, this.formPassword.value.oldPassword).subscribe( - () => { - this.closeModalOptsProfile(); - this.formPassword.reset(); - this.loading = false; - this.passwordError = false; - }, - (error) => { - this.passwordError = true; - this.loading = false; - } - ); - } - public openModalOptsProfile(): void { - this.isModalOptsProfile = true; - } - public showOldPassword(): void { - this.isShowOldPassword = !this.isShowOldPassword; - } - public showPassword(): void { - this.isShowPassword = !this.isShowPassword; - } - public showConfirmPassword(): void { - this.isShowConfirmPassword = !this.isShowConfirmPassword; - } - public logout(): void { - this.authService.logout(); - } - public deleteAccount(shouldDelete: boolean): void { - this.toggleDeleteAccountModal(); - if (shouldDelete) { - this.profileService.deleteProfile().subscribe(() => { - this.logout(); - }); - } } - // Structure section - public openModalOptsStructure(index: number, s: StructureWithOwners): void { - this.modalOptsStructureIndex = index; - this.currentStructureOwners = s; - } public addStructure(): void { this.router.navigateByUrl('/create-structure'); } - private toggleDeleteStructureModal(): void { - this.deleteModalStructureOpenned = !this.deleteModalStructureOpenned; - } - private toggleDeleteAccountModal(): void { - this.deleteModalAccountOpenned = !this.deleteModalAccountOpenned; - } - public deleteStructure(shouldDelete: boolean): void { - this.toggleDeleteStructureModal(); - if (shouldDelete) { - this.structureService.delete(this.currentStructureOwners.structure._id).subscribe((structure: Structure) => { - this.ngOnInit(); - }); - } - } - - public verifyEmailAlreadyUsed(inputEmail, formControl: FormControl): void { - if (formControl.valid) { - this.profileService.isEmailAlreadyUsed(inputEmail).subscribe((isExist) => { - if (isExist) { - formControl.setErrors({ alreadyExist: true }); - } - }); - } - } - public removeOwner(owner: string): void { - this.structureService.removeOwnerFromStructure(owner, this.currentStructureOwners.structure._id).subscribe(() => { - this.currentStructureOwners.owners = this.currentStructureOwners.owners.filter((o) => o.id !== owner); - if (this.currentStructureOwners.owners.length == 0) { - this.closeModalOptsProfile(); - } - }); - } - public addOwner(): void { - // stop here if form is invalid - if (this.formAddAccount.invalid) { - return; - } - this.loading = true; - const user = new TempUser(); - user.email = this.fAddAccount.email.value; - this.structureService.addOwnerToStructure(user, this.currentStructureOwners.structure._id).subscribe( - () => { - this.closeModalOptsProfile(); - this.formAddAccount.reset(); - this.loading = false; - }, - (err) => { - this.ownerAlreadyLinked = true; - this.loading = false; - } - ); + public logout(): void { + this.authService.logout(); } } diff --git a/src/app/profile/profile.module.ts b/src/app/profile/profile.module.ts index adf5fb74ccae8cf5c59f9de05a0fd95e7ce1b3f4..a9427003f2507d4092e966617363aa223996b4f5 100644 --- a/src/app/profile/profile.module.ts +++ b/src/app/profile/profile.module.ts @@ -3,11 +3,10 @@ import { ProfileComponent } from './profile.component'; import { SharedModule } from '../shared/shared.module'; import { CommonModule } from '@angular/common'; import { BrowserModule } from '@angular/platform-browser'; -import { ModalOptionsComponent } from './modal-options/modal-options.component'; @NgModule({ imports: [CommonModule, BrowserModule, SharedModule], - declarations: [ProfileComponent, ModalOptionsComponent], + declarations: [ProfileComponent], exports: [ProfileComponent], }) export class ProfileModule {} diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts index 4fecd7be063fdc5bf811c6f6105dca31bf35b3b4..9cad91820ad53c6195edba75cd07a1d27d01aac1 100644 --- a/src/app/shared/components/index.ts +++ b/src/app/shared/components/index.ts @@ -12,6 +12,8 @@ import { HourPickerComponent } from './hour-picker/hour-picker.component'; import { CopyPasteComponent } from './hour-picker/copy-paste/copy-paste.component'; import { RadioFormComponent } from './radio-form/radio-form.component'; import { ModalConfirmationComponent } from './modal-confirmation/modal-confirmation.component'; +import { StructureOptionsModalComponent } from './structure-options-modal/structure-options-modal.component'; +import { ModalOptionsComponent } from './modal-options/modal-options.component'; // tslint:disable-next-line: max-line-length export { @@ -29,6 +31,8 @@ export { CopyPasteComponent, RadioFormComponent, ModalConfirmationComponent, + StructureOptionsModalComponent, + ModalOptionsComponent, }; // tslint:disable-next-line:variable-name @@ -47,4 +51,6 @@ export const SharedComponents = [ CopyPasteComponent, RadioFormComponent, ModalConfirmationComponent, + StructureOptionsModalComponent, + ModalOptionsComponent, ]; diff --git a/src/app/profile/modal-options/modal-options.component.html b/src/app/shared/components/modal-options/modal-options.component.html similarity index 92% rename from src/app/profile/modal-options/modal-options.component.html rename to src/app/shared/components/modal-options/modal-options.component.html index 6d8a62025d9bdd3ba23176954b43e8dca002b8b4..0e45ca7cc1e91a5f82d66650fc0b615808afc922 100644 --- a/src/app/profile/modal-options/modal-options.component.html +++ b/src/app/shared/components/modal-options/modal-options.component.html @@ -28,7 +28,13 @@ <app-svg-icon [type]="'ico'" [iconColor]="'inherit'" [icon]="'remove'"></app-svg-icon> <p>Supprimer un compte</p> </div> - <div (click)="closeModal(functionType.editStructure)" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="9px"> + <div + *ngIf="!isEditFormView" + (click)="closeModal(functionType.editStructure)" + fxLayout="row" + fxLayoutAlign="start center" + fxLayoutGap="9px" + > <app-svg-icon [type]="'ico'" [iconColor]="'inherit'" [icon]="'edit'"></app-svg-icon> <p>Modifier la structure</p> </div> diff --git a/src/app/profile/modal-options/modal-options.component.scss b/src/app/shared/components/modal-options/modal-options.component.scss similarity index 78% rename from src/app/profile/modal-options/modal-options.component.scss rename to src/app/shared/components/modal-options/modal-options.component.scss index 907e3f944e88d23fa74cc3de44d9d17b466da45f..33159ef26d8514ce033954ebc711b493e2be634a 100644 --- a/src/app/profile/modal-options/modal-options.component.scss +++ b/src/app/shared/components/modal-options/modal-options.component.scss @@ -1,7 +1,7 @@ -@import '../../../assets/scss/color'; -@import '../../../assets/scss/typography'; -@import '../../../assets/scss/shapes'; -@import '../../../assets/scss/z-index'; +@import '../../../../assets/scss/color'; +@import '../../../../assets/scss/typography'; +@import '../../../../assets/scss/shapes'; +@import '../../../../assets/scss/z-index'; .modalOptions { width: 300px; diff --git a/src/app/profile/modal-options/modal-options.component.spec.ts b/src/app/shared/components/modal-options/modal-options.component.spec.ts similarity index 100% rename from src/app/profile/modal-options/modal-options.component.spec.ts rename to src/app/shared/components/modal-options/modal-options.component.spec.ts diff --git a/src/app/profile/modal-options/modal-options.component.ts b/src/app/shared/components/modal-options/modal-options.component.ts similarity index 81% rename from src/app/profile/modal-options/modal-options.component.ts rename to src/app/shared/components/modal-options/modal-options.component.ts index e9eb32e289eda09013fd52963fa1a67a2b8f51da..4de502a5c414fe46cc6ebf71b77002bb53ba0276 100644 --- a/src/app/profile/modal-options/modal-options.component.ts +++ b/src/app/shared/components/modal-options/modal-options.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FunctionTypeModalOptions } from '../enum/functionTypeModalOptions.enum'; +import { FunctionTypeModalOptions } from '../../enum/functionTypeModalOptions.enum'; @Component({ selector: 'app-modal-options', @@ -12,6 +12,7 @@ export class ModalOptionsComponent implements OnInit { constructor() {} @Input() isModalProfileOpts = false; @Input() hasOwners = true; + @Input() public isEditFormView? = false; @Output() closed = new EventEmitter<number>(); ngOnInit(): void {} diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.html b/src/app/shared/components/structure-options-modal/structure-options-modal.component.html new file mode 100644 index 0000000000000000000000000000000000000000..a5f68cc4d0a307ce11d08f91d231ff29168fd1a1 --- /dev/null +++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.html @@ -0,0 +1,227 @@ +<nav aria-label="modalOption"> + <ul> + <li> + <button [ngClass]="{ active: active }" (click)="openModalOpts()" class="btn-primary transparent"> + <app-svg-icon [type]="'ico'" [iconColor]="'inherit'" [icon]="'moreOpts'"></app-svg-icon> + </button> + <ul *ngIf="showModalOption" class="dropdown"> + <app-modal-options + [isModalProfileOpts]="!structure" + [isEditFormView]="structure && isEditFormView" + [hasOwners]="structure && structure.owners.length > 0" + (closed)="closeModalOpts($event)" + ></app-modal-options> + </ul> + </li> + </ul> +</nav> +<div *ngIf="editModal" class="modalBackground"> + <div class="modal" (clickOutside)="closeModalOptsProfile()"> + <form + *ngIf="editModal == typeModalProfile.password" + [formGroup]="formPassword" + class="contentModal" + fxLayout="column" + fxLayoutAlign="center start" + fxLayoutGap="20px" + > + <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> + <h2>Changer de mot de passe</h2> + <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> + </div> + <div class="form-group" fxLayout="column" fxLayoutGap="4px"> + <label for="oldPassword">Ancien mot de passe</label> + <p *ngIf="passwordError" class="special invalid">Votre ancien mot de passe est incorrect.</p> + <div fxLayout="row" fxLayoutGap="13px"> + <input + [type]="isShowOldPassword ? 'text' : 'password'" + formControlName="oldPassword" + class="form-input password" + autocomplete="on" + /> + <app-svg-icon + (click)="showOldPassword()" + [type]="'form'" + [iconClass]="'grey'" + [icon]="'eyePassword'" + ></app-svg-icon> + <app-svg-icon *ngIf="passwordError" [type]="'form'" [icon]="'notValidate'"></app-svg-icon> + </div> + </div> + <div class="form-group" fxLayout="column"> + <label for="password">Nouveau mot de passe</label> + <p class="special" [ngClass]="{ invalid: fpass.password.invalid && fpass.password.value }"> + Le mot de passe doit contenir au minimum : 8 caractères dont un caractère spécial, un caractère en majuscule + et un chiffre. + </p> + <div fxLayout="row" fxLayoutGap="13px"> + <input + [type]="isShowPassword ? 'text' : 'password'" + formControlName="password" + class="form-input password" + autocomplete="on" + /> + <app-svg-icon + (click)="showPassword()" + [type]="'form'" + [iconClass]="'grey'" + [icon]="'eyePassword'" + ></app-svg-icon> + <app-svg-icon *ngIf="fpass.password.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon> + <app-svg-icon + *ngIf="fpass.password.invalid && fpass.password.value" + [type]="'form'" + [icon]="'notValidate'" + ></app-svg-icon> + </div> + </div> + <div class="form-group" fxLayout="column"> + <label for="confirmPassword">Confirmation du mot de passe</label> + <div fxLayout="row" fxLayoutGap="13px"> + <input + [type]="isShowConfirmPassword ? 'text' : 'password'" + formControlName="confirmPassword" + class="form-input password" + autocomplete="on" + /> + <app-svg-icon + (click)="showConfirmPassword()" + [type]="'form'" + [iconClass]="'grey'" + [icon]="'eyePassword'" + ></app-svg-icon> + <app-svg-icon + *ngIf="fpass.confirmPassword.valid && fpass.password.value" + [type]="'form'" + [icon]="'validate'" + ></app-svg-icon> + <app-svg-icon + *ngIf="fpass.confirmPassword.invalid && fpass.confirmPassword.value" + [type]="'form'" + [icon]="'notValidate'" + ></app-svg-icon> + </div> + </div> + <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> + <button + type="submit" + [ngClass]="{ invalid: formPassword.invalid }" + class="btn-primary small leave" + (click)="submitPassword()" + > + Valider + </button> + </div> + </form> + <form + *ngIf="editModal == typeModalProfile.email" + [formGroup]="formEmail" + class="contentModal" + fxLayout="column" + fxLayoutAlign="center start" + > + <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> + <h2>Changer de courriel</h2> + <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> + </div> + <div class="form-group" fxLayout="column"> + <label for="email">Nouveau courriel</label> + <p class="special invalid" *ngIf="this.fmail.email.hasError('alreadyExist')">L'email est déja utilisé.</p> + <div fxLayout="row" fxLayoutGap="13px"> + <input + type="text" + formControlName="email" + class="form-input" + autocomplete="on" + (keyup)="verifyEmailAlreadyUsed($event.target.value, this.fmail.email)" + /> + <app-svg-icon *ngIf="fmail.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon> + <app-svg-icon + *ngIf="fmail.email.invalid && fmail.email.value" + [type]="'form'" + [icon]="'notValidate'" + ></app-svg-icon> + </div> + </div> + <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> + <button + type="submit" + [ngClass]="{ invalid: formEmail.invalid }" + class="btn-primary small leave" + (click)="submitEmail()" + > + Valider + </button> + </div> + </form> + <div + *ngIf="editModal == typeModalProfile.deleteAccount" + class="contentModal" + fxLayout="column" + fxLayoutAlign="center start" + fxLayoutGap="30px" + > + <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> + <h2>Supprimer un compte</h2> + <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> + </div> + <div fxLayout="column" fxLayoutGap="16px"> + <div class="row removeOwner" *ngFor="let owner of structure.owners" fxLayoutGap="16px"> + <button class="btn-primary small" (click)="removeOwner(owner.id)">X</button> + <span> + {{ owner.email }} + </span> + </div> + </div> + <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> + <button type="button" class="btn-primary small leave" (click)="closeModalOptsProfile()">Terminer</button> + </div> + </div> + <form + *ngIf="editModal == typeModalProfile.addAccount" + [formGroup]="formAddAccount" + class="contentModal" + fxLayout="column" + fxLayoutAlign="center start" + fxLayoutGap="30px" + > + <div fxLayout="row" class="headerModal" fxLayoutAlign="space-between center"> + <h2>Ajouter un compte</h2> + <div class="ico-close-details" (click)="closeModalOptsProfile()"></div> + </div> + <div class="form-group" fxLayout="column"> + <label for="email">Courriel du compte à ajouter</label> + <p *ngIf="ownerAlreadyLinked" class="special invalid">L'email est déjà rattaché à la structure.</p> + <div fxLayout="row" fxLayoutGap="13px"> + <input type="text" formControlName="email" class="form-input" autocomplete="on" /> + <app-svg-icon *ngIf="fAddAccount.email.valid" [type]="'form'" [icon]="'validate'"></app-svg-icon> + <app-svg-icon + *ngIf="fAddAccount.email.invalid && fAddAccount.email.value" + [type]="'form'" + [icon]="'notValidate'" + ></app-svg-icon> + </div> + </div> + <div class="footerModal" fxLayout="row" fxLayoutAlign="center center"> + <button + type="submit" + [ngClass]="{ invalid: formAddAccount.invalid }" + class="btn-primary small leave" + (click)="addOwner()" + > + Envoyer + </button> + </div> + </form> + </div> +</div> +<app-modal-confirmation + [openned]="deleteModalStructureOpenned" + [content]="'Voulez-vous vraiment supprimer cette structure ?'" + (closed)="deleteStructure($event)" +></app-modal-confirmation> +<app-modal-confirmation + [openned]="deleteModalAccountOpenned" + [content]="'Voulez-vous vraiment supprimer votre compte ?'" + (closed)="deleteAccount($event)" +></app-modal-confirmation> diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.scss b/src/app/shared/components/structure-options-modal/structure-options-modal.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..6edbfaaaf25e17a16eab777fc26c60686beec7d7 --- /dev/null +++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.scss @@ -0,0 +1,86 @@ +@import '../../../../assets/scss/color'; +@import '../../../../assets/scss/typography'; + +ul { + list-style: none; + margin: 0; + padding-left: 0; +} + +li { + fill: $secondary-color; + color: $black; + display: block; + float: left; + position: relative; + text-decoration: none; + button { + width: 40px; + fill: $secondary-color; + &.active { + background-color: $secondary-color; + fill: $white; + border-color: $secondary-color; + } + &:hover { + background-color: $secondary-color; + fill: $white; + border-color: $secondary-color; + } + } +} + +ul li ul { + position: absolute; + display: block; + margin-left: -268px; + margin-top: 7px; +} + +button { + &.transparent { + background: none; + border: 1px solid $grey-4; + border-radius: 6px; + } +} +.contentModal { + padding: 35px 34px 18px 54px !important; + .headerModal { + width: 100%; + } + p { + &.special { + margin: 8px 0; + @include cn-regular-14; + color: $grey-3; + &.invalid { + color: $orange-warning; + } + } + } + .removeOwner { + button { + width: 40px; + background-color: $red-default; + } + span { + @include cn-bold-18; + } + } + button { + &.invalid { + opacity: 0.4; + } + } + .form-group { + width: 100%; + padding-right: 40px; + input { + width: 100%; + } + } + .ico-close-details { + min-width: 40px; + } +} diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts b/src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ffffb034a11840470e58c5969e4b8bedc0d616e --- /dev/null +++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StructureOptionsModalComponent } from './structure-options-modal.component'; + +describe('StructureOptionsModalComponent', () => { + let component: StructureOptionsModalComponent; + let fixture: ComponentFixture<StructureOptionsModalComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [StructureOptionsModalComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(StructureOptionsModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/structure-options-modal/structure-options-modal.component.ts b/src/app/shared/components/structure-options-modal/structure-options-modal.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..dccf978c4e929bdb5d20882d324656e9f4a42366 --- /dev/null +++ b/src/app/shared/components/structure-options-modal/structure-options-modal.component.ts @@ -0,0 +1,237 @@ +import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core'; +import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { StructureWithOwners } from '../../../models/structureWithOwners.model'; +import { TempUser } from '../../../models/temp-user.model'; +import { User } from '../../../models/user.model'; +import { TypeModalProfile } from '../../../profile/enum/TypeModalProfile.enum'; +import { ProfileService } from '../../../profile/services/profile.service'; +import { AuthService } from '../../../services/auth.service'; +import { StructureService } from '../../../services/structure.service'; +import { CustomRegExp } from '../../../utils/CustomRegExp'; +import { FunctionTypeModalOptions } from '../../enum/functionTypeModalOptions.enum'; +import { MustMatch } from '../../validator/form'; + +@Component({ + selector: 'app-structure-options-modal', + templateUrl: './structure-options-modal.component.html', + styleUrls: ['./structure-options-modal.component.scss'], +}) +export class StructureOptionsModalComponent implements OnInit { + // Global var + @Input() public structure?: StructureWithOwners; + @Input() public userProfile?: User; + @Input() public isEditFormView? = false; + @Output() closed = new EventEmitter(); + public active: boolean; + + // Password profile + public formPassword: FormGroup; + public isShowOldPassword = false; + public isShowPassword = false; + public isShowConfirmPassword = false; + public passwordError = false; + + // AddAccount + public formAddAccount: FormGroup; + public ownerAlreadyLinked = false; + + // Email profile + public formEmail: FormGroup; + public changeEmail = false; + + // Modal var + public editModal: TypeModalProfile; + public deleteModalAccountOpenned = false; + public deleteModalStructureOpenned = false; + public showModalOption = false; + public typeModalProfile = TypeModalProfile; + + constructor( + private router: Router, + private formBuilder: FormBuilder, + private profileService: ProfileService, + private authService: AuthService, + private structureService: StructureService + ) {} + + ngOnInit(): void { + this.formPassword = this.formBuilder.group( + { + oldPassword: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]], + password: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]], + confirmPassword: [''], + }, + { validator: MustMatch('password', 'confirmPassword') } + ); + this.formEmail = this.formBuilder.group({ + email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]], + }); + this.formAddAccount = this.formBuilder.group({ + email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]], + }); + } + + public openModalOpts(): void { + this.showModalOption = true; + this.active = true; + } + + // getter for form fields + get fmail(): { [key: string]: AbstractControl } { + return this.formEmail.controls; + } + + // getter for form fields + get fAddAccount(): { [key: string]: AbstractControl } { + return this.formAddAccount.controls; + } + + // getter for form fields + get fpass(): { [key: string]: AbstractControl } { + return this.formPassword.controls; + } + + public showOldPassword(): void { + this.isShowOldPassword = !this.isShowOldPassword; + } + public showPassword(): void { + this.isShowPassword = !this.isShowPassword; + } + public showConfirmPassword(): void { + this.isShowConfirmPassword = !this.isShowConfirmPassword; + } + + public closeModalOpts(functionType: number): void { + switch (functionType) { + case FunctionTypeModalOptions.changeEmail: + this.editModal = TypeModalProfile.email; + break; + case FunctionTypeModalOptions.changePassword: + this.editModal = TypeModalProfile.password; + break; + case FunctionTypeModalOptions.deleteAccount: + this.toggleDeleteAccountModal(); + break; + case FunctionTypeModalOptions.addUser: + this.editModal = TypeModalProfile.addAccount; + this.ownerAlreadyLinked = false; + break; + case FunctionTypeModalOptions.removeUser: + this.editModal = TypeModalProfile.deleteAccount; + break; + case FunctionTypeModalOptions.editStructure: + this.router.navigateByUrl('/create-structure', { state: { data: this.structure.structure } }); + break; + case FunctionTypeModalOptions.removeStructure: + this.toggleDeleteStructureModal(); + break; + default: + break; + } + this.showModalOption = false; + this.active = false; + } + + // Profile Section + public closeModalOptsProfile(): void { + this.editModal = null; + //this.formAddAccount.reset(); + this.formEmail.reset(); + this.formPassword.reset(); + } + + private toggleDeleteAccountModal(): void { + this.deleteModalAccountOpenned = !this.deleteModalAccountOpenned; + } + private toggleDeleteStructureModal(): void { + this.deleteModalStructureOpenned = !this.deleteModalStructureOpenned; + } + + public deleteAccount(shouldDelete: boolean): void { + this.toggleDeleteAccountModal(); + if (shouldDelete) { + this.profileService.deleteProfile().subscribe(() => { + this.logout(); + }); + } + } + + public deleteStructure(shouldDelete: boolean): void { + this.toggleDeleteStructureModal(); + if (shouldDelete) { + this.structureService.delete(this.structure.structure._id).subscribe(() => { + this.closed.emit(''); + }); + } + } + + public logout(): void { + this.authService.logout(); + } + + public submitPassword(): void { + // stop here if form is invalid + if (this.formPassword.invalid) { + return; + } + this.profileService.changePassword(this.formPassword.value.password, this.formPassword.value.oldPassword).subscribe( + () => { + this.closeModalOptsProfile(); + this.formPassword.reset(); + this.passwordError = false; + }, + (error) => { + this.passwordError = true; + } + ); + } + + public addOwner(): void { + // stop here if form is invalid + if (this.formAddAccount.invalid) { + return; + } + const user = new TempUser(); + user.email = this.fAddAccount.email.value; + this.structureService.addOwnerToStructure(user, this.structure.structure._id).subscribe( + () => { + this.closeModalOptsProfile(); + this.formAddAccount.reset(); + }, + (err) => { + this.ownerAlreadyLinked = true; + } + ); + } + + public removeOwner(owner: string): void { + this.structureService.removeOwnerFromStructure(owner, this.structure.structure._id).subscribe(() => { + this.structure.owners = this.structure.owners.filter((o) => o.id !== owner); + if (this.structure.owners.length == 0) { + this.closeModalOptsProfile(); + } + }); + } + + public verifyEmailAlreadyUsed(inputEmail, formControl: FormControl): void { + if (formControl.valid) { + this.profileService.isEmailAlreadyUsed(inputEmail).subscribe((isExist) => { + if (isExist) { + formControl.setErrors({ alreadyExist: true }); + } + }); + } + } + + public submitEmail(): void { + // stop here if form is invalid + if (this.formEmail.invalid) { + return; + } + this.profileService.changeEmail(this.formEmail.value.email, this.userProfile.email).subscribe(() => { + this.closeModalOptsProfile(); + this.formEmail.reset(); + }); + } +} diff --git a/src/app/profile/enum/functionTypeModalOptions.enum.ts b/src/app/shared/enum/functionTypeModalOptions.enum.ts similarity index 100% rename from src/app/profile/enum/functionTypeModalOptions.enum.ts rename to src/app/shared/enum/functionTypeModalOptions.enum.ts diff --git a/src/app/utils/CustomRegExp.ts b/src/app/utils/CustomRegExp.ts index 9fdba4fe0454ca916ba5a0efd6c1eb83e8c4d65d..a4c02ad0a9a8bc495115182f25daab47e7ee213e 100644 --- a/src/app/utils/CustomRegExp.ts +++ b/src/app/utils/CustomRegExp.ts @@ -17,7 +17,7 @@ export class CustomRegExp { public static readonly FACEBOOK: string = '(facebook.com/.{1,})'; public static readonly TWITTER: string = '(twitter.com/.{1,})'; public static readonly INSTAGRAM: string = '(instagram.com/.{1,})'; - public static readonly NO_NULL_NUMBER: string = '[1-9]{1}[0-9]'; + public static readonly NO_NULL_NUMBER: string = '[1-9]{1}[0-9]*?'; /** * Validate a location request in search bar */ diff --git a/src/styles.scss b/src/styles.scss index 09328f51f4da22f0e39a1cfe27e37e16bec7240c..966c57e678d6dba6efa711125c2345e7b9c6a4d1 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -195,6 +195,7 @@ button { position: absolute; content: ''; top: 0; + left: 0; background-color: $modal-background; .modal { max-height: 90%;