<commit_before>import { createAction } from 'redux-actions'
import { combineEpics } from 'redux-observable'
import { regionsSettings } from '../../regions/regionsOperations'
import { ACTION_TYPES as PRICING_ACTION_TYPES } from '../../pricingOperations'
import { timeFormat } from 'd3-time-format'
import * as numeral from 'numeral'
import * as _ from 'lodash'
import { Observable } from 'rxjs/Rx'
import { Direction, NotificationType, PriceMovementTypes, Rate } from '../../types'

const DISMISS_NOTIFICATION_AFTER_X_IN_MS = 6000
export const PRICE_STALE_AFTER_X_IN_MS = 6000

export interface SpotPrice {
  currencyPair: any
  symbol: any
  ratePrecision: number
  currencyChartIsOpening: boolean
  bid: Rate
  ask: Rate
  mid: Rate
  valueDate: Date
  creationTimestamp: Date
  priceMovementType: PriceMovementTypes
  spread: {
    value: number
    formattedValue: string,
  }
  isTradable: boolean,
  priceStale: boolean,
  isTradeExecutionInFlight: boolean,
  notification: any,
}

export enum ACTION_TYPES {
  EXECUTE_TRADE = '@ReactiveTraderCloud/EXECUTE_TRADE',
  TRADE_EXECUTED = '@ReactiveTraderCloud/TRADE_EXECUTED',
  UNDOCK_TILE = '@ReactiveTraderCloud/UNDOCK_TILE',
  TILE_UNDOCKED = '@ReactiveTraderCloud/TILE_UNDOCKED',
  DISPLAY_CURRENCY_CHART = '@ReactiveTraderCloud/DISPLAY_CURRENCY_CHART',
  CURRENCY_CHART_OPENED = '@ReactiveTraderCloud/CURRENCY_CHART_OPENED',
  UPDATE_TILES = '@ReactiveTraderCloud/UPDATE_TILES',
  DISMISS_NOTIFICATION = '@ReactiveTraderCloud/DISMISS_NOTIFICATION',
  PRICING_STALE = '@ReactiveTraderCloud/PRICING_STALE',
}

const stalePriceErrorMessage = 'Pricing is unavailable'

export const executeTrade = createAction(ACTION_TYPES.EXECUTE_TRADE, payload => payload)
export const tradeExecuted = createAction(ACTION_TYPES.TRADE_EXECUTED)
export const undockTile = createAction(ACTION_TYPES.UNDOCK_TILE, payload => payload)
export const tileUndocked = createAction(ACTION_TYPES.TILE_UNDOCKED, payload => payload)
export const displayCurrencyChart = createAction(ACTION_TYPES.DISPLAY_CURRENCY_CHART, payload => payload)
export const currencyChartOpened = createAction(ACTION_TYPES.CURRENCY_CHART_OPENED, payload => payload)
export const updateTiles = createAction(ACTION_TYPES.UPDATE_TILES)
export const dismissNotification = createAction(ACTION_TYPES.DISMISS_NOTIFICATION, payload => payload)
export const stalePricing = createAction(ACTION_TYPES.PRICING_STALE)

export const spotRegionSettings = id => regionsSettings(`${id} Spot`, 370, 155, true)

export function spotTileEpicsCreator(executionService$, pricingService$, referenceDataService$) {
  function executeTradeEpic(action$) {
    return action$.ofType(ACTION_TYPES.EXECUTE_TRADE)
      .flatMap((action) => {
        return executionService$.executeTrade(action.payload)
      })
      .map(tradeExecuted)
  }

  function onPriceUpdateEpic(action$) {
    return action$.ofType(PRICING_ACTION_TYPES.PRICING_SERVICE)
      .map((payload) => {
        _.values(payload.payload).forEach((item: SpotPrice) => {
          // TODO: do it better
          item.currencyPair = item.currencyPair || referenceDataService$.getCurrencyPair(item.symbol)
        })
        return payload
      })
      .map(action => action.payload)
      .map(updateTiles)
  }

  function displayCurrencyChart(action$) {
    return action$.ofType(ACTION_TYPES.DISPLAY_CURRENCY_CHART)
      .flatMap((payload) => {
        return Observable.fromPromise(payload.payload.openFin.displayCurrencyChart(payload.payload.symbol))
      })
      .map((symbol) => {
        return currencyChartOpened(symbol)
      })
  }

  function onTradeExecuted(action$) {
    return action$.ofType(ACTION_TYPES.TRADE_EXECUTED)
      .delay(DISMISS_NOTIFICATION_AFTER_X_IN_MS)
      .map(action => ({ symbol: action.payload.trade.CurrencyPair || action.payload.trade.currencyPair.symbol }))
      .map(dismissNotification)
  }

  return combineEpics(executeTradeEpic, onPriceUpdateEpic, displayCurrencyChart, onTradeExecuted)
}

export const spotTileReducer = (state: any = {}, { type, payload }) => {
  switch (type) {
    case ACTION_TYPES.UPDATE_TILES:
      // TODO: prices shoould not update while execution is in progress
      return _.values(payload).reduce(spotTileAccumulator(state), {})
    case ACTION_TYPES.DISPLAY_CURRENCY_CHART:
      state[payload.symbol].currencyChartIsOpening = true
      return state
    case ACTION_TYPES.CURRENCY_CHART_OPENED:
      state[payload].currencyChartIsOpening = false
      return state
    case ACTION_TYPES.EXECUTE_TRADE:
      state[payload.CurrencyPair].isTradeExecutionInFlight = true
      return state
    case ACTION_TYPES.TRADE_EXECUTED:
      const response = payload
      const symbol = response.hasError ? response.trade.CurrencyPair : response.trade.currencyPair.symbol
      const item = state[symbol]
      item.hasError = response.hasError
      item.isTradeExecutionInFlight = false
      item.notification = buildNotification(response.trade, response.error)
      return state
    case ACTION_TYPES.DISMISS_NOTIFICATION:
      state[payload.symbol].notification = null
      return state
    case ACTION_TYPES.PRICING_STALE:
      const stalePrice = _.pick(state, payload.symbol)
      if (stalePrice) {
        stalePrice[payload.symbol].priceStale = true
        stalePrice[payload.symbol].notification = buildNotification({},  stalePriceErrorMessage)
        return _.assign(state, stalePrice)<commit_msg>made the reducer functions for spot tile more pure<commit_after>import { createAction } from 'redux-actions'
import { combineEpics } from 'redux-observable'
import { regionsSettings } from '../../regions/regionsOperations'
import { ACTION_TYPES as PRICING_ACTION_TYPES } from '../../pricingOperations'
import { timeFormat } from 'd3-time-format'
import * as numeral from 'numeral'
import * as _ from 'lodash'
import { Observable } from 'rxjs/Rx'
import { Direction, NotificationType, PriceMovementTypes, Rate } from '../../types'

const DISMISS_NOTIFICATION_AFTER_X_IN_MS = 6000
export const PRICE_STALE_AFTER_X_IN_MS = 6000

export interface SpotPrice {
  currencyPair: any
  symbol: any
  ratePrecision: number
  currencyChartIsOpening: boolean
  bid: Rate
  ask: Rate
  mid: Rate
  valueDate: Date
  creationTimestamp: Date
  priceMovementType: PriceMovementTypes
  spread: {
    value: number
    formattedValue: string,
  }
  isTradable: boolean,
  priceStale: boolean,
  isTradeExecutionInFlight: boolean,
  notification: any,
}

export enum ACTION_TYPES {
  EXECUTE_TRADE = '@ReactiveTraderCloud/EXECUTE_TRADE',
  TRADE_EXECUTED = '@ReactiveTraderCloud/TRADE_EXECUTED',
  UNDOCK_TILE = '@ReactiveTraderCloud/UNDOCK_TILE',
  TILE_UNDOCKED = '@ReactiveTraderCloud/TILE_UNDOCKED',
  DISPLAY_CURRENCY_CHART = '@ReactiveTraderCloud/DISPLAY_CURRENCY_CHART',
  CURRENCY_CHART_OPENED = '@ReactiveTraderCloud/CURRENCY_CHART_OPENED',
  UPDATE_TILES = '@ReactiveTraderCloud/UPDATE_TILES',
  DISMISS_NOTIFICATION = '@ReactiveTraderCloud/DISMISS_NOTIFICATION',
  PRICING_STALE = '@ReactiveTraderCloud/PRICING_STALE',
}

const stalePriceErrorMessage = 'Pricing is unavailable'

export const executeTrade = createAction(ACTION_TYPES.EXECUTE_TRADE, payload => payload)
export const tradeExecuted = createAction(ACTION_TYPES.TRADE_EXECUTED)
export const undockTile = createAction(ACTION_TYPES.UNDOCK_TILE, payload => payload)
export const tileUndocked = createAction(ACTION_TYPES.TILE_UNDOCKED, payload => payload)
export const displayCurrencyChart = createAction(ACTION_TYPES.DISPLAY_CURRENCY_CHART, payload => payload)
export const currencyChartOpened = createAction(ACTION_TYPES.CURRENCY_CHART_OPENED, payload => payload)
export const updateTiles = createAction(ACTION_TYPES.UPDATE_TILES)
export const dismissNotification = createAction(ACTION_TYPES.DISMISS_NOTIFICATION, payload => payload)
export const stalePricing = createAction(ACTION_TYPES.PRICING_STALE)

export const spotRegionSettings = id => regionsSettings(`${id} Spot`, 370, 155, true)

export function spotTileEpicsCreator(executionService$, pricingService$, referenceDataService$) {
  function executeTradeEpic(action$) {
    return action$.ofType(ACTION_TYPES.EXECUTE_TRADE)
      .flatMap((action) => {
        return executionService$.executeTrade(action.payload)
      })
      .map(tradeExecuted)
  }

  function onPriceUpdateEpic(action$) {
    return action$.ofType(PRICING_ACTION_TYPES.PRICING_SERVICE)
      .map((payload) => {
        _.values(payload.payload).forEach((item: SpotPrice) => {
          // TODO: do it better
          item.currencyPair = item.currencyPair || referenceDataService$.getCurrencyPair(item.symbol)
        })
        return payload
      })
      .map(action => action.payload)
      .map(updateTiles)
  }

  function displayCurrencyChart(action$) {
    return action$.ofType(ACTION_TYPES.DISPLAY_CURRENCY_CHART)
      .flatMap((payload) => {
        return Observable.fromPromise(payload.payload.openFin.displayCurrencyChart(payload.payload.symbol))
      })
      .map((symbol) => {
        return currencyChartOpened(symbol)
      })
  }

  function onTradeExecuted(action$) {
    return action$.ofType(ACTION_TYPES.TRADE_EXECUTED)
      .delay(DISMISS_NOTIFICATION_AFTER_X_IN_MS)
      .map(action => ({ symbol: action.payload.trade.CurrencyPair || action.payload.trade.currencyPair.symbol }))
      .map(dismissNotification)
  }

  return combineEpics(executeTradeEpic, onPriceUpdateEpic, displayCurrencyChart, onTradeExecuted)
}

const changeValueInState = (state, symbol, flagKey, value) => {
  const target = _.pick(state, symbol)
  if (target[symbol] && target[symbol][flagKey]) {
    target[symbol][flagKey] = value
  }
  return _.assign(state, target)
}

export const spotTileReducer = (state: any = {}, { type, payload }) => {
  switch (type) {
    case ACTION_TYPES.UPDATE_TILES:
      // TODO: prices shoould not update while execution is in progress
      return _.values(payload).reduce(spotTileAccumulator(state), {})
    case ACTION_TYPES.DISPLAY_CURRENCY_CHART:
      return changeValueInState(state, payload.symbol, 'currencyChartIsOpening', true)
    case ACTION_TYPES.CURRENCY_CHART_OPENED:
      return changeValueInState(state, payload.symbol, 'currencyChartIsOpening', false)
    case ACTION_TYPES.EXECUTE_TRADE:
      return changeValueInState(state, payload.CurrencyPair, 'isTradeExecutionInFlight', true)
    case ACTION_TYPES.TRADE_EXECUTED:
      const response = payload
      const symbol = response.hasError ? response.trade.CurrencyPair : response.trade.currencyPair.symbol
      const item = state[symbol]
      item.hasError = response.hasError
      item.isTradeExecutionInFlight = false
      item.notification = buildNotification(response.trade, response.error)
      return state
    case ACTION_TYPES.DISMISS_NOTIFICATION:
      return changeValueInState(state, payload.symbol, 'notification', null)
    case ACTION_TYPES.PRICING_STALE:
      const stalePrice = _.pick(state, payload.symbol)
      if (stalePrice) {
        stalePrice[payload.symbol].priceStale = true
        stalePrice[payload.symbol].notification = buildNotification({},  stalePriceErrorMessage)
        return _.assign(state, stalePrice)
{'fraction_non_alphanumeric': 0.09495256846250223, 'fraction_numerical': 0.0026848040093073204, 'mean_word_length': 4.7073544433095, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4035943', 'n_tokens_mistral': 3513, 'n_tokens_neox': 3497, 'n_words': 649}