import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { SpinnerService } from '@core/services/spinner.service'; import { ReferenceFieldAPI } from '@core/typings/api/reference-fields.typing'; import { ReferenceFieldsUI } from '@core/typings/ui/reference-fields.typing'; import { ClientSettingsService } from '@features/client-settings/client-settings.service'; import { SimpleNumberMap, TypeaheadSelectOption } from '@yourcause/common'; import { ModalFactory } from '@yourcause/common/modals'; import { CreateEditReferenceFieldModalComponent } from '../create-edit-reference-field-modal/create-edit-reference-field-modal.component'; import { ReferenceFieldsService } from '../services/reference-fields.service'; @Component({ selector: 'gc-data-set-field-configuration', templateUrl: './data-set-field-configuration.component.html', styleUrls: ['./data-set-field-configuration.component.scss'] }) export class DataSetFieldConfigurationComponent implements OnInit { @Input() field: ReferenceFieldAPI.ReferenceFieldBaseModel; @Input() referenceFieldId: number; @Input() pendingKeyToBeCreated: string; @Input() disabled = false; @Output() onHideParentModal = new EventEmitter(); @Output() onValidityChange = new EventEmitter(); @Output() onSubsetFieldsChange = new EventEmitter(); DataSetCollectionType = ReferenceFieldAPI.DataSetCollectionType; rows: ReferenceFieldsUI.TableFieldForUi[]; availableFields: ReferenceFieldAPI.ReferenceFieldDisplayModel[]; availableFieldsMap: SimpleNumberMap; hasExistingFields = false; isValid = false; allOptionsRequired = false; constructor ( private spinnerService: SpinnerService, private referenceFieldService: ReferenceFieldsService, private modalFactory: ModalFactory, private clientSettingsService: ClientSettingsService ) { } get isDisabled () { return this.disabled || this.isStandardProductField; } get refByIdMap () { return this.referenceFieldService.referenceFieldMapById; } get isStandardProductField () { if (this.clientSettingsService.clientSettings.isRootClient) { // Standard Product Field limitations do not apply to the root zone return false; } return this.field?.isStandardProductField ?? false; } async ngOnInit () { this.spinnerService.startSpinner(); await this.getSubsetRows(this.referenceFieldId); this.setAvailableFieldsMapAndValidity(); this.setAllOptionsAreRequired(); this.spinnerService.stopSpinner(); } setAllOptionsAreRequired () { this.allOptionsRequired = this.rows.length && this.rows.every((row) => row.isRequired); } setAvailableFieldsMapAndValidity () { this.availableFields = this.referenceFieldService.getSubsetRowFields( this.field?.formAudience ); this.availableFieldsMap = this.referenceFieldService.getAvailableFieldsMap( this.rows, this.availableFields ); this.hasExistingFields = this.referenceFieldService.getExistingFields( this.rows, this.availableFields ); this.setValidity(); }; setValidity () { this.isValid = this.rows.length > 0 && this.rows.every((row) => row.referenceFieldId); this.onValidityChange.emit(this.isValid); } addExistingField (referenceFieldId?: number) { const columnOrder = this.rows.length; this.rows = [ ...this.rows, this.getBlankRow(columnOrder, referenceFieldId) ]; this.emitSubsetFields(); this.setAvailableFieldsMapAndValidity(); } setRequired (isRequired: boolean) { this.rows = this.rows.map((row) => { return { ...row, isRequired }; }); this.emitSubsetFields(); } emitSubsetFields () { this.onSubsetFieldsChange.emit(this.rows); } async createNewField () { this.onHideParentModal.emit(true); const response = await this.modalFactory.open( CreateEditReferenceFieldModalComponent, { forceIsDataPoint: true, pendingKeyToBeCreated: this.pendingKeyToBeCreated, forcedAudienceSelection: this.field.formAudience } ); if (response) { this.spinnerService.startSpinner(); const newField = await this.referenceFieldService.handleCreateOrUpdateField( null, response.field, response.tableFields, true ); if (newField) { this.addExistingField(newField.referenceFieldId); } this.spinnerService.stopSpinner(); } this.onHideParentModal.emit(false); } fieldChanged (row: ReferenceFieldsUI.TableFieldForUi) { const refId = row.referenceFieldId; if (refId) { row.label = this.refByIdMap[row.referenceFieldId].name; row.isRequired = this.allOptionsRequired; } else { row.label = ''; } this.emitSubsetFields(); this.setAvailableFieldsMapAndValidity(); } removeRow (index: number) { this.rows = [ ...this.rows.slice(0, index), ...this.rows.slice(index + 1) ]; this.emitSubsetFields(); this.setAvailableFieldsMapAndValidity(); } onDrop (rows: ReferenceFieldsUI.TableFieldForUi[]) { this.rows = rows; this.emitSubsetFields(); this.setAvailableFieldsMapAndValidity(); } getBlankRow ( columnOrder: number, referenceFieldId?: number ): ReferenceFieldsUI.TableFieldForUi { const field = this.refByIdMap[referenceFieldId]; return { referenceFieldId: referenceFieldId || null, referenceFieldName: field?.name ?? '', label: field?.name ?? '', isRequired: false, showInTable: true, columnOrder, summarizeData: false, summarizeLabel: '', aggregateColumnReferenceFieldId: null, referenceField: field }; } async getSubsetRows (refFieldId: number) { let subsetRows: ReferenceFieldsUI.TableFieldForUi[] = []; if (refFieldId) { subsetRows = await this.referenceFieldService.setDataPointsForSubset( refFieldId ); } else { subsetRows = []; } this.rows = [ ...subsetRows ]; } }