import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { AdHocReportingUI } from '@core/typings/ui/ad-hoc-reporting.typing'; import { RootObjectNames } from '@features/reporting/services/ad-hoc-reporting-definitions.service'; import { AdHocReportingService } from '@features/reporting/services/ad-hoc-reporting.service'; import { ArrayHelpersService, FilterTypes, TypeaheadSelectOption } from '@yourcause/common'; import { isEqual } from 'lodash'; import { DashboardsService } from '../dashboards.service'; import { GCDashboards } from '../dashboards.typing'; @Component({ selector: 'gc-table-column-config', templateUrl: './table-column-config.component.html', styleUrls: ['./table-column-config.component.scss'] }) export class TableColumnConfigComponent implements OnChanges { @Input() columns: GCDashboards.SimpleColumn[] = []; @Input() object: RootObjectNames; @Input() recordIds: number[]; @Input() maxColumns = Infinity; @Input() minColumns = 0; @Input() showColumnHeaderInput = true; @Input() isForRecordSummary: boolean; @Input() allowedColumnTypes: (FilterTypes|'multi-list'|'currency')[]; @Input() includeBucketNameInOverride = true; @Output() columnConfigValid = new EventEmitter(); @Output() columnsChanged = new EventEmitter(); allColumns: AdHocReportingUI.ColumnImplementation[] = []; allColumnOptions: TypeaheadSelectOption[]; _columns: GCDashboards.SimpleColumn[] = []; columnOptionsMap: { [index: number]: TypeaheadSelectOption[]; } = {}; columnErrorMapByIndex: { [x: number]: { [x: string]: { i18nKey: string; defaultValue: string; }; }; } = {}; constructor ( private adHocReportingService: AdHocReportingService, private dashboardsService: DashboardsService, private arrayHelper: ArrayHelpersService ) { } ngOnChanges (changes: SimpleChanges) { if (changes.columns) { const hasChanged = !isEqual(this.columns, this._columns); if (hasChanged) { this._columns = this.columns.map((column) => { return { ...column }; }); if (this.allColumnOptions) { this.setColumnOptionsMap(); } this.setValidity(); } } if (changes.object || changes.formIds) { this.setColumnOptions(); } } setValidity () { let isValid = true; this._columns.forEach((col, index) => { if (!col.columnNameOverride) { this.columnErrorMapByIndex[index] = { required: { i18nKey: 'common:textThisInputIsRequired', defaultValue: 'This input is required' } }; isValid = false; } else if ( !this.adHocReportingService.isColumnHeaderValid(col.columnNameOverride) ) { this.columnErrorMapByIndex[index] = { noSpecialCharacters: { i18nKey: 'common:textInvalidColumnHeaderSpecialChars', defaultValue: 'Invalid column header. Must not contain special characters.' } }; isValid = false; } else { this.columnErrorMapByIndex[index] = {}; } }); this.columnConfigValid.emit(isValid); } onDrop (columns: GCDashboards.SimpleColumn[]) { this._columns = columns; this.setColumnOptionsMap(); this.emitColumnsChanged(); } async setColumnOptions () { const currentBuckets = this.adHocReportingService.getBuckets( this.object, this.recordIds || [], [], AdHocReportingUI.Usage.DASHBOARDS ); this.allColumns = currentBuckets.reduce((acc, bucket) => { return [ ...acc, ...bucket.allColumns ]; }, [] as AdHocReportingUI.ColumnImplementation[]); if (this.isForRecordSummary) { this.allColumns = this.allColumns.filter(column => { return column.definition.canBeUsedForRecordSummary; }); } this.allColumnOptions = this.arrayHelper.sort( this.allColumns.filter(col => !col.definition.dashboardOnly).map(column => { const def = column.definition; const columnDisplay = def.display; return { label: `${column.definition.display} (${column.definition.parentBucketName})`, htmlLabel: this.dashboardsService.getHtmlColumnLabel( columnDisplay, column.definition.parentBucketName ), value: `${column.definition.parentBucket}.${column.definition.column}`, option: this.dashboardsService.getHtmlOptionLabel( columnDisplay, column.definition.parentBucketName ) }; }), 'label' ); this.setColumnOptionsMap(); } setColumnOptionsMap () { this.columnOptionsMap = this._columns.reduce((acc, selectedCol, index) => { return { ...acc, [index]: this.allColumnOptions.filter(fetchedColumn => { const previouslyPickedthisItem = fetchedColumn.value === selectedCol.column; const pickedInAnotherRow = this._columns.some(_item => { return _item.column === fetchedColumn.value; }); return (previouslyPickedthisItem || !pickedInAnotherRow); }) }; }, {}); } columnHeaderChanged () { this.emitColumnsChanged(); } columnChanged (index: number) { const column = this._columns[index]; const found = this.allColumns.find((col) => { return this.isSameColumn(column.column, col.definition); }); let columnNameOverride = ''; if (found) { columnNameOverride = this.includeBucketNameInOverride ? `${found.definition.display} (${found.definition.parentBucketName})` : found.definition.display; } const updatedColumn = { ...column, columnNameOverride }; this._columns = [ ...this._columns.slice(0, index), updatedColumn, ...this._columns.slice(index + 1) ]; this.emitColumnsChanged(); } isSameColumn ( thisColumn: string, compareColumn: AdHocReportingUI.ColumnDefinition ) { return thisColumn === `${compareColumn.parentBucket}.${compareColumn.column}`; } addColumn () { this._columns = [ ...this._columns, { column: '', columnNameOverride: '' } ]; this.setColumnOptionsMap(); this.emitColumnsChanged(); } removeColumn (index: number) { this._columns = [ ...this._columns.slice(0, index), ...this._columns.slice(index + 1) ]; this.setColumnOptionsMap(); this.emitColumnsChanged(); } emitColumnsChanged () { this.setValidity(); this.columnsChanged.emit(this._columns); } }