import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; import * as moment from 'moment'; import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators'; import { Account } from '../../core/account'; import { AccountService } from '../../core/account.service'; import { Product } from '../../core/product'; import { ProductSku } from '../../core/product-sku'; import { ToasterService } from '../../core/toaster.service'; import { ProductService } from '../../product/product.service'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { MathService } from '../../shared/math.service'; import { RateContract } from '../rate-contract'; import { RateContractItem } from '../rate-contract-item'; import { RateContractService } from '../rate-contract.service'; import { RateContractDetailDatasource } from './rate-contract-detail-datasource'; @Component({ selector: 'app-rate-contract-detail', templateUrl: './rate-contract-detail.component.html', styleUrls: ['./rate-contract-detail.component.css'], }) export class RateContractDetailComponent implements OnInit, AfterViewInit { @ViewChild('accountElement', { static: true }) accountElement?: ElementRef; @ViewChild('productElement', { static: true }) productElement?: ElementRef; public itemsObservable = new BehaviorSubject([]); dataSource: RateContractDetailDatasource = new RateContractDetailDatasource(this.itemsObservable); form: FormGroup<{ date: FormControl; account: FormControl; validFrom: FormControl; validTill: FormControl; addRow: FormGroup<{ product: FormControl; price: FormControl; }>; narration: FormControl; }>; item: RateContract = new RateContract(); product: Product | null = null; displayedColumns = ['product', 'price', 'action']; accounts: Observable; products: Observable; constructor( private route: ActivatedRoute, private router: Router, private toaster: ToasterService, private dialog: MatDialog, private math: MathService, private ser: RateContractService, private productSer: ProductService, private accountSer: AccountService, ) { this.form = new FormGroup({ date: new FormControl(new Date(), { nonNullable: true }), account: new FormControl(null), validFrom: new FormControl(new Date(), { nonNullable: true }), validTill: new FormControl(new Date(), { nonNullable: true }), addRow: new FormGroup({ product: new FormControl(''), price: new FormControl('', { nonNullable: true }), }), narration: new FormControl('', { nonNullable: true }), }); this.accounts = this.form.controls.account.valueChanges.pipe( map((x) => ((x as Account).name !== undefined ? (x as Account).name : (x as string))), map((x) => (x !== null && x.length >= 1 ? x : null)), debounceTime(150), distinctUntilChanged(), switchMap((x) => (x === null ? observableOf([]) : this.accountSer.autocomplete(x))), ); // Listen to Product Autocomplete Change this.products = this.form.controls.addRow.controls.product.valueChanges.pipe( map((x) => (x !== null && x.length >= 1 ? x : null)), debounceTime(150), distinctUntilChanged(), switchMap((x) => (x === null ? observableOf([]) : this.productSer.autocompleteSku(x, true))), ); } ngOnInit() { this.route.data.subscribe((value) => { const data = value as { item: RateContract }; this.loadItem(data.item); }); } loadItem(item: RateContract) { this.item = item; this.form.setValue({ date: moment(this.item.date, 'DD-MMM-YYYY').toDate(), validFrom: moment(this.item.validFrom, 'DD-MMM-YYYY').toDate(), validTill: moment(this.item.validTill, 'DD-MMM-YYYY').toDate(), account: this.item.vendor, addRow: { product: '', price: '', }, narration: this.item.narration, }); this.dataSource = new RateContractDetailDatasource(this.itemsObservable); this.updateView(); } ngAfterViewInit() { setTimeout(() => { if (this.accountElement) { this.accountElement.nativeElement.focus(); } }, 0); } addRow() { const formValue = this.form.value.addRow!; const price = this.math.parseAmount(formValue.price, 2); if (this.product === null || price <= 0) { return; } const oldFiltered = this.item.items.filter((x) => x.sku.id === (this.product as Product).id); if (oldFiltered.length) { this.toaster.show('Danger', 'Product already added'); return; } this.item.items.push( new RateContractItem({ price, sku: this.product, }), ); this.resetAddRow(); this.updateView(); } resetAddRow() { this.form.controls.addRow.reset(); this.product = null; setTimeout(() => { if (this.productElement) { this.productElement.nativeElement.focus(); } }, 0); } displayFn(item?: Account | Product): string { return item ? item.name : ''; } updateView() { this.itemsObservable.next(this.item.items); } accountSelected(event: MatAutocompleteSelectedEvent): void { this.form.controls.account.setValue(event.option.value); } productSelected(event: MatAutocompleteSelectedEvent): void { this.product = event.option.value; } deleteRow(row: RateContractItem) { this.item.items.splice(this.item.items.indexOf(row), 1); this.updateView(); } save() { this.ser.saveOrUpdate(this.getItem()).subscribe( () => { this.toaster.show('Success', ''); this.router.navigateByUrl('/rate-contracts'); }, (error) => { this.toaster.show('Danger', error); }, ); } delete() { this.ser.delete(this.item.id as string).subscribe( () => { this.toaster.show('Success', ''); this.router.navigateByUrl('/rate-contracts'); }, (error) => { this.toaster.show('Danger', error); }, ); } confirmDelete(): void { const dialogRef = this.dialog.open(ConfirmDialogComponent, { width: '250px', data: { title: 'Delete RateContract?', content: 'Are you sure? This cannot be undone.' }, }); dialogRef.afterClosed().subscribe((result: boolean) => { if (result) { this.delete(); } }); } getItem(): RateContract { const formModel = this.form.value; this.item.date = moment(formModel.date).format('DD-MMM-YYYY'); this.item.validFrom = moment(formModel.validFrom).format('DD-MMM-YYYY'); this.item.validTill = moment(formModel.validTill).format('DD-MMM-YYYY'); if (formModel.account !== null && typeof formModel.account !== 'string') { this.item.vendor = formModel.account!; } this.item.narration = formModel.narration!; return this.item; } }