// Front-end and Back-End use different formats for settings. // Front-end format for settings is more descriptive to allow dynamically creation of the template. But We need to config // Between the two formats to read and save to the backend. // // Example of front-end SBO Settings // const SETTINGS: SBOSettings = { // cheapest: { // title: 'i prefer', // options: [{id: 'cheap', name:'Cheapest', isActive:true}, { id: 'fast', name:'Fastest', isActive: false}], // mutuallyExclusiveOptions: true // }, // typeFilter: { // title: 'packaging', // options: [{id: 'Cut Strips', name:'Cut Strip', isActive: true}, {id:'Reel', name: 'Reel', isActive: false}, {id: 'Arrow Reel', name:'Arrow Reel', isActive: false}] // }, // regionFilter: { // title: 'ships from', // options: [{id:'NAC', name:'America's', isActive: true}, {id:'EUROPE', name:'Europe', isActive: false}, {id: 'ASIA', name:'Asia', isActive: false}] // } // }; // Example of back-end SBO Settings // { // "bomName": "Old_BOM", // "region": "ASIA", // "description": "", // "multiplier": 1, // "lastViewed": "2017-11-07T20:53:56.926+00:00", // "lastUpdated": "2017-11-07T20:53:56.926+00:00", // "lastEdited": "2017-11-07T20:19:24.992+00:00", // "SBOsettings": { // "cheapest": true, // "typeFilter": [], // "regionFilter": [] // } // } import { Injectable } from '@angular/core'; import { SocketsService, UserService, AnalyticsService, SBOSettings, MessageBusService, ApiSocketEmitAction, PaginationParamsModel, BomRegionDto, BomRegion } from '@arrow/bom/core'; import { ConfigService } from '@arrow/bom/config'; import { HttpClient } from '@angular/common/http'; import { DownloadSettingsPayload } from './models/download-settings.model'; import { Observable } from 'rxjs'; @Injectable() export class SettingsService { settings: SBOSettings = { cheapest: { title: 'I Prefer', options: [] }, typeFilter: { title: 'Packaging', options: [] }, regionFilter : { title: 'Ships From', options: [] } }; bomId: string; constructor( private _http: HttpClient, private _sockets: SocketsService, private _messageBus: MessageBusService, private _configService: ConfigService, private _userService: UserService, private _analyticsService: AnalyticsService ) {} private transform4be(settings: SBOSettings, paginationParams: PaginationParamsModel): any { const obj4be: { // Object for backend cheapest: boolean; typeFilter: string[]; regionFilter: string[]; bomId: string; pageNum: number; perPage: number; filter: any; sorting: any; } = { cheapest: settings.cheapest.options.find(opt => opt.id === 'cheap') .isActive, typeFilter: settings.typeFilter.options .filter(opt => opt.isActive) .map(opt => opt.id), regionFilter: settings.regionFilter.options .filter(opt => opt.isActive) .map(opt => opt.id), bomId: this.bomId, pageNum: paginationParams.currentPage, perPage: paginationParams.itemsPerPage, filter: paginationParams.filter, sorting: paginationParams.sorting, }; return obj4be; } private setSboSettings(settings: any): void { this.settings.cheapest = { title: 'I Prefer', options: [ { id: 'cheap', name: 'Cheapest', isActive: settings.cheapest }, { id: 'fast', name: 'Fastest', isActive: !settings.cheapest } ], mutuallyExclusiveOptions: true }; this.settings.typeFilter = { title: 'Packaging', options: [ { id: 'Cut Strip', name: 'Cut Strip', isActive: false }, { id: 'Reel', name: 'Reel', isActive: false }, { id: '', name: 'Other', isActive: false }, { id: 'Arrow Reel', name: 'Arrow Reel', isActive: false } ].map(option => { option.isActive = settings.typeFilter.find( (filterId: string) => filterId === option.id ) === undefined ? false : true; return option; }) }; // Remove the "Arrow Reel" package type if ff for "Arrow Reel" is off if (!this._userService.canArrowReel) { const arwReelIndex = this.settings.typeFilter.options.findIndex( opt => opt.id === 'Arrow Reel' ); this.settings.typeFilter.options.splice(arwReelIndex, 1); } } private setBomRegions(regions: BomRegionDto[]): void { this.settings.regionFilter = { title: 'Ships From', options: [] }; regions.forEach((region: BomRegionDto) => { this.settings.regionFilter.options.push({ id: region.regionName, name: this.mapDtoRegionName2Fe(region.regionName), isActive: region.isSelected, isCurrent: region.isCurrent }) }); } private mapDtoRegionName2Fe(dtoRegionName: string): string { switch (dtoRegionName.toUpperCase()) { case 'NAC': // Arrow.com case 'AC': // MyArrow return "America"; case 'ASIA': // Arrow.com case '?': // MyArrow return "Asia"; case "EUROPE": // Arrow.com case "EU": // MyArrow return "Europe"; default: return dtoRegionName; } } populateBomRegionFullName(bomRegions: BomRegion[]): BomRegion[] { if (bomRegions === null || bomRegions === undefined) return []; bomRegions.forEach(bomRegion => { bomRegion.regionFullName = this.mapDtoRegionName2Fe(bomRegion.regionName); }); return bomRegions; } setMetadata(sboSettings: any) { this.setSboSettings(sboSettings); this._messageBus.to('ch:sbo', { name: 'settings', payload: null }); } setRegions(bomRegions: BomRegionDto[] | []) { this.setBomRegions(bomRegions); this._messageBus.to('ch:sbo', { name: 'settings', payload: null }); } setBomId(id: string) { this.bomId = id; } getSettings(): any { // 'hack' to deep clone a object. // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Deep_Clone if (this.settings) return JSON.parse(JSON.stringify(this.settings)); return false; } saveSettings(settings: SBOSettings, paginationParams: PaginationParamsModel): boolean { // JSON.stringify is a 'hack' to compare two objects because {} === {} is always false. Object.is() is of no use either // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Examples // See: https://stackoverflow.com/questions/1068834/object-comparison-in-javascript const oldSettings = JSON.stringify(this.settings); const newSettings = JSON.stringify(settings); // Check if something changed and save to backend if so, ignore otherwise. if (newSettings === oldSettings) return false; // Update settings with newest value using string version to get a clone instead of reference. this.settings = JSON.parse(newSettings); this._analyticsService.googleTrackInventorySettings( JSON.parse(oldSettings), this.settings ); // Proceed to save data to backend. this._sockets.emitAction(ApiSocketEmitAction.ALTER_SBO_PREFERENCES, this.transform4be(settings, paginationParams)); this._messageBus.to('ch:loader', { payload: true }); return true; } saveDownloadSettings(data: DownloadSettingsPayload): Observable { const url = `${this._configService.apiCoreUrl}/api/user-settings/excel-settings/${data.bomId}`; return this._http.put( url, { includeCrosses: data.includeCrosses, columnsSelected: data.columnsSelected }, { withCredentials: true } ); } }