import { Observable, Observer } from 'rxjs' import { combineEpics, ActionsObservable } from 'redux-observable' import { Store } from 'redux' import { uniq, chain } from 'lodash' import * as api from './api' import * as actions from './actions' import * as selectors from './selectors' import { IProfile } from './interfaces' import * as AuthSelectors from '../auth/selectors' import { SocketCluster, SocketChannel, } from '../socket/constants' import * as ActivityGroupActions from '../activityGroups/actions' import * as EndUsersActions from '../endUsers/actions' import { IActivityGroup } from '../activityGroups/interfaces' import { IEndUser } from '../endUsers/interfaces' import { makeJoinChannelPendingEpic, } from '../socket/epic' const socketJoinPending = makeJoinChannelPendingEpic(SocketCluster.MESSAGES, SocketChannel.ORG_PRIVATE) export const triggerFetchEnrichmentEpic = (action$: ActionsObservable, store: Store) => { return action$.ofType( ActivityGroupActions.receiveActivityGroups.toString(), ActivityGroupActions.fetchActivityGroupsSuccess.toString(), ActivityGroupActions.fetchActivityGroupsByEmailSuccess.toString(), ) .pluck('payload') .map((activityGroups: IActivityGroup[]) => { return uniq(activityGroups.map(activityGroups => activityGroups.email)) }) .map((emails: string[]) => { const statusByEmail = selectors.statusByEmail(store.getState()) return uniq(emails.filter(email => !(email in statusByEmail))) }) .filter(emails => emails.length > 0) .map(emails => actions.fetchEnrichment({ emails })) } const emailsFromEndUsers$ = (action$: ActionsObservable) => { return action$.ofType( EndUsersActions.fetchEndUsersSuccess.toString(), ).pluck('payload') } const updateEnduser$ = (action$: ActionsObservable) => { return action$.ofType( EndUsersActions.updateEndUser.toString(), ).pluck('payload') .map((endUser) => { return [endUser] }) } const triggerFetchEnrichmentFromEndUserEpic = (action$: ActionsObservable, store: Store) => { return Observable.merge( emailsFromEndUsers$(action$), updateEnduser$(action$), ) .map((endUsers: IEndUser[]) => chain(endUsers).map('email').uniq().compact().value()) .map((emails: string[]) => { const statusByEmail = selectors.statusByEmail(store.getState()) return uniq(emails.filter(email => !(email in statusByEmail))) }) .filter(emails => emails.length > 0) .map(emails => actions.fetchEnrichment({ emails })) } export const fetchEnrichmentEpic = (action$: ActionsObservable, store: Store) => { return action$.ofType(actions.fetchEnrichment.toString()) .pluck('payload') .map(({ emails }) => ({ emails, accessToken: AuthSelectors.accessToken(store.getState()), })) .mergeMap(({ emails, accessToken }) => { return api.fetchEnrichment(emails, accessToken) .map(profiles => actions.fetchEnrichmentSuccess({ emails, profiles })) .startWith(actions.fetchEnrichmentPending({ emails })) .catch((error: any) => Observable.of(actions.fetchEnrichmentFailure({ emails, error }))) }) } export const joinPrivateOrgChannelPendingEpic = (action$: ActionsObservable) => { return socketJoinPending(action$) .switchMap(({ channel }) => { return Observable.create((observer: Observer) => { channel.on('new-clearbit-info', (body: IProfile) => { observer.next(actions.receiveProfiles([body])) }) }) }) } export const epic = combineEpics( triggerFetchEnrichmentEpic, triggerFetchEnrichmentFromEndUserEpic, fetchEnrichmentEpic, joinPrivateOrgChannelPendingEpic, )