import { ApiResponse , ApiResponseResult , ApiResponseAggregations } from '../models/api-response' ; import * as apiAction from '../actions/api' ; import * as paginationAction from '../actions/pagination' ; prop prop prop prop prop export interface State { pages : ApiResponse [ ] ; entities : ApiResponseResult [ ] ; hashtags : Array < { tag : string ; count : number ; } > ; aggregations : ApiResponseAggregations ; valid : boolean ; } prop prop prop prop prop export const initialState = { pages : [ ] , entities : [ ] , hashtags : [ ] , aggregations : null , valid : true , } ; /**
 * The actual reducer function. Reducers can be thought of as the tables in the DataBase.
 * These are the functions which are responsible for maintaing, and updating the
 * `State` of the application they control.
 *
 * Here the reducer controls the part of state which is responsilble for storing the
 * results fetched from the API.
 */ export function reducer ( state = initialState , action ) { switch ( action . type ) { case apiAction . ActionTypes . SEARCH_COMPLETE_SUCCESS : { const apiResponse = action . payload ; const tagStrings = [ ] . concat ( ... apiResponse . statuses . map ( item => item . hashtags ) ) ; const hashtags = Array . from ( new Set ( tagStrings ) ) . map ( tag => { return { tag , count : tagStrings . filter ( y => y === tag ) . length } ; } ) ; return Object . assign ( { } , state , { pages : [ apiResponse ] , entities : apiResponse . statuses , aggregations : apiResponse . aggregations , hashtags , valid : true } ) ; } case apiAction . ActionTypes . SEARCH_COMPLETE_FAIL : { return Object . assign ( { } , state , { valid : false } ) ; } case paginationAction . ActionTypes . PAGINATION_COMPLETE_SUCCESS : { const apiResponse = action . payload ; const oldTagStrings = state . hashtags . map ( hashtag => hashtag . tag ) ; const tagStrings = oldTagStrings . concat ( ... apiResponse . statuses . map ( item => item . hashtags ) ) ; const hashtags = Array . from ( new Set ( tagStrings ) ) . map ( tag => { return { tag , count : tagStrings . filter ( y => y === tag ) . length } ; } ) ; return Object . assign ( { } , state , { pages : [ ... state . pages , apiResponse ] , entities : [ ... state . entities , ... apiResponse . statuses ] , aggregations : apiResponse . aggregations || state . aggregations , hashtags : [ ... hashtags ] , valid : true } ) ; } case paginationAction . ActionTypes . PAGINATION_COMPLETE_FAIL : { return state ; } default : { return state ; } } } /**
 * Because the data structure is defined within the reducer it is optimal to
 * locate our selector functions at this level. If store is to be thought of
 * as a database, and reducers the tables, selectors can be considered the
 * queries into said database. Remember to keep your selectors small and
 * focused so they can be combined and composed to fit each particular
 * use-case.
 */ export const getEntities = ( state ) => state . entities ; export const getPages = ( state ) => state . pages ; export const getHashtags = ( state ) => state . hashtags ; export const isResultValid = ( state ) => state . valid ; export const lastRecord = ( state ) => state . entities . length - 1 ; export const getAggregations = ( state ) => state . aggregations ;