From 12730f7821b7ba7ee625eb030a624ce7d7e8a21b Mon Sep 17 00:00:00 2001 From: Marlene Simondant <msimondant@grandlyon.com> Date: Tue, 11 Oct 2022 16:08:14 +0200 Subject: [PATCH 1/8] Create routing and basic page --- src/app/profile/profile-routing.module.ts | 5 ++ src/app/profile/profile.component.html | 6 +-- src/app/profile/profile.component.ts | 2 +- src/app/profile/profile.module.ts | 2 + .../structures-management.component.html | 51 +++++++++++++++++++ .../structures-management.component.scss | 46 +++++++++++++++++ .../structures-management.component.spec.ts | 24 +++++++++ .../structures-management.component.ts | 38 ++++++++++++++ 8 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 src/app/profile/structures-management/structures-management.component.html create mode 100644 src/app/profile/structures-management/structures-management.component.scss create mode 100644 src/app/profile/structures-management/structures-management.component.spec.ts create mode 100644 src/app/profile/structures-management/structures-management.component.ts diff --git a/src/app/profile/profile-routing.module.ts b/src/app/profile/profile-routing.module.ts index 0143e14e2..2ddd5a0c6 100644 --- a/src/app/profile/profile-routing.module.ts +++ b/src/app/profile/profile-routing.module.ts @@ -4,6 +4,7 @@ import { RoleGuard } from '../guards/role.guard'; import { StructureResolver } from '../resolvers/structure.resolver'; import { RouteRole } from '../shared/enum/routeRole.enum'; import { StructureMembersManagementComponent } from './structure-members-management/structure-members-management.component'; +import { StructuresManagementComponent } from './structures-management/structures-management.component'; import { ProfileComponent } from './profile.component'; import { StructureEditionSummaryComponent } from './structure-edition-summary/structure-edition-summary.component'; import { AuthGuard } from '../guards/auth.guard'; @@ -22,6 +23,10 @@ const routes: Routes = [ canActivate: [AuthGuard], component: EditComponent, }, + { + path: 'structures-management', + component: StructuresManagementComponent, + }, footerOutletRoute, { path: '', diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html index a5a2cfcc4..79b9379cf 100644 --- a/src/app/profile/profile.component.html +++ b/src/app/profile/profile.component.html @@ -77,18 +77,16 @@ [iconBtn]="'edit'" [text]="'Gérer mes structures'" [style]="buttonTypeEnum.SecondaryWide" - routerLink="./" + routerLink="./structures-management" [routerLinkActive]="'active'" - [disabled]="true" ></app-button> <app-button class="hide-on-desktop" [type]="'button'" [iconBtn]="'edit'" [style]="buttonTypeEnum.SecondaryOnlyIcon" - routerLink="/" + routerLink="./structures-management" [routerLinkActive]="'active'" - [disabled]="true" ></app-button> </div> <div fxLayoutGap="16px" fxLayout="column" fxFill> diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts index d977fbecd..70d3558d1 100644 --- a/src/app/profile/profile.component.ts +++ b/src/app/profile/profile.component.ts @@ -14,7 +14,7 @@ import { Location } from '@angular/common'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', - styleUrls: ['./profile.component.scss'] + styleUrls: ['./profile.component.scss'], }) export class ProfileComponent implements OnInit { public userProfile: User; diff --git a/src/app/profile/profile.module.ts b/src/app/profile/profile.module.ts index 632d3356d..a81d170f9 100644 --- a/src/app/profile/profile.module.ts +++ b/src/app/profile/profile.module.ts @@ -9,6 +9,7 @@ import { StructureEditionSummaryComponent } from './structure-edition-summary/st import { EditComponent } from './edit/edit.component'; import { StructureMembersManagementComponent } from './structure-members-management/structure-members-management.component'; import { StructureAddMemberModalComponent } from './structure-add-member-modal/structure-add-member-modal.component'; +import { StructuresManagementComponent } from './structures-management/structures-management.component'; import { MissingInformationComponent } from './structure-edition-summary/missing-information/missing-information.component'; import { NoInformationComponent } from './structure-edition-summary/no-information/no-information.component'; @@ -23,6 +24,7 @@ import { NoInformationComponent } from './structure-edition-summary/no-informati StructureAddMemberModalComponent, StructureEditionSummaryComponent, StructureMembersManagementComponent, + StructuresManagementComponent, ], imports: [CommonModule, ProfileRoutingModule, SharedModule], }) diff --git a/src/app/profile/structures-management/structures-management.component.html b/src/app/profile/structures-management/structures-management.component.html new file mode 100644 index 000000000..b860d0cef --- /dev/null +++ b/src/app/profile/structures-management/structures-management.component.html @@ -0,0 +1,51 @@ +<div class="content-container full-screen"> + <div class="container"> + <div class="header"> + <div fxLayout="row" fxLayoutAlign="space-between center" fxFill> + <div fxLayout="row" fxLayoutAlign="start center" class="headerBack"> + <app-svg-icon [iconClass]="'backArrow'" [type]="'ico'" [icon]="'arrowBack'" (click)="goBack()"></app-svg-icon> + <h1>Gérer mes structures</h1> + </div> + <app-button + [style]="buttonTypeEnum.SecondaryWide" + [iconBtn]="'add'" + [text]="'Ajouter une structure'" + routerLink="/form/structure" + tabindex="0" + ></app-button> + </div> + </div> + <div *ngIf="structures"> + <div fxLayoutGap="16px" fxLayout="column" fxFill> + <ng-container *ngIf="structures"> + <div *ngFor="let list of structures; let i = index" class="structureCard"> + <div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px"> + <div fxLayout="column" fxLayoutAlign="space-between start"> + <p class="structureName">{{ list.structure.structureName }}</p> + <p class="structureLocation">{{ list.structure.address.commune }}</p> + </div> + <div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="12px"> + <app-button + [type]="'button'" + [text]="'Quitter la structure'" + [style]="buttonTypeEnum.SecondaryWide" + routerLink="./" + [routerLinkActive]="'active'" + ></app-button> + + <app-button + class="deleteAction" + [type]="'button'" + [text]="'Supprimer la structure'" + [style]="buttonTypeEnum.SecondaryWide" + routerLink="./" + [routerLinkActive]="'active'" + ></app-button> + </div> + </div> + </div> + </ng-container> + </div> + </div> + </div> +</div> diff --git a/src/app/profile/structures-management/structures-management.component.scss b/src/app/profile/structures-management/structures-management.component.scss new file mode 100644 index 000000000..386d2920f --- /dev/null +++ b/src/app/profile/structures-management/structures-management.component.scss @@ -0,0 +1,46 @@ +@import '../../../assets/scss/color'; +@import '../../../assets/scss/typography'; +@import '../../../assets/scss/breakpoint'; + +.container { + margin: 1rem auto; + max-width: 980px; + padding: 2rem; + background: $white; + .header { + margin-bottom: 2rem; + } + .headerBack { + cursor: pointer; + span { + color: $red; + } + } + h1 { + @include lato-regular-24; + color: $grey-1; + cursor: initial; + } + + .structureCard { + padding: 5px 6px; + border-bottom: 1px solid $grey-8; + overflow: hidden; + + p { + margin: 0 !important; + &.structureName { + @include lato-bold-16; + } + &.structureLocation { + @include lato-regular-13; + font-style: italic; + color: $grey-3; + } + } + + app-button.deleteAction > ::ng-deep button > div { + color: $red; + } + } +} diff --git a/src/app/profile/structures-management/structures-management.component.spec.ts b/src/app/profile/structures-management/structures-management.component.spec.ts new file mode 100644 index 000000000..9d8850d4e --- /dev/null +++ b/src/app/profile/structures-management/structures-management.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StructuresManagementComponent } from './structures-management.component'; + +describe('StructuresManagementComponent', () => { + let component: StructuresManagementComponent; + let fixture: ComponentFixture<StructuresManagementComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [StructuresManagementComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(StructuresManagementComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/profile/structures-management/structures-management.component.ts b/src/app/profile/structures-management/structures-management.component.ts new file mode 100644 index 000000000..8128f9b20 --- /dev/null +++ b/src/app/profile/structures-management/structures-management.component.ts @@ -0,0 +1,38 @@ +import { Component, OnInit } from '@angular/core'; +import { StructureWithOwners } from '../../models/structureWithOwners.model'; +import { User } from '../../models/user.model'; +import { StructureService } from '../../services/structure.service'; +import { ButtonType } from '../../shared/components/button/buttonType.enum'; +import { ProfileService } from '../services/profile.service'; + +@Component({ + selector: 'app-structures-management', + templateUrl: './structures-management.component.html', + styleUrls: ['./structures-management.component.scss'], +}) +export class StructuresManagementComponent implements OnInit { + public userProfile: User; + public structures: StructureWithOwners[] = []; + public buttonTypeEnum = ButtonType; + + constructor(private profileService: ProfileService, private structureService: StructureService) {} + + ngOnInit(): void { + this.profileService.getProfile().then((profile: User) => { + this.userProfile = profile; + this.getStructures(); + }); + } + public goBack(): void { + history.back(); + } + + private getStructures() { + this.structures = []; + this.userProfile.structuresLink.forEach((structureId) => { + this.structureService.getStructureWithOwners(structureId, null).subscribe((s) => { + this.structures.push(s); + }); + }); + } +} -- GitLab From 2b7f4025878ebeeaf2df94eeabf9b2e2c43804f2 Mon Sep 17 00:00:00 2001 From: Marlene Simondant <msimondant@grandlyon.com> Date: Thu, 13 Oct 2022 11:33:19 +0200 Subject: [PATCH 2/8] modal + leave + cancel delete --- ...tructure-members-management.component.html | 14 ++-- .../structures-management.component.html | 46 +++++++++-- .../structures-management.component.scss | 55 ++++++++++--- .../structures-management.component.ts | 82 ++++++++++++++++++- .../custom-modal/custom-modal.component.html | 28 +++++++ .../custom-modal/custom-modal.component.scss | 46 +++++++++++ .../custom-modal.component.spec.ts | 24 ++++++ .../custom-modal/custom-modal.component.ts | 22 +++++ src/app/shared/components/index.ts | 3 + 9 files changed, 295 insertions(+), 25 deletions(-) create mode 100644 src/app/shared/components/custom-modal/custom-modal.component.html create mode 100644 src/app/shared/components/custom-modal/custom-modal.component.scss create mode 100644 src/app/shared/components/custom-modal/custom-modal.component.spec.ts create mode 100644 src/app/shared/components/custom-modal/custom-modal.component.ts diff --git a/src/app/profile/structure-members-management/structure-members-management.component.html b/src/app/profile/structure-members-management/structure-members-management.component.html index 6d2f1c3da..8d393238f 100644 --- a/src/app/profile/structure-members-management/structure-members-management.component.html +++ b/src/app/profile/structure-members-management/structure-members-management.component.html @@ -78,17 +78,19 @@ [structure]="structureWithOwners" (closed)="closeAddMemberModal($event)" ></app-structure-add-member-modal> -<app-modal-confirmation +<app-custom-modal *ngIf="excludeModalOpenned" [openned]="excludeModalOpenned" [content]="'Souhaitez-vous exclure ce membre\n(' + displayMemberName(memberToExclude) + ') ?'" - [customConfirmationText]="'Oui'" + [hideTitle]="true" + [customValidationButton]="'Oui'" (closed)="excludeMember(memberToExclude, $event)" -></app-modal-confirmation> -<app-modal-confirmation +></app-custom-modal> +<app-custom-modal *ngIf="cancelAddTempUserModalOpenned" [openned]="cancelAddTempUserModalOpenned" [content]="'Souhaitez-vous annuler la demande de rattachement de ce membre\n(' + tempUserToCancel.email + ') ?'" - [customConfirmationText]="'Oui'" + [hideTitle]="true" + [customValidationButton]="'Oui'" (closed)="cancelAddTempUser(tempUserToCancel, $event)" -></app-modal-confirmation> +></app-custom-modal> diff --git a/src/app/profile/structures-management/structures-management.component.html b/src/app/profile/structures-management/structures-management.component.html index b860d0cef..cc6de84fc 100644 --- a/src/app/profile/structures-management/structures-management.component.html +++ b/src/app/profile/structures-management/structures-management.component.html @@ -1,7 +1,7 @@ <div class="content-container full-screen"> <div class="container"> <div class="header"> - <div fxLayout="row" fxLayoutAlign="space-between center" fxFill> + <div fxLayout="row wrap" fxLayoutAlign="space-between center" fxFill> <div fxLayout="row" fxLayoutAlign="start center" class="headerBack"> <app-svg-icon [iconClass]="'backArrow'" [type]="'ico'" [icon]="'arrowBack'" (click)="goBack()"></app-svg-icon> <h1>Gérer mes structures</h1> @@ -19,27 +19,42 @@ <div fxLayoutGap="16px" fxLayout="column" fxFill> <ng-container *ngIf="structures"> <div *ngFor="let list of structures; let i = index" class="structureCard"> - <div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px"> - <div fxLayout="column" fxLayoutAlign="space-between start"> + <div class="structureCardContent" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px"> + <div class="structureDetails" fxLayout="column" fxLayoutAlign="space-between start"> <p class="structureName">{{ list.structure.structureName }}</p> <p class="structureLocation">{{ list.structure.address.commune }}</p> </div> - <div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="12px"> + <div *ngIf="isBeingDeleted(list.structure)" class="deleteInProgress"> + <app-svg-icon [iconClass]="'icon-26'" [type]="'form'" [icon]="'notValidate'"></app-svg-icon> + <span>Suppression en cours</span> + </div> + <div class="buttons" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="12px"> <app-button [type]="'button'" [text]="'Quitter la structure'" [style]="buttonTypeEnum.SecondaryWide" + (click)="selectedStructure = list.structure; leaveModalOpenned = true" + ></app-button> + <app-button + *ngIf="!isBeingDeleted(list.structure)" + class="deleteAction" + [type]="'button'" + [text]="'Supprimer la structure'" + [style]="buttonTypeEnum.SecondaryWide" routerLink="./" [routerLinkActive]="'active'" + (click)="selectedStructure = list.structure; deleteModalOpenned = true" ></app-button> <app-button + *ngIf="isBeingDeleted(list.structure)" class="deleteAction" [type]="'button'" - [text]="'Supprimer la structure'" + [text]="'Annuler la suppression'" [style]="buttonTypeEnum.SecondaryWide" routerLink="./" [routerLinkActive]="'active'" + (click)="selectedStructure = list.structure; deleteModalOpenned = true" ></app-button> </div> </div> @@ -47,5 +62,26 @@ </ng-container> </div> </div> + <app-custom-modal + *ngIf="leaveModalOpenned" + [openned]="leaveModalOpenned" + [content]="'Souhaitez-vous quitter cette structure ?'" + [hideTitle]="true" + (closed)="leaveStructure(selectedStructure, $event)" + ></app-custom-modal> + <app-custom-modal + *ngIf="deleteModalOpenned" + [openned]="deleteModalOpenned" + [content]="'Souhaitez-vous supprimer cette structure ?'" + [hideTitle]="true" + (closed)="deleteStructure(selectedStructure, $event)" + ></app-custom-modal> + <app-custom-modal + *ngIf="cancelDeleteModalOpenned" + [openned]="cancelDeleteModalOpenned" + [content]="'Souhaitez-vous annuler la suppression de cette structure ?'" + [hideTitle]="true" + (closed)="cancelDelete(selectedStructure, $event)" + ></app-custom-modal> </div> </div> diff --git a/src/app/profile/structures-management/structures-management.component.scss b/src/app/profile/structures-management/structures-management.component.scss index 386d2920f..6b7b9c682 100644 --- a/src/app/profile/structures-management/structures-management.component.scss +++ b/src/app/profile/structures-management/structures-management.component.scss @@ -26,21 +26,52 @@ padding: 5px 6px; border-bottom: 1px solid $grey-8; overflow: hidden; - - p { - margin: 0 !important; - &.structureName { - @include lato-bold-16; + .structureCardContent { + @media #{$phone} { + flex-wrap: wrap; } - &.structureLocation { - @include lato-regular-13; - font-style: italic; - color: $grey-3; + .structureDetails { + width: max-content; + width: 45%; + margin-bottom: 8px; + @media #{$phone} { + width: initial; + } + p { + margin: 0 !important; + &.structureName { + @include lato-bold-16; + } + &.structureLocation { + @include lato-regular-13; + font-style: italic; + color: $grey-3; + } + } } - } + .deleteInProgress { + display: flex; + color: $orange-warning; + padding-bottom: 5px; - app-button.deleteAction > ::ng-deep button > div { - color: $red; + span { + max-width: 110px; + } + ::ng-deep svg { + margin-right: 8px; + } + } + .buttons { + @media #{$tablet} { + max-width: 45%; + } + @media #{$phone} { + max-width: initial; + } + } + app-button.deleteAction > ::ng-deep button > div { + color: $red; + } } } } diff --git a/src/app/profile/structures-management/structures-management.component.ts b/src/app/profile/structures-management/structures-management.component.ts index 8128f9b20..06f07ef89 100644 --- a/src/app/profile/structures-management/structures-management.component.ts +++ b/src/app/profile/structures-management/structures-management.component.ts @@ -1,6 +1,10 @@ import { Component, OnInit } from '@angular/core'; +import { forkJoin, Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { Structure } from '../../models/structure.model'; import { StructureWithOwners } from '../../models/structureWithOwners.model'; import { User } from '../../models/user.model'; +import { NotificationService } from '../../services/notification.service'; import { StructureService } from '../../services/structure.service'; import { ButtonType } from '../../shared/components/button/buttonType.enum'; import { ProfileService } from '../services/profile.service'; @@ -13,9 +17,18 @@ import { ProfileService } from '../services/profile.service'; export class StructuresManagementComponent implements OnInit { public userProfile: User; public structures: StructureWithOwners[] = []; + public selectedStructure: string; + public deleteInProgress: boolean; public buttonTypeEnum = ButtonType; + public leaveModalOpenned: boolean = false; + public deleteModalOpenned: boolean = false; + public cancelDeleteModalOpenned: boolean = false; - constructor(private profileService: ProfileService, private structureService: StructureService) {} + constructor( + private profileService: ProfileService, + private structureService: StructureService, + private notificationService: NotificationService + ) {} ngOnInit(): void { this.profileService.getProfile().then((profile: User) => { @@ -28,11 +41,76 @@ export class StructuresManagementComponent implements OnInit { } private getStructures() { + // TODO : faire pareil pour la liste des structure dans le profil + + const structures$: Observable<any>[] = []; this.structures = []; + + this.userProfile.structuresLink.forEach((structureId) => { + structures$.push( + this.structureService.getStructureWithOwners(structureId, null).pipe( + tap((structure) => { + this.structures.push(structure); + }) + ) + ); + }); + forkJoin(structures$).subscribe(() => { + this.structures = this.structures.sort((a, b) => + a.structure.structureName.localeCompare(b.structure.structureName) + ); + }); + + /* + this.structures = []; + this.userProfile.structuresLink.forEach((structureId) => { this.structureService.getStructureWithOwners(structureId, null).subscribe((s) => { this.structures.push(s); + // TODO : trouver bonne synthaxe pour le faire quand tous le ssubscribes sont terminés + this.structures = this.structures.sort((a, b) => + a.structure.structureName.localeCompare(b.structure.structureName) + ); }); - }); + });*/ + } + + public leaveStructure(structure: Structure, shouldExclude: boolean): void { + this.leaveModalOpenned = false; + if (shouldExclude) { + this.structureService.removeOwnerFromStructure(this.userProfile._id, structure._id).subscribe( + () => { + this.structures = this.structures.filter((obj) => obj.structure._id !== structure._id); + this.notificationService.showSuccess(`Vous avez bien quitté ${structure.structureName}`, ''); + }, + () => { + this.notificationService.showError('Une erreur est survenue, veuillez réessayer.', ''); + } + ); + } + } + + public deleteStructure(structure: Structure, shouldDelete: boolean): void { + this.deleteModalOpenned = false; + if (shouldDelete) { + this.structureService.delete(structure._id).subscribe((res) => { + //TODO : maj liste structures + }); + } + } + + public isBeingDeleted(structure: Structure): boolean { + //TODO : return this.structure.tobeDeletedAt && this.structure.tobeDeletedAt.length > 0 + return true; + } + + public cancelDeleteStructure(structure: Structure, shouldCancel: boolean): void { + this.cancelDeleteModalOpenned = false; + if (shouldCancel) { + //TODO : cancel delete + //this.structureService.CancelDelete(structure._id).subscribe((res) => { + //DO something + //}); + } } } diff --git a/src/app/shared/components/custom-modal/custom-modal.component.html b/src/app/shared/components/custom-modal/custom-modal.component.html new file mode 100644 index 000000000..34f4b756c --- /dev/null +++ b/src/app/shared/components/custom-modal/custom-modal.component.html @@ -0,0 +1,28 @@ +<div *ngIf="openned" class="modalBackground"> + <div class="modal"> + <div class="contentModal" fxLayout="column" fxLayoutAlign="space-around center"> + <div class="headerModal"> + <svg aria-hidden="true" (click)="closeModal(false)"> + <use [attr.xlink:href]="'assets/form/sprite.svg#close'"></use> + </svg> + <div class="contentText"> + <h3 *ngIf="!hideTitle && customTitle">{{ customTitle }}</h3> + <h3 *ngIf="!hideTitle && !customTitle">ATTENTION</h3> + <p [ngClass]="{ mainText: hideTitle }">{{ content }}</p> + </div> + </div> + <div class="footerModal" fxLayout="row" fxLayoutAlign="space-around center" fxLayoutGap="8px"> + <app-button + (action)="closeModal(false)" + [text]="customCancelButton ? customCancelButton : 'Annuler'" + [style]="buttonTypeEnum.modalSecondary" + ></app-button> + <app-button + (action)="closeModal(true)" + [text]="customValidationButton ? customValidationButton : 'Valider'" + [style]="buttonTypeEnum.modalPrimary" + ></app-button> + </div> + </div> + </div> +</div> diff --git a/src/app/shared/components/custom-modal/custom-modal.component.scss b/src/app/shared/components/custom-modal/custom-modal.component.scss new file mode 100644 index 000000000..6c682cc2c --- /dev/null +++ b/src/app/shared/components/custom-modal/custom-modal.component.scss @@ -0,0 +1,46 @@ +@import '../../../../assets/scss/color'; +@import '../../../../assets/scss/typography'; +@import '../../../../assets/scss/shapes'; +@import '../../../../assets/scss/z-index'; + +.modalBackground { + .modal { + max-width: 390px; + .contentModal { + padding: 15px 5px 15px 45px; + .headerModal { + display: flex; + flex-direction: row-reverse; + svg { + cursor: pointer; + height: 40px; + width: 40px; + } + .contentText { + flex-direction: column; + max-width: 300px; + h3 { + @include lato-bold-18; + color: $red; + margin: 10px 0 25px; + text-align: center; + } + p { + text-align: center; + margin: 10px; + } + p.mainText { + @include lato-regular-18; + } + } + } + .footerModal { + padding-right: 40px; + gap: 8px; + app-button { + flex: 1; + } + } + } + } +} diff --git a/src/app/shared/components/custom-modal/custom-modal.component.spec.ts b/src/app/shared/components/custom-modal/custom-modal.component.spec.ts new file mode 100644 index 000000000..899fc30d3 --- /dev/null +++ b/src/app/shared/components/custom-modal/custom-modal.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CustomModalComponent } from './custom-modal.component'; + +describe('CustomModalComponent', () => { + let component: CustomModalComponent; + let fixture: ComponentFixture<CustomModalComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CustomModalComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CustomModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/custom-modal/custom-modal.component.ts b/src/app/shared/components/custom-modal/custom-modal.component.ts new file mode 100644 index 000000000..c5401d3bc --- /dev/null +++ b/src/app/shared/components/custom-modal/custom-modal.component.ts @@ -0,0 +1,22 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ButtonType } from '../button/buttonType.enum'; + +@Component({ + selector: 'app-custom-modal', + templateUrl: './custom-modal.component.html', + styleUrls: ['./custom-modal.component.scss'], +}) +export class CustomModalComponent { + @Input() public openned: boolean; + @Input() public content: string; + @Input() public hideTitle?: boolean; + @Input() public customTitle?: string; + @Input() public customValidationButton?: string; + @Input() public customCancelButton?: string; + @Output() closed = new EventEmitter<boolean>(); + public buttonTypeEnum = ButtonType; + + public closeModal(value: boolean): void { + this.closed.emit(value); + } +} diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts index b8449db73..1c8245ed8 100644 --- a/src/app/shared/components/index.ts +++ b/src/app/shared/components/index.ts @@ -10,6 +10,7 @@ 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 { CustomModalComponent } from './custom-modal/custom-modal.component'; import { ModalJoinConfirmationComponent } from './modal-join-confirmation/modal-join-confirmation.component'; import { StructureOptionsModalComponent } from './structure-options-modal/structure-options-modal.component'; import { ModalOptionsComponent } from './modal-options/modal-options.component'; @@ -32,6 +33,7 @@ export { CopyPasteComponent, RadioFormComponent, ModalConfirmationComponent, + CustomModalComponent, StructureOptionsModalComponent, ModalOptionsComponent, TextInputModalComponent, @@ -53,6 +55,7 @@ export const SharedComponents = [ CopyPasteComponent, RadioFormComponent, ModalConfirmationComponent, + CustomModalComponent, ModalJoinConfirmationComponent, StructureOptionsModalComponent, ModalOptionsComponent, -- GitLab From 2b840c750eebacc1859f81f2a898c7dd67ccd8bd Mon Sep 17 00:00:00 2001 From: Etienne LOUPIAS <eloupias@grandlyon.com> Date: Thu, 13 Oct 2022 11:56:01 +0200 Subject: [PATCH 3/8] add cancelDelete service --- src/app/models/structure.model.ts | 2 ++ .../structures-management.component.html | 2 +- .../structures-management.component.ts | 10 +++------- src/app/services/structure.service.ts | 4 ++++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/app/models/structure.model.ts b/src/app/models/structure.model.ts index 344e442ea..c77043910 100644 --- a/src/app/models/structure.model.ts +++ b/src/app/models/structure.model.ts @@ -12,6 +12,8 @@ export class Structure { public numero: string = null; public createdAt: string = null; public updatedAt: string = null; + public toBeDeletedAt: string = null; + public deletedAt: string = null; public structureName: string = null; public structureType: string = null; public description: string = null; diff --git a/src/app/profile/structures-management/structures-management.component.html b/src/app/profile/structures-management/structures-management.component.html index cc6de84fc..198fc48b3 100644 --- a/src/app/profile/structures-management/structures-management.component.html +++ b/src/app/profile/structures-management/structures-management.component.html @@ -54,7 +54,7 @@ [style]="buttonTypeEnum.SecondaryWide" routerLink="./" [routerLinkActive]="'active'" - (click)="selectedStructure = list.structure; deleteModalOpenned = true" + (click)="selectedStructure = list.structure; cancelDeleteModalOpenned = true" ></app-button> </div> </div> diff --git a/src/app/profile/structures-management/structures-management.component.ts b/src/app/profile/structures-management/structures-management.component.ts index 06f07ef89..9f8c6419c 100644 --- a/src/app/profile/structures-management/structures-management.component.ts +++ b/src/app/profile/structures-management/structures-management.component.ts @@ -100,17 +100,13 @@ export class StructuresManagementComponent implements OnInit { } public isBeingDeleted(structure: Structure): boolean { - //TODO : return this.structure.tobeDeletedAt && this.structure.tobeDeletedAt.length > 0 - return true; + return Boolean(structure.toBeDeletedAt); } - public cancelDeleteStructure(structure: Structure, shouldCancel: boolean): void { + public cancelDelete(structure: Structure, shouldCancel: boolean): void { this.cancelDeleteModalOpenned = false; if (shouldCancel) { - //TODO : cancel delete - //this.structureService.CancelDelete(structure._id).subscribe((res) => { - //DO something - //}); + this.structureService.cancelDelete(structure._id).subscribe((res) => {}); } } } diff --git a/src/app/services/structure.service.ts b/src/app/services/structure.service.ts index 662d69955..698064f0d 100644 --- a/src/app/services/structure.service.ts +++ b/src/app/services/structure.service.ts @@ -64,6 +64,10 @@ export class StructureService { return this.http.delete<Structure>(`${this.baseUrl}/${id}`); } + public cancelDelete(id: string): Observable<Structure> { + return this.http.post<Structure>(`${this.baseUrl}/${id}/cancelDelete`, null); + } + public removeTempUserFromStructure(idOwner: string, idStructure: string): Observable<any> { return this.http.delete<any>(`${this.baseUrl}/${idStructure}/tempUser/${idOwner}`); } -- GitLab From 22e8ee724832dc365e7905afe897209b24b91223 Mon Sep 17 00:00:00 2001 From: Marlene Simondant <msimondant@grandlyon.com> Date: Thu, 13 Oct 2022 13:56:39 +0200 Subject: [PATCH 4/8] cancel delete --- src/app/profile/profile.component.ts | 21 ++++++++++---- .../structures-management.component.html | 8 +++-- .../structures-management.component.scss | 29 ++++++++++--------- .../structures-management.component.ts | 21 +++----------- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts index 70d3558d1..be72fb47a 100644 --- a/src/app/profile/profile.component.ts +++ b/src/app/profile/profile.component.ts @@ -7,8 +7,8 @@ import { StructureService } from '../services/structure.service'; import { ButtonType } from '../shared/components/button/buttonType.enum'; import { ProfileService } from './services/profile.service'; import { Utils } from '../utils/utils'; -import { catchError, map } from 'rxjs/operators'; -import { Observable } from 'rxjs'; +import { catchError, map, tap } from 'rxjs/operators'; +import { forkJoin, Observable } from 'rxjs'; import { Location } from '@angular/common'; @Component({ @@ -61,11 +61,22 @@ export class ProfileComponent implements OnInit { } private getStructuresFromProfile() { + const structures$: Observable<any>[] = []; this.structures = []; + this.userProfile.structuresLink.forEach((structureId) => { - this.structureService.getStructureWithOwners(structureId, null).subscribe((s) => { - this.structures.push(s); - }); + structures$.push( + this.structureService.getStructureWithOwners(structureId, null).pipe( + tap((structure) => { + this.structures.push(structure); + }) + ) + ); + }); + forkJoin(structures$).subscribe(() => { + this.structures = this.structures.sort((a, b) => + a.structure.structureName.localeCompare(b.structure.structureName) + ); }); } diff --git a/src/app/profile/structures-management/structures-management.component.html b/src/app/profile/structures-management/structures-management.component.html index 198fc48b3..66a5cc53e 100644 --- a/src/app/profile/structures-management/structures-management.component.html +++ b/src/app/profile/structures-management/structures-management.component.html @@ -24,9 +24,11 @@ <p class="structureName">{{ list.structure.structureName }}</p> <p class="structureLocation">{{ list.structure.address.commune }}</p> </div> - <div *ngIf="isBeingDeleted(list.structure)" class="deleteInProgress"> - <app-svg-icon [iconClass]="'icon-26'" [type]="'form'" [icon]="'notValidate'"></app-svg-icon> - <span>Suppression en cours</span> + <div class="warningContainer"> + <div *ngIf="isBeingDeleted(list.structure)" class="deleteInProgress"> + <app-svg-icon [iconClass]="'icon-26'" [type]="'form'" [icon]="'notValidate'"></app-svg-icon> + <span>Suppression en cours</span> + </div> </div> <div class="buttons" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="12px"> <app-button diff --git a/src/app/profile/structures-management/structures-management.component.scss b/src/app/profile/structures-management/structures-management.component.scss index 6b7b9c682..f2136ca12 100644 --- a/src/app/profile/structures-management/structures-management.component.scss +++ b/src/app/profile/structures-management/structures-management.component.scss @@ -31,7 +31,6 @@ flex-wrap: wrap; } .structureDetails { - width: max-content; width: 45%; margin-bottom: 8px; @media #{$phone} { @@ -49,16 +48,18 @@ } } } - .deleteInProgress { - display: flex; - color: $orange-warning; - padding-bottom: 5px; - - span { - max-width: 110px; - } - ::ng-deep svg { - margin-right: 8px; + .warningContainer { + width: 131px; + .deleteInProgress { + display: flex; + color: $orange-warning; + padding-bottom: 5px; + span { + max-width: 110px; + } + ::ng-deep svg { + margin-right: 8px; + } } } .buttons { @@ -68,9 +69,9 @@ @media #{$phone} { max-width: initial; } - } - app-button.deleteAction > ::ng-deep button > div { - color: $red; + app-button.deleteAction > ::ng-deep button > div { + color: $red; + } } } } diff --git a/src/app/profile/structures-management/structures-management.component.ts b/src/app/profile/structures-management/structures-management.component.ts index 9f8c6419c..bbb604194 100644 --- a/src/app/profile/structures-management/structures-management.component.ts +++ b/src/app/profile/structures-management/structures-management.component.ts @@ -41,8 +41,6 @@ export class StructuresManagementComponent implements OnInit { } private getStructures() { - // TODO : faire pareil pour la liste des structure dans le profil - const structures$: Observable<any>[] = []; this.structures = []; @@ -60,19 +58,6 @@ export class StructuresManagementComponent implements OnInit { a.structure.structureName.localeCompare(b.structure.structureName) ); }); - - /* - this.structures = []; - - this.userProfile.structuresLink.forEach((structureId) => { - this.structureService.getStructureWithOwners(structureId, null).subscribe((s) => { - this.structures.push(s); - // TODO : trouver bonne synthaxe pour le faire quand tous le ssubscribes sont terminés - this.structures = this.structures.sort((a, b) => - a.structure.structureName.localeCompare(b.structure.structureName) - ); - }); - });*/ } public leaveStructure(structure: Structure, shouldExclude: boolean): void { @@ -94,7 +79,7 @@ export class StructuresManagementComponent implements OnInit { this.deleteModalOpenned = false; if (shouldDelete) { this.structureService.delete(structure._id).subscribe((res) => { - //TODO : maj liste structures + this.getStructures(); }); } } @@ -106,7 +91,9 @@ export class StructuresManagementComponent implements OnInit { public cancelDelete(structure: Structure, shouldCancel: boolean): void { this.cancelDeleteModalOpenned = false; if (shouldCancel) { - this.structureService.cancelDelete(structure._id).subscribe((res) => {}); + this.structureService.cancelDelete(structure._id).subscribe((res) => { + this.getStructures(); + }); } } } -- GitLab From ff3a6fe84d3afe2bac1a2cc80e6ba99d8a98c533 Mon Sep 17 00:00:00 2001 From: Marlene Simondant <msimondant@grandlyon.com> Date: Thu, 13 Oct 2022 14:36:54 +0200 Subject: [PATCH 5/8] update both user et structures on init and on delete --- src/app/profile/profile.component.ts | 4 +--- .../structures-management.component.ts | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts index be72fb47a..7749a50f8 100644 --- a/src/app/profile/profile.component.ts +++ b/src/app/profile/profile.component.ts @@ -74,9 +74,7 @@ export class ProfileComponent implements OnInit { ); }); forkJoin(structures$).subscribe(() => { - this.structures = this.structures.sort((a, b) => - a.structure.structureName.localeCompare(b.structure.structureName) - ); + this.structures.sort((a, b) => a.structure.structureName.localeCompare(b.structure.structureName)); }); } diff --git a/src/app/profile/structures-management/structures-management.component.ts b/src/app/profile/structures-management/structures-management.component.ts index bbb604194..a409d2c46 100644 --- a/src/app/profile/structures-management/structures-management.component.ts +++ b/src/app/profile/structures-management/structures-management.component.ts @@ -31,16 +31,14 @@ export class StructuresManagementComponent implements OnInit { ) {} ngOnInit(): void { - this.profileService.getProfile().then((profile: User) => { - this.userProfile = profile; - this.getStructures(); - }); + this.getUserAndStructures(); } + public goBack(): void { history.back(); } - private getStructures() { + private getStructures(): void { const structures$: Observable<any>[] = []; this.structures = []; @@ -54,9 +52,14 @@ export class StructuresManagementComponent implements OnInit { ); }); forkJoin(structures$).subscribe(() => { - this.structures = this.structures.sort((a, b) => - a.structure.structureName.localeCompare(b.structure.structureName) - ); + this.structures.sort((a, b) => a.structure.structureName.localeCompare(b.structure.structureName)); + }); + } + + private getUserAndStructures(): void { + this.profileService.getProfile().then((profile: User) => { + this.userProfile = profile; + this.getStructures(); }); } @@ -79,7 +82,7 @@ export class StructuresManagementComponent implements OnInit { this.deleteModalOpenned = false; if (shouldDelete) { this.structureService.delete(structure._id).subscribe((res) => { - this.getStructures(); + this.getUserAndStructures(); }); } } -- GitLab From 762932bdb39838f239a76cb068d6b7e8f2ffbc48 Mon Sep 17 00:00:00 2001 From: Etienne LOUPIAS <eloupias@grandlyon.com> Date: Mon, 17 Oct 2022 11:50:01 +0200 Subject: [PATCH 6/8] fix deletedAt intialized to null --- src/app/models/structure.model.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/models/structure.model.ts b/src/app/models/structure.model.ts index c77043910..8841a553a 100644 --- a/src/app/models/structure.model.ts +++ b/src/app/models/structure.model.ts @@ -13,7 +13,6 @@ export class Structure { public createdAt: string = null; public updatedAt: string = null; public toBeDeletedAt: string = null; - public deletedAt: string = null; public structureName: string = null; public structureType: string = null; public description: string = null; -- GitLab From bead7b55292b43bce75dee722207028f7106899a Mon Sep 17 00:00:00 2001 From: Marlene Simondant <msimondant@grandlyon.com> Date: Mon, 17 Oct 2022 15:30:13 +0200 Subject: [PATCH 7/8] ajustements --- .../structures-management.component.html | 18 +++++++++--------- .../structures-management.component.scss | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/profile/structures-management/structures-management.component.html b/src/app/profile/structures-management/structures-management.component.html index 66a5cc53e..5b343bc1b 100644 --- a/src/app/profile/structures-management/structures-management.component.html +++ b/src/app/profile/structures-management/structures-management.component.html @@ -18,14 +18,14 @@ <div *ngIf="structures"> <div fxLayoutGap="16px" fxLayout="column" fxFill> <ng-container *ngIf="structures"> - <div *ngFor="let list of structures; let i = index" class="structureCard"> + <div *ngFor="let elt of structures" class="structureCard"> <div class="structureCardContent" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px"> <div class="structureDetails" fxLayout="column" fxLayoutAlign="space-between start"> - <p class="structureName">{{ list.structure.structureName }}</p> - <p class="structureLocation">{{ list.structure.address.commune }}</p> + <p class="structureName">{{ elt.structure.structureName }}</p> + <p class="structureLocation">{{ elt.structure.address.commune }}</p> </div> <div class="warningContainer"> - <div *ngIf="isBeingDeleted(list.structure)" class="deleteInProgress"> + <div *ngIf="isBeingDeleted(elt.structure)" class="deleteInProgress"> <app-svg-icon [iconClass]="'icon-26'" [type]="'form'" [icon]="'notValidate'"></app-svg-icon> <span>Suppression en cours</span> </div> @@ -35,28 +35,28 @@ [type]="'button'" [text]="'Quitter la structure'" [style]="buttonTypeEnum.SecondaryWide" - (click)="selectedStructure = list.structure; leaveModalOpenned = true" + (click)="selectedStructure = elt.structure; leaveModalOpenned = true" ></app-button> <app-button - *ngIf="!isBeingDeleted(list.structure)" + *ngIf="!isBeingDeleted(elt.structure)" class="deleteAction" [type]="'button'" [text]="'Supprimer la structure'" [style]="buttonTypeEnum.SecondaryWide" routerLink="./" [routerLinkActive]="'active'" - (click)="selectedStructure = list.structure; deleteModalOpenned = true" + (click)="selectedStructure = elt.structure; deleteModalOpenned = true" ></app-button> <app-button - *ngIf="isBeingDeleted(list.structure)" + *ngIf="isBeingDeleted(elt.structure)" class="deleteAction" [type]="'button'" [text]="'Annuler la suppression'" [style]="buttonTypeEnum.SecondaryWide" routerLink="./" [routerLinkActive]="'active'" - (click)="selectedStructure = list.structure; cancelDeleteModalOpenned = true" + (click)="selectedStructure = elt.structure; cancelDeleteModalOpenned = true" ></app-button> </div> </div> diff --git a/src/app/profile/structures-management/structures-management.component.scss b/src/app/profile/structures-management/structures-management.component.scss index f2136ca12..7796be699 100644 --- a/src/app/profile/structures-management/structures-management.component.scss +++ b/src/app/profile/structures-management/structures-management.component.scss @@ -49,13 +49,13 @@ } } .warningContainer { - width: 131px; + width: 8rem; .deleteInProgress { display: flex; color: $orange-warning; padding-bottom: 5px; span { - max-width: 110px; + max-width: 6.875rem; } ::ng-deep svg { margin-right: 8px; -- GitLab From f27d67b30f19b88427cf31673b1b573087edfa3c Mon Sep 17 00:00:00 2001 From: Marlene Simondant <msimondant@grandlyon.com> Date: Mon, 24 Oct 2022 11:56:01 +0200 Subject: [PATCH 8/8] if user has no structure display 'add structure' button --- src/app/profile/profile.component.html | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html index 79b9379cf..6918307a6 100644 --- a/src/app/profile/profile.component.html +++ b/src/app/profile/profile.component.html @@ -71,7 +71,7 @@ <div fxLayout="row" fxLayoutAlign="start center" fxFill> <h1>Structures</h1> <app-button - *ngIf="!isPublic" + *ngIf="!isPublic && userProfile.structuresLink.length > 0" class="hide-on-mobile" [type]="'button'" [iconBtn]="'edit'" @@ -81,6 +81,7 @@ [routerLinkActive]="'active'" ></app-button> <app-button + *ngIf="!isPublic && userProfile.structuresLink.length > 0" class="hide-on-desktop" [type]="'button'" [iconBtn]="'edit'" @@ -100,6 +101,16 @@ </div> </ng-container> </div> + <div fxLayoutAlign="center center" fxFill> + <app-button + *ngIf="!isPublic && userProfile.structuresLink.length == 0" + [style]="buttonTypeEnum.SecondaryUltraWide" + [iconBtn]="'add'" + [text]="'Ajouter une structure'" + routerLink="/form/structure" + tabindex="0" + ></app-button> + </div> </div> </section> -- GitLab