) {
const prevIndex = this.list.indexOf(event.item.data);
moveItemInArray(this.list, prevIndex, event.currentIndex);
- this.table.renderRows();
+ this.data.next(this.list);
}
}
diff --git a/bookie/src/app/product/product-detail/product-detail.component.html b/bookie/src/app/product/product-detail/product-detail.component.html
index 71d1c84..824c5a2 100644
--- a/bookie/src/app/product/product-detail/product-detail.component.html
+++ b/bookie/src/app/product/product-detail/product-detail.component.html
@@ -26,34 +26,18 @@
- Fraction
-
+ Price
+
-
- Fraction Units
-
-
-
- Yield
-
-
-
-
- {{item.isPurchased ? 'Purchase Price' : 'Cost Price' }}
-
-
-
- Sale Price
-
+ Quantity
+
- Is Purchased?
- Is Sold?
+ Has Happy Hour?
+ Is Not Available?
Is Active?
+
+ Tax
+
+
+ {{ t.name }}
+
+
+
diff --git a/bookie/src/app/product/product-detail/product-detail.component.ts b/bookie/src/app/product/product-detail/product-detail.component.ts
index ae0cc1e..21f3689 100644
--- a/bookie/src/app/product/product-detail/product-detail.component.ts
+++ b/bookie/src/app/product/product-detail/product-detail.component.ts
@@ -1,12 +1,13 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
-import {ToasterService} from '../../core/toaster.service';
-import {ActivatedRoute, Router} from '@angular/router';
-import {ProductService} from '../product.service';
-import {Product} from '../../core/product';
-import {ProductGroup} from '../../core/product-group';
-import {ConfirmDialogComponent} from '../../shared/confirm-dialog/confirm-dialog.component';
+import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import { ToasterService } from '../../core/toaster.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { ProductService } from '../product.service';
+import { Product } from '../../core/product';
+import { ProductGroup } from '../../core/product-group';
+import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { MatDialog } from '@angular/material/dialog';
-import {FormBuilder, FormGroup} from '@angular/forms';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { Tax } from "../../core/tax";
@Component({
selector: 'app-product-detail',
@@ -17,6 +18,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
@ViewChild('nameElement', { static: true }) nameElement: ElementRef;
form: FormGroup;
productGroups: ProductGroup[];
+ taxes: Tax[];
item: Product;
constructor(
@@ -35,22 +37,21 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
code: {value: '', disabled: true},
name: '',
units: '',
- fraction: '',
- fractionUnits: '',
- productYield: '',
+ productGroup: '',
+ tax: '',
price: '',
- salePrice: '',
- isPurchased: '',
- isSold: '',
- isActive: '',
- productGroup: ''
+ hasHappyHour: '',
+ isNotAvailable: '',
+ quantity: '',
+ isActive: ''
});
}
ngOnInit() {
this.route.data
- .subscribe((data: { item: Product, productGroups: ProductGroup[] }) => {
+ .subscribe((data: { item: Product, productGroups: ProductGroup[], taxes: Tax[] }) => {
this.productGroups = data.productGroups;
+ this.taxes = data.taxes;
this.showItem(data.item);
});
}
@@ -64,7 +65,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
productGroup: this.item.tax.id ? this.item.tax.id : '',
tax: this.item.productGroup.id ? this.item.productGroup.id : '',
price: this.item.price || '',
- hadHappyHour: this.item.hasHappyHour,
+ hasHappyHour: this.item.hasHappyHour,
isNotAvailable: this.item.isNotAvailable,
quantity: this.item.quantity || '',
isActive: this.item.isActive,
diff --git a/bookie/src/app/product/product-list-resolver.service.spec.ts b/bookie/src/app/product/product-list-resolver.service.spec.ts
index 41f0290..e9e1da9 100644
--- a/bookie/src/app/product/product-list-resolver.service.spec.ts
+++ b/bookie/src/app/product/product-list-resolver.service.spec.ts
@@ -1,15 +1,15 @@
import {inject, TestBed} from '@angular/core/testing';
-import {ProductListResolverService} from './product-list-resolver.service';
+import {ProductListResolver} from './product-list-resolver.service';
-describe('ProductListResolverService', () => {
+describe('ProductListResolver', () => {
beforeEach(() => {
TestBed.configureTestingModule({
- providers: [ProductListResolverService]
+ providers: [ProductListResolver]
});
});
- it('should be created', inject([ProductListResolverService], (service: ProductListResolverService) => {
+ it('should be created', inject([ProductListResolver], (service: ProductListResolver) => {
expect(service).toBeTruthy();
}));
});
diff --git a/bookie/src/app/product/product-list/product-list-datasource.ts b/bookie/src/app/product/product-list/product-list-datasource.ts
index 4c479c2..74561d5 100644
--- a/bookie/src/app/product/product-list/product-list-datasource.ts
+++ b/bookie/src/app/product/product-list/product-list-datasource.ts
@@ -1,34 +1,37 @@
-import {DataSource} from '@angular/cdk/collections';
-import { MatPaginator } from '@angular/material/paginator';
-import {map, tap} from 'rxjs/operators';
-import {merge, Observable, of as observableOf} from 'rxjs';
-import {Product} from '../../core/product';
+import { DataSource } from '@angular/cdk/collections';
+import { map, tap } from 'rxjs/operators';
+import { merge, Observable } from 'rxjs';
+import { Product } from '../../core/product';
export class ProductListDataSource extends DataSource {
- private dataObservable: Observable;
+ public data: Product[];
+ public viewData: Product[];
private filterValue: string;
- constructor(private paginator: MatPaginator, private filter: Observable, public data: Product[]) {
+ constructor(private readonly filter: Observable, private readonly dataObs: Observable) {
super();
+ this.data = [];
+ this.viewData = [];
this.filter = filter.pipe(
tap(x => this.filterValue = x)
);
+ this.dataObs = dataObs.pipe(
+ tap(x => this.data = x)
+ );
}
connect(): Observable {
- this.dataObservable = observableOf(this.data);
const dataMutations = [
- this.dataObservable,
- this.filter,
- this.paginator.page
+ this.dataObs,
+ this.filter
];
return merge(...dataMutations).pipe(
map((x: any) => {
- return this.getPagedData(this.getFilteredData([...this.data]));
- }),
- tap((x: Product[]) => this.paginator.length = x.length)
+ this.viewData = this.getFilteredData([...this.data]);
+ return this.viewData;
+ })
);
}
@@ -36,20 +39,10 @@ export class ProductListDataSource extends DataSource {
}
private getFilteredData(data: Product[]): Product[] {
- const filter = (this.filterValue === undefined) ? '' : this.filterValue;
- return filter.split(' ').reduce((p: Product[], c: string) => {
- return p.filter(x => {
- const productString = (
- x.code + ' ' + x.name + ' ' + x.units + ' ' + x.productGroup + (x.isActive ? 'active' : 'deactive')
- ).toLowerCase();
- return productString.indexOf(c) !== -1;
+ const filter = (this.filterValue === undefined) ? "" : this.filterValue;
+ return data.filter(x => {
+ return x.productGroup.id === filter || filter === "";
}
);
- }, Object.assign([], data));
- }
-
- private getPagedData(data: Product[]) {
- const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
- return data.splice(startIndex, this.paginator.pageSize);
}
}
diff --git a/bookie/src/app/product/product-list/product-list.component.html b/bookie/src/app/product/product-list/product-list.component.html
index 1b9589b..b5976ab 100644
--- a/bookie/src/app/product/product-list/product-list.component.html
+++ b/bookie/src/app/product/product-list/product-list.component.html
@@ -1,7 +1,10 @@
Products
-
diff --git a/bookie/src/app/product/product-list/product-list.component.ts b/bookie/src/app/product/product-list/product-list.component.ts
index 044de22..3194173 100644
--- a/bookie/src/app/product/product-list/product-list.component.ts
+++ b/bookie/src/app/product/product-list/product-list.component.ts
@@ -1,11 +1,15 @@
import { Component, OnInit, ViewChild } from '@angular/core';
-import { MatPaginator } from '@angular/material/paginator';
-import { ProductListDataSource } from './product-list-datasource';
-import { Product } from '../../core/product';
-import { ActivatedRoute } from '@angular/router';
+import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder, FormGroup } from '@angular/forms';
-import { Observable } from 'rxjs';
+import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
+import { ProductListDataSource } from './product-list-datasource';
+import { MatTable } from "@angular/material";
+import { Product } from '../../core/product';
import { ToCsvService } from "../../shared/to-csv.service";
+import { ToasterService } from "../../core/toaster.service";
+import { ProductService } from "../product.service";
+import { ProductGroup } from "../../core/product-group";
+import { BehaviorSubject } from "rxjs";
@Component({
selector: 'app-product-list',
@@ -13,29 +17,64 @@ import { ToCsvService } from "../../shared/to-csv.service";
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
- @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+ @ViewChild('table', { static: true }) table: MatTable;
dataSource: ProductListDataSource;
- filter: Observable = new Observable();
+ filter: BehaviorSubject;
form: FormGroup;
list: Product[];
+ data: BehaviorSubject;
+ productGroups: ProductGroup[];
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns: string[] = ['name', 'price', 'productGroup', 'tax', 'info', 'quantity'];
- constructor(private route: ActivatedRoute, private fb: FormBuilder, private toCsv: ToCsvService) {
+ constructor(
+ private route: ActivatedRoute,
+ private fb: FormBuilder,
+ private router: Router,
+ private toaster: ToasterService,
+ private toCsv: ToCsvService,
+ private ser: ProductService
+ ) {
this.form = this.fb.group({
productGroup: ''
});
+ this.filter = new BehaviorSubject("");
+ this.data = new BehaviorSubject([]);
+ this.data.subscribe((data: Product[]) => {
+ this.list = data;
+ })
}
- filterOn(val: string) {
- console.log(val);
+
+ filterOn(val: any) {
+ this.filter.next(val.value);
}
ngOnInit() {
this.route.data
- .subscribe((data: { list: Product[] }) => {
- this.list = data.list;
+ .subscribe((data: { list: Product[], productGroups: ProductGroup[] }) => {
+ this.data.next(data.list);
+ this.productGroups = data.productGroups;
});
- this.dataSource = new ProductListDataSource(this.paginator, this.filter, this.list);
+ this.dataSource = new ProductListDataSource(this.filter, this.data);
+ }
+
+ updateSortOrder() {
+ this.ser.updateSortOrder(this.dataSource.viewData)
+ .subscribe(
+ (result) => {
+ this.toaster.show('Success', '');
+ this.router.navigateByUrl('/products');
+ },
+ (error) => {
+ this.toaster.show('Danger', error.error);
+ }
+ );
+ }
+
+ dropTable(event: CdkDragDrop) {
+ const prevIndex = this.list.indexOf(event.item.data);
+ moveItemInArray(this.list, prevIndex, event.currentIndex);
+ this.data.next(this.list);
}
exportCsv() {
@@ -48,7 +87,7 @@ export class ProductListComponent implements OnInit {
Tax: 'tax'
};
- const csvData = new Blob([this.toCsv.toCsv(headers, this.dataSource.data)], {type: 'text/csv;charset=utf-8;'});
+ const csvData = new Blob([this.toCsv.toCsv(headers, this.dataSource.viewData)], {type: 'text/csv;charset=utf-8;'});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(csvData);
link.setAttribute('download', 'products.csv');
diff --git a/bookie/src/app/product/product-resolver.service.spec.ts b/bookie/src/app/product/product-resolver.service.spec.ts
index d58b20d..6b63a8a 100644
--- a/bookie/src/app/product/product-resolver.service.spec.ts
+++ b/bookie/src/app/product/product-resolver.service.spec.ts
@@ -1,15 +1,15 @@
import {inject, TestBed} from '@angular/core/testing';
-import {ProductResolverService} from './product-resolver.service';
+import {ProductResolver} from './product-resolver.service';
-describe('ProductResolverService', () => {
+describe('ProductResolver', () => {
beforeEach(() => {
TestBed.configureTestingModule({
- providers: [ProductDetailResolverService]
+ providers: [ProductResolver]
});
});
- it('should be created', inject([ProductDetailResolverService], (service: ProductDetailResolverService) => {
+ it('should be created', inject([ProductResolver], (service: ProductResolver) => {
expect(service).toBeTruthy();
}));
});
diff --git a/bookie/src/app/product/product-routing.module.spec.ts b/bookie/src/app/product/product-routing.module.spec.ts
deleted file mode 100644
index 3f054cf..0000000
--- a/bookie/src/app/product/product-routing.module.spec.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import {ProductRoutingModule} from './product-routing.module';
-
-describe('ProductRoutingModule', () => {
- let productRoutingModule: ProductRoutingModule;
-
- beforeEach(() => {
- productRoutingModule = new ProductRoutingModule();
- });
-
- it('should create an instance', () => {
- expect(productRoutingModule).toBeTruthy();
- });
-});
diff --git a/bookie/src/app/product/product-routing.module.ts b/bookie/src/app/product/product-routing.module.ts
deleted file mode 100644
index 0b0b470..0000000
--- a/bookie/src/app/product/product-routing.module.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import {NgModule} from '@angular/core';
-import {CommonModule} from '@angular/common';
-import {RouterModule, Routes} from '@angular/router';
-
-import {ProductListResolver} from './product-list-resolver.service';
-import {ProductResolver} from './product-resolver.service';
-import {ProductDetailComponent} from './product-detail/product-detail.component';
-import {ProductListComponent} from './product-list/product-list.component';
-
-import {AuthGuard} from '../auth/auth-guard.service';
-import {ProductGroupListResolver} from '../product-group/product-group-list-resolver.service';
-
-const productRoutes: Routes = [
- {
- path: '',
- component: ProductListComponent,
- canActivate: [AuthGuard],
- data: {
- permission: 'Products'
- },
- resolve: {
- list: ProductListResolver
- }
- },
- {
- path: 'new',
- component: ProductDetailComponent,
- canActivate: [AuthGuard],
- data: {
- permission: 'Products'
- },
- resolve: {
- item: ProductResolver,
- productGroups: ProductGroupListResolver
- }
- },
- {
- path: ':id',
- component: ProductDetailComponent,
- canActivate: [AuthGuard],
- data: {
- permission: 'Products'
- },
- resolve: {
- item: ProductResolver,
- productGroups: ProductGroupListResolver
- }
- }
-];
-
-@NgModule({
- imports: [
- CommonModule,
- RouterModule.forChild(productRoutes)
-
- ],
- exports: [
- RouterModule
- ],
- providers: [
- ProductListResolver,
- ProductResolver
- ]
-})
-export class ProductRoutingModule {
-}
diff --git a/bookie/src/app/product/product.module.spec.ts b/bookie/src/app/product/product.module.spec.ts
deleted file mode 100644
index 0ec58f1..0000000
--- a/bookie/src/app/product/product.module.spec.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import {ProductModule} from './product.module';
-
-describe('ProductModule', () => {
- let productModule: ProductModule;
-
- beforeEach(() => {
- productModule = new ProductModule();
- });
-
- it('should create an instance', () => {
- expect(productModule).toBeTruthy();
- });
-});
diff --git a/bookie/src/app/product/product.service.ts b/bookie/src/app/product/product.service.ts
index 4ecbc5d..2fecb02 100644
--- a/bookie/src/app/product/product.service.ts
+++ b/bookie/src/app/product/product.service.ts
@@ -1,9 +1,9 @@
-import {Injectable} from '@angular/core';
-import {Observable} from 'rxjs/internal/Observable';
-import {catchError} from 'rxjs/operators';
-import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
-import {Product} from '../core/product';
-import {ErrorLoggerService} from '../core/error-logger.service';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { catchError } from 'rxjs/operators';
+import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
+import { Product } from '../core/product';
+import { ErrorLoggerService } from '../core/error-logger.service';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
@@ -48,6 +48,13 @@ export class ProductService {
);
}
+ updateSortOrder(list: Product[]): Observable {
+ return >this.http.post(url, list, httpOptions)
+ .pipe(
+ catchError(this.log.handleError(serviceName, 'updateSortOrder'))
+ );
+ }
+
saveOrUpdate(product: Product): Observable {
if (!product.id) {
return this.save(product);
diff --git a/bookie/src/app/product/products-routing.module.spec.ts b/bookie/src/app/product/products-routing.module.spec.ts
new file mode 100644
index 0000000..712ce45
--- /dev/null
+++ b/bookie/src/app/product/products-routing.module.spec.ts
@@ -0,0 +1,13 @@
+import {ProductsRoutingModule} from './products-routing.module';
+
+describe('ProductsRoutingModule', () => {
+ let productsRoutingModule: ProductsRoutingModule;
+
+ beforeEach(() => {
+ productsRoutingModule = new ProductsRoutingModule();
+ });
+
+ it('should create an instance', () => {
+ expect(productsRoutingModule).toBeTruthy();
+ });
+});
diff --git a/bookie/src/app/product/products-routing.module.ts b/bookie/src/app/product/products-routing.module.ts
new file mode 100644
index 0000000..8ace696
--- /dev/null
+++ b/bookie/src/app/product/products-routing.module.ts
@@ -0,0 +1,70 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ProductListResolver } from './product-list-resolver.service';
+import { ProductResolver } from './product-resolver.service';
+import { ProductDetailComponent } from './product-detail/product-detail.component';
+import { ProductListComponent } from './product-list/product-list.component';
+
+import { AuthGuard } from '../auth/auth-guard.service';
+import { ProductGroupListResolver } from '../product-group/product-group-list-resolver.service';
+import { TaxListResolver } from "../taxes/tax-list-resolver.service";
+
+const productRoutes: Routes = [
+ {
+ path: '',
+ component: ProductListComponent,
+ canActivate: [AuthGuard],
+ data: {
+ permission: 'Products'
+ },
+ resolve: {
+ list: ProductListResolver,
+ productGroups: ProductGroupListResolver
+ }
+ },
+ {
+ path: 'new',
+ component: ProductDetailComponent,
+ canActivate: [AuthGuard],
+ data: {
+ permission: 'Products'
+ },
+ resolve: {
+ item: ProductResolver,
+ productGroups: ProductGroupListResolver,
+ taxes: TaxListResolver
+ }
+ },
+ {
+ path: ':id',
+ component: ProductDetailComponent,
+ canActivate: [AuthGuard],
+ data: {
+ permission: 'Products'
+ },
+ resolve: {
+ item: ProductResolver,
+ productGroups: ProductGroupListResolver,
+ taxes: TaxListResolver
+ }
+ }
+];
+
+@NgModule({
+ imports: [
+ CommonModule,
+ RouterModule.forChild(productRoutes)
+
+ ],
+ exports: [
+ RouterModule
+ ],
+ providers: [
+ ProductListResolver,
+ ProductResolver
+ ]
+})
+export class ProductsRoutingModule {
+}
diff --git a/bookie/src/app/product/products.module.spec.ts b/bookie/src/app/product/products.module.spec.ts
new file mode 100644
index 0000000..4532102
--- /dev/null
+++ b/bookie/src/app/product/products.module.spec.ts
@@ -0,0 +1,13 @@
+import {ProductsModule} from './products.module';
+
+describe('ProductsModule', () => {
+ let productsModule: ProductsModule;
+
+ beforeEach(() => {
+ productsModule = new ProductsModule();
+ });
+
+ it('should create an instance', () => {
+ expect(productsModule).toBeTruthy();
+ });
+});
diff --git a/bookie/src/app/product/product.module.ts b/bookie/src/app/product/products.module.ts
similarity index 78%
rename from bookie/src/app/product/product.module.ts
rename to bookie/src/app/product/products.module.ts
index 961a628..ed2b228 100644
--- a/bookie/src/app/product/product.module.ts
+++ b/bookie/src/app/product/products.module.ts
@@ -3,7 +3,7 @@ import {CommonModule} from '@angular/common';
import {ProductListComponent} from './product-list/product-list.component';
import {ProductDetailComponent} from './product-detail/product-detail.component';
-import {ProductRoutingModule} from './product-routing.module';
+import {ProductsRoutingModule} from './products-routing.module';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -15,14 +15,16 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
-import {CdkTableModule} from '@angular/cdk/table';
-import {ReactiveFormsModule} from '@angular/forms';
-import {FlexLayoutModule} from '@angular/flex-layout';
+import { CdkTableModule } from '@angular/cdk/table';
+import { ReactiveFormsModule } from '@angular/forms';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { DragDropModule } from "@angular/cdk/drag-drop";
@NgModule({
imports: [
CommonModule,
CdkTableModule,
+ DragDropModule,
FlexLayoutModule,
MatTableModule,
MatPaginatorModule,
@@ -36,12 +38,12 @@ import {FlexLayoutModule} from '@angular/flex-layout';
MatSelectModule,
MatCheckboxModule,
ReactiveFormsModule,
- ProductRoutingModule
+ ProductsRoutingModule
],
declarations: [
ProductListComponent,
ProductDetailComponent
]
})
-export class ProductModule {
+export class ProductsModule {
}