import { VerificationRulesService } from './../../../../shared/services/administration/verification-rules.service'; import { VerificationRule } from './../../../../shared/models/verification-rule.interface'; import { Component, Input, OnInit } from '@angular/core'; import { AbstractControl, FormBuilder } from '@angular/forms'; import { Category } from 'src/app/shared/models/category.interface'; import { DocumentClassification } from 'src/app/shared/models/document-classification.interface'; import { DocumentSubclassification } from 'src/app/shared/models/document-subclassification.interface'; import { IPowerClient } from 'src/app/shared/models/ipower-client.interface'; import { CategoriesService } from 'src/app/shared/services/administration/categories.service'; import { DocumentClassificationsService } from 'src/app/shared/services/administration/document-classifications.service'; import { DocumentSubclassificationsService } from 'src/app/shared/services/administration/document-subclassifications.service'; import { IpowerClientsService } from 'src/app/shared/services/administration/ipower-clients.service'; import { VerificationRuleSearchFormValue } from './verification-rule-search-form-value.interface'; import { ErrorHandlingService } from 'src/app/shared/services/error-handling/error-handling.service'; import { USER_RIGHTS } from 'src/app/shared/enums/USER_RIGHTS.enum'; import { AuthService } from 'src/app/shared/services/auth.service'; import { Observable } from 'rxjs'; import { environment } from 'src/environments/environment'; @Component({ selector: 'app-verification-rule-search-form', templateUrl: './verification-rule-search-form.component.html', styleUrls: ['./verification-rule-search-form.component.scss'] }) export class VerificationRuleSearchFormComponent implements OnInit { @Input() disabled: boolean = false; documentClassificationsList: DocumentClassification[]; documentSubclassificationsList: DocumentSubclassification[]; availableDocumentSubclassifications: DocumentSubclassification[]; previouslySelectedClassificationId: number; categoryNameSuggestions: string[]; categoryCodeSuggestions: string[]; categorySuggestions: Category[]; selectedCategory: Category = null; ipowerClientNameSuggestions: string[]; ipowerClientCodeSuggestions: string[]; ipowerClientSuggestions: IPowerClient[]; selectedIPowerClient: IPowerClient = null; displayValidationMessagesEvenIfPristine: boolean; verificationRuleForm = this.fb.group({ ipowerName: [null], ipowerCode: [null], categoryName: [null], categoryCode: [null], documentClassification: [null], subCategoryCode: [null] // This actually represents the complete DocumentSubclassification object. }); constructor( private fb: FormBuilder, private documentClassificationsService: DocumentClassificationsService, private documentSubclassificationsService: DocumentSubclassificationsService, private verificationRulesService: VerificationRulesService, private categoriesService: CategoriesService, private ipowerClientsService: IpowerClientsService, private errorHandlingService: ErrorHandlingService, private authService: AuthService ) { } ngOnInit(): void { if (this.disabled) { Object.keys(this.verificationRuleForm.controls).forEach(ctrl => this.verificationRuleForm.get(ctrl).disable()); return; // Don't even bother initialising or requesting anything. } this.initData(); } initData() { this.documentClassificationsService.getAll().subscribe( value => this.documentClassificationsList = value, err => this.errorHandlingService.showHttpResponseError(err) ); // This is NOT the list of Subclassifications used for the dropdown. this.documentSubclassificationsService.getAll().subscribe( value => { this.documentSubclassificationsList = value; this.availableDocumentSubclassifications = value; }, err => this.errorHandlingService.showHttpResponseError(err) ); } clear() { this.verificationRuleForm.reset(); this.selectedCategory = null; this.selectedIPowerClient = null; } documentClassificationSelected(selection: DocumentClassification) { // If a different Classification has been selected, reset the Subclassification's value. if (this.previouslySelectedClassificationId && selection.classificationId != this.previouslySelectedClassificationId) { this.verificationRuleForm.get('subCategoryCode').reset(); } this.previouslySelectedClassificationId = this.verificationRuleForm.get('documentClassification').value.classificationId; this.availableDocumentSubclassifications = this.documentSubclassificationsList.filter(element => element.documentClassification.classificationId == selection.classificationId); } documentSubclassificationSelected(selection: DocumentSubclassification) { this.verificationRuleForm.get('documentClassification').setValue(selection.documentClassification); } /* * Auto-suggest/complete Categories */ autosuggestCategoryName(event) { if (!event.query || event.query.length < 3) { this.categoryNameSuggestions = []; return; } let classId = this.verificationRuleForm.get('documentClassification').value ? this.verificationRuleForm.get('documentClassification').value.classificationId : null; this.categoriesService.autosuggestCategoryName(event.query, classId).subscribe( (values: Category[]) => { let temp: string[] = []; this.categorySuggestions = values; values.map(val => temp.push(val.categoryName)); this.categoryNameSuggestions = temp }, err => this.errorHandlingService.showHttpResponseError(err) ); } autosuggestCategoryCode(event) { if (event.query.length < 3) { this.categoryCodeSuggestions = []; return; } let classId = this.verificationRuleForm.get('documentClassification').value ? this.verificationRuleForm.get('documentClassification').value.classificationId : null; this.categoriesService.autosuggestCategoryCode(event.query, classId).subscribe( (values: Category[]) => { let temp: string[] = []; this.categorySuggestions = values; values.map(val => temp.push(val.categoryCode)); this.categoryCodeSuggestions = temp }, err => this.errorHandlingService.showHttpResponseError(err) ); } categoryNameSelected(name: string) { this.selectedCategory = this.categorySuggestions.find(cat => cat.categoryName == name); this.verificationRuleForm.get('categoryCode').patchValue(this.selectedCategory.categoryCode); this.verificationRuleForm.updateValueAndValidity(); } categoryCodeSelected(code: string) { this.selectedCategory = this.categorySuggestions.find(cat => cat.categoryCode == code); this.verificationRuleForm.get('categoryName').patchValue(this.selectedCategory.categoryName); this.verificationRuleForm.updateValueAndValidity(); } // /* // * Auto-suggest/complete iPower Clients // */ // autosuggestIPowerClientName(event) { // if (!event.query || event.query.length < 3) { // this.ipowerClientNameSuggestions = []; // return; // } // this.ipowerClientsService.getClientsByNameDistinct(event.query).subscribe( // (values: IPowerClient[]) => { // let temp: string[] = []; // this.ipowerClientSuggestions = values; // values.map(val => temp.push(val.name)); // this.ipowerClientNameSuggestions = temp // }, // err => this.errorHandlingService.showHttpResponseError(err) // ); // } // autosuggestIPowerClientCode(event) { // if (!event.query || event.query.length < 3) { // this.ipowerClientCodeSuggestions = []; // return; // } // this.ipowerClientsService.getClientsByCodeDistinct(event.query).subscribe( // (values: IPowerClient[]) => { // let temp: string[] = []; // this.ipowerClientSuggestions = values; // values.map(val => temp.push(val.clientCode)); // this.ipowerClientCodeSuggestions = temp // }, // err => this.errorHandlingService.showHttpResponseError(err) // ); // } autosuggestIPowerClientCode(event) { if (event.query.length < 3) { this.ipowerClientCodeSuggestions = []; return; } // If the user has the right to Preview of Scheduling Procedure (A02), we use the endpoint that returns all iPowerClients, // otherwise, the one that checks for the user's User_Access too. Whether the user can see ANY rule has already been handled by the 'search' button. let endpointToSubscribeTo: Observable = this.authService.userHasRightForClient(USER_RIGHTS.B01, environment.globalRightsClientID) ? this.ipowerClientsService.getClientsByCodeOnly(event.query) : this.authService.userRights.find(rdc => USER_RIGHTS.B02.isGrantedToUser(rdc.rights)) != null ? this.ipowerClientsService.getClientsByCodeDistinct(event.query) : null; endpointToSubscribeTo.subscribe( (values: IPowerClient[]) => { let temp: string[] = []; this.ipowerClientSuggestions = values; values.map(val => temp.push(val.clientCode)); this.ipowerClientCodeSuggestions = temp }, err => this.errorHandlingService.showHttpResponseError(err) ); } /* * Auto-suggest & Auto-complete IPower Client */ autosuggestIPowerClientName(event): void { if (!event.query || event.query.length < 3) { this.ipowerClientNameSuggestions = []; return; } // If the user has the right to Preview of Scheduling Procedure (A02), we use the endpoint that returns all iPowerClients, // otherwise, the one that checks for the user's User_Access too. Whether the user can see ANY rule has already been handled by the 'search' button. let endpointToSubscribeTo: Observable = this.authService.userHasRightForClient(USER_RIGHTS.B01, environment.globalRightsClientID) ? this.ipowerClientsService.getClientsByNameOnly(event.query) : this.authService.userRights.find(rdc => USER_RIGHTS.B02.isGrantedToUser(rdc.rights)) != null ? this.ipowerClientsService.getClientsByNameDistinct(event.query) : null; endpointToSubscribeTo.subscribe( (values: IPowerClient[]) => { this.ipowerClientSuggestions = values; const temp: string[] = []; values.map(val => temp.push(val.name)); this.ipowerClientNameSuggestions = temp; }, err => this.errorHandlingService.showHttpResponseError(err) ); } ipowerClientNameSelected(name: string) { this.selectedIPowerClient = this.ipowerClientSuggestions.find(client => client.name == name); this.verificationRuleForm.get('ipowerCode').patchValue(this.selectedIPowerClient.clientCode); this.verificationRuleForm.updateValueAndValidity(); } ipowerClientCodeSelected(code: string) { this.selectedIPowerClient = this.ipowerClientSuggestions.find(client => client.clientCode == code); this.verificationRuleForm.get('ipowerName').patchValue(this.selectedIPowerClient.name); this.verificationRuleForm.updateValueAndValidity(); } /* * Utility Methods */ // Auto-suggest inputs - We have to ensure our reactive form holds values that represent the selectedCategory, otherwise truncate it. syncSelectedCategory() { // Ιf our form has no value, truncate the selectedCategory either way. if (!this.verificationRuleForm.get('categoryName').value && !this.verificationRuleForm.get('categoryCode').value) { this.selectedCategory = null; return; } // If both or either of our form's values match the selectedCategory's and the other one doesn't have a value, all is good. // Just sync the values in case one is missing. Otherwise truncate the selectedCategory. if ( this.verificationRuleForm.get('categoryName').value == this.selectedCategory.categoryName || this.verificationRuleForm.get('categoryCode').value == this.selectedCategory.categoryCode ) { this.selectedCategory.categoryName = this.verificationRuleForm.get('categoryName').value; this.selectedCategory.categoryCode = this.verificationRuleForm.get('categoryCode').value; } // If both our values were different from the selectedCategory's, truncate it. This is an extremely abnormal scenario. else { console.error('WARNING - syncSelectedCategory()', 'Both of our form\'s values were different from the selectedCategory\'s.'); this.selectedCategory = null; this.verificationRuleForm.get('categoryName').setValue(''); this.verificationRuleForm.get('categoryCode').setValue(''); this.verificationRuleForm.updateValueAndValidity(); } } // Auto-suggest inputs - We have to ensure our reactive form holds values that represent the selectedIPowerClient, otherwise truncate it. syncSelectedIPowerClient() { // Ιf our form has no value, truncate the selectedIPowerClient either way. if (!this.verificationRuleForm.get('ipowerName').value && !this.verificationRuleForm.get('ipowerCode').value) { this.selectedIPowerClient = null; return; } // If both or either of our form's values match the selectedIPowerClient's and the other one doesn't have a value, all is good. // Just sync the values in case one is missing. Otherwise truncate the selectedIPowerClient. if ( this.verificationRuleForm.get('ipowerName').value == this.selectedIPowerClient.name || this.verificationRuleForm.get('ipowerCode').value == this.selectedIPowerClient.clientCode ) { this.selectedIPowerClient.name = this.verificationRuleForm.get('ipowerName').value; this.selectedIPowerClient.clientCode = this.verificationRuleForm.get('ipowerCode').value; } // If both our values were different from the selectedIPowerClient's, truncate it. This is an extremely abnormal scenario. else { console.error('WARNING - syncSelectedIPowerClient()', 'Both of our form\'s values were different from the selectedIPowerClient\'s.'); this.selectedIPowerClient = null; this.verificationRuleForm.get('ipowerName').setValue(''); this.verificationRuleForm.get('ipowerCode').setValue(''); this.verificationRuleForm.updateValueAndValidity(); } } /* * API methods */ public resetForm(): void { this.verificationRuleForm.reset(); } // TODO: Set type public formValue(): VerificationRuleSearchFormValue { this.syncSelectedCategory(); this.syncSelectedIPowerClient(); let formValue: VerificationRuleSearchFormValue = { clientId: this.selectedIPowerClient ? this.selectedIPowerClient.id : '', categoryId: this.selectedCategory ? this.selectedCategory.id : null, docClassificationId: this.verificationRuleForm.get('documentClassification').value ? this.verificationRuleForm.get('documentClassification').value.classificationId : '', // The backend only requires the subcategory's name, and not the whole object. Don't ask me. docSubcategory: this.verificationRuleForm.get('subCategoryCode').value ? this.verificationRuleForm.get('subCategoryCode').value['subclassificationName'] : '' } return formValue; } public isValid(): boolean { return this.verificationRuleForm.valid; } }