import { createAction , createReducer , current } from '@reduxjs/toolkit' ; import sortArray from 'array-sort' ; import { Target } from 'office-ui-fabric-react/lib/Callout' ; import { IColumn , IGroup } from 'office-ui-fabric-react/lib/DetailsList' ; import * as strings from 'PortfolioWebPartsStrings' ; import { getObjectValue as get } from 'pp365-shared/lib/helpers/getObjectValue' ; import { DataSource } from 'pp365-shared/lib/models/DataSource' ; import { indexOf , omit , uniq } from 'underscore' ; import { IPortfolioAggregationProps , IPortfolioAggregationState } from './types' ; function arrayMove < T = any > ( arr , old_index , new_index ) { const _arr = [ ... arr ] ; if ( new_index >= _arr . length ) { let k = new_index - _arr . length + 1 ; while ( k -- ) { _arr . push ( undefined ) ; } } _arr . splice ( new_index , 0 , _arr . splice ( old_index , 1 ) [ 0 ] ) ; return _arr ; } export const DATA_FETCHED = createAction < { items : any [ ] ; dataSources ? : DataSource [ ] ; } > ( 'DATA_FETCHED' ) ; export const TOGGLE_COLUMN_FORM_PANEL = createAction < { isOpen : boolean ; column ? : IColumn ; } > ( 'TOGGLE_COLUMN_FORM_PANEL' ) ; export const ADD_COLUMN = createAction < { column : IColumn ; } > ( 'ADD_COLUMN' ) ; export const DELETE_COLUMN = createAction ( 'DELETE_COLUMN' ) ; export const COLUMN_HEADER_CONTEXT_MENU = createAction < { column : IColumn ; target : Target ; } > ( 'COLUMN_HEADER_CONTEXT_MENU' ) ; export const SET_GROUP_BY = createAction < { column : IColumn ; } > ( 'SET_GROUP_BY' ) ; export const SET_SORT = createAction < { column : IColumn ; sortDesencing : boolean ; } > ( 'SET_SORT' ) ; export const MOVE_COLUMN = createAction < { column : IColumn ; move : number ; } > ( 'MOVE_COLUMN' ) ; export const SET_DATA_SOURCE = createAction < { dataSource : DataSource ; } > ( 'SET_DATA_SOURCE' ) ; export const START_FETCH = createAction ( 'START_FETCH' ) ; export const SEARCH = createAction < { searchTerm : string ; } > ( 'SEARCH' ) ; export const DATA_FETCH_ERROR = createAction < { error : Error ; } > ( 'DATA_FETCH_ERROR' ) ; param props param state const persistColumns = ( props , columns ) => { props . onUpdateProperty ( 'columns' , columns . map ( ( col ) => omit ( col , 'calculatedWidth' , 'currentWidth' ) ) ) ; } ; export const initState = ( props ) : IPortfolioAggregationState => ( { loading : true , dataSource : props . dataSource , dataSources : [ ] , items : [ ] , searchTerm : '' , columns : props . columns || [ ] , groups : null , addColumnPanel : { isOpen : false } } ) ; /**
 * Create reducer for Projects
 */ export default ( props ) => createReducer ( initState ( props ) , { [ DATA_FETCHED . type ] : ( state , { payload } ) => { if ( payload . items ) { state . items = props . postTransform ? props . postTransform ( payload . items ) : payload . items ; state . items = sortArray ( [ ... state . items ] , [ state . sortBy ?. fieldName ? state . sortBy . fieldName : 'SiteTitle' ] , { reverse : state . sortBy ?. isSortedDescending ? state . sortBy . isSortedDescending : false } ) ; state . loading = false ; } if ( payload . dataSources ) state . dataSources = payload . dataSources ; } , [ TOGGLE_COLUMN_FORM_PANEL . type ] : ( state , { payload } ) => { state . editColumn = payload . column || null ; state . addColumnPanel = { isOpen : payload . isOpen } ; } , [ ADD_COLUMN . type ] : ( state , { payload } ) => { if ( state . editColumn ) { state . columns = [ ... state . columns ] . map ( ( c ) => { if ( c . fieldName === payload . column . fieldName ) return payload . column ; return c ; } ) ; } else state . columns = [ ... state . columns , payload . column ] ; state . editColumn = null ; state . addColumnPanel = { isOpen : false } ; state . columnAdded = new Date ( ) . getTime ( ) ; persistColumns ( props , current ( state ) . columns ) ; } , [ DELETE_COLUMN . type ] : ( state ) => { state . columns = state . columns . filter ( ( c ) => c . fieldName !== state . editColumn . fieldName ) ; state . editColumn = null ; state . addColumnPanel = { isOpen : false } ; persistColumns ( props , current ( state ) . columns ) ; } , [ COLUMN_HEADER_CONTEXT_MENU . type ] : ( state , { payload } ) => { state . columnContextMenu = payload ? { column : payload . column , target : payload . target as any } : null ; } , [ SET_GROUP_BY . type ] : ( state , { payload } ) => { state . items = sortArray ( [ ... state . items ] , [ payload . column . fieldName ] ) ; state . groupBy = payload . column ; const groupNames = state . items . map ( ( g ) => get < string > ( g , state . groupBy . fieldName , strings . NotSet ) ) ; const uniqueGroupNames = uniq ( groupNames ) ; state . groups = uniqueGroupNames . sort ( ( a , b ) => ( a > b ? 1 : - 1 ) ) . map ( ( name , idx ) => { const count = groupNames . filter ( ( n ) => n === name ) . length ; const group = { key : `Group_${ idx }` , name : `${ state . groupBy . name }: ${ name }` , startIndex : groupNames . indexOf ( name , 0 ) , count , isShowingAll : count === state . items . length , isDropEnabled : false , isCollapsed : false } ; return group ; } ) ; } , [ SET_SORT . type ] : ( state , { payload } ) => { const { column , sortDesencing } = payload ; state . sortBy = column ; if ( state . groupBy ) { state . groupBy = null ; state . groups = null ; } state . items = sortArray ( [ ... state . items ] , [ column . fieldName ] , { reverse : ! sortDesencing } ) ; state . columns = [ ... state . columns ] . map ( ( col ) => { col . isSorted = col . key === column . key ; if ( col . isSorted ) { col . isSortedDescending = sortDesencing ; } return col ; } ) ; } , [ MOVE_COLUMN . type ] : ( state , { payload } ) => { const index = indexOf ( state . columns . map ( ( c ) => c . fieldName ) , payload . column . fieldName ) ; state . columns = arrayMove ( current ( state ) . columns , index , index + payload . move ) ; persistColumns ( props , current ( state ) . columns ) ; } , [ SET_DATA_SOURCE . type ] : ( state , { payload } ) => { state . dataSource = payload . dataSource . title ; } , [ START_FETCH . type ] : ( state ) => { state . loading = true ; } , [ SEARCH . type ] : ( state , { payload } ) => { state . searchTerm = payload . searchTerm ; } , [ DATA_FETCH_ERROR . type ] : ( state , { payload } ) => { state . error = payload . error ; } } ) ;