Skip to content
18 changes: 10 additions & 8 deletions dev/user-frontend-ionic/projects/auth/src/lib/login/login.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { IonInput, ToastController } from '@ionic/angular';
import { AuthenticatedUser, NavigationService } from '@multi/shared';
import { AuthenticatedUser, FeaturesService, NavigationService } from '@multi/shared';
import { Observable } from 'rxjs';
import { finalize, take, tap } from 'rxjs/operators';
import { AuthService } from '../common/auth.service';
Expand Down Expand Up @@ -78,7 +78,8 @@ export class LoginPage implements OnInit {
private loginRepository: LoginRepository,
private route: ActivatedRoute,
private router: Router,
private navigationService: NavigationService
private navigationService: NavigationService,
private featuresService: FeaturesService
) {
this.translatedPageContent$ = this.loginRepository.translatedPageContent$;
this.hideBackButton$ = this.navigationService.isExternalNavigation$;
Expand Down Expand Up @@ -149,12 +150,13 @@ export class LoginPage implements OnInit {
}
this.authService.dispatchLoginAction();

if (this.returnUrl) {
this.router.navigateByUrl(this.returnUrl);
return;
}

this.router.navigate(['/features/widgets']);
this.featuresService.loadAndStoreFeatures().subscribe(() => {
if (this.returnUrl) {
this.router.navigateByUrl(this.returnUrl);
} else {
this.router.navigate(['/features/widgets']);
}
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ export class PreferencesService {
return getRefreshAuthToken().pipe(
take(1),
filter(token => token != null),
concatMap(token => this.keepAuthService.removeSavedCredentials(token)),
finalize(() => deleteRefreshAuthToken())
concatMap(token =>
this.keepAuthService.removeSavedCredentials(token).pipe(
finalize(() => deleteRefreshAuthToken())
)),
).subscribe();
}
}
17 changes: 6 additions & 11 deletions dev/user-frontend-ionic/projects/map/src/lib/map.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@
* termes.
*/

import { Component, Inject, OnDestroy, ViewChild } from '@angular/core';
import { Component, DestroyRef, inject, Inject, ViewChild } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { Geolocation } from '@capacitor/geolocation';
import { TranslateService } from '@ngx-translate/core';
import { NetworkService } from '@multi/shared';
import * as Leaflet from 'leaflet';
import { Subject } from 'rxjs';
import { finalize, take, takeUntil } from 'rxjs/operators';
import { finalize, take } from 'rxjs/operators';
import { MapModuleConfig, MAP_CONFIG } from './map.config';
import { Marker, markersList$, setMarkers } from './map.repository';
import { MapService } from './map.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

const CATEGORIES = [
'presidences_points',
Expand All @@ -64,7 +64,7 @@ const CATEGORIES = [
templateUrl: './map.page.html',
styleUrls: ['../../../../src/theme/app-theme/styles/map/map.page.scss'],
})
export class MapPage implements OnDestroy {
export class MapPage {

@ViewChild('popover') popover;

Expand All @@ -77,7 +77,7 @@ export class MapPage implements OnDestroy {
private markersByCategory: Map<string, Leaflet.Marker[]> = new Map();
private layerGroupByCategory: Map<string, Leaflet.LayerGroup> = new Map();
private positionLayerGroup: Leaflet.LayerGroup;
private unsubscribe$: Subject<boolean> = new Subject<boolean>();
private destroyRef = inject(DestroyRef)

constructor(
private mapService: MapService,
Expand All @@ -89,7 +89,7 @@ export class MapPage implements OnDestroy {
this.initCategoriesForm();

this.categoriesForm.valueChanges.pipe(
takeUntil(this.unsubscribe$)
takeUntilDestroyed(this.destroyRef)
).subscribe(formValues => {
this.categoriesSelected = CATEGORIES.filter((value, index) => formValues[index]);
this.refreshMap();
Expand All @@ -116,11 +116,6 @@ export class MapPage implements OnDestroy {
this.map.remove();
}

ngOnDestroy() {
this.unsubscribe$.next(true);
this.unsubscribe$.complete();
}

onLocateUserClick() {
this.refreshUserPosition();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

import { SecureStoragePlugin } from 'capacitor-secure-storage-plugin';
import { from, Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { catchError, map, switchMap } from 'rxjs/operators';

const AUTH_TOKEN_KEY = 'auth-token';

Expand All @@ -53,14 +53,45 @@ export const updateAuthToken = (token: string): Observable<boolean> => from(
);

export const getAuthToken = (): Observable<string | null> => from(
SecureStoragePlugin.get({key: AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value),
catchError(() => of(null)),
);
SecureStoragePlugin.keys()).pipe(
map(result => result.value),
switchMap(keys => {
// On vérifie l'existence de la clé avant suppression pour éviter de tomber dans le catch de l'erreur du plugin
// https://github.com/martinkasa/capacitor-secure-storage-plugin/issues/39
if (keys.includes(AUTH_TOKEN_KEY)) {
return from(SecureStoragePlugin.get({key: AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value),
catchError(() => {
return of(null)
}));
} else {
return of(null);
}
}),
catchError(() => of(null))
);

export const deleteAuthToken = (): Observable<boolean> => from(
SecureStoragePlugin.remove({key: AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value)
);
SecureStoragePlugin.keys()).pipe(
map(result => result.value),
switchMap(keys => {
// On vérifie l'existence de la clé avant suppression pour éviter de tomber dans le catch de l'erreur du plugin
// https://github.com/martinkasa/capacitor-secure-storage-plugin/issues/39
if (keys.includes(AUTH_TOKEN_KEY)) {
return from(
SecureStoragePlugin.remove({key: AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value),
catchError(() => {
return of(null)
}));
} else {
return of(null);
}
}),
catchError(() => of(null))
);



Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

import { SecureStoragePlugin } from 'capacitor-secure-storage-plugin';
import { from, Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { catchError, map, switchMap } from 'rxjs/operators';

const REFRESH_AUTH_TOKEN_KEY = 'refresh-auth-token';

Expand All @@ -53,14 +53,42 @@ export const updateRefreshAuthToken = (token: string): Observable<boolean> => fr
);

export const getRefreshAuthToken = (): Observable<string | null> => from(
SecureStoragePlugin.get({key: REFRESH_AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value),
catchError(() => of(null)),
);
SecureStoragePlugin.keys()).pipe(
map(result => result.value),
switchMap(keys => {
// On vérifie l'existence de la clé avant suppression pour éviter de tomber dans le catch de l'erreur du plugin
// https://github.com/martinkasa/capacitor-secure-storage-plugin/issues/39
if (keys.includes(REFRESH_AUTH_TOKEN_KEY)) {
return from(SecureStoragePlugin.get({key: REFRESH_AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value),
catchError(() => {
return of(null)
}),)
} else {
return of(null);
}
}),
catchError(() => of(null))
);

export const deleteRefreshAuthToken = (): Observable<boolean> => from(
SecureStoragePlugin.remove({key: REFRESH_AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value)
);
SecureStoragePlugin.keys()).pipe(
map(result => result.value),
switchMap(keys => {
// On vérifie l'existence de la clé avant suppression pour éviter de tomber dans le catch de l'erreur du plugin
// https://github.com/martinkasa/capacitor-secure-storage-plugin/issues/39
if (keys.includes(REFRESH_AUTH_TOKEN_KEY)) {
return from(
SecureStoragePlugin.remove({key: REFRESH_AUTH_TOKEN_KEY}))
.pipe(
map(result => result.value),
catchError(() => {
return of(null)
}));
} else {
return of(null);
}
}),
catchError(() => of(null))
);
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { Observable, ReplaySubject, Subject } from 'rxjs';
import { filter, shareReplay } from 'rxjs/operators';

/**
Expand All @@ -54,9 +54,9 @@ import { filter, shareReplay } from 'rxjs/operators';
})
export class WidgetLifecycleService {
private widgetViewWillEnterSubject: Subject<string[]> = new Subject();
private widgetViewDidEnterSubject: Subject<string[]> = new Subject();
private widgetViewDidEnterSubject: ReplaySubject<string[]> = new ReplaySubject<string[]>(1);
private widgetViewWillLeaveSubject: Subject<string[]> = new Subject();
private widgetViewDidLeaveSubject: Subject<string[]> = new Subject();
private widgetViewDidLeaveSubject: ReplaySubject<string[]> = new ReplaySubject<string[]>(1);

sendWidgetViewWillEnter(widgets) {
this.widgetViewWillEnterSubject.next(widgets);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@
import {
AfterViewInit,
ChangeDetectorRef,
Component,
EventEmitter,
Component, DestroyRef,
EventEmitter, inject,
Input,
OnDestroy,
Output,
ViewChild,
ViewContainerRef
} from '@angular/core';
import { Subscription } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ProjectModuleService } from '../../project-module/project-module.service';
import { WidgetLifecycleService } from './widget-lifecycle.service';

Expand All @@ -57,15 +56,13 @@ import { WidgetLifecycleService } from './widget-lifecycle.service';
templateUrl: './widget.component.html',
styleUrls: ['../../../../../../src/theme/app-theme/styles/shared/widget.component.scss'],
})
export class WidgetComponent implements AfterViewInit, OnDestroy {
export class WidgetComponent implements AfterViewInit {
@Input() widgetId: string;
@Input() widgetColor: string;
@ViewChild('widget', { read: ViewContainerRef }) widgetContainerRef: ViewContainerRef;
@Output() widgetIsEmpty = new EventEmitter<boolean>();
private widgetViewWillEnterSubscription: Subscription;
private widgetViewDidEnterSubscription: Subscription;
private widgetViewWillLeaveSubscription: Subscription;
private widgetViewDidLeaveSubscription: Subscription;

private destroyRef = inject(DestroyRef);

constructor(
private projectModuleService: ProjectModuleService,
Expand All @@ -82,9 +79,11 @@ export class WidgetComponent implements AfterViewInit, OnDestroy {

widgetInstance.widgetColor = this.widgetColor;
if (widgetInstance.isEmpty$) {
widgetInstance.isEmpty$.subscribe((isEmpty: boolean) => {
this.widgetIsEmpty.emit(isEmpty);
});
widgetInstance.isEmpty$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((isEmpty: boolean) => {
this.widgetIsEmpty.emit(isEmpty);
});
}

this.cdr.detectChanges();
Expand All @@ -93,36 +92,25 @@ export class WidgetComponent implements AfterViewInit, OnDestroy {
}
}

ngOnDestroy() {
if(this.widgetViewWillEnterSubscription) {
this.widgetViewWillEnterSubscription.unsubscribe();
}
if(this.widgetViewDidEnterSubscription) {
this.widgetViewDidEnterSubscription.unsubscribe();
}
if(this.widgetViewWillLeaveSubscription) {
this.widgetViewWillLeaveSubscription.unsubscribe();
}
if(this.widgetViewDidLeaveSubscription) {
this.widgetViewDidLeaveSubscription.unsubscribe();
}
}

private handleWidgetLifecycle(widgetInstance: any) {
if (widgetInstance.widgetViewWillEnter && typeof widgetInstance.widgetViewWillEnter === 'function') {
this.widgetViewWillEnterSubscription = this.widgetLifecycleService.widgetViewWillEnter(this.widgetId)
this.widgetLifecycleService.widgetViewWillEnter(this.widgetId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => widgetInstance.widgetViewWillEnter());
}
if (widgetInstance.widgetViewDidEnter && typeof widgetInstance.widgetViewDidEnter === 'function') {
this.widgetViewDidEnterSubscription = this.widgetLifecycleService.widgetViewDidEnter(this.widgetId)
this.widgetLifecycleService.widgetViewDidEnter(this.widgetId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => widgetInstance.widgetViewDidEnter());
}
if (widgetInstance.widgetViewWillLeave && typeof widgetInstance.widgetViewWillLeave === 'function') {
this.widgetViewWillLeaveSubscription = this.widgetLifecycleService.widgetViewWillLeave(this.widgetId)
this.widgetLifecycleService.widgetViewWillLeave(this.widgetId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => widgetInstance.widgetViewWillLeave());
}
if (widgetInstance.widgetViewDidLeave && typeof widgetInstance.widgetViewDidLeave === 'function') {
this.widgetViewDidLeaveSubscription = this.widgetLifecycleService.widgetViewDidLeave(this.widgetId)
this.widgetLifecycleService.widgetViewDidLeave(this.widgetId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => widgetInstance.widgetViewDidLeave());
}
}
Expand Down
26 changes: 14 additions & 12 deletions dev/user-frontend-ionic/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,21 @@
~ termes.
-->

<ion-app *ngIf="(currentPageLayout$ | async) as currentPageLayout">
<ion-app *ngIf="(currentPageLayout$ | async) as currentPageLayout; else noContent">
<app-layout [currentPageLayout]='currentPageLayout'></app-layout>
</ion-app>

<div *ngIf="(isNothingToShow$ | async) === true" class="custom-alert">
<div class="flex-container">
<ion-card class="center-card">
<ion-card-header>
<ion-card-title class="text-center app-title-4">{{"ERROR.NO_NETWORK.TITLE" | translate}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-text class="app-text-4">{{"ERROR.NO_NETWORK.FIRST_LAUNCH" | translate}}</ion-text>
</ion-card-content>
</ion-card>
<ng-template #noContent>
<div *ngIf="(isNothingToShow$ | async) === true" class="custom-alert">
<div class="flex-container">
<ion-card class="center-card">
<ion-card-header>
<ion-card-title class="text-center app-title-4">{{"ERROR.NO_NETWORK.TITLE" | translate}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-text class="app-text-4">{{"ERROR.NO_NETWORK.FIRST_LAUNCH" | translate}}</ion-text>
</ion-card-content>
</ion-card>
</div>
</div>
</div>
</ng-template>
Loading