develop #8
|
@ -40,7 +40,7 @@
|
|||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": false,
|
||||
"sourceMap": true,
|
||||
"optimization": false,
|
||||
"namedChunks": true
|
||||
},
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --proxy-config proxy.conf.json",
|
||||
"start": "ng serve --host 0.0.0.0 --proxy-config proxy.conf.json",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"browser": {
|
||||
"fs": false
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.2.14",
|
||||
"@angular/cdk": "^12.2.13",
|
||||
|
@ -21,10 +24,11 @@
|
|||
"@angular/platform-browser": "~12.2.14",
|
||||
"@angular/platform-browser-dynamic": "~12.2.14",
|
||||
"@angular/router": "~12.2.14",
|
||||
"@js-joda/core": "^4.3.1",
|
||||
"@mdi/angular-material": "^6.5.95",
|
||||
"bootstrap": "^4.5.2",
|
||||
"copy-webpack-plugin": "^10.0.0",
|
||||
"@js-joda/core": "^4.3.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"ngx-material-file-input": "^2.1.1",
|
||||
"rxjs": "^7.4.0",
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {NgModule} from '@angular/core'
|
||||
import {RouterModule, Routes} from '@angular/router'
|
||||
import {Login, Logout} from './accounts'
|
||||
|
||||
import {LoginComponent} from './pages/login/login.component';
|
||||
import {LogoutComponent} from "./pages/logout/logout.component";
|
||||
|
||||
const routes: Routes = [{path: 'login', component: LoginComponent}, {path: 'logout', component: LogoutComponent}, {path: '', redirectTo: 'login'}];
|
||||
const routes: Routes = [{
|
||||
path: 'login',
|
||||
component: Login
|
||||
}, {
|
||||
path: 'logout',
|
||||
component: Logout
|
||||
}, {
|
||||
path: '',
|
||||
redirectTo: 'login'
|
||||
}]
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {NgModule} from '@angular/core'
|
||||
|
||||
import {AccountsRoutingModule} from './accounts-routing.module';
|
||||
import {LoginComponent} from './pages/login/login.component';
|
||||
import {SharedModule} from "../shared/shared.module";
|
||||
import {LogoutComponent} from './pages/logout/logout.component';
|
||||
import {CommonModule} from "@angular/common";
|
||||
import {BrowserModule} from "@angular/platform-browser";
|
||||
import {AccountsRoutingModule} from './accounts-routing.module'
|
||||
import {SharedModule} from '../shared/shared.module'
|
||||
import {Login, Logout} from './accounts'
|
||||
import {CreInputsModule} from '../shared/components/inputs/inputs.module'
|
||||
import {CreButtonsModule} from '../shared/components/buttons/buttons.module'
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [LoginComponent, LogoutComponent],
|
||||
declarations: [
|
||||
Login,
|
||||
Logout
|
||||
],
|
||||
imports: [
|
||||
SharedModule,
|
||||
AccountsRoutingModule,
|
||||
CreInputsModule,
|
||||
CreButtonsModule,
|
||||
]
|
||||
})
|
||||
export class AccountsModule {
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import {Component, HostListener, ViewChild} from '@angular/core'
|
||||
import {FormControl, Validators} from '@angular/forms'
|
||||
import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component'
|
||||
import {AccountService} from './services/account.service'
|
||||
import {AppState} from '../shared/app-state'
|
||||
import {ErrorHandler, ErrorService} from '../shared/service/error.service'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {CreForm, ICreForm} from "../shared/components/forms/forms";
|
||||
import {AlertService} from "../shared/service/alert.service";
|
||||
|
||||
@Component({
|
||||
selector: 'cre-login',
|
||||
templateUrl: 'login.html',
|
||||
styles: [
|
||||
'cre-form { min-width: 25rem; margin-top: 50vh; transform: translateY(-70%) }'
|
||||
]
|
||||
})
|
||||
export class Login extends ErrorHandlingComponent {
|
||||
@ViewChild(CreForm) form: ICreForm
|
||||
|
||||
userIdControl = new FormControl(null, Validators.compose([Validators.required, Validators.pattern(new RegExp('^[0-9]+$'))]))
|
||||
passwordControl = new FormControl(null, Validators.required)
|
||||
|
||||
errorHandlers: ErrorHandler[] = [{
|
||||
filter: error => error.status === 403,
|
||||
messageProducer: () => 'Les identifiants entrés sont invalides'
|
||||
}]
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private alertService: AlertService,
|
||||
private appState: AppState,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
activatedRoute: ActivatedRoute
|
||||
) {
|
||||
super(errorService, activatedRoute, router)
|
||||
this.appState.title = 'Connexion'
|
||||
}
|
||||
|
||||
// Allows to send the form by pressing Enter
|
||||
@HostListener('window:keyup.enter', ['$event'])
|
||||
onEnterKeyEvent() {
|
||||
if (this.form.formGroup) {
|
||||
this.submit()
|
||||
}
|
||||
}
|
||||
|
||||
submit() {
|
||||
this.subscribeAndNavigate(
|
||||
this.accountService.login(this.userIdControl.value, this.passwordControl.value),
|
||||
'/color/list'
|
||||
)
|
||||
}
|
||||
|
||||
get controls(): { userId: FormControl, password: FormControl } {
|
||||
return {
|
||||
userId: this.userIdControl,
|
||||
password: this.passwordControl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cre-logout',
|
||||
template: ''
|
||||
})
|
||||
export class Logout extends SubscribingComponent {
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private alertService: AlertService,
|
||||
private appState: AppState,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
activatedRoute: ActivatedRoute
|
||||
) {
|
||||
super(errorService, activatedRoute, router)
|
||||
this.appState.title = 'Connexion'
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.appState.isAuthenticated) {
|
||||
this.urlUtils.navigateTo('/account/login')
|
||||
}
|
||||
|
||||
this.subscribeAndNavigate(
|
||||
this.accountService.logout(),
|
||||
'/account/login'
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<cre-form #form [formControls]="controls" class="mx-auto">
|
||||
<cre-form-title>Connexion au système</cre-form-title>
|
||||
<cre-form-content>
|
||||
<cre-input
|
||||
[control]="userIdControl"
|
||||
label="Numéro d'utilisateur"
|
||||
icon="account">
|
||||
<ng-template let-errors="errors">
|
||||
<span *ngIf="errors && errors.pattern">Le numéro d'utilisateur doit être un nombre</span>
|
||||
</ng-template>
|
||||
</cre-input>
|
||||
|
||||
<cre-input
|
||||
[control]="passwordControl"
|
||||
type="password"
|
||||
label="Mot de passe"
|
||||
icon="lock">
|
||||
</cre-input>
|
||||
</cre-form-content>
|
||||
<cre-form-actions>
|
||||
<cre-accent-button
|
||||
type="submit"
|
||||
[disabled]="!form.valid"
|
||||
(click)="submit()">
|
||||
Connexion
|
||||
</cre-accent-button>
|
||||
</cre-form-actions>
|
||||
</cre-form>
|
|
@ -1,36 +0,0 @@
|
|||
<form [formGroup]="form">
|
||||
<mat-card class="x-centered y-centered">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Connexion au système</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<mat-form-field>
|
||||
<mat-label>Numéro d'utilisateur</mat-label>
|
||||
<input matInput [formControl]="idFormControl" type="text"/>
|
||||
<mat-icon matSuffix>person</mat-icon>
|
||||
<mat-error *ngIf="idFormControl.invalid">
|
||||
<span *ngIf="idFormControl.errors.required">Un numéro d'utilisateur est requis</span>
|
||||
<span *ngIf="idFormControl.errors.pattern">Le numéro d'utilisateur doit être un nombre</span>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Mot de passe</mat-label>
|
||||
<input matInput [formControl]="passwordFormControl" type="password"/>
|
||||
<mat-icon matSuffix>lock</mat-icon>
|
||||
<mat-error *ngIf="passwordFormControl.invalid">
|
||||
<span *ngIf="passwordFormControl.errors.required">Un mot de passe est requis</span>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</mat-card-content>
|
||||
<mat-card-actions class="justify-content-end">
|
||||
<button
|
||||
mat-raised-button
|
||||
type="submit"
|
||||
color="accent"
|
||||
[disabled]="form.invalid"
|
||||
(click)="submit()">
|
||||
Connexion
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
|
@ -1,8 +0,0 @@
|
|||
mat-card
|
||||
width: 25rem
|
||||
|
||||
.alert p
|
||||
margin: 0
|
||||
|
||||
mat-form-field
|
||||
width: 100%
|
|
@ -1,53 +0,0 @@
|
|||
import {Component, OnInit} from '@angular/core'
|
||||
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
|
||||
import {AccountService} from '../../services/account.service'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {ErrorService} from '../../../shared/service/error.service'
|
||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||
import {AppState} from '../../../shared/app-state'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.sass']
|
||||
})
|
||||
export class LoginComponent extends ErrorHandlingComponent implements OnInit {
|
||||
form: FormGroup
|
||||
idFormControl: FormControl
|
||||
passwordFormControl: FormControl
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private accountService: AccountService,
|
||||
private appState: AppState,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
activatedRoute: ActivatedRoute
|
||||
) {
|
||||
super(errorService, activatedRoute, router)
|
||||
this.appState.title = 'Connexion'
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.errorService.activeErrorHandler = this
|
||||
|
||||
if (this.accountService.isLoggedIn()) {
|
||||
this.router.navigate(['/color'])
|
||||
}
|
||||
|
||||
this.idFormControl = this.formBuilder.control(null, Validators.compose([Validators.required, Validators.pattern(new RegExp('^[0-9]+$'))]))
|
||||
this.passwordFormControl = this.formBuilder.control(null, Validators.required)
|
||||
this.form = this.formBuilder.group({
|
||||
id: this.idFormControl,
|
||||
password: this.passwordFormControl
|
||||
})
|
||||
}
|
||||
|
||||
submit() {
|
||||
this.accountService.login(
|
||||
this.idFormControl.value,
|
||||
this.passwordFormControl.value,
|
||||
() => this.router.navigate(['/color'])
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {AccountService} from "../../services/account.service";
|
||||
import {Router} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'cre-logout',
|
||||
templateUrl: './logout.component.html',
|
||||
styleUrls: ['./logout.component.sass']
|
||||
})
|
||||
export class LogoutComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.accountService.isLoggedIn()) {
|
||||
this.router.navigate(['/account/login'])
|
||||
}
|
||||
|
||||
this.accountService.logout(() => {
|
||||
this.router.navigate(['/account/login'])
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
import {Injectable, OnDestroy} from '@angular/core'
|
||||
import {Subject} from 'rxjs'
|
||||
import {Observable, Subject} from 'rxjs'
|
||||
import {take, takeUntil} from 'rxjs/operators'
|
||||
import {AppState} from '../../shared/app-state'
|
||||
import {HttpClient, HttpResponse} from '@angular/common/http'
|
||||
import {environment} from '../../../../environments/environment'
|
||||
import {ApiService} from '../../shared/service/api.service'
|
||||
import {User, Permission} from '../../shared/model/user'
|
||||
import {Permission, User} from '../../shared/model/user'
|
||||
import {ErrorService} from '../../shared/service/error.service'
|
||||
import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component'
|
||||
import {AlertService} from '../../shared/service/alert.service'
|
||||
import {JwtService} from "./jwt.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -20,6 +20,7 @@ export class AccountService implements OnDestroy {
|
|||
private http: HttpClient,
|
||||
private api: ApiService,
|
||||
private appState: AppState,
|
||||
private jwtService: JwtService,
|
||||
private errorService: ErrorService,
|
||||
private alertService: AlertService
|
||||
) {
|
||||
|
@ -30,20 +31,16 @@ export class AccountService implements OnDestroy {
|
|||
this.destroy$.complete()
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return this.appState.isAuthenticated
|
||||
}
|
||||
|
||||
checkAuthenticationStatus() {
|
||||
if (!this.appState.authenticatedUser) {
|
||||
if (!this.appState.isAuthenticated) {
|
||||
// Try to get current default group user
|
||||
this.http.get<User>(`${environment.apiUrl}/user/current`, {withCredentials: true})
|
||||
this.http.get<User>(`${environment.apiUrl}/user/group/currentuser`, {withCredentials: true})
|
||||
.pipe(
|
||||
take(1),
|
||||
takeUntil(this.destroy$),
|
||||
).subscribe(
|
||||
{
|
||||
next: user => this.appState.authenticatedUser = user,
|
||||
next: user => this.appState.authenticateGroupUser(user),
|
||||
error: err => {
|
||||
if (err.status === 404 || err.status === 403) {
|
||||
console.warn('No default user is defined on this computer')
|
||||
|
@ -55,67 +52,74 @@ export class AccountService implements OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
login(id: number, password: string, success: () => void) {
|
||||
const loginForm = {id, password}
|
||||
globalLoadingWheel.show()
|
||||
this.http.post<any>(`${environment.apiUrl}/login`, loginForm, {
|
||||
login(userId: number, password: string): Observable<any> {
|
||||
const subject = new Subject<void>()
|
||||
|
||||
this.http.post<any>(`${environment.apiUrl}/login`, {id: userId, password}, {
|
||||
withCredentials: true,
|
||||
observe: 'response' as 'body'
|
||||
})
|
||||
.pipe(
|
||||
take(1),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe({
|
||||
next: (response: HttpResponse<any>) => {
|
||||
this.appState.authenticationExpiration = parseInt(response.headers.get('X-Authentication-Expiration'))
|
||||
this.appState.isAuthenticated = true
|
||||
this.setLoggedInUserFromApi()
|
||||
success()
|
||||
},
|
||||
error: err => {
|
||||
globalLoadingWheel.hide()
|
||||
if (err.status === 401 || err.status === 403) {
|
||||
this.alertService.pushError('Les identifiants entrés sont invalides')
|
||||
} else {
|
||||
this.errorService.handleError(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
logout(success: () => void) {
|
||||
this.api.get<void>('/logout', true).pipe(
|
||||
}).pipe(
|
||||
take(1),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.appState.resetAuthenticatedUser()
|
||||
this.checkAuthenticationStatus()
|
||||
success()
|
||||
},
|
||||
error: err => this.errorService.handleError(err)
|
||||
})
|
||||
).subscribe({
|
||||
next: (response: HttpResponse<void>) => {
|
||||
this.loginUser(response)
|
||||
|
||||
subject.next()
|
||||
subject.complete()
|
||||
},
|
||||
error: error => {
|
||||
if (error.status === 403) {
|
||||
this.alertService.pushError('Les identifiants entrés sont invalides')
|
||||
} else {
|
||||
this.errorService.handleError(error)
|
||||
}
|
||||
|
||||
subject.next()
|
||||
subject.complete()
|
||||
}
|
||||
})
|
||||
|
||||
return subject
|
||||
}
|
||||
|
||||
private loginUser(response: HttpResponse<void>) {
|
||||
const authorization = response.headers.get("Authorization")
|
||||
const user = this.jwtService.parseUser(authorization)
|
||||
|
||||
this.appState.authenticateUser(user)
|
||||
}
|
||||
|
||||
logout(): Observable<void> {
|
||||
const subject = new Subject<void>()
|
||||
|
||||
this.api.get<void>('/logout').pipe(
|
||||
take(1),
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.logoutUser()
|
||||
|
||||
subject.next()
|
||||
subject.complete()
|
||||
},
|
||||
error: error => {
|
||||
this.errorService.handleError(error)
|
||||
|
||||
subject.next()
|
||||
subject.complete()
|
||||
}
|
||||
})
|
||||
|
||||
return subject
|
||||
}
|
||||
|
||||
private logoutUser() {
|
||||
this.appState.resetAuthenticatedUser()
|
||||
this.checkAuthenticationStatus()
|
||||
}
|
||||
|
||||
hasPermission(permission: Permission): boolean {
|
||||
return this.appState.authenticatedUser && this.appState.authenticatedUser.permissions.indexOf(permission) >= 0
|
||||
}
|
||||
|
||||
private setLoggedInUserFromApi() {
|
||||
this.api.get<User>('/user/current', true)
|
||||
.pipe(
|
||||
take(1),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe({
|
||||
next: user => {
|
||||
this.appState.authenticatedUser = user
|
||||
// At this point the loading wheel should be visible
|
||||
globalLoadingWheel.hide()
|
||||
},
|
||||
error: err => this.errorService.handleError(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import jwtDecode from "jwt-decode";
|
||||
import { User } from "../../shared/model/user";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class JwtService {
|
||||
parseUser(jwt: string): User {
|
||||
const decoded = jwtDecode(jwt) as any
|
||||
return JSON.parse(decoded.user)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<cre-action-bar [reverse]="true">
|
||||
<cre-action-group>
|
||||
<cre-accent-button routerLink="/catalog/company/add">Ajouter</cre-accent-button>
|
||||
<cre-accent-button *ngIf="hasEditPermission" routerLink="/catalog/company/add">Ajouter</cre-accent-button>
|
||||
</cre-action-group>
|
||||
</cre-action-bar>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<cre-action-bar [reverse]="true">
|
||||
<cre-action-group>
|
||||
<cre-accent-button routerLink="/catalog/materialtype/add">Ajouter</cre-accent-button>
|
||||
<cre-accent-button *ngIf="hasEditPermission" routerLink="/catalog/materialtype/add">Ajouter</cre-accent-button>
|
||||
</cre-action-group>
|
||||
</cre-action-bar>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<cre-primary-button routerLink="/color/list">Retour</cre-primary-button>
|
||||
</cre-action-group>
|
||||
<cre-action-group>
|
||||
<cre-submit-button [form]="recipeForm.creForm" (submit)="recipeForm.submit()"></cre-submit-button>
|
||||
<cre-form-submit-button [form]="recipeForm.creForm" (submit)="recipeForm.submit()"></cre-form-submit-button>
|
||||
</cre-action-group>
|
||||
</cre-action-bar>
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ abstract class _BaseMixPage extends SubscribingComponent {
|
|||
protected mixService: MixService,
|
||||
private recipeService: RecipeService,
|
||||
private materialTypeService: MaterialTypeService,
|
||||
private materialService: MaterialService,
|
||||
protected materialService: MaterialService,
|
||||
errorService: ErrorService,
|
||||
router: Router,
|
||||
activatedRoute: ActivatedRoute
|
||||
|
@ -50,13 +50,15 @@ abstract class _BaseMixPage extends SubscribingComponent {
|
|||
|
||||
set recipe(recipe: Recipe) {
|
||||
this._recipe = recipe
|
||||
this.materials$ = this.materialService.getAllForMixCreation(recipe.id)
|
||||
this.materials$ = this.fetchMaterials(recipe.id)
|
||||
}
|
||||
|
||||
get recipe(): Recipe {
|
||||
return this._recipe
|
||||
}
|
||||
|
||||
protected abstract fetchMaterials(recipeId: number): Observable<Material[]>
|
||||
|
||||
abstract submit(dto: MixSaveDto)
|
||||
}
|
||||
|
||||
|
@ -65,6 +67,10 @@ abstract class _BaseMixPage extends SubscribingComponent {
|
|||
templateUrl: 'add.html'
|
||||
})
|
||||
export class MixAdd extends _BaseMixPage {
|
||||
protected fetchMaterials(recipeId: number): Observable<Material[]> {
|
||||
return this.materialService.getAllForMixCreation(recipeId)
|
||||
}
|
||||
|
||||
submit(dto: MixSaveDto) {
|
||||
this.subscribeAndNavigate(
|
||||
this.mixService.saveDto(dto),
|
||||
|
@ -80,21 +86,27 @@ export class MixAdd extends _BaseMixPage {
|
|||
export class MixEdit extends _BaseMixPage {
|
||||
mix: Mix
|
||||
|
||||
private mixId: number
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit()
|
||||
|
||||
this.mixId = this.urlUtils.parseIntUrlParam('id')
|
||||
|
||||
this.fetchMix()
|
||||
}
|
||||
|
||||
private fetchMix() {
|
||||
const mixId = this.urlUtils.parseIntUrlParam('id')
|
||||
|
||||
this.subscribe(
|
||||
this.mixService.getById(mixId),
|
||||
this.mixService.getById(this.mixId),
|
||||
mix => this.mix = mix
|
||||
)
|
||||
}
|
||||
|
||||
protected fetchMaterials(recipeId: number): Observable<Material[]> {
|
||||
return this.materialService.getAllForMixUpdate(this.mixId)
|
||||
}
|
||||
|
||||
submit(dto: MixSaveDto) {
|
||||
this.subscribeAndNavigate(
|
||||
this.mixService.updateDto({...dto, id: this.mix.id}),
|
||||
|
|
|
@ -46,7 +46,7 @@ export class RecipeForm extends SubscribingComponent {
|
|||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
super.ngOnInit()
|
||||
|
||||
this.fetchCompanies()
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import {Title} from '@angular/platform-browser'
|
|||
})
|
||||
export class AppState {
|
||||
private readonly KEY_AUTHENTICATED = 'authenticated'
|
||||
private readonly KEY_AUTHENTICATION_EXPIRATION = 'authentication-expiration'
|
||||
private readonly KEY_DEFAULT_GROUP_USER_AUTHENTICATED = 'default-group-user-authenticated'
|
||||
private readonly KEY_LOGGED_IN_USER = 'logged-in-user'
|
||||
|
||||
authenticatedUser$ = new Subject<{ authenticated: boolean, authenticatedUser: User }>()
|
||||
|
@ -19,9 +19,19 @@ export class AppState {
|
|||
) {
|
||||
}
|
||||
|
||||
authenticateUser(user: User) {
|
||||
this.authenticatedUser = user
|
||||
this.isAuthenticated = true
|
||||
}
|
||||
|
||||
authenticateGroupUser(user: User) {
|
||||
this.authenticatedUser = user
|
||||
this.isDefaultGroupUserAuthenticated = true
|
||||
}
|
||||
|
||||
resetAuthenticatedUser() {
|
||||
this.isAuthenticated = false
|
||||
this.authenticationExpiration = -1
|
||||
this.isDefaultGroupUserAuthenticated = false
|
||||
this.authenticatedUser = null
|
||||
}
|
||||
|
||||
|
@ -36,7 +46,7 @@ export class AppState {
|
|||
return sessionStorage.getItem(this.KEY_AUTHENTICATED) === 'true'
|
||||
}
|
||||
|
||||
set isAuthenticated(value: boolean) {
|
||||
private set isAuthenticated(value: boolean) {
|
||||
sessionStorage.setItem(this.KEY_AUTHENTICATED, value.toString())
|
||||
this.authenticatedUser$.next({
|
||||
authenticated: value,
|
||||
|
@ -44,12 +54,16 @@ export class AppState {
|
|||
})
|
||||
}
|
||||
|
||||
get authenticationExpiration(): number {
|
||||
return parseInt(sessionStorage.getItem(this.KEY_AUTHENTICATION_EXPIRATION))
|
||||
get isDefaultGroupUserAuthenticated(): boolean {
|
||||
return sessionStorage.getItem(this.KEY_DEFAULT_GROUP_USER_AUTHENTICATED) === 'true'
|
||||
}
|
||||
|
||||
set authenticationExpiration(value: number) {
|
||||
sessionStorage.setItem(this.KEY_AUTHENTICATION_EXPIRATION, value.toString())
|
||||
private set isDefaultGroupUserAuthenticated(value: boolean) {
|
||||
sessionStorage.setItem(this.KEY_DEFAULT_GROUP_USER_AUTHENTICATED, value.toString())
|
||||
}
|
||||
|
||||
get hasCredentials(): boolean {
|
||||
return this.isAuthenticated || this.isDefaultGroupUserAuthenticated
|
||||
}
|
||||
|
||||
get authenticatedUser(): User {
|
||||
|
@ -57,9 +71,9 @@ export class AppState {
|
|||
return userString ? JSON.parse(userString) : null
|
||||
}
|
||||
|
||||
set authenticatedUser(value: User) {
|
||||
private set authenticatedUser(value: User) {
|
||||
if (value === null) {
|
||||
sessionStorage.removeItem(this.KEY_LOGGED_IN_USER)
|
||||
// sessionStorage.removeItem(this.KEY_LOGGED_IN_USER)
|
||||
} else {
|
||||
sessionStorage.setItem(this.KEY_LOGGED_IN_USER, JSON.stringify(value))
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {Component, ContentChild, EventEmitter, Input, Output} from '@angular/core'
|
||||
import {ICreForm} from './forms';
|
||||
|
||||
@Component({
|
||||
selector: 'cre-submit-button',
|
||||
selector: 'cre-form-submit-button',
|
||||
templateUrl: 'submit-button.html'
|
||||
})
|
||||
export class CreSubmitButton {
|
||||
@Input() form: ICreForm
|
||||
@Input() valid: boolean | null
|
||||
@Input() text = 'Enregistrer'
|
||||
|
||||
@Output() submit = new EventEmitter<void>()
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content [class.no-action]="!hasActions">
|
||||
<form [formGroup]="form">
|
||||
<form [formGroup]="formGroup">
|
||||
<ng-content select="cre-form-content"></ng-content>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Component, ContentChild, Directive, Input, OnInit, ViewEncapsulation} fr
|
|||
import {FormBuilder, FormGroup} from '@angular/forms'
|
||||
|
||||
export interface ICreForm {
|
||||
form: FormGroup
|
||||
formGroup: FormGroup
|
||||
valid: boolean
|
||||
invalid: boolean
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ export class CreForm implements ICreForm, OnInit {
|
|||
@ContentChild(CreFormActions) formActions: CreFormActions
|
||||
@Input() formControls: { [key: string]: any }
|
||||
|
||||
form: FormGroup
|
||||
formGroup: FormGroup
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder
|
||||
|
@ -43,7 +43,7 @@ export class CreForm implements ICreForm, OnInit {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.form = this.formBuilder.group(this.formControls)
|
||||
this.formGroup = this.formBuilder.group(this.formControls)
|
||||
}
|
||||
|
||||
get hasActions(): boolean {
|
||||
|
@ -51,10 +51,10 @@ export class CreForm implements ICreForm, OnInit {
|
|||
}
|
||||
|
||||
get valid(): boolean {
|
||||
return this.form && this.form.valid
|
||||
return this.formGroup && this.formGroup.valid
|
||||
}
|
||||
|
||||
get invalid(): boolean {
|
||||
return !this.form || this.form.invalid
|
||||
return !this.formGroup || this.formGroup.invalid
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
<cre-accent-button [disabled]="disableButton" (click)="submit.emit()">Enregistrer</cre-accent-button>
|
||||
<cre-accent-button [disabled]="disableButton" (click)="submit.emit()">{{text}}</cre-accent-button>
|
||||
|
|
|
@ -58,9 +58,10 @@ export class HeaderComponent extends SubscribingComponent {
|
|||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.accountService.logout(() => {
|
||||
console.log('Successfully logged out')
|
||||
})
|
||||
this.subscribe(
|
||||
this.accountService.logout(),
|
||||
() => console.info('Successfully logged out')
|
||||
)
|
||||
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
|
@ -71,7 +72,7 @@ export class HeaderComponent extends SubscribingComponent {
|
|||
|
||||
set activeLink(link: string) {
|
||||
this._activeLink = link
|
||||
this.router.navigate([link])
|
||||
this.urlUtils.navigateTo(link)
|
||||
}
|
||||
|
||||
get activeLink() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
AfterViewInit, ChangeDetectorRef,
|
||||
AfterViewInit,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild,
|
||||
Directive,
|
||||
|
@ -16,7 +17,7 @@ import {
|
|||
import {AbstractControl, FormControl, ValidationErrors, ValidatorFn, Validators} from '@angular/forms'
|
||||
import {COMMA, ENTER} from '@angular/cdk/keycodes'
|
||||
import {isObservable, Observable, Subject} from 'rxjs'
|
||||
import {map, startWith, takeUntil} from 'rxjs/operators'
|
||||
import {map, takeUntil} from 'rxjs/operators'
|
||||
import {MatChipInputEvent} from '@angular/material/chips'
|
||||
import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@ import {Observable, Subject} from 'rxjs'
|
|||
import {environment} from '../../../../environments/environment'
|
||||
import {AppState} from '../app-state'
|
||||
import {Router} from '@angular/router'
|
||||
import {map, share, takeUntil, tap} from 'rxjs/operators'
|
||||
import {map, share, takeUntil} from 'rxjs/operators'
|
||||
import {valueOr} from '../utils/utils'
|
||||
import {ErrorService} from './error.service'
|
||||
import {globalLoadingWheel} from '../components/loading-wheel/loading-wheel.component'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -71,14 +70,13 @@ export class ApiService implements OnDestroy {
|
|||
observe: 'response'
|
||||
}
|
||||
if (needAuthentication) {
|
||||
if (this.checkAuthenticated()) {
|
||||
if (this.appState.hasCredentials) {
|
||||
if (httpOptions) {
|
||||
httpOptions.withCredentials = true
|
||||
} else {
|
||||
console.error('httpOptions need to be specified to use credentials in HTTP methods.')
|
||||
}
|
||||
} else {
|
||||
this.appState.resetAuthenticatedUser()
|
||||
this.navigateToLogin()
|
||||
}
|
||||
}
|
||||
|
@ -90,11 +88,6 @@ export class ApiService implements OnDestroy {
|
|||
.pipe(takeUntil(this._destroy$), map(r => r.body), share())
|
||||
}
|
||||
|
||||
private checkAuthenticated(): boolean {
|
||||
return (this.appState.isAuthenticated && Date.now() <= this.appState.authenticationExpiration) ||
|
||||
(this.appState.authenticatedUser && this.appState.authenticatedUser.group != null)
|
||||
}
|
||||
|
||||
private navigateToLogin() {
|
||||
this.router.navigate(['/account/login'])
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<cre-action-bar>
|
||||
<cre-action-group></cre-action-group>
|
||||
<cre-action-group>
|
||||
<cre-accent-button routerLink="/misc/touch-up-kit/add">Ajouter</cre-accent-button>
|
||||
<cre-accent-button *ngIf="canEditTouchUpKits" routerLink="/misc/touch-up-kit/add">Ajouter</cre-accent-button>
|
||||
</cre-action-group>
|
||||
</cre-action-bar>
|
||||
|
||||
|
|
Loading…
Reference in New Issue