| @@ -0,0 +1,7 @@ | |||
| export interface ListColDefinition { | |||
| name: string, | |||
| text: string, | |||
| type: string, | |||
| field?: string | |||
| subResource?: string | |||
| } | |||
| @@ -0,0 +1,59 @@ | |||
| <app-paging #pagingComponent | |||
| [getDataFunction]="getDataFunction" | |||
| [dataSource]="dataSource" | |||
| [searchable]="searchable" | |||
| [hidePageSize]="hidePageSize" | |||
| > | |||
| <div *ngIf="listColDefinitions" class="table-responsive"> | |||
| <table mat-table [dataSource]="dataSource" matSort (matSortChange)="onSortChange($event)" class="mat-elevation-z8"> | |||
| <!-- Iterate over listColDefinitions to define columns --> | |||
| <ng-container *ngFor="let column of listColDefinitions"> | |||
| <ng-container [matColumnDef]="column.name"> | |||
| <!-- Header Cell --> | |||
| <th mat-header-cell *matHeaderCellDef> | |||
| {{ column.text | translate }} | |||
| </th> | |||
| <!-- Conditional Cells --> | |||
| <td mat-cell *matCellDef="let element"> | |||
| <ng-container [ngSwitch]="column.type"> | |||
| <!-- Detail Column --> | |||
| <ng-container *ngSwitchCase="COLUMN_TYPE_DETAIL" > | |||
| <span class="btn btn-primary spt-icon-details" | |||
| data-type="user-tool" data-action="edit" | |||
| (click)="navigateToDetailsFunction(element, column)"> | |||
| </span> | |||
| </ng-container> | |||
| <!-- Position Column --> | |||
| <ng-container *ngSwitchCase="COLUMN_TYPE_POSITION"> | |||
| {{ pagingComponent.getPageSize() * (pagingComponent.getPageIndex() - 1) + dataSource.filteredData.indexOf(element) + 1 }} | |||
| </ng-container> | |||
| <!-- Image Column --> | |||
| <ng-container *ngSwitchCase="COLUMN_TYPE_IMAGE"> | |||
| <img [src]="getElementImage(element, column)" width="40" height="40"/> | |||
| </ng-container> | |||
| <!-- Text Column --> | |||
| <ng-container *ngSwitchCase="COLUMN_TYPE_TEXT"> | |||
| {{ getElementValue(element, column) }} | |||
| </ng-container> | |||
| <!-- Text Linked Column --> | |||
| <ng-container *ngSwitchCase="COLUMN_TYPE_TEXT_LINKED"> | |||
| <span class="btn-link" (click)="navigateToDetailsFunction(element, column)"> | |||
| {{ getElementValue(element, column) }} | |||
| </span> | |||
| </ng-container> | |||
| </ng-container> | |||
| </td> | |||
| </ng-container> | |||
| </ng-container> | |||
| <!-- Header and Row Definitions --> | |||
| <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> | |||
| <tr mat-row *matRowDef="let row; columns: displayedColumns; index as i;" | |||
| (click)="onRowSelected(row, i)" | |||
| [ngClass]="{'highlighted': selectedRowIndex === i}"> | |||
| </tr> | |||
| </table> | |||
| </div> | |||
| </app-paging> | |||
| @@ -0,0 +1,23 @@ | |||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { ListComponent } from './list.component'; | |||
| describe('ListComponent', () => { | |||
| let component: ListComponent; | |||
| let fixture: ComponentFixture<ListComponent>; | |||
| beforeEach(async () => { | |||
| await TestBed.configureTestingModule({ | |||
| declarations: [ListComponent] | |||
| }) | |||
| .compileComponents(); | |||
| fixture = TestBed.createComponent(ListComponent); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| }); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -0,0 +1,128 @@ | |||
| import {AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core'; | |||
| import {MatSort, Sort} from "@angular/material/sort"; | |||
| import {PagingComponent} from "@app/_components/paging/paging.component"; | |||
| import {MatTableDataSource} from "@angular/material/table"; | |||
| import {ListColDefinition} from "@app/_components/list/list-col-definition"; | |||
| import {OrderFilter} from "@app/_models/orderFilter"; | |||
| type GeneralDataSource = MatTableDataSource<any>; | |||
| @Component({ | |||
| selector: 'app-list', | |||
| templateUrl: './list.component.html', | |||
| styleUrl: './list.component.scss' | |||
| }) | |||
| export class ListComponent implements OnInit, AfterViewInit { | |||
| @Input() public dataSource!: GeneralDataSource; | |||
| @Input() public getDataFunction!: Function; | |||
| @Input() public navigateToDetailsFunction!: Function; | |||
| @Input() public searchable: boolean; | |||
| @Input() public listColDefinitions!: ListColDefinition[]; | |||
| @Input() public hidePageSize: boolean; | |||
| @ViewChild(MatSort) sort; | |||
| @ViewChild("pagingComponent", { static: false }) pagingComponent!: PagingComponent; | |||
| public static COLUMN_TYPE_DETAIL: string = 'detail'; | |||
| public static COLUMN_TYPE_POSITION: string = 'position'; | |||
| public static COLUMN_TYPE_TEXT: string = 'text'; | |||
| public static COLUMN_TYPE_TEXT_LINKED: string = 'text_linked'; | |||
| public static COLUMN_TYPE_IMAGE: string = 'image'; | |||
| public static validColumnTypes: string[] = [ | |||
| ListComponent.COLUMN_TYPE_DETAIL, | |||
| ListComponent.COLUMN_TYPE_POSITION, | |||
| ListComponent.COLUMN_TYPE_TEXT, | |||
| ListComponent.COLUMN_TYPE_TEXT_LINKED, | |||
| ListComponent.COLUMN_TYPE_IMAGE | |||
| ]; | |||
| protected displayedColumns!: string[]; | |||
| protected selectedRowIndex: number | null = null; | |||
| constructor() { | |||
| this.searchable = true; | |||
| this.sort = new MatSort(); | |||
| this.hidePageSize = false; | |||
| } | |||
| ngOnInit(): void { | |||
| this.displayedColumns = []; | |||
| this.listColDefinitions.forEach((value, index) => { | |||
| this.displayedColumns.push(value.name); | |||
| }); | |||
| } | |||
| ngAfterViewInit(): void { | |||
| // this.searchBoxOpen = false; | |||
| } | |||
| getData(): void { | |||
| this.getDataFunction() | |||
| } | |||
| setData(dataSource: any, dataLength: number): void { | |||
| this.dataSource = dataSource; | |||
| this.pagingComponent.dataSource = dataSource; | |||
| this.pagingComponent.setDataLength(dataLength); | |||
| } | |||
| onSortChange = (sortState: Sort) => { | |||
| this.pagingComponent.resetPageIndex() | |||
| let order: OrderFilter; | |||
| if (sortState.direction === "") { | |||
| order = OrderFilter.Undefined; | |||
| } else { | |||
| order = sortState.direction; | |||
| } | |||
| this.pagingComponent.getData(); | |||
| } | |||
| onRowSelected(row: any, index: number) { | |||
| console.log('row selected'); | |||
| console.log(row, index); | |||
| this.selectedRowIndex = index; | |||
| } | |||
| getElementValue(element: any, column: ListColDefinition): any { | |||
| if (column.field) { | |||
| return column.subResource ? element[column.subResource][column.field] : element[column.field]; | |||
| } | |||
| } | |||
| getElementImage(element: any, column: ListColDefinition): any { | |||
| let elementValue = this.getElementValue(element, column); | |||
| if (elementValue !== undefined && elementValue !== null) { | |||
| return elementValue; | |||
| } | |||
| return "/assets/images/icons/dummy-product.png" | |||
| } | |||
| get COLUMN_TYPE_DETAIL(): string { return ListComponent.COLUMN_TYPE_DETAIL; } | |||
| get COLUMN_TYPE_POSITION(): string { return ListComponent.COLUMN_TYPE_POSITION; } | |||
| get COLUMN_TYPE_IMAGE(): string { return ListComponent.COLUMN_TYPE_IMAGE; } | |||
| get COLUMN_TYPE_TEXT(): string { return ListComponent.COLUMN_TYPE_TEXT; } | |||
| get COLUMN_TYPE_TEXT_LINKED(): string { return ListComponent.COLUMN_TYPE_TEXT_LINKED; } | |||
| public static createColDefinition( | |||
| name: string, | |||
| text: string, | |||
| type: string, | |||
| field?: string, | |||
| subResource?: string | |||
| ): ListColDefinition { | |||
| if (!this.validColumnTypes.includes(type)) { | |||
| throw Error('invalid column type'); | |||
| } | |||
| let res: ListColDefinition = {} as ListColDefinition; | |||
| res.name = name; | |||
| res.text = text; | |||
| res.type = type; | |||
| res.field = field; | |||
| res.subResource = subResource | |||
| return res; | |||
| } | |||
| } | |||
| @@ -10,7 +10,7 @@ | |||
| [dataSource]="dataSource" | |||
| [searchable]="true" | |||
| [hidePageSize]="true" | |||
| > | |||
| > | |||
| <div *ngIf="searchSelectColDefs" class="table-responsive"> | |||
| <table mat-table [dataSource]="dataSource" matSort (matSortChange)="onSortChange($event)" class="mat-elevation-z8"> | |||
| @@ -1,3 +1,19 @@ | |||
| <div class="spt-container"> | |||
| <div *ngIf="!this.user" class="top-btn"> | |||
| <button *ngIf="bShowNewProductButton" class="btn btn-primary" (click)="openModalNewProduct()">+ {{ 'basic.new-product' | translate }}</button> | |||
| <button *ngIf="!bShowNewProductButton" class="btn btn-primary" (click)="openModalAssignProduct()">+ {{ 'basic.assign-product' | translate }}</button> | |||
| </div> | |||
| <app-list #listComponent | |||
| [dataSource]="getDataSource()" | |||
| [getDataFunction]="getData" | |||
| [navigateToDetailsFunction]="navigateToProductDetails" | |||
| [listColDefinitions]="listColDefinitions" | |||
| [searchable]="true" | |||
| [hidePageSize]="false" | |||
| ></app-list> | |||
| </div> | |||
| <div class="spt-container"> | |||
| <div *ngIf="!this.user" class="top-btn"> | |||
| <button *ngIf="bShowNewProductButton" class="btn btn-primary" (click)="openModalNewProduct()">+ {{ 'basic.new-product' | translate }}</button> | |||
| @@ -71,4 +87,4 @@ | |||
| </table> | |||
| </div> | |||
| </app-paging> | |||
| </div> | |||
| </div> | |||
| @@ -18,6 +18,8 @@ import {OrderFilter} from "@app/_models/orderFilter"; | |||
| import {NewProductComponent} from "@app/_views/products/new-product/new-product.component"; | |||
| import {AssignProductComponent} from "@app/_views/products/assign-product/assign-product.component"; | |||
| import {TranslateService} from "@ngx-translate/core"; | |||
| import {ListColDefinition} from "@app/_components/list/list-col-definition"; | |||
| import {ListComponent} from "@app/_components/list/list.component"; | |||
| type GeneralDataSource = MatTableDataSource<any>; | |||
| @Component({ | |||
| @@ -32,6 +34,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| @Input() public contact!: ContactJsonld; | |||
| @ViewChild(MatSort) sort; | |||
| @ViewChild("pagingComponent", { static: false }) pagingComponent!: PagingComponent; | |||
| @ViewChild("listComponent", { static: false }) listComponent!: ListComponent; | |||
| protected displayedColumns: string[]; | |||
| @@ -48,6 +51,8 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| protected bShowNewProductButton: boolean; | |||
| protected nameOrderAsc: OrderFilter; | |||
| public listColDefinitions!: ListColDefinition[]; | |||
| constructor( | |||
| private router: Router, | |||
| private productService: ProductService, | |||
| @@ -71,6 +76,13 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| this.dataSourceContactPartnerProducts = new MatTableDataSource<ContactPartnerProductJsonld>(this.contactPartnerProducts); | |||
| this.bShowNewProductButton = true; | |||
| this.nameOrderAsc = OrderFilter.Asc; | |||
| this.listColDefinitions = [ | |||
| ListComponent.createColDefinition('detail', 'overview.details', ListComponent.COLUMN_TYPE_DETAIL), | |||
| ListComponent.createColDefinition('pos', 'overview.number', ListComponent.COLUMN_TYPE_POSITION), | |||
| ListComponent.createColDefinition('img', 'overview.image', ListComponent.COLUMN_TYPE_IMAGE, 'imageUrl'), | |||
| ListComponent.createColDefinition('name', 'form.product', ListComponent.COLUMN_TYPE_TEXT_LINKED, 'name'), | |||
| ]; | |||
| } | |||
| ngOnInit(){ | |||
| @@ -83,8 +95,9 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| ngAfterViewInit() { | |||
| this.dataSourceProducts.sort = this.sort; | |||
| this.dataSourceProducts.paginator = this.pagingComponent.paginator; | |||
| this.pagingComponent.getData(); | |||
| //this.dataSourceProducts.paginator = this.pagingComponent.paginator; | |||
| //this.pagingComponent.getData(); | |||
| this.listComponent.getData(); | |||
| } | |||
| getDataSource(): GeneralDataSource { | |||
| @@ -113,24 +126,28 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| getProducts = (searchValue = undefined) => { | |||
| this.productsSub = this.productService.productsGetCollection( | |||
| this.pagingComponent.getPageIndex(), | |||
| this.pagingComponent.getPageSize(), | |||
| this.listComponent.pagingComponent.getPageIndex(), | |||
| this.listComponent.pagingComponent.getPageSize(), | |||
| searchValue, | |||
| undefined, | |||
| this.nameOrderAsc, | |||
| ).subscribe( | |||
| data => { | |||
| this.products = data["hydra:member"]; | |||
| this.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.listComponent.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.dataSourceProducts = new MatTableDataSource<ProductJsonld>(this.products); | |||
| this.listComponent.setData(this.dataSourceProducts, Number(data["hydra:totalItems"])); | |||
| } | |||
| ); | |||
| } | |||
| getUserProducts = (searchValue = undefined) => { | |||
| this.productsSub = this.userProductService.userProductsGetCollection( | |||
| this.pagingComponent.getPageIndex(), | |||
| this.pagingComponent.getPageSize(), | |||
| this.listComponent.pagingComponent.getPageIndex(), | |||
| this.listComponent.pagingComponent.getPageSize(), | |||
| this.user.id, | |||
| undefined, | |||
| undefined, | |||
| @@ -146,7 +163,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| } | |||
| }) | |||
| this.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.listComponent.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.dataSourceProducts = new MatTableDataSource<ProductJsonld>(this.products); | |||
| } | |||
| ); | |||
| @@ -154,8 +171,8 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| getPartnerProducts = (searchValue= undefined) => { | |||
| this.productsSub = this.partnerProductService.partnerProductsGetCollection( | |||
| this.pagingComponent.getPageIndex(), | |||
| this.pagingComponent.getPageSize(), | |||
| this.listComponent.pagingComponent.getPageIndex(), | |||
| this.listComponent.pagingComponent.getPageSize(), | |||
| this.partner.id, | |||
| undefined, | |||
| undefined, | |||
| @@ -165,7 +182,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| ).subscribe( | |||
| data => { | |||
| this.partnerProducts = data["hydra:member"]; | |||
| this.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.listComponent.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.dataSourcePartnerProducts = new MatTableDataSource<PartnerProductJsonld>(this.partnerProducts); | |||
| } | |||
| ); | |||
| @@ -173,15 +190,15 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| getContactPartnerProduct = (searchValue = undefined) => { | |||
| this.productsSub = this.contactPartnerProductService.contactPartnerProductsGetCollection( | |||
| this.pagingComponent.getPageIndex(), | |||
| this.pagingComponent.getPageSize(), | |||
| this.listComponent.pagingComponent.getPageIndex(), | |||
| this.listComponent.pagingComponent.getPageSize(), | |||
| this.contact.id, | |||
| undefined, | |||
| searchValue | |||
| ).subscribe( | |||
| data => { | |||
| this.contactPartnerProducts = data["hydra:member"]; | |||
| this.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.listComponent.pagingComponent.setDataLength(Number(data["hydra:totalItems"])); | |||
| this.dataSourceContactPartnerProducts = new MatTableDataSource<ContactPartnerProductJsonld>(this.contactPartnerProducts); | |||
| } | |||
| ); | |||
| @@ -224,7 +241,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||
| this.pagingComponent.getData(); | |||
| } | |||
| navigateToProductDetails(element: any) { | |||
| navigateToProductDetails = (element: any, column?: any)=> { | |||
| let product: ProductJsonld; | |||
| if (this.user !== undefined) { | |||
| product = element['partner']; | |||
| @@ -65,6 +65,7 @@ import { AssignProductComponent } from './_views/products/assign-product/assign- | |||
| import { LinkedLabelComponent } from './_components/linked-label/linked-label.component'; | |||
| import {LoadingInterceptor} from "@app/_helpers/loading-interceptor.service"; | |||
| import { SearchSelectComponent } from './_components/search-select/search-select.component'; | |||
| import { ListComponent } from './_components/list/list.component'; | |||
| export function apiConfigFactory(): Configuration { | |||
| @@ -152,6 +153,7 @@ export function HttpLoaderFactory(http: HttpClient) { | |||
| AssignProductComponent, | |||
| LinkedLabelComponent, | |||
| SearchSelectComponent, | |||
| ListComponent, | |||
| ], | |||
| providers: [ | |||
| {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | |||