diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 9f29fd079e045c8b09c0ffe1028c89a66f5e801b..045be83e7bbd0f56c3f29a5805bd5d48fe7b6ed6 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -12,6 +12,7 @@ import { ProfileComponent } from './profile/profile.component'; import { ResetEmailComponent } from './reset-email/reset-email.component'; import { ResetPasswordComponent } from './reset-password/reset-password.component'; import { TempUserResolver } from './resolvers/temp-user.resolver'; +import { StructureJoinComponent } from './structure-join/structure-join.component'; import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component'; import { StructureListComponent } from './structure-list/structure-list.component'; import { UserVerificationComponent } from './user-verification/user-verification.component'; @@ -67,6 +68,11 @@ const routes: Routes = [ canActivate: [AuthGuard], component: ProfileComponent, }, + { + path: 'join', + canActivate: [AuthGuard], + component: StructureJoinComponent, + }, { path: 'reset-password', component: ResetPasswordComponent, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 25507d5d2b9314a989b4db56290d694e3c01d433..8db542e8f1a79efb23270730473c3bcc42c0d9e2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -31,6 +31,7 @@ import { AdminGuard } from './guards/admin.guard'; import { DeactivateGuard } from './guards/deactivate.guard'; import { FooterFormComponent } from './form/footer-form/footer-form.component'; import { TempUserResolver } from './resolvers/temp-user.resolver'; +import { StructureJoinComponent } from './structure-join/structure-join.component'; @NgModule({ declarations: [ @@ -51,6 +52,7 @@ import { TempUserResolver } from './resolvers/temp-user.resolver'; ResetPasswordComponent, FormComponent, FooterFormComponent, + StructureJoinComponent, ], imports: [BrowserModule, HttpClientModule, AppRoutingModule, SharedModule, MapModule, ProfileModule, AdminModule], providers: [ diff --git a/src/app/form/form.component.html b/src/app/form/form.component.html index f1b1929d9e3a227379f6cacc435da79c81e25622..c4b68351b627134666f237a1a60c33163ea23813 100644 --- a/src/app/form/form.component.html +++ b/src/app/form/form.component.html @@ -53,8 +53,8 @@ fxLayoutAlign="space-between center" fxLayoutAlign.lt-sm="center" > - <h2> - Revendiquer la structure <span>{{ claimStructure.structureName }}</span> + <h2 class="no-wrap"> + {{ isJoinMode ? 'Rejoindre' : 'Revendiquer' }} la structure <span>{{ claimStructure.structureName }}</span> </h2> <div> <p>Une fois réalisé cela vous permettra de devenir propriétaire de cette structure</p> diff --git a/src/app/form/form.component.scss b/src/app/form/form.component.scss index 8ab5aa6f497016a494aa88bad2231c11d91eba64..398ad100c90ea760c5c057ccdb8ca69a33dc901b 100644 --- a/src/app/form/form.component.scss +++ b/src/app/form/form.component.scss @@ -109,6 +109,9 @@ h3 { span { color: $secondary-color; } + &.no-wrap { + white-space: nowrap; + } } h3 { @include cn-bold-22; diff --git a/src/app/form/form.component.ts b/src/app/form/form.component.ts index a5547fc2338f5987338933bcb7d9bde83860c900..f1dfb68e23415aebbac6e2f992afce4b09556f5e 100644 --- a/src/app/form/form.component.ts +++ b/src/app/form/form.component.ts @@ -70,6 +70,7 @@ export class FormComponent implements OnInit { public isEditMode = false; public isClaimMode = false; public isAccountMode = false; + public isJoinMode = false; public isLoading = false; public isWifiChoosen = false; @@ -97,6 +98,10 @@ export class FormComponent implements OnInit { this.initForm(new Structure(history.state.data)); } else if (history.state.newUser) { this.isClaimMode = true; + // Handle join strucutre, the case is very similar to claim + if (history.state.isJoin) { + this.isJoinMode = true; + } this.createAccountForm(); this.claimStructure = history.state.newUser; this.setValidationsForm(); @@ -550,9 +555,16 @@ export class FormComponent implements OnInit { const user = new User(this.accountForm.value); // Create user and claim structure this.authService.register(user).subscribe(() => { - this.structureService.claimStructureWithAccount(this.claimStructure._id, user).subscribe(() => { - this.progressStatus = 100; - }); + // If joinMode, send join request, if not send claim request; + if (this.isJoinMode) { + this.structureService.joinStructure(this.claimStructure._id, user.email).subscribe(() => { + this.progressStatus = 100; + }); + } else { + this.structureService.claimStructureWithAccount(this.claimStructure._id, user).subscribe(() => { + this.progressStatus = 100; + }); + } }); } @@ -615,6 +627,21 @@ export class FormComponent implements OnInit { this.progressStatus -= 25; } + /** + * Page algo for claim structure case + */ + public previousPageAccount(): void { + if (this.currentPage == PageTypeEnum.accountCredentials) { + this.currentPage = PageTypeEnum.accountInfo; + this.updatePageValid(); + } else if (this.currentPage == PageTypeEnum.cgu) { + this.currentPage = PageTypeEnum.accountCredentials; + this.updatePageValid(); + } + + this.progressStatus -= 25; + } + public nextPage(): void { if (this.isClaimMode) { this.nextPageClaim(); @@ -648,6 +675,8 @@ export class FormComponent implements OnInit { public previousPage(): void { if (this.isClaimMode) { this.previousPageClaim(); + } else if (this.isAccountMode) { + this.previousPageAccount(); } else { // Check if user already connected to skip accountForm pages. if (this.currentPage == PageTypeEnum.structureNameAndAddress && this.profile) { diff --git a/src/app/guards/auth.guard.ts b/src/app/guards/auth.guard.ts index 3d3205c2e848f41f2425f3a04bb931ce66c15a63..1c6867835a8bd97ffb2dcf23cb5a56ae0fe8942d 100644 --- a/src/app/guards/auth.guard.ts +++ b/src/app/guards/auth.guard.ts @@ -10,10 +10,11 @@ import { Observable } from 'rxjs'; export class AuthGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) {} - canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): UrlTree | boolean { + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { if (this.authService.isLoggedIn()) { return true; } - return this.router.parseUrl('/home'); + this.router.navigate(['/home'], { queryParams: { returnUrl: state.url } }); + return false; } } diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index aab75d532c60f128d51ad51bfb731bb4f8c3a9c1..ab1858df680e8a105390cb22da91fa037d12deac 100644 --- a/src/app/header/header.component.ts +++ b/src/app/header/header.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { NavigationEnd, NavigationStart, Router } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, NavigationStart, Router } from '@angular/router'; import { ProfileService } from '../profile/services/profile.service'; import { AuthService } from '../services/auth.service'; @@ -13,20 +13,39 @@ export class HeaderComponent implements OnInit { public isPopUpOpen = false; public displaySignUp = true; public currentRoute = ''; - public formeRoute = '/create-structure'; + public formRoute = '/create-structure'; + public returnUrl = null; - constructor(private authService: AuthService, private profileService: ProfileService, private router: Router) { + constructor( + private authService: AuthService, + private profileService: ProfileService, + private router: Router, + private route: ActivatedRoute + ) { this.router.events.subscribe((event) => { if (event instanceof NavigationEnd) { this.currentRoute = event.url; } }); } - ngOnInit(): void {} + ngOnInit(): void { + this.route.queryParams.subscribe((params) => { + if (params.verified || params.returnUrl) { + Promise.resolve().then(() => { + if (!this.isLoggedIn) { + this.isPopUpOpen = true; + this.displaySignUp = true; + } + }); + this.returnUrl = params.returnUrl; + } + }); + } public openMenu(): void { this.showMenu = true; } + public closeMenu(route: string): void { this.router.navigateByUrl(route); this.showMenu = false; @@ -47,6 +66,9 @@ export class HeaderComponent implements OnInit { } else { this.isPopUpOpen = false; } + if (this.returnUrl && this.isLoggedIn) { + this.router.navigateByUrl(this.returnUrl); + } } public get isAdmin(): boolean { @@ -58,6 +80,6 @@ export class HeaderComponent implements OnInit { } public displayLogo(): boolean { - return this.formeRoute !== this.currentRoute; + return this.formRoute !== this.currentRoute; } } diff --git a/src/app/services/structure.service.ts b/src/app/services/structure.service.ts index e370f3c669393d4ecb92c227519ea2b4430cacce..7848ab3c416b4ab0301b6c19aeed26283e0275cc 100644 --- a/src/app/services/structure.service.ts +++ b/src/app/services/structure.service.ts @@ -50,6 +50,14 @@ export class StructureService { return this.http.get<Structure>(`${this.baseUrl}/${id}`); } + public validateStructureJoin(id: string, userId: string, state: boolean): Observable<Structure> { + return this.http.post<any>(`${this.baseUrl}/${id}/join/${userId}/${state}`, null); + } + + public joinStructure(id: string, email: string): Observable<Structure> { + return this.http.post<any>(`${this.baseUrl}/${id}/join`, { email }); + } + public delete(id: string): Observable<Structure> { return this.http.delete<Structure>(`${this.baseUrl}/${id}`); } diff --git a/src/app/structure-join/structure-join.component.html b/src/app/structure-join/structure-join.component.html new file mode 100644 index 0000000000000000000000000000000000000000..4d51a54ef9e1d015418c59e6fb408c7e8d61eb93 --- /dev/null +++ b/src/app/structure-join/structure-join.component.html @@ -0,0 +1,6 @@ +<div fxLayout="column" class="content-container full-screen"> + <div class="section-container" fxLayout="column" fxLayoutAlign="center center"> + <h1>Validation de la demande de rattachement</h1> + <p>Merci de patienter...</p> + </div> +</div> diff --git a/src/app/structure-join/structure-join.component.scss b/src/app/structure-join/structure-join.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/app/structure-join/structure-join.component.spec.ts b/src/app/structure-join/structure-join.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab4d922786d1468d788fa84a37c613e4ac723f5b --- /dev/null +++ b/src/app/structure-join/structure-join.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StructureJoinComponent } from './structure-join.component'; + +describe('StructureJoinComponent', () => { + let component: StructureJoinComponent; + let fixture: ComponentFixture<StructureJoinComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ StructureJoinComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(StructureJoinComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/structure-join/structure-join.component.ts b/src/app/structure-join/structure-join.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..c38d140326e9d01dc9f772b98c0343d6a46d9173 --- /dev/null +++ b/src/app/structure-join/structure-join.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit } from '@angular/core'; +import { Router, ActivatedRoute } from '@angular/router'; +import { StructureService } from '../services/structure.service'; + +@Component({ + selector: 'app-structure-join', + templateUrl: './structure-join.component.html', + styleUrls: ['./structure-join.component.scss'], +}) +export class StructureJoinComponent implements OnInit { + constructor(private router: Router, private route: ActivatedRoute, private structureService: StructureService) {} + + ngOnInit(): void { + this.route.queryParamMap.subscribe((params) => { + if ( + params.get('id') && + params.get('userId') && + (params.get('status') === 'true' || params.get('status') === 'false') + ) { + this.structureService + .validateStructureJoin(params.get('id'), params.get('userId'), params.get('status') === 'true' ? true : false) + .subscribe( + (res) => { + this.router.navigateByUrl('/home'); + }, + (err) => { + this.router.navigateByUrl('/home'); + } + ); + } + }); + } +} diff --git a/src/app/structure-list/components/structure-details/structure-details.component.html b/src/app/structure-list/components/structure-details/structure-details.component.html index e14724b24e1b6f6eb12813b246c2f0004d16570e..803f77bdf6c632862698beef3a6be853370b124f 100644 --- a/src/app/structure-list/components/structure-details/structure-details.component.html +++ b/src/app/structure-list/components/structure-details/structure-details.component.html @@ -118,6 +118,7 @@ </div> <div fxLayout="row" fxLayoutAlign="center center" class="hide-on-print"> <a *ngIf="!isClaimed" (click)="handleClaim()" class="primary" tabindex="0">Revendiquer cette structure</a> + <a *ngIf="displayJoin()" (click)="handleJoin()" class="primary" tabindex="0">Rejoindre cette structure</a> <!-- temporary remove edit --> <a *ngIf="profileService.isLinkedToStructure(structure._id) || profileService.isAdmin()" @@ -326,3 +327,11 @@ " (closed)="claimStructure($event)" ></app-modal-confirmation> + +<app-modal-confirmation + [openned]="joinModalOpenned" + [content]=" + 'Voulez-vous vraiment rejoindre cette structure ? Une demande sera envoyée aux membres pour validation' + " + (closed)="joinStructure($event)" +></app-modal-confirmation> diff --git a/src/app/structure-list/components/structure-details/structure-details.component.ts b/src/app/structure-list/components/structure-details/structure-details.component.ts index ecbeb3a00bbb13d79c875ef389b4fbe40fe850b6..42eb58de7c62f987b51e1145ae1a2e0cb7a50de5 100644 --- a/src/app/structure-list/components/structure-details/structure-details.component.ts +++ b/src/app/structure-list/components/structure-details/structure-details.component.ts @@ -36,6 +36,7 @@ export class StructureDetailsComponent implements OnInit { public currentProfile: User = null; public deleteModalOpenned = false; public claimModalOpenned = false; + public joinModalOpenned = false; constructor( private printService: PrintService, @@ -122,6 +123,10 @@ export class StructureDetailsComponent implements OnInit { this.claimModalOpenned = !this.claimModalOpenned; } + public toggleJoinModal(): void { + this.joinModalOpenned = !this.joinModalOpenned; + } + public handleClaim(): void { if (this.userIsLoggedIn()) { this.toggleClaimModal(); @@ -130,6 +135,14 @@ export class StructureDetailsComponent implements OnInit { } } + public handleJoin(): void { + if (this.userIsLoggedIn()) { + this.toggleJoinModal(); + } else { + this.router.navigate(['create-structure'], { state: { newUser: this.structure, isJoin: true } }); + } + } + public deleteStructure(shouldDelete: boolean): void { this.toggleDeleteModal(); if (shouldDelete) { @@ -156,6 +169,15 @@ export class StructureDetailsComponent implements OnInit { } } + public joinStructure(shouldClaim: boolean): void { + this.toggleJoinModal(); + if (shouldClaim) { + this.structureService.joinStructure(this.structure._id, this.authService.userValue.username).subscribe((res) => { + this.isClaimed = true; + }); + } + } + public getAccessLabel(accessModality: AccessModality): string { switch (accessModality) { case AccessModality.free: @@ -222,4 +244,10 @@ export class StructureDetailsComponent implements OnInit { ['ordinateurs', 'tablettes', 'bornesNumeriques', 'imprimantes', 'scanners', 'wifiEnAccesLibre'].includes(eqpt) ); } + + public displayJoin(): boolean { + return ( + !(this.profileService.isLinkedToStructure(this.structure._id) || this.profileService.isAdmin()) && this.isClaimed + ); + } }