import { Observable } from 'rxjs' import { combineEpics, ActionsObservable } from 'redux-observable' import { Store } from 'redux' import { uniq, chain, get, map } from 'lodash' import * as api from './api' import * as actions from './actions' import * as selectors from './selectors' import * as helpers from './helpers' import { IActivity } from '../activity/interfaces' import { IActivityGroup } from '../activityGroups/interfaces' import * as ActivityActions from '../activity/actions' import * as SettingsActions from '../settings/actions' import * as UserPropertiesActions from '../userProperties/actions' import * as ActivityGroupActions from '../activityGroups/actions' import * as EndUsersActions from '../endUsers/actions' import { IEndUser } from '../endUsers/interfaces' import { IUserProperties } from '../userProperties/interfaces' import { ImagePayload } from './interfaces' const emailsFromActivities$ = (action$: ActionsObservable) => { return action$.ofType( ActivityActions.receiveActivities.toString(), ActivityActions.fetchActivitiesSuccess.toString(), ActivityActions.fetchActivitiesByEmailSuccess.toString(), ) .pluck('payload') .map((activities: IActivity[]) => { return uniq(activities.map(activity => activity.email)) }) } const emailsFromActivityGroups$ = (action$: ActionsObservable) => { return action$.ofType( ActivityGroupActions.receiveActivityGroups.toString(), ActivityGroupActions.fetchActivityGroupsSuccess.toString(), ActivityGroupActions.fetchActivityGroupsByEmailSuccess.toString(), ) .pluck('payload') .map((activityGroups: IActivityGroup[]) => chain(activityGroups).map(activityGroup => activityGroup.email) .uniq() .value()) } const emailsFromEndUsers$ = (action$: ActionsObservable) => { return action$.ofType( EndUsersActions.fetchEndUsersSuccess.toString(), ) .pluck('payload') .map((endUsers: IEndUser[]) => chain(endUsers).map('email').uniq().compact().value()) } const updateEnduser$ = (action$: ActionsObservable) => { return action$.ofType( EndUsersActions.updateEndUser.toString(), ).pluck('payload') .map((endUser: IEndUser) => { return endUser.email }) } export const emailsFromDomainMuteList = (action$: ActionsObservable) => { return action$.ofType( UserPropertiesActions.fetchUserPropertiesSuccess.toString(), ) .pluck('payload') .map((userProperties: IUserProperties) => { const domainMuteList = get(userProperties, ['extensionSettings', 'domainMuteList'], []) return map(domainMuteList, 'domain') }) } export const emailsFromNewDomain = (action$: ActionsObservable) => { return action$.ofType( SettingsActions.addDomainToMuteList.toString(), ) .pluck('payload') .map(domain => domain ? [domain] : []) } export const fetchGravatarsEpic = (action$: ActionsObservable, store: Store) => { return Observable.merge( emailsFromActivities$(action$), emailsFromActivityGroups$(action$), emailsFromEndUsers$(action$), updateEnduser$(action$), ) .flatMap(emails => emails) .filter((email: string) => { const gravatarStatusByEmail = selectors.gravatarStatusByEmail(store.getState()) return !gravatarStatusByEmail.hasOwnProperty(email) }) .mergeMap((email: string) => { return api.fetchGravatar(email) .map(({ url, dataUrl }: ImagePayload) => actions.fetchGravatarSuccess({ email, avatarUrl: url, avatarDataUrl: dataUrl, })) .startWith(actions.fetchGravatarPending({ email })) .catch(() => Observable.of(actions.fetchGravatarFailure({ email }))) }) } export const fetchCompanyLogosEpic = (action$: ActionsObservable, store: Store) => { return Observable.merge( emailsFromActivities$(action$), emailsFromActivityGroups$(action$), emailsFromDomainMuteList(action$), emailsFromNewDomain(action$), ) .flatMap((emails: string[]) => { return uniq(emails.map(email => helpers.extractDomain(email))) }) .filter((domain) => { const companyLogoStatusByDomain = selectors.companyLogoStatusByDomain(store.getState()) return !companyLogoStatusByDomain.hasOwnProperty(domain) }) .mergeMap((domain) => { return api.fetchCompanyLogo(domain) .map(({ url, dataUrl }: ImagePayload) => actions.fetchCompanyLogoSuccess({ domain, logoUrl: url, logoDataUrl: dataUrl, })) .startWith(actions.fetchCompanyLogoPending({ domain })) .catch(() => Observable.of(actions.fetchCompanyLogoFailure({ domain }))) }) } export const epic = combineEpics( fetchGravatarsEpic, fetchCompanyLogosEpic, )