import { Injectable, OnDestroy } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Subject, of } from 'rxjs'; import { map, mergeMap, catchError, withLatestFrom, takeUntil } from 'rxjs/operators'; import { Location } from '@angular/common'; import { environment, API_URL } from '../../../environments/environment'; import { LoggerService } from '../../shared/services/logger.service'; import { SessionService } from '../../shared/services/session.service'; import { CommonService } from '../../shared/services/common.service'; import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component'; import { GetInfo, Channel, OnChainBalance, LightningBalance, ChannelsStatus, ChannelStats, Peer, Audit, Transaction, Invoice } from '../../shared/models/eclModels'; import * as fromRTLReducer from '../../store/rtl.reducers'; import * as fromECLReducer from './ecl.reducers'; import * as ECLActions from './ecl.actions'; import * as RTLActions from '../../store/rtl.actions'; import { ECLInvoiceInformationComponent } from '../transactions/invoice-information-modal/invoice-information.component'; @Injectable() export class ECLEffects implements OnDestroy { CHILD_API_URL = API_URL + '/ecl'; private unSubs: Array> = [new Subject(), new Subject()]; constructor( private actions$: Actions, private httpClient: HttpClient, private store: Store, private sessionService: SessionService, private logger: LoggerService, private commonService: CommonService, private router: Router, private location: Location) { this.store.select('ecl') .pipe(takeUntil(this.unSubs[0])) .subscribe((rtlStore) => { if(rtlStore.initialAPIResponseStatus[0] === 'INCOMPLETE' && rtlStore.initialAPIResponseStatus.length > 4) { // Num of Initial APIs + 1 rtlStore.initialAPIResponseStatus[0] = 'COMPLETE'; this.store.dispatch(new RTLActions.CloseSpinner()); } }); } @Effect() infoFetchECL = this.actions$.pipe( ofType(ECLActions.FETCH_INFO_ECL), withLatestFrom(this.store.select('root')), mergeMap(([action, store]: [ECLActions.FetchInfo, fromRTLReducer.RootState]) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchInfo')); return this.httpClient.get(this.CHILD_API_URL + environment.GETINFO_API) .pipe( takeUntil(this.actions$.pipe(ofType(RTLActions.SET_SELECTED_NODE))), map((info) => { this.logger.info(info); this.initializeRemainingData(info, action.payload.loadPage); return { type: ECLActions.SET_INFO_ECL, payload: info ? info : {} }; }), catchError((err) => { const code = (err.error && err.error.error && err.error.error.message && err.error.error.message.code) ? err.error.error.message.code : (err.error && err.error.error && err.error.error.code) ? err.error.error.code : err.status ? err.status : ''; const message = ((err.error && err.error.message) ? err.error.message + ' ' : '') + ((err.error && err.error.error && err.error.error.error && typeof err.error.error.error === 'string') ? err.error.error.error : (err.error && err.error.error && err.error.error.errno && typeof err.error.error.errno === 'string') ? err.error.error.errno : (err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error : (err.error && typeof err.error === 'string') ? err.error : 'Unknown Error'); this.router.navigate(['/error'], { state: { errorCode: code, errorMessage: message }}); this.handleErrorWithoutAlert('FetchInfo', 'Fetching Node Info Failed.', err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() fetchFees = this.actions$.pipe( ofType(ECLActions.FETCH_FEES_ECL), mergeMap((action: ECLActions.FetchFees) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchFees')); return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API + '/fees') .pipe(map((fees: any) => { this.logger.info(fees); return { type: ECLActions.SET_FEES_ECL, payload: fees ? fees : {} }; }, catchError((err: any) => { this.handleErrorWithoutAlert('FetchFees', 'Fetching Fees Failed.', err); return of({type: RTLActions.VOID}); }) )); } )); @Effect() fetchPayments = this.actions$.pipe( ofType(ECLActions.FETCH_PAYMENTS_ECL), mergeMap((action: ECLActions.FetchPayments) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchPayments')); return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API + '/payments') .pipe(map((payments: any) => { this.logger.info(payments); return { type: ECLActions.SET_PAYMENTS_ECL, payload: payments ? payments : {} }; }, catchError((err: any) => { this.handleErrorWithoutAlert('FetchPayments', 'Fetching Payments Failed.', err); return of({type: RTLActions.VOID}); }) )); } )); @Effect() channelsFetch = this.actions$.pipe( ofType(ECLActions.FETCH_CHANNELS_ECL), mergeMap((action: ECLActions.FetchChannels) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchChannels')); return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API) .pipe(map((channelsRes: {activeChannels: Channel[], pendingChannels: Channel[], inactiveChannels: Channel[], lightningBalances: LightningBalance, channelStatus: ChannelsStatus}) => { this.logger.info(channelsRes); this.store.dispatch(new ECLActions.SetActiveChannels((channelsRes && channelsRes.activeChannels.length > 0) ? channelsRes.activeChannels : [])); this.store.dispatch(new ECLActions.SetPendingChannels((channelsRes && channelsRes.pendingChannels.length > 0) ? channelsRes.pendingChannels : [])); this.store.dispatch(new ECLActions.SetInactiveChannels((channelsRes && channelsRes.inactiveChannels.length > 0) ? channelsRes.inactiveChannels : [])); this.store.dispatch(new ECLActions.SetLightningBalance(channelsRes.lightningBalances)); if (action.payload.fetchPayments) { this.store.dispatch(new ECLActions.FetchPayments()); } return { type: ECLActions.SET_CHANNELS_STATUS_ECL, payload: channelsRes.channelStatus }; }, catchError((err: any) => { this.handleErrorWithoutAlert('FetchChannels', 'Fetching Channels Failed.', err); return of({type: RTLActions.VOID}); }) )); } )); @Effect() channelStatsFetch = this.actions$.pipe( ofType(ECLActions.FETCH_CHANNEL_STATS_ECL), mergeMap((action: ECLActions.FetchChannelStats) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchChannelStats')); return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/stats') .pipe(map((channelStats: ChannelStats[]) => { this.logger.info(channelStats); return { type: ECLActions.SET_CHANNEL_STATS_ECL, payload: (channelStats && channelStats.length > 0) ? channelStats : [] }; }, catchError((err: any) => { this.handleErrorWithoutAlert('FetchChannelStats', 'Fetching Channel Stats Failed.', err); return of({type: RTLActions.VOID}); }) )); } )); @Effect() fetchOnchainBalance = this.actions$.pipe( ofType(ECLActions.FETCH_ONCHAIN_BALANCE_ECL), mergeMap((action: ECLActions.FetchOnchainBalance) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchOnchainBalance')); return this.httpClient.get(this.CHILD_API_URL + environment.ON_CHAIN_API + '/balance'); }), map((balance) => { this.logger.info(balance); return { type: ECLActions.SET_ONCHAIN_BALANCE_ECL, payload: balance ? balance : {} }; }), catchError((err: any) => { this.handleErrorWithoutAlert('FetchOnchainBalance', 'Fetching Onchain Balances Failed.', err); return of({type: RTLActions.VOID}); } )); @Effect() peersFetch = this.actions$.pipe( ofType(ECLActions.FETCH_PEERS_ECL), mergeMap((action: ECLActions.FetchPeers) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchPeers')); return this.httpClient.get(this.CHILD_API_URL + environment.PEERS_API) .pipe( map((peers: Peer[]) => { this.logger.info(peers); return { type: ECLActions.SET_PEERS_ECL , payload: peers && peers.length ? peers : [] }; }), catchError((err: any) => { this.handleErrorWithoutAlert('FetchPeers', 'Fetching Peers Failed.', err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() getNewAddress = this.actions$.pipe( ofType(ECLActions.GET_NEW_ADDRESS_ECL), mergeMap((action: ECLActions.GetNewAddress) => { return this.httpClient.get(this.CHILD_API_URL + environment.ON_CHAIN_API) .pipe(map((newAddress: any) => { this.logger.info(newAddress); this.store.dispatch(new RTLActions.CloseSpinner()); return { type: ECLActions.SET_NEW_ADDRESS_ECL, payload: newAddress }; }), catchError((err: any) => { this.handleErrorWithAlert('ERROR', 'Generate New Address Failed', this.CHILD_API_URL + environment.ON_CHAIN_API, err); return of({type: RTLActions.VOID}); })); }) ); @Effect({ dispatch: false }) setNewAddress = this.actions$.pipe( ofType(ECLActions.SET_NEW_ADDRESS_ECL), map((action: ECLActions.SetNewAddress) => { this.logger.info(action.payload); return action.payload; }) ); @Effect() saveNewPeer = this.actions$.pipe( ofType(ECLActions.SAVE_NEW_PEER_ECL), withLatestFrom(this.store.select('ecl')), mergeMap(([action, eclData]: [ECLActions.SaveNewPeer, fromECLReducer.ECLState]) => { this.store.dispatch(new ECLActions.ClearEffectError('SaveNewPeer')); return this.httpClient.post(this.CHILD_API_URL + environment.PEERS_API + ((action.payload.id.includes('@') ? '?uri=' : '?nodeId=') + action.payload.id), {}) .pipe( map((postRes: Peer[]) => { this.logger.info(postRes); this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new ECLActions.SetPeers((postRes && postRes.length) ? postRes : [])); return { type: ECLActions.NEWLY_ADDED_PEER_ECL, payload: { peer: postRes[0] } }; }), catchError((err: any) => { this.handleErrorWithoutAlert('SaveNewPeer', 'Peer Connection Failed.', err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() detachPeer = this.actions$.pipe( ofType(ECLActions.DETACH_PEER_ECL), mergeMap((action: ECLActions.DisconnectPeer) => { return this.httpClient.delete(this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.nodeId) .pipe( map((postRes: any) => { this.logger.info(postRes); this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.OpenSnackBar('Disconnecting Peer!')); return { type: ECLActions.REMOVE_PEER_ECL, payload: { nodeId: action.payload.nodeId } }; }), catchError((err: any) => { this.handleErrorWithAlert('ERROR', 'Unable to Detach Peer. Try again later.', this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.nodeId, err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() openNewChannel = this.actions$.pipe( ofType(ECLActions.SAVE_NEW_CHANNEL_ECL), mergeMap((action: ECLActions.SaveNewChannel) => { this.store.dispatch(new ECLActions.ClearEffectError('SaveNewChannel')); const reqBody = action.payload.feeRate && action.payload.feeRate > 0 ? { nodeId: action.payload.nodeId, fundingSatoshis: action.payload.amount, channelFlags: +!action.payload.private, fundingFeerateSatByte: action.payload.feeRate } : { nodeId: action.payload.nodeId, fundingSatoshis: action.payload.amount, channelFlags: +!action.payload.private} return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API, reqBody) .pipe( map((postRes: any) => { this.logger.info(postRes); this.store.dispatch(new ECLActions.FetchPeers()); this.store.dispatch(new ECLActions.FetchOnchainBalance()); this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.OpenSnackBar('Channel Added Successfully!')); return { type: ECLActions.FETCH_CHANNELS_ECL }; }), catchError((err: any) => { this.handleErrorWithoutAlert('SaveNewChannel', 'Opening Channel Failed.', err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() updateChannel = this.actions$.pipe( ofType(ECLActions.UPDATE_CHANNELS_ECL), mergeMap((action: ECLActions.UpdateChannels) => { let queryParam = '?feeBaseMsat=' + action.payload.baseFeeMsat + '&feeProportionalMillionths=' + action.payload.feeRate; if (action.payload.channelIds) { queryParam = queryParam + '&channelIds=' + action.payload.channelIds; } else { queryParam = queryParam + '&channelId=' + action.payload.channelId; } return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API + '/updateRelayFee' + queryParam, {}) .pipe( map((postRes: any) => { this.logger.info(postRes); this.store.dispatch(new RTLActions.CloseSpinner()); if(action.payload.channelIds) { this.store.dispatch(new RTLActions.OpenSnackBar('Channels Updated Successfully.')); } else { this.store.dispatch(new RTLActions.OpenSnackBar('Channel Updated Successfully!')); } return { type: ECLActions.FETCH_CHANNELS_ECL }; }), catchError((err: any) => { this.handleErrorWithAlert('ERROR', 'Update Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() closeChannel = this.actions$.pipe( ofType(ECLActions.CLOSE_CHANNEL_ECL), mergeMap((action: ECLActions.CloseChannel) => { return this.httpClient.delete(this.CHILD_API_URL + environment.CHANNELS_API + '?channelId=' + action.payload.channelId + '&force=' + action.payload.force) .pipe( map((postRes: any) => { this.logger.info(postRes); setTimeout(() => { this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new ECLActions.FetchChannels({fetchPayments: false})); this.store.dispatch(new RTLActions.OpenSnackBar('Channel Closed Successfully!')); }, 2000); return { type: RTLActions.VOID }; }), catchError((err: any) => { this.handleErrorWithAlert('ERROR', 'Unable to Close Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_API, err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() queryRoutesFetch = this.actions$.pipe( ofType(ECLActions.GET_QUERY_ROUTES_ECL), mergeMap((action: ECLActions.GetQueryRoutes) => { return this.httpClient.get(this.CHILD_API_URL + environment.PAYMENTS_API + '/route?nodeId=' + action.payload.nodeId + '&amountMsat=' + action.payload.amount) .pipe( map((qrRes: any) => { this.logger.info(qrRes); return { type: ECLActions.SET_QUERY_ROUTES_ECL, payload: qrRes }; }), catchError((err: any) => { this.store.dispatch(new ECLActions.SetQueryRoutes([])); this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.PAYMENTS_API + '/route?nodeId=' + action.payload.nodeId + '&amountMsat=' + action.payload.amount, err); return of({type: RTLActions.VOID}); }) ); } )); @Effect({ dispatch: false }) setQueryRoutes = this.actions$.pipe( ofType(ECLActions.SET_QUERY_ROUTES_ECL), map((action: ECLActions.SetQueryRoutes) => { return action.payload; }) ); @Effect() sendPayment = this.actions$.pipe( ofType(ECLActions.SEND_PAYMENT_ECL), withLatestFrom(this.store.select('root')), mergeMap(([action, store]: [ECLActions.SendPayment, any]) => { this.store.dispatch(new ECLActions.ClearEffectError('SendPayment')); return this.httpClient.post(this.CHILD_API_URL + environment.PAYMENTS_API, action.payload) .pipe( map((sendRes: any) => { this.logger.info(sendRes); if (sendRes.error) { this.store.dispatch(new RTLActions.CloseSpinner()); this.logger.error('Error: ' + sendRes.payment_error); const myErr = {status: sendRes.payment_error.status, error: sendRes.payment_error.error && sendRes.payment_error.error.error && typeof(sendRes.payment_error.error.error) === 'object' ? sendRes.payment_error.error.error : {error: sendRes.payment_error.error && sendRes.payment_error.error.error ? sendRes.payment_error.error.error : 'Unknown Error'}}; if (action.payload.fromDialog) { this.handleErrorWithoutAlert('SendPayment', 'Send Payment Failed.', myErr); } else { this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, myErr); } return of({type: RTLActions.VOID}); } else { setTimeout(() => { this.store.dispatch(new ECLActions.SendPaymentStatus(sendRes)); this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new ECLActions.FetchChannels({fetchPayments: true})); this.store.dispatch(new ECLActions.FetchPayments()); this.store.dispatch(new RTLActions.OpenSnackBar('Payment Submitted!')); }, 3000); return { type: RTLActions.VOID }; } }), catchError((err: any) => { this.logger.error('Error: ' + JSON.stringify(err)); const myErr = {status: err.status, error: err.error && err.error.error && typeof(err.error.error) === 'object' ? err.error.error : {error: err.error && err.error.error ? err.error.error : 'Unknown Error'}}; if (action.payload.fromDialog) { this.handleErrorWithoutAlert('SendPayment', 'Send Payment Failed.', myErr); } else { this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.PAYMENTS_API, myErr); } return of({type: RTLActions.VOID}); }) ); }) ); @Effect() transactionsFetch = this.actions$.pipe( ofType(ECLActions.FETCH_TRANSACTIONS_ECL), mergeMap((action: ECLActions.FetchTransactions) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchTransactions')); return this.httpClient.get(this.CHILD_API_URL + environment.ON_CHAIN_API + '/transactions?count=1000&skip=0'); }), map((transactions) => { this.logger.info(transactions); return { type: ECLActions.SET_TRANSACTIONS_ECL, payload: (transactions && transactions.length > 0) ? transactions : [] }; }), catchError((err: any) => { this.handleErrorWithoutAlert('FetchTransactions', 'Fetching Transactions Failed.', err); return of({type: RTLActions.VOID}); } )); @Effect() SendOnchainFunds = this.actions$.pipe( ofType(ECLActions.SEND_ONCHAIN_FUNDS_ECL), mergeMap((action: ECLActions.SendOnchainFunds) => { this.store.dispatch(new ECLActions.ClearEffectError('SendOnchainFunds')); return this.httpClient.post(this.CHILD_API_URL + environment.ON_CHAIN_API, action.payload) .pipe(map((postRes: any) => { this.logger.info(postRes); this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new ECLActions.FetchOnchainBalance()); return { type: ECLActions.SEND_ONCHAIN_FUNDS_RES_ECL, payload: postRes }; }), catchError((err: any) => { this.handleErrorWithoutAlert('SendOnchainFunds', 'Sending Fund Failed.', err); return of({type: RTLActions.VOID}); })); }) ); @Effect() createInvoice = this.actions$.pipe( ofType(ECLActions.CREATE_INVOICE_ECL), mergeMap((action: ECLActions.CreateInvoice) => { this.store.dispatch(new ECLActions.ClearEffectError('CreateInvoice')); return this.httpClient.post(this.CHILD_API_URL + environment.INVOICES_API, action.payload) .pipe(map((postRes: Invoice) => { this.logger.info(postRes); this.store.dispatch(new RTLActions.CloseSpinner()); postRes.amount = action.payload.amountMsat; postRes.timestamp = new Date().getTime() / 1000; postRes.timestampStr = this.commonService.convertTimestampToDate(+postRes.timestamp); postRes.expiresAt = Math.round(postRes.timestamp + action.payload.expireIn); postRes.expiresAtStr = this.commonService.convertTimestampToDate(+postRes.expiresAt); postRes.description = action.payload.description; postRes.status = 'unpaid'; this.store.dispatch(new RTLActions.OpenAlert({ data: { invoice: postRes, newlyAdded: false, component: ECLInvoiceInformationComponent }})); return { type: ECLActions.FETCH_INVOICES_ECL }; }), catchError((err: any) => { this.handleErrorWithoutAlert('CreateInvoice', 'Create Invoice Failed.', err); return of({type: RTLActions.VOID}); }) ); } )); @Effect() invoicesFetch = this.actions$.pipe( ofType(ECLActions.FETCH_INVOICES_ECL), mergeMap((action: ECLActions.FetchInvoices) => { this.store.dispatch(new ECLActions.ClearEffectError('FetchInvoices')); return this.httpClient.get(this.CHILD_API_URL + environment.INVOICES_API) .pipe(map((res: Invoice[]) => { this.logger.info(res); return { type: ECLActions.SET_INVOICES_ECL, payload: res }; }), catchError((err: any) => { this.handleErrorWithoutAlert('FetchInvoices', 'Fetching Invoices Failed.', err); return of({type: RTLActions.VOID}); } )); })); @Effect() peerLookup = this.actions$.pipe( ofType(ECLActions.PEER_LOOKUP_ECL), mergeMap((action: ECLActions.PeerLookup) => { this.store.dispatch(new ECLActions.ClearEffectError('Lookup')); return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/nodes/' + action.payload) .pipe( map((resPeer) => { this.logger.info(resPeer); this.store.dispatch(new RTLActions.CloseSpinner()); return { type: ECLActions.SET_LOOKUP_ECL, payload: resPeer }; }), catchError((err: any) => { this.store.dispatch(new ECLActions.EffectError({ action: 'Lookup', code: err.status, message: err.error.message })); this.handleErrorWithAlert('ERROR', 'Peer Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/nodes/' + action.payload, err); return of({type: RTLActions.VOID}); }) ); }) ); @Effect({ dispatch: false }) setLookup = this.actions$.pipe( ofType(ECLActions.SET_LOOKUP_ECL), map((action: ECLActions.SetLookup) => { this.logger.info(action.payload); return action.payload; }) ); initializeRemainingData(info: any, landingPage: string) { this.sessionService.setItem('eclUnlocked', 'true'); const node_data = { identity_pubkey: info.nodeId, alias: info.alias, testnet: info.network === 'testnet', chains: info.publicAddresses, uris: info.uris, version: info.version, currency_unit: 'BTC', smaller_currency_unit: 'Sats', numberOfPendingChannels: 0 }; this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node Data...')); this.store.dispatch(new RTLActions.SetNodeData(node_data)); this.store.dispatch(new ECLActions.FetchChannels({fetchPayments: true})); this.store.dispatch(new ECLActions.FetchFees()); this.store.dispatch(new ECLActions.FetchOnchainBalance()); this.store.dispatch(new ECLActions.FetchPeers()); let newRoute = this.location.path(); if(newRoute.includes('/lnd/')) { newRoute = newRoute.replace('/lnd/', '/ecl/'); } else if (newRoute.includes('/cl/')) { newRoute = newRoute.replace('/cl/', '/ecl/'); } if (newRoute.includes('/login') || newRoute.includes('/error') || newRoute === '' || landingPage === 'HOME' || newRoute.includes('?access-key=')) { newRoute = '/ecl/home'; } this.router.navigate([newRoute]); } handleErrorWithoutAlert(actionName: string, genericErrorMessage: string, err: { status: number, error: any }) { this.logger.error('ERROR IN: ' + actionName + '\n' + JSON.stringify(err)); if (err.status === 401) { this.logger.info('Redirecting to Login'); this.store.dispatch(new RTLActions.CloseAllDialogs()); this.store.dispatch(new RTLActions.Logout()); this.store.dispatch(new RTLActions.OpenSnackBar('Authentication Failed. Redirecting to Login.')); } else { this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new ECLActions.EffectError({ action: actionName, code: err.status.toString(), message: (err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error : genericErrorMessage })); } } handleErrorWithAlert(alerType: string, alertTitle: string, errURL: string, err: { status: number, error: any }) { this.logger.error(err); if (err.status === 401) { this.logger.info('Redirecting to Login'); this.store.dispatch(new RTLActions.CloseAllDialogs()); this.store.dispatch(new RTLActions.Logout()); this.store.dispatch(new RTLActions.OpenSnackBar('Authentication Failed. Redirecting to Login.')); } else { this.store.dispatch(new RTLActions.CloseSpinner()); this.store.dispatch(new RTLActions.OpenAlert({ data: { type: alerType, alertTitle: alertTitle, message: { code: err.status, message: (err.error.error && err.error.error.error && err.error.error.error.error && typeof err.error.error.error.error === 'string') ? err.error.error.error.error : (err.error.error && err.error.error.error && typeof err.error.error.error === 'string') ? err.error.error.error : (err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error : typeof err.error === 'string' ? err.error : 'Unknown Error', URL: errURL }, component: ErrorMessageComponent } })); } } ngOnDestroy() { this.unSubs.forEach(completeSub => { completeSub.next(); completeSub.complete(); }); } }