diff --git a/src/app/app.component.html b/src/app/app.component.html index 14ce919..bcd2663 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,5 +1,6 @@ +
diff --git a/src/app/modules/accounts/services/account.service.ts b/src/app/modules/accounts/services/account.service.ts index 6d02458..fda72d8 100644 --- a/src/app/modules/accounts/services/account.service.ts +++ b/src/app/modules/accounts/services/account.service.ts @@ -7,6 +7,7 @@ import {environment} from '../../../../environments/environment' import {ApiService} from '../../shared/service/api.service' import {Employee, EmployeePermission} from '../../shared/model/employee' import {ErrorService} from '../../shared/service/error.service' +import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component' @Injectable({ providedIn: 'root' @@ -47,6 +48,7 @@ export class AccountService implements OnDestroy { login(id: number, password: string, success: () => void) { const loginForm = {id, password} + globalLoadingWheel.show() this.http.post(`${environment.apiUrl}/login`, loginForm, { withCredentials: true, observe: 'response' as 'body' @@ -92,7 +94,11 @@ export class AccountService implements OnDestroy { takeUntil(this.destroy$) ) .subscribe({ - next: employee => this.appState.authenticatedEmployee = employee, + next: employee => { + this.appState.authenticatedEmployee = employee + // At this point the loading wheel should be visible + globalLoadingWheel.hide() + }, error: err => this.errorService.handleError(err) }) } diff --git a/src/app/modules/colors/components/images-editor/images-editor.component.ts b/src/app/modules/colors/components/images-editor/images-editor.component.ts index 42c4499..55814bd 100644 --- a/src/app/modules/colors/components/images-editor/images-editor.component.ts +++ b/src/app/modules/colors/components/images-editor/images-editor.component.ts @@ -6,6 +6,7 @@ import {Observable} from 'rxjs' import {RecipeImageService} from '../../services/recipe-image.service' import {environment} from '../../../../../environments/environment' import {ErrorService} from '../../../shared/service/error.service' +import {globalLoadingWheel} from '../../../shared/components/loading-wheel/loading-wheel.component' @Component({ selector: 'cre-images-editor', @@ -36,6 +37,7 @@ export class ImagesEditorComponent extends SubscribingComponent { this.subscribe( this.imageIds$, ids => this.hasImages = ids.length > 0, + false, 1 ) } diff --git a/src/app/modules/colors/pages/explore/explore.component.ts b/src/app/modules/colors/pages/explore/explore.component.ts index 5f68076..65f7f28 100644 --- a/src/app/modules/colors/pages/explore/explore.component.ts +++ b/src/app/modules/colors/pages/explore/explore.component.ts @@ -7,6 +7,7 @@ import {Observable, Subject} from 'rxjs' import {ErrorModel, ErrorService} from '../../../shared/service/error.service' import {AlertService} from '../../../shared/service/alert.service' import {GlobalAlertHandlerComponent} from '../../../shared/components/global-alert-handler/global-alert-handler.component' +import {globalLoadingWheel} from '../../../shared/components/loading-wheel/loading-wheel.component' @Component({ selector: 'cre-explore', @@ -88,7 +89,8 @@ export class ExploreComponent extends ErrorHandlingComponent { saveModifications() { this.subscribe( this.recipeService.saveExplorerModifications(this.recipe.id, this.note, this.mixesLocationChanges), - () => this.alertService.pushSuccess('Les modifications ont été enregistrées') + () => this.alertService.pushSuccess('Les modifications ont été enregistrées'), + true ) } @@ -103,7 +105,8 @@ export class ExploreComponent extends ErrorHandlingComponent { performDeductQuantities(observable: Observable) { this.subscribe( observable, - () => this.alertService.pushSuccess('Les quantités des produits utilisés ont été déduites de l\'inventaire') + () => this.alertService.pushSuccess('Les quantités des produits utilisés ont été déduites de l\'inventaire'), + true ) } } diff --git a/src/app/modules/groups/pages/list/list.component.ts b/src/app/modules/groups/pages/list/list.component.ts index a98648c..4844dbf 100644 --- a/src/app/modules/groups/pages/list/list.component.ts +++ b/src/app/modules/groups/pages/list/list.component.ts @@ -8,6 +8,7 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com import {ActivatedRoute, Router} from '@angular/router' import {ErrorModel, ErrorService} from '../../../shared/service/error.service' import {AlertService} from '../../../shared/service/alert.service' +import {globalLoadingWheel} from '../../../shared/components/loading-wheel/loading-wheel.component' @Component({ selector: 'cre-groups', @@ -53,7 +54,8 @@ export class ListComponent extends ErrorHandlingComponent { setDefaultGroup(group: EmployeeGroup) { this.subscribe( this.groupService.setDefaultGroup(group), - () => this.defaultGroup = group + () => this.defaultGroup = group, + true ) } diff --git a/src/app/modules/material/pages/list/list.component.ts b/src/app/modules/material/pages/list/list.component.ts index 7092ac6..96686fa 100644 --- a/src/app/modules/material/pages/list/list.component.ts +++ b/src/app/modules/material/pages/list/list.component.ts @@ -62,6 +62,7 @@ export class ListComponent extends ErrorHandlingComponent { ) }) }, + false, 1 ) } diff --git a/src/app/modules/shared/components/header/header.component.ts b/src/app/modules/shared/components/header/header.component.ts index 9f3585f..ea14e7d 100644 --- a/src/app/modules/shared/components/header/header.component.ts +++ b/src/app/modules/shared/components/header/header.component.ts @@ -46,6 +46,7 @@ export class HeaderComponent extends SubscribingComponent { this._activeLink = data.url } }, + false, 1 ) diff --git a/src/app/modules/shared/components/loading-wheel/loading-wheel.component.html b/src/app/modules/shared/components/loading-wheel/loading-wheel.component.html new file mode 100644 index 0000000..67b0f2f --- /dev/null +++ b/src/app/modules/shared/components/loading-wheel/loading-wheel.component.html @@ -0,0 +1,6 @@ +
+
+
+ +
+
diff --git a/src/app/modules/shared/components/loading-wheel/loading-wheel.component.sass b/src/app/modules/shared/components/loading-wheel/loading-wheel.component.sass new file mode 100644 index 0000000..27c3fcb --- /dev/null +++ b/src/app/modules/shared/components/loading-wheel/loading-wheel.component.sass @@ -0,0 +1,18 @@ +.spinner-wrapper + transition: all 100ms + + &.visible + opacity: 1 !important + visibility: unset !important + + &:not(.visible) + opacity: 0 + visibility: hidden + + .spinner + max-width: max-content + position: fixed + left: 50% + top: 50% + transform: translate(-50%, -50%) + z-index: 11 diff --git a/src/app/modules/shared/components/loading-wheel/loading-wheel.component.ts b/src/app/modules/shared/components/loading-wheel/loading-wheel.component.ts new file mode 100644 index 0000000..0f648f9 --- /dev/null +++ b/src/app/modules/shared/components/loading-wheel/loading-wheel.component.ts @@ -0,0 +1,24 @@ +import {Component} from '@angular/core' + +export let globalLoadingWheel: LoadingWheelComponent | null + +@Component({ + selector: 'cre-loading-wheel', + templateUrl: './loading-wheel.component.html', + styleUrls: ['./loading-wheel.component.sass'] +}) +export class LoadingWheelComponent { + visible = false + + constructor() { + globalLoadingWheel = this + } + + show() { + this.visible = true + } + + hide() { + this.visible = false + } +} diff --git a/src/app/modules/shared/components/subscribing.component.ts b/src/app/modules/shared/components/subscribing.component.ts index d19ce1b..c73a786 100644 --- a/src/app/modules/shared/components/subscribing.component.ts +++ b/src/app/modules/shared/components/subscribing.component.ts @@ -4,6 +4,7 @@ import {Observable, Subject} from 'rxjs' import {ActivatedRoute, Router} from '@angular/router' import {UrlUtils} from '../utils/url.utils' import {ErrorHandler, ErrorModel, ErrorService} from '../service/error.service' +import {globalLoadingWheel} from './loading-wheel/loading-wheel.component' export abstract class SubscribingComponent implements OnInit, OnDestroy { protected subscribers$ = [] @@ -17,33 +18,48 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy { ) { } - subscribe(observable: Observable, resultConsumer: (T) => void, take_count = -1) { + subscribe(observable: Observable, resultConsumer: (T) => void, showWheel = false, take_count = -1) { if (take_count >= 0) { observable.pipe(take(take_count), takeUntil(this.destroy$)) } else { observable.pipe(takeUntil(this.destroy$)) } + this.showLoadingWheel(showWheel) this.subscribers$.push(observable.subscribe({ - next: resultConsumer, - error: err => this.errorService.handleError(err) + next: t => { + resultConsumer(t) + this.hideLoadingWheel(showWheel) + }, + error: err => { + this.errorService.handleError(err) + this.hideLoadingWheel(showWheel) + } })) } - subscribeAndNavigate(observable: Observable, route: string) { + subscribeAndNavigate(observable: Observable, route: string, showWheel = true) { this.subscribe( observable, () => this.urlUtils.navigateTo(route), + showWheel, 1 ) } - subscribeEntityById(service: any, id: number, resultConsumer: (T) => void, notFoundRoute: string) { + subscribeEntityById(service: any, id: number, resultConsumer: (T) => void, notFoundRoute: string, showWheel = true) { + this.showLoadingWheel(showWheel) this.subscribers$.push(service.getById(id) .pipe(take(1), takeUntil(this.destroy$)) .subscribe({ - next: e => resultConsumer(e), - error: err => this.handleNotFoundError(err, notFoundRoute) + next: e => { + resultConsumer(e) + this.hideLoadingWheel(showWheel) + }, + error: err => { + this.handleNotFoundError(err, notFoundRoute) + this.hideLoadingWheel(showWheel) + } })) } @@ -62,6 +78,18 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy { this.errorService.handleError(error) } } + + protected showLoadingWheel(shouldShowWheel) { + if (shouldShowWheel) { + globalLoadingWheel.show() + } + } + + protected hideLoadingWheel(shouldShowWheel) { + if (shouldShowWheel) { + globalLoadingWheel.hide() + } + } } export abstract class ErrorHandlingComponent extends SubscribingComponent implements ErrorHandler { diff --git a/src/app/modules/shared/service/api.service.ts b/src/app/modules/shared/service/api.service.ts index 3deff1e..5389e7d 100644 --- a/src/app/modules/shared/service/api.service.ts +++ b/src/app/modules/shared/service/api.service.ts @@ -4,10 +4,10 @@ import {Observable, Subject} from 'rxjs' import {environment} from '../../../../environments/environment' import {AppState} from '../app-state' import {Router} from '@angular/router' -import {map, share, takeUntil} from 'rxjs/operators' +import {map, share, takeUntil, tap} from 'rxjs/operators' import {valueOr} from '../utils/utils' import {ErrorService} from './error.service' -import {AccountService} from '../../accounts/services/account.service' +import {globalLoadingWheel} from '../components/loading-wheel/loading-wheel.component' @Injectable({ providedIn: 'root' diff --git a/src/app/modules/shared/shared.module.ts b/src/app/modules/shared/shared.module.ts index 3d8407a..c2325f0 100644 --- a/src/app/modules/shared/shared.module.ts +++ b/src/app/modules/shared/shared.module.ts @@ -28,12 +28,14 @@ import {MatOptionModule} from '@angular/material/core' import {MaterialFileInputModule} from 'ngx-material-file-input' import {FileButtonComponent} from './file-button/file-button.component' import {GlobalAlertHandlerComponent} from './components/global-alert-handler/global-alert-handler.component' -import {MatSliderModule} from '@angular/material/slider'; -import { SliderFieldComponent } from './components/slider-field/slider-field.component' +import {MatSliderModule} from '@angular/material/slider' +import {SliderFieldComponent} from './components/slider-field/slider-field.component' +import {LoadingWheelComponent} from './components/loading-wheel/loading-wheel.component' +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner' @NgModule({ - declarations: [HeaderComponent, EmployeeInfoComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent], + declarations: [HeaderComponent, EmployeeInfoComponent, LabeledIconComponent, ConfirmBoxComponent, PermissionsListComponent, PermissionsFieldComponent, NavComponent, EntityListComponent, EntityAddComponent, EntityEditComponent, FileButtonComponent, GlobalAlertHandlerComponent, SliderFieldComponent, LoadingWheelComponent], exports: [ CommonModule, HttpClientModule, @@ -60,7 +62,8 @@ import { SliderFieldComponent } from './components/slider-field/slider-field.com EntityAddComponent, EntityEditComponent, FileButtonComponent, - GlobalAlertHandlerComponent + GlobalAlertHandlerComponent, + LoadingWheelComponent ], imports: [ MatTabsModule, @@ -76,6 +79,7 @@ import { SliderFieldComponent } from './components/slider-field/slider-field.com MatSelectModule, MatOptionModule, MatSliderModule, + MatProgressSpinnerModule, ReactiveFormsModule, RouterModule, CommonModule, diff --git a/src/styles.sass b/src/styles.sass index 5896eac..2e6f3f5 100644 --- a/src/styles.sass +++ b/src/styles.sass @@ -200,6 +200,7 @@ div.empty left: 0 background-color: black opacity: 0.4 + z-index: 10 .color-warning color: #fdd835