| @@ -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" | [dataSource]="dataSource" | ||||
| [searchable]="true" | [searchable]="true" | ||||
| [hidePageSize]="true" | [hidePageSize]="true" | ||||
| > | |||||
| > | |||||
| <div *ngIf="searchSelectColDefs" class="table-responsive"> | <div *ngIf="searchSelectColDefs" class="table-responsive"> | ||||
| <table mat-table [dataSource]="dataSource" matSort (matSortChange)="onSortChange($event)" class="mat-elevation-z8"> | <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 class="spt-container"> | ||||
| <div *ngIf="!this.user" class="top-btn"> | <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)="openModalNewProduct()">+ {{ 'basic.new-product' | translate }}</button> | ||||
| @@ -71,4 +87,4 @@ | |||||
| </table> | </table> | ||||
| </div> | </div> | ||||
| </app-paging> | </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 {NewProductComponent} from "@app/_views/products/new-product/new-product.component"; | ||||
| import {AssignProductComponent} from "@app/_views/products/assign-product/assign-product.component"; | import {AssignProductComponent} from "@app/_views/products/assign-product/assign-product.component"; | ||||
| import {TranslateService} from "@ngx-translate/core"; | 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>; | type GeneralDataSource = MatTableDataSource<any>; | ||||
| @Component({ | @Component({ | ||||
| @@ -32,6 +34,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| @Input() public contact!: ContactJsonld; | @Input() public contact!: ContactJsonld; | ||||
| @ViewChild(MatSort) sort; | @ViewChild(MatSort) sort; | ||||
| @ViewChild("pagingComponent", { static: false }) pagingComponent!: PagingComponent; | @ViewChild("pagingComponent", { static: false }) pagingComponent!: PagingComponent; | ||||
| @ViewChild("listComponent", { static: false }) listComponent!: ListComponent; | |||||
| protected displayedColumns: string[]; | protected displayedColumns: string[]; | ||||
| @@ -48,6 +51,8 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| protected bShowNewProductButton: boolean; | protected bShowNewProductButton: boolean; | ||||
| protected nameOrderAsc: OrderFilter; | protected nameOrderAsc: OrderFilter; | ||||
| public listColDefinitions!: ListColDefinition[]; | |||||
| constructor( | constructor( | ||||
| private router: Router, | private router: Router, | ||||
| private productService: ProductService, | private productService: ProductService, | ||||
| @@ -71,6 +76,13 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| this.dataSourceContactPartnerProducts = new MatTableDataSource<ContactPartnerProductJsonld>(this.contactPartnerProducts); | this.dataSourceContactPartnerProducts = new MatTableDataSource<ContactPartnerProductJsonld>(this.contactPartnerProducts); | ||||
| this.bShowNewProductButton = true; | this.bShowNewProductButton = true; | ||||
| this.nameOrderAsc = OrderFilter.Asc; | 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(){ | ngOnInit(){ | ||||
| @@ -83,8 +95,9 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| ngAfterViewInit() { | ngAfterViewInit() { | ||||
| this.dataSourceProducts.sort = this.sort; | 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 { | getDataSource(): GeneralDataSource { | ||||
| @@ -113,24 +126,28 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| getProducts = (searchValue = undefined) => { | getProducts = (searchValue = undefined) => { | ||||
| this.productsSub = this.productService.productsGetCollection( | this.productsSub = this.productService.productsGetCollection( | ||||
| this.pagingComponent.getPageIndex(), | |||||
| this.pagingComponent.getPageSize(), | |||||
| this.listComponent.pagingComponent.getPageIndex(), | |||||
| this.listComponent.pagingComponent.getPageSize(), | |||||
| searchValue, | searchValue, | ||||
| undefined, | undefined, | ||||
| this.nameOrderAsc, | this.nameOrderAsc, | ||||
| ).subscribe( | ).subscribe( | ||||
| data => { | data => { | ||||
| this.products = data["hydra:member"]; | 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.dataSourceProducts = new MatTableDataSource<ProductJsonld>(this.products); | ||||
| this.listComponent.setData(this.dataSourceProducts, Number(data["hydra:totalItems"])); | |||||
| } | } | ||||
| ); | ); | ||||
| } | } | ||||
| getUserProducts = (searchValue = undefined) => { | getUserProducts = (searchValue = undefined) => { | ||||
| this.productsSub = this.userProductService.userProductsGetCollection( | this.productsSub = this.userProductService.userProductsGetCollection( | ||||
| this.pagingComponent.getPageIndex(), | |||||
| this.pagingComponent.getPageSize(), | |||||
| this.listComponent.pagingComponent.getPageIndex(), | |||||
| this.listComponent.pagingComponent.getPageSize(), | |||||
| this.user.id, | this.user.id, | ||||
| undefined, | undefined, | ||||
| 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); | this.dataSourceProducts = new MatTableDataSource<ProductJsonld>(this.products); | ||||
| } | } | ||||
| ); | ); | ||||
| @@ -154,8 +171,8 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| getPartnerProducts = (searchValue= undefined) => { | getPartnerProducts = (searchValue= undefined) => { | ||||
| this.productsSub = this.partnerProductService.partnerProductsGetCollection( | this.productsSub = this.partnerProductService.partnerProductsGetCollection( | ||||
| this.pagingComponent.getPageIndex(), | |||||
| this.pagingComponent.getPageSize(), | |||||
| this.listComponent.pagingComponent.getPageIndex(), | |||||
| this.listComponent.pagingComponent.getPageSize(), | |||||
| this.partner.id, | this.partner.id, | ||||
| undefined, | undefined, | ||||
| undefined, | undefined, | ||||
| @@ -165,7 +182,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| ).subscribe( | ).subscribe( | ||||
| data => { | data => { | ||||
| this.partnerProducts = data["hydra:member"]; | 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); | this.dataSourcePartnerProducts = new MatTableDataSource<PartnerProductJsonld>(this.partnerProducts); | ||||
| } | } | ||||
| ); | ); | ||||
| @@ -173,15 +190,15 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| getContactPartnerProduct = (searchValue = undefined) => { | getContactPartnerProduct = (searchValue = undefined) => { | ||||
| this.productsSub = this.contactPartnerProductService.contactPartnerProductsGetCollection( | this.productsSub = this.contactPartnerProductService.contactPartnerProductsGetCollection( | ||||
| this.pagingComponent.getPageIndex(), | |||||
| this.pagingComponent.getPageSize(), | |||||
| this.listComponent.pagingComponent.getPageIndex(), | |||||
| this.listComponent.pagingComponent.getPageSize(), | |||||
| this.contact.id, | this.contact.id, | ||||
| undefined, | undefined, | ||||
| searchValue | searchValue | ||||
| ).subscribe( | ).subscribe( | ||||
| data => { | data => { | ||||
| this.contactPartnerProducts = data["hydra:member"]; | 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); | this.dataSourceContactPartnerProducts = new MatTableDataSource<ContactPartnerProductJsonld>(this.contactPartnerProducts); | ||||
| } | } | ||||
| ); | ); | ||||
| @@ -224,7 +241,7 @@ export class ProductListComponent implements OnInit, AfterViewInit { | |||||
| this.pagingComponent.getData(); | this.pagingComponent.getData(); | ||||
| } | } | ||||
| navigateToProductDetails(element: any) { | |||||
| navigateToProductDetails = (element: any, column?: any)=> { | |||||
| let product: ProductJsonld; | let product: ProductJsonld; | ||||
| if (this.user !== undefined) { | if (this.user !== undefined) { | ||||
| product = element['partner']; | 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 { LinkedLabelComponent } from './_components/linked-label/linked-label.component'; | ||||
| import {LoadingInterceptor} from "@app/_helpers/loading-interceptor.service"; | import {LoadingInterceptor} from "@app/_helpers/loading-interceptor.service"; | ||||
| import { SearchSelectComponent } from './_components/search-select/search-select.component'; | import { SearchSelectComponent } from './_components/search-select/search-select.component'; | ||||
| import { ListComponent } from './_components/list/list.component'; | |||||
| export function apiConfigFactory(): Configuration { | export function apiConfigFactory(): Configuration { | ||||
| @@ -152,6 +153,7 @@ export function HttpLoaderFactory(http: HttpClient) { | |||||
| AssignProductComponent, | AssignProductComponent, | ||||
| LinkedLabelComponent, | LinkedLabelComponent, | ||||
| SearchSelectComponent, | SearchSelectComponent, | ||||
| ListComponent, | |||||
| ], | ], | ||||
| providers: [ | providers: [ | ||||
| {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | ||||