Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client
1 result
Show changes
Showing
with 935 additions and 50 deletions
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Routes, RouterModule, Route } from '@angular/router';
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 { ProfileComponent } from './profile.component';
import { StructureEditionSummaryComponent } from './structure-edition-summary/structure-edition-summary.component';
import { AuthGuard } from '../guards/auth.guard';
import { EditComponent } from './edit/edit.component';
import { FooterComponent } from '../footer/footer.component';
const footerOutletRoute: Route = {
path: '',
outlet: 'footer',
component: FooterComponent,
};
const routes: Routes = [
{
path: 'edit',
canActivate: [AuthGuard],
component: EditComponent,
},
footerOutletRoute,
{
path: '',
children: [
......@@ -29,6 +45,15 @@ const routes: Routes = [
structure: StructureResolver,
},
},
{
path: 'structure-members-management/:id',
component: StructureMembersManagementComponent,
canActivate: [RoleGuard],
data: { allowedRoles: [RouteRole.structureAdmin] },
resolve: {
structure: StructureResolver,
},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
......
<div class="structureMember">
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" fxFill>
<app-svg-icon
class="avatar hide-on-mobile"
[type]="'avatar'"
[icon]="'defaultAvatar'"
[iconClass]="'icon-40'"
></app-svg-icon>
<div class="nameJobSection" fxLayout="column" fxLayoutAlign="start start">
<a routerLink="/profile/{{ member._id }}" class="name">{{ member.name }} {{ member.surname }}</a>
<p class="jobEmployer">{{ getJobEmployer() }}</p>
</div>
<div fxLayout="column" fxLayoutAlign="space-between start" fxLayoutGap="4px">
<p>{{ member.phone }}</p>
<a class="email" href="mailto:{{ member.email }}">{{ member.email }}</a>
</div>
</div>
</div>
@import '../../../../assets/scss/color';
@import '../../../../assets/scss/typography';
@import '../../../../assets/scss/breakpoint';
@import '../../../../assets/scss/shapes';
.structureMember {
@include lato-regular-14;
.avatar {
display: flex;
align-items: center;
background-color: $grey-8;
border-radius: 4px;
}
p {
margin: 0;
&.jobEmployer {
display: flex;
height: 34px;
align-items: center;
}
}
a {
&.name {
@include lato-bold-14;
color: $black;
}
&.email {
text-decoration: underline;
color: $grey-1;
}
}
.nameJobSection {
width: 50%;
}
}
import { Component, Input } from '@angular/core';
import { User } from '../../../models/user.model';
@Component({
selector: 'app-profile-structure-member',
templateUrl: './profile-structure-member.component.html',
styleUrls: ['./profile-structure-member.component.scss']
})
export class ProfileStructureMemberComponent {
@Input() public member: User;
constructor() {}
getJobEmployer(): string {
if (this.member.job?.name && this.member.employer?.name) {
return this.member.job.name + ', ' + this.member.employer.name;
}
if (this.member.job?.name && !this.member.employer?.name) {
return this.member.job.name;
}
if (!this.member.job?.name && this.member.employer?.name) {
return this.member.employer.name;
}
return '';
}
}
<div class="structureCard" fxLayout="column" fxLayoutAlign="center" [ngClass]="{ fold: !showDetails }">
<div
class="collapseHeader"
fxLayout="row"
fxLayoutAlign="space-between center"
fxLayoutGap="20px"
(click)="toggleDetails()"
>
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px">
<app-svg-icon [type]="'ico'" [icon]="'structureAvatar'" [iconClass]="'icon-52'"></app-svg-icon>
<div fxLayout="column" fxLayoutAlign="space-between start">
<p class="structureName">{{ structureWithOwners.structure.structureName }}</p>
<p class="structureType">{{ getStructureTypeLabel() }}</p>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px">
<div *ngIf="!isPublic && !isValid()" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="7px">
<app-svg-icon [iconClass]="'icon-26'" [type]="'form'" [icon]="'notValidate'"></app-svg-icon>
<p class="invalidText hide-on-mobile">
Informations
<br />
manquantes
</p>
</div>
<app-svg-icon *ngIf="!showDetails" [type]="'ico'" [icon]="'unfold'" [iconClass]="'icon-26'"></app-svg-icon>
<app-svg-icon *ngIf="showDetails" [type]="'ico'" [icon]="'fold'" [iconClass]="'icon-26'"></app-svg-icon>
</div>
</div>
<div [@collapse]="showDetails">
<div class="collapseContent" fxLayout="column" fxLayoutAlign="center" fxLayoutGap="10px">
<div fxLayout="column">
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="20px">
<p class="section-title">informations</p>
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="12px">
<app-button
*ngIf="!isPublic"
class="hide-on-mobile"
[type]="'button'"
[iconBtn]="'eyePassword'"
[iconType]="'form'"
[text]="'Voir la structure'"
[style]="buttonTypeEnum.SecondaryWide"
routerLink="./"
[queryParams]="{ id: structureWithOwners.structure._id }"
[routerLinkActive]="'active'"
></app-button>
<app-button
*ngIf="!isPublic"
class="hide-on-desktop"
[type]="'button'"
[iconBtn]="'eyePassword'"
[iconType]="'form'"
[style]="buttonTypeEnum.SecondaryOnlyIcon"
routerLink="./"
[queryParams]="{ id: structureWithOwners.structure._id }"
[routerLinkActive]="'active'"
></app-button>
<app-button
*ngIf="!isPublic"
class="hide-on-mobile"
[type]="'button'"
[iconBtn]="'edit'"
[text]="'Modifier la structure'"
[style]="buttonTypeEnum.SecondaryWide"
routerLink="./edit-structure/{{ structureWithOwners.structure._id }}"
[routerLinkActive]="'active'"
[ngClass]="{ warning: !isValid() }"
></app-button>
<app-button
*ngIf="!isPublic"
class="hide-on-desktop"
[type]="'button'"
[iconBtn]="'edit'"
[style]="buttonTypeEnum.SecondaryOnlyIcon"
routerLink="./edit-structure/{{ structureWithOwners.structure._id }}"
[routerLinkActive]="'active'"
[ngClass]="{ warning: !isValid() }"
></app-button>
</div>
</div>
<div class="infoSection" fxLayout="column" fxLayoutAlign="space-between start" fxLayoutGap="4px">
<div>
<p>{{ getAddress() }}</p>
</div>
<div>
<p>{{ structureWithOwners.structure.contactPhone }}</p>
</div>
<div>
<a class="email" href="mailto:{{ structureWithOwners.structure.contactMail }}">
{{ structureWithOwners.structure.contactMail }}
</a>
</div>
</div>
</div>
<div *ngIf="members.length > 0" fxLayout="column" fxLayoutGap="9px">
<div fxLayout="row" fxLayoutAlign="space-between center">
<p class="section-title">membres</p>
<app-button
*ngIf="!isPublic"
class="hide-on-mobile"
[type]="'button'"
[iconBtn]="'edit'"
[text]="'Gérer les membres'"
[style]="buttonTypeEnum.SecondaryWide"
routerLink="./structure-members-management/{{ structureWithOwners.structure._id }}"
[routerLinkActive]="'active'"
></app-button>
<app-button
*ngIf="!isPublic"
class="hide-on-desktop"
[type]="'button'"
[iconBtn]="'edit'"
[style]="buttonTypeEnum.SecondaryOnlyIcon"
routerLink="./structure-members-management/{{ structureWithOwners.structure._id }}"
[routerLinkActive]="'active'"
></app-button>
</div>
<div *ngFor="let member of members; let i = index">
<app-profile-structure-member [member]="member"></app-profile-structure-member>
</div>
</div>
<div class="call-to-action" *ngIf="!isPublic && members.length === 0" fxLayout="row" fxLayoutAlign="center">
<app-button
[type]="'button'"
[iconBtn]="'add'"
[text]="'Ajouter un membre'"
[style]="buttonTypeEnum.SecondaryUltraWide"
[routerLinkActive]="'active'"
(click)="addMemberModalOpenned = true"
></app-button>
</div>
</div>
</div>
</div>
<app-structure-add-member-modal
*ngIf="addMemberModalOpenned"
[openned]="addMemberModalOpenned"
[structure]="structureWithOwners"
(closed)="closeAddMemberModal($event)"
></app-structure-add-member-modal>
@import '../../../assets/scss/color';
@import '../../../assets/scss/typography';
@import '../../../assets/scss/breakpoint';
@import '../../../assets/scss/shapes';
.structureCard {
padding: 5px 6px;
border: 1px solid $grey-5;
border-radius: 4px;
overflow: hidden;
&.fold {
background-color: $grey-8;
border: 1px solid $grey-8;
}
.collapseHeader {
cursor: pointer;
p {
margin: 0 !important;
&.structureName {
@include lato-bold-16;
}
&.structureType {
@include lato-regular-14;
font-style: italic;
color: $grey-3;
}
&.invalidText {
@include lato-regular-13;
margin: 0 0.5rem;
color: $orange-warning;
}
}
}
.collapseContent {
padding: 0 10px;
.infoSection {
@include lato-regular-14;
.email {
text-decoration: underline;
color: $grey-1;
}
}
.section-title {
text-transform: uppercase;
@include lato-bold-14;
color: $grey-3;
}
p {
margin: 0 !important;
}
}
app-button {
&.warning {
position: relative;
&:after {
content: '';
background-image: url('../../../assets/form/notValidateWithBorder.svg');
background-size: cover;
width: 24px;
height: 24px;
position: absolute;
top: -6px;
right: -6px;
}
}
}
.call-to-action {
margin-top: 18px;
}
}
::ng-deep app-button.warning button .text {
border: 1px solid $orange-warning !important;
}
import { animate, AUTO_STYLE, state, style, transition, trigger } from '@angular/animations';
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { structureFormStep } from '../../form/form-view/structure-form/structureFormStep.enum';
import { Structure } from '../../models/structure.model';
import { StructureWithOwners } from '../../models/structureWithOwners.model';
import { NotificationService } from '../../services/notification.service';
import { ButtonType } from '../../shared/components/button/buttonType.enum';
import { formUtils } from '../../utils/formUtils';
import { User } from './../../models/user.model';
import { UserService } from './../../services/user.service';
@Component({
selector: 'app-profile-structure',
templateUrl: './profile-structure.component.html',
styleUrls: ['./profile-structure.component.scss'],
animations: [
trigger('collapse', [
state('true', style({ height: AUTO_STYLE, visibility: AUTO_STYLE, margin: '8px 0' })),
state('false', style({ height: '0px', visibility: 'hidden', margin: '0' })),
transition('true => false', animate('300ms ease-out')),
transition('false => true', animate('300ms ease-out')),
]),
],
})
export class ProfileStructureComponent implements OnInit {
@Input() public structureWithOwners: StructureWithOwners;
@Input() public userProfile: User;
@Input() public isPublic: boolean;
public members: User[] = [];
public structureForm: FormGroup;
public buttonTypeEnum = ButtonType;
public showDetails: boolean = false;
public addMemberModalOpenned: boolean = false;
constructor(
private router: Router,
private userService: UserService,
private notificationService: NotificationService
) {}
ngOnInit(): void {
this.structureForm = new formUtils().createStructureForm(this.structureWithOwners.structure, true);
this.structureWithOwners.owners
.filter((owner) => {
return owner._id !== this.userProfile._id;
})
.forEach((owner) => {
this.userService.getUser(owner._id).subscribe((res) => {
this.members.push(res);
});
});
}
public goBack(): void {
history.back();
}
public goToEdit(step: structureFormStep): void {
this.router.navigate(['/form/structure', this.structureWithOwners.structure._id, structureFormStep[step]]);
}
public isValid(): boolean {
return this.structureForm.valid;
}
public getStructureTypeLabel(): string {
return new Structure(this.structureWithOwners.structure).getLabelTypeStructure();
}
public toggleDetails(): void {
this.showDetails = !this.showDetails;
}
public getAddress(): string {
const address = this.structureWithOwners.structure.address;
return address.numero + ' ' + address.street + ' - ' + address.commune;
}
public closeAddMemberModal(memberAddRequested: boolean): void {
this.addMemberModalOpenned = false;
if (memberAddRequested) {
this.ngOnInit();
this.notificationService.showSuccess(`La demande d'ajout a bien été effectuée`, '');
}
}
}
......@@ -67,47 +67,38 @@
</section>
<section>
<div fxLayout="row" fxLayoutAlign="start center" fxFill>
<h1>Structures</h1>
<app-button
*ngIf="!isPublic"
class="hide-on-mobile"
[type]="'button'"
[iconBtn]="'edit'"
[text]="'Gérer mes structures'"
[style]="buttonTypeEnum.SecondaryWide"
routerLink="/profile/edit"
[routerLinkActive]="'active'"
></app-button>
<app-button
class="hide-on-desktop"
[type]="'button'"
[iconBtn]="'edit'"
[style]="buttonTypeEnum.SecondaryOnlyIcon"
routerLink="/profile/edit"
[routerLinkActive]="'active'"
></app-button>
</div>
<div fxLayout="column">
<div class="section-container" fxLayoutGap="18px" fxLayout="column">
<div fxLayoutGap="12px" fxLayout="column" fxFill>
<div fxLayout="row" fxLayoutAlign="start center" fxFill>
<h1>Structures</h1>
<app-button
*ngIf="!isPublic"
class="hide-on-mobile"
[type]="'button'"
[iconBtn]="'edit'"
[text]="'Gérer mes structures'"
[style]="buttonTypeEnum.SecondaryWide"
routerLink="./"
[routerLinkActive]="'active'"
[disabled]="true"
></app-button>
<app-button
class="hide-on-desktop"
[type]="'button'"
[iconBtn]="'edit'"
[style]="buttonTypeEnum.SecondaryOnlyIcon"
routerLink="/"
[routerLinkActive]="'active'"
[disabled]="true"
></app-button>
</div>
<div fxLayoutGap="16px" fxLayout="column" fxFill>
<ng-container *ngIf="userProfile.structuresLink.length > 0 && structures">
<div class="structureCard" *ngFor="let s of structures; let i = index">
<div class="structureInfo" fxLayout="column" fxLayoutGap="14px">
<div fxLayout="row" fxLayoutAlign="space-between start" fxLayoutGap="20px">
<a class="structureName" [routerLink]="['./']" [queryParams]="{ id: s.structure._id }">{{
s.structure.structureName
}}</a>
<app-structure-options-modal
*ngIf="!isPublic"
[structure]="s"
(closed)="ngOnInit()"
(closedWithRefresh)="ngOnInit()"
></app-structure-options-modal>
</div>
<div fxLayout="column" fxLayoutGap="14px" class="ownersBlock">
<p class="ownerName" *ngFor="let owner of s.owners">{{ owner.email }}</p>
</div>
</div>
<div *ngFor="let structure of structures; let i = index">
<app-profile-structure
[structureWithOwners]="structure"
[userProfile]="this.userProfile"
[isPublic]="this.isPublic"
></app-profile-structure>
</div>
</ng-container>
</div>
......
import { NgModule } from '@angular/core';
import { ProfileComponent } from './profile.component';
import { SharedModule } from '../shared/shared.module';
import { CommonModule } from '@angular/common';
import { ProfileRoutingModule } from './profile-routing.module';
import { ProfileStructureMemberComponent } from './profile-structure/profile-structure-member/profile-structure-member.component';
import { ProfileStructureComponent } from './profile-structure/profile-structure.component';
import { ProfileComponent } from './profile.component';
import { StructureEditionSummaryComponent } from './structure-edition-summary/structure-edition-summary.component';
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 { MissingInformationComponent } from './structure-edition-summary/missing-information/missing-information.component';
import { NoInformationComponent } from './structure-edition-summary/no-information/no-information.component';
@NgModule({
declarations: [ProfileComponent, StructureEditionSummaryComponent, EditComponent, MissingInformationComponent, NoInformationComponent],
declarations: [
EditComponent,
MissingInformationComponent,
NoInformationComponent,
ProfileComponent,
ProfileStructureComponent,
ProfileStructureMemberComponent,
StructureAddMemberModalComponent,
StructureEditionSummaryComponent,
StructureMembersManagementComponent,
],
imports: [CommonModule, ProfileRoutingModule, SharedModule],
})
export class ProfileModule {}
<div class="modalBackground">
<div class="modal">
<div class="modalHeader">
<h3>Ajouter un membre</h3>
</div>
<form [formGroup]="formAddAccount" class="modalContent">
<div class="form-group" fxLayout="column">
<label for="email">Email de la personne à 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="buttons" fxLayout="row" fxLayoutAlign="space-between center">
<app-button [text]="'Annuler'" (action)="closeModal(false)"></app-button>
<app-button
[text]="'Valider'"
[disabled]="formAddAccount.invalid"
(action)="addOwner()"
[style]="buttonTypeEnum.Primary"
>
</app-button>
</div>
</form>
</div>
</div>
@import '../../../assets/scss/color';
@import '../../../assets/scss/typography';
@import '../../../assets/scss/shapes';
@import '../../../assets/scss/z-index';
.modalBackground {
.modal {
max-width: 390px;
background-color: $white;
.modalHeader {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid $grey-6;
padding: 0 8px;
h3 {
@include lato-bold-18;
}
}
.modalContent {
padding: 24px 40px;
}
p {
text-align: center;
margin: 10px 0;
&.special {
margin: 8px 0;
@include lato-regular-14;
color: $grey-3;
&.invalid {
color: $orange-warning;
}
}
}
.buttons {
gap: 24px;
padding-top: 8px;
}
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StructureAddMemberModalComponent } from './structure-add-member-modal.component';
describe('StructureMembersManagementComponent', () => {
let component: StructureAddMemberModalComponent;
let fixture: ComponentFixture<StructureAddMemberModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [StructureAddMemberModalComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(StructureAddMemberModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { StructureWithOwners } from '../../models/structureWithOwners.model';
import { TempUser } from '../../models/temp-user.model';
import { StructureService } from '../../services/structure.service';
import { ButtonType } from '../../shared/components/button/buttonType.enum';
import { CustomRegExp } from '../../utils/CustomRegExp';
@Component({
selector: 'app-structure-add-member-modal',
templateUrl: './structure-add-member-modal.component.html',
styleUrls: ['./structure-add-member-modal.component.scss'],
})
export class StructureAddMemberModalComponent implements OnInit {
@Input() public structure: StructureWithOwners;
@Output() closed = new EventEmitter();
public buttonTypeEnum = ButtonType;
public formAddAccount: FormGroup;
public ownerAlreadyLinked = false;
constructor(private formBuilder: FormBuilder, private structureService: StructureService) {}
ngOnInit(): void {
this.formAddAccount = this.formBuilder.group({
email: ['', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]],
});
}
public closeModal(value: boolean): void {
this.closed.emit(value);
}
// getter for form fields
get fAddAccount(): { [key: string]: AbstractControl } {
return this.formAddAccount.controls;
}
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.closed.emit(true);
},
(err) => {
this.ownerAlreadyLinked = true;
}
);
}
}
<div class="content-container full-screen">
<div class="container members-management">
<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 les membres<br />de {{ structure.structureName }}</h1>
</div>
<app-button
[style]="buttonTypeEnum.Secondary"
[text]="'Ajouter un membre'"
(click)="addMemberModalOpenned = true"
tabindex="0"
></app-button>
</div>
</div>
<div *ngIf="structureWithOwners && tempUsers">
<div fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="baseline baseline">
<div *ngFor="let member of structureWithOwners.owners" class="member-card">
<div fxLayout="row" fxLayoutAlign="space-between center" fxFill>
<div fxLayout="row" fxLayoutAlign="start center" class="user">
<app-svg-icon
class="avatar"
[type]="'avatar'"
[icon]="'defaultAvatar'"
[iconClass]="'icon-40'"
></app-svg-icon>
<div class="info-member">
<p class="member">{{ displayMemberName(member) }}</p>
<p class="job" *ngIf="displayJobEmployer(member)">{{ displayJobEmployer(member) }}</p>
</div>
</div>
<app-button
class="button-member"
[style]="buttonTypeEnum.Secondary"
[text]="'Exclure ce membre'"
(click)="memberToExclude = member; excludeModalOpenned = true"
tabindex="0"
></app-button>
</div>
</div>
<div *ngFor="let member of tempUsers" class="member-card">
<div fxLayout="row" fxLayoutAlign="space-between center" fxFill class="card-container">
<div fxLayout="row" fxLayoutAlign="start center" class="user">
<app-svg-icon
class="avatar"
[type]="'avatar'"
[icon]="'defaultAvatar'"
[iconClass]="'icon-40'"
></app-svg-icon>
<div class="info-member">
<p class="member">{{ member.email }}</p>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="start center" class="pendingContainer">
<div class="info-pendingStructure">
<app-svg-icon class="check-icon" [type]="'ico'" [icon]="'check'"></app-svg-icon>
<p class="text">Demande de rattachement envoyée le {{ member.updatedAt | date: 'dd/MM/YYYY' }}</p>
</div>
<app-button
[style]="buttonTypeEnum.Secondary"
[text]="'Annuler la demande'"
(click)="tempUserToCancel = member; cancelAddTempUserModalOpenned = true"
tabindex="0"
></app-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<app-structure-add-member-modal
*ngIf="addMemberModalOpenned"
[openned]="addMemberModalOpenned"
[structure]="structureWithOwners"
(closed)="closeAddMemberModal($event)"
></app-structure-add-member-modal>
<app-modal-confirmation
*ngIf="excludeModalOpenned"
[openned]="excludeModalOpenned"
[content]="'Souhaitez-vous exclure ce membre\n(' + displayMemberName(memberToExclude) + ')&nbsp;?'"
[customConfirmationText]="'Oui'"
(closed)="excludeMember(memberToExclude, $event)"
></app-modal-confirmation>
<app-modal-confirmation
*ngIf="cancelAddTempUserModalOpenned"
[openned]="cancelAddTempUserModalOpenned"
[content]="'Souhaitez-vous annuler la demande de rattachement de ce membre\n(' + tempUserToCancel.email + ')&nbsp;?'"
[customConfirmationText]="'Oui'"
(closed)="cancelAddTempUser(tempUserToCancel, $event)"
></app-modal-confirmation>
@import '../../../assets/scss/color';
@import '../../../assets/scss/typography';
@import '../../../assets/scss/breakpoint';
.container {
margin: 1rem auto;
max-width: 980px;
padding: 2rem;
background: $white;
border-radius: 8px;
border: 1px solid $grey-6;
.header {
margin-bottom: 2rem;
}
.headerBack {
cursor: pointer;
}
h1 {
@include lato-regular-24;
color: $grey-1;
cursor: initial;
}
.member-card {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
.user {
margin-right: 1rem;
}
.avatar {
background-color: $grey-8;
border-radius: 4px;
}
.info-member {
margin-left: 1rem;
p {
margin: 0;
}
.member {
@include lato-bold-14;
}
.job {
@include lato-regular-14;
}
}
.info-pendingStructure {
display: flex;
margin-right: 1rem;
max-width: 200px;
p {
margin: 0;
}
.text {
@include lato-regular-13;
color: $grey-3;
margin-left: 3px;
}
}
.card-container {
@media #{$large-phone} {
flex-direction: column !important;
align-items: flex-start !important;
}
}
}
}
.members-management {
::ng-deep .btn-regular.secondary .text {
width: 184px !important;
height: 24px !important;
}
.button-member {
::ng-deep .btn-regular.secondary .text {
color: $red !important;
}
}
::ng-deep .modalBackground p {
white-space: pre-wrap;
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StructureMembersManagementComponent } from './structure-members-management.component';
describe('StructureMembersManagementComponent', () => {
let component: StructureMembersManagementComponent;
let fixture: ComponentFixture<StructureMembersManagementComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [StructureMembersManagementComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(StructureMembersManagementComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Owner } from '../../models/owner.model';
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 { NotificationService } from '../../services/notification.service';
import { StructureService } from '../../services/structure.service';
import { ButtonType } from '../../shared/components/button/buttonType.enum';
import { Utils } from '../../utils/utils';
import { ProfileService } from '../services/profile.service';
@Component({
selector: 'app-structure-members-management',
templateUrl: './structure-members-management.component.html',
styleUrls: ['./structure-members-management.component.scss'],
})
export class StructureMembersManagementComponent implements OnInit {
public structure: Structure;
public structureWithOwners: StructureWithOwners;
public tempUsers: TempUser[];
public tempUserToCancel: TempUser;
public memberToExclude: Owner;
public addMemberModalOpenned: boolean = false;
public excludeModalOpenned = false;
public cancelAddTempUserModalOpenned = false;
public buttonTypeEnum = ButtonType;
constructor(
private route: ActivatedRoute,
private structureService: StructureService,
private profileService: ProfileService,
private notificationService: NotificationService
) {}
ngOnInit(): void {
this.route.data.subscribe(async (data) => {
if (data.structure) {
this.structure = new Structure(data.structure);
let currentProfile = await this.profileService.getProfile();
this.structureService.getStructureWithOwners(data.structure._id, currentProfile).subscribe((s) => {
this.structureWithOwners = s;
});
this.structureService.getTempUsers(data.structure._id).subscribe((data) => {
this.tempUsers = data;
});
}
});
}
public goBack(): void {
history.back();
}
public displayJobEmployer(profile: User): string {
return new Utils().getJobEmployer(profile);
}
public displayMemberName(member: Owner): string {
return member.name + ' ' + member.surname.toUpperCase();
}
public excludeMember(member: Owner, shouldExclude: boolean): void {
this.excludeModalOpenned = false;
if (shouldExclude) {
this.structureService.removeOwnerFromStructure(member._id, this.structure._id).subscribe(
() => {
this.structureWithOwners.owners = this.structureWithOwners.owners.filter((obj) => obj._id !== member._id);
this.notificationService.showSuccess(
`${this.displayMemberName(member)} a bien été exclu de ${this.structure.structureName}`,
''
);
},
() => {
this.notificationService.showError(
`${this.displayMemberName(member)} n'a pas pu être exclu de ${
this.structure.structureName
}. Merci de réessayer plus tard.`,
"Echec de l'exclusion"
);
}
);
}
}
public cancelAddTempUser(member: TempUser, shouldExclude: boolean): void {
this.cancelAddTempUserModalOpenned = false;
if (shouldExclude) {
this.structureService.removeTempUserFromStructure(member._id, this.structure._id).subscribe(
() => {
this.tempUsers = this.tempUsers.filter((obj) => obj._id !== member._id);
this.notificationService.showSuccess(
`La demande d'ajout de ${member.email} à ${this.structure.structureName} a bien été annulée`,
''
);
},
() => {
this.notificationService.showError(
`La demande d'ajout de ${member.email} à ${this.structure.structureName} n'a pas pu être annulée. Merci de réessayer plus tard.`,
"Echec de l'annulation"
);
}
);
}
}
public closeAddMemberModal(memberAddRequested: boolean): void {
this.addMemberModalOpenned = false;
if (memberAddRequested) {
this.ngOnInit();
this.notificationService.showSuccess(`La demande d'ajout a bien été effectuée`, '');
}
}
}
......@@ -10,7 +10,7 @@ export class TempUserResolver implements Resolve<TempUser> {
constructor(private tempUserService: TempUserService, private router: Router) {}
resolve(route: ActivatedRouteSnapshot): Observable<TempUser> {
const userId = route.queryParams.id;
const userId = route.params.id;
return this.tempUserService.getUser(userId).pipe(
map((res) => res),
catchError(() => {
......
......@@ -64,6 +64,9 @@ export class StructureService {
return this.http.delete<Structure>(`${this.baseUrl}/${id}`);
}
public removeTempUserFromStructure(idOwner: string, idStructure: string): Observable<any> {
return this.http.delete<any>(`${this.baseUrl}/${idStructure}/tempUser/${idOwner}`);
}
public removeOwnerFromStructure(idOwner: string, idStructure: string): Observable<any> {
return this.http.delete<any>(`${this.baseUrl}/${idStructure}/owner/${idOwner}`);
}
......@@ -174,6 +177,10 @@ export class StructureService {
return this.http.post<any>(`${this.baseUrl}/${structureId}/withOwners`, { emailUser: profile?.email });
}
public getTempUsers(structureId: string): Observable<TempUser[]> {
return this.http.get<TempUser[]>(`${this.baseUrl}/${structureId}/tempUsers`);
}
public sendMailOnStructureError(structureId: string, content: string): Observable<any> {
return this.http.post<any>(`${this.baseUrl}/reportStructureError`, {
structureId,
......
......@@ -3,21 +3,21 @@
<label for="email">Courriel du compte</label>
<div fxLayout="row" fxLayoutGap="13px">
<input type="text" autocomplete="on" formControlName="email" class="form-input" />
<img *ngIf="f.email.invalid && f.email.value" src="../../assets/form/notvalidate.svg" alt="logo invalid" />
<img *ngIf="f.email.invalid && f.email.value" src="../../assets/form/notValidate.svg" alt="logo invalid" />
</div>
</div>
<div class="form-group" fxLayout="column">
<label for="surname">Nom</label>
<div fxLayout="row" fxLayoutGap="13px">
<input type="text" autocomplete="on" formControlName="surname" class="form-input" />
<img *ngIf="f.surname.invalid && f.surname.value" src="../../assets/form/notvalidate.svg" alt="logo invalid" />
<img *ngIf="f.surname.invalid && f.surname.value" src="../../assets/form/notValidate.svg" alt="logo invalid" />
</div>
</div>
<div class="form-group" fxLayout="column">
<label for="name">Prénom</label>
<div fxLayout="row" fxLayoutGap="13px">
<input type="text" autocomplete="on" formControlName="name" class="form-input" />
<img *ngIf="f.name.invalid && f.name.value" src="../../assets/form/notvalidate.svg" alt="logo invalid" />
<img *ngIf="f.name.invalid && f.name.value" src="../../assets/form/notValidate.svg" alt="logo invalid" />
</div>
</div>
<div class="form-group" fxLayout="column">
......@@ -30,7 +30,7 @@
formControlName="phone"
class="form-input"
/>
<img *ngIf="f.phone.invalid && f.phone.value" src="../../assets/form/notvalidate.svg" alt="logo invalid" />
<img *ngIf="f.phone.invalid && f.phone.value" src="../../assets/form/notValidate.svg" alt="logo invalid" />
</div>
</div>
<div class="form-group password" fxLayout="column">
......@@ -52,7 +52,7 @@
src="../../assets/form/eyePassword.svg"
alt="logo eyePassword"
/>
<img *ngIf="f.password.invalid && f.password.value" src="../../assets/form/notvalidate.svg" alt="logo invalid" />
<img *ngIf="f.password.invalid && f.password.value" src="../../assets/form/notValidate.svg" alt="logo invalid" />
</div>
</div>
<div class="form-group password" fxLayout="column">
......@@ -72,7 +72,7 @@
/>
<img
*ngIf="f.confirmPassword.invalid && f.confirmPassword.value"
src="../../assets/form/notvalidate.svg"
src="../../assets/form/notValidate.svg"
alt="logo invalid"
/>
</div>
......