2023-10-20 17:01:09 +02:00
import { DatePipe } from '@angular/common' ;
import { HttpErrorResponse } from '@angular/common/http' ;
import { Component , OnInit } from '@angular/core' ;
import { UntypedFormGroup } from '@angular/forms' ;
import { MatDialog } from '@angular/material/dialog' ;
import { ActivatedRoute , ParamMap , Router } from '@angular/router' ;
import { BaseEntity } from '@common/base/base-entity.model' ;
import { BasePendingChangesComponent } from '@common/base/base-pending-changes.component' ;
import { FormService } from '@common/forms/form-service' ;
import { HttpError , HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service' ;
import { FilterService } from '@common/modules/text-filter/filter-service' ;
import { TranslateService } from '@ngx-translate/core' ;
2024-03-21 08:46:18 +01:00
import { interval , Observable } from 'rxjs' ;
2023-10-20 17:01:09 +02:00
import { takeUntil } from 'rxjs/operators' ;
import { nameof } from 'ts-simple-nameof' ;
import { Guid } from '../types/guid' ;
import { BaseEditorModel } from './base-form-editor-model' ;
import { SnackBarNotificationLevel , UiNotificationService } from '@app/core/services/notification/ui-notification-service' ;
import { QueryParamsService } from '@app/core/services/utilities/query-params.service' ;
2024-03-21 08:46:18 +01:00
import { LockService } from '@app/core/services/lock/lock.service' ;
import { LockPersist } from '@app/core/model/lock/lock.model' ;
import { LockTargetType } from '@app/core/common/enum/lock-target-type' ;
import { isNullOrUndefined } from '@swimlane/ngx-datatable' ;
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component' ;
import { AuthService } from '@app/core/services/auth/auth.service' ;
import { ConfigurationService } from '@app/core/services/configuration/configuration.service' ;
2023-10-20 17:01:09 +02:00
@Component ( {
selector : 'app-base-editor-component' ,
template : ''
} )
export abstract class BaseEditor < EditorModelType extends BaseEditorModel , EntityType > extends BasePendingChangesComponent implements OnInit {
isNew = true ;
isDeleted = false ;
2024-03-21 08:46:18 +01:00
isLocked : Boolean = false ;
2023-10-20 17:01:09 +02:00
formGroup : UntypedFormGroup = null ;
lookupParams : any ;
// Getter Setter for editorModel. We use it to notify when the editor model is changed.
get editorModel ( ) : EditorModelType { return this . _editorModel ; }
set editorModel ( value : EditorModelType ) { this . _editorModel = value ; }
private _editorModel : EditorModelType ;
protected lv = 0 ;
abstract getItem ( itemId : Guid , successFunction : ( item : EntityType ) = > void ) : void ;
abstract prepareForm ( data : EntityType ) : void ;
abstract formSubmit ( ) : void ;
abstract delete ( ) : void ;
abstract refreshData ( ) : void ;
abstract refreshOnNavigateToData ( id? : Guid ) : void ;
abstract persistEntity ( onSuccess ? : ( response ) = > void ) : void ;
abstract buildForm ( ) : void ;
constructor (
protected dialog : MatDialog ,
protected language : TranslateService ,
protected formService : FormService ,
protected router : Router ,
protected uiNotificationService : UiNotificationService ,
protected httpErrorHandlingService : HttpErrorHandlingService ,
protected filterService : FilterService ,
protected datePipe : DatePipe ,
protected route : ActivatedRoute ,
2024-03-21 08:46:18 +01:00
protected queryParamsService : QueryParamsService ,
protected lockService : LockService ,
protected authService : AuthService ,
protected configurationService : ConfigurationService ,
2023-10-20 17:01:09 +02:00
) { super ( ) ; }
public ngOnInit ( ) : void {
const entity = this . route . snapshot . data [ 'entity' ] as EntityType ;
if ( entity ) {
this . isNew = false ;
this . prepareForm ( entity ) ;
} else {
this . prepareForm ( null ) ;
}
this . route . queryParamMap . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( params : ParamMap ) = > {
// If lookup is on the query params load it
if ( params . keys . length > 0 && params . has ( 'lookup' ) ) {
this . lookupParams = this . queryParamsService . deSerializeLookup ( params . get ( 'lookup' ) ) ;
}
} ) ;
}
public isFormValid() {
return this . formGroup . valid ;
}
public isFormDisabled() {
return this . formGroup . disabled ;
}
public save() {
this . clearErrorModel ( ) ;
}
public cancel ( ) : void {
this . router . navigate ( [ '..' ] , { relativeTo : this.route , queryParams : { 'lookup' : this . queryParamsService . serializeLookup ( this . lookupParams ) , 'lv' : ++ this . lv } , replaceUrl : true } ) ; // ! lv is always zero . replaceUrl?
}
onCallbackSuccess ( data? : any ) : void {
console . log ( "Success:" , data ) ;
this . uiNotificationService . snackBarNotification ( this . isNew ? this . language . instant ( 'COMMONS.SNACK-BAR.SUCCESSFUL-CREATION' ) : this . language . instant ( 'COMMONS.SNACK-BAR.SUCCESSFUL-UPDATE' ) , SnackBarNotificationLevel . Success ) ;
this . refreshOnNavigateToData ( data ? data.id : null ) ;
}
onCallbackError ( errorResponse : HttpErrorResponse ) {
console . log ( "Error:" , errorResponse ) ;
const error : HttpError = this . httpErrorHandlingService . getError ( errorResponse ) ;
if ( error . statusCode === 400 ) {
this . editorModel . validationErrorModel . fromJSONObject ( errorResponse . error ) ;
2024-01-31 16:07:16 +01:00
if ( errorResponse . error . code === 120 ) {
this . uiNotificationService . snackBarNotification ( errorResponse . error . error , SnackBarNotificationLevel . Error ) ;
}
2023-10-20 17:01:09 +02:00
this . formService . validateAllFormFields ( this . formGroup ) ;
} else {
this . uiNotificationService . snackBarNotification ( error . getMessagesString ( ) , SnackBarNotificationLevel . Warning ) ;
}
}
clearErrorModel() {
this . editorModel . validationErrorModel . clear ( ) ;
this . formService . validateAllFormFields ( this . formGroup ) ;
}
// private refreshOnNavigateToData(id?: Guid): void {
// if (this.isNew) {
// this.formGroup.markAsPristine();
// this.router.navigate([this.formUtilsService.getFormRoute(this.editorModel.type) + '/' + (id ? id : this.editorModel.id)]);
// } else { this.internalRefreshData(); }
// }
internalRefreshData ( ) : void {
// setTimeout(() => {
// this.formGroup = null;
// this.editorModel = null;
// });
this . refreshData ( ) ;
}
canDeactivate ( ) : boolean | Observable < boolean > {
return this . formGroup ? ! this . formGroup.dirty : true ;
}
public static commonFormFieldNames ( ) : string [ ] {
return [
nameof < BaseEntity > ( x = > x . id ) ,
nameof < BaseEntity > ( x = > x . isActive ) ,
nameof < BaseEntity > ( x = > x . createdAt ) ,
nameof < BaseEntity > ( x = > x . updatedAt ) ,
nameof < BaseEntity > ( x = > x . hash ) ,
] ;
}
2024-03-21 08:46:18 +01:00
//
//
// Lock
//
//
protected checkLock ( itemId : Guid , targetType : LockTargetType ) {
if ( itemId != null ) {
this . isNew = false ;
// check if locked.
this . lockService . checkLockStatus ( itemId ) . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( lockStatus = > {
this . isLocked = lockStatus . status ;
if ( this . isLocked ) {
this . formGroup . disable ( ) ;
this . dialog . open ( PopupNotificationDialogComponent , {
data : {
title : this.language.instant ( 'DATASET-WIZARD.LOCKED.TITLE' ) ,
message : this.language.instant ( 'DATASET-WIZARD.LOCKED.MESSAGE' )
} , maxWidth : '30em'
} ) ;
}
if ( ! this . isLocked && ! isNullOrUndefined ( this . authService . currentAccountIsAuthenticated ( ) ) ) {
// lock it.
this . lockService . lock ( itemId , targetType ) . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( async result = > {
this . isLocked = true ;
interval ( this . configurationService . lockInterval ) . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( ) = > this . touchLock ( itemId ) ) ;
} ) ;
}
} ) ;
}
}
private unlockTarget ( targetId : Guid ) {
this . lockService . unlockTarget ( targetId ) . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( async result = > { } ) ;
}
private touchLock ( targetId : Guid ) {
this . lockService . touchLock ( targetId ) . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( async result = > { } ) ;
}
ngOnDestroy ( ) : void {
super . ngOnDestroy ( ) ;
if ( this . isLocked ) this . unlockTarget ( this . editorModel . id ) ;
}
2023-10-20 17:01:09 +02:00
}