module Decisions.Update exposing ( update , makeNestedColumnGetter , makeNestedColumnSetter ) import Dict import Decisions.Messages exposing (..) import Decisions.Model exposing (..) import Decisions.Ports import Decisions.PostCellUpdate import InputTable.Update import InputTable.Model exposing (..) import InputTable.Messages import PostVisibleColumns import Utils import String import Set import List.Extra import Navigation type alias Config = { postRowsUrl : String , postVisibleColumnsUrl : String , currentPage : Int } update : Config -> Msg -> Model -> ( Model, Cmd Msg ) update config msg model = case msg of Table tableMsg -> let ( newTableState, tableCmd ) = InputTable.Update.update tableMsg model.tableState postCellData columnId rowId value = let cellData = { columnId = columnId , rowId = rowId , value = value } in Decisions.PostCellUpdate.postCellUpdate config.postRowsUrl cellData postBoolCellData columnId rowId value = let cellData = { columnId = columnId , rowId = rowId , value = value } in Decisions.PostCellUpdate.postBoolCellUpdate config.postRowsUrl cellData postNestedUpdate rowId columnId parentValue childValue = if columnId == "DECISIONS_ID" then postDecisionUpdate config newTableState [ rowId ] parentValue childValue else ( newTableState, Decisions.PostCellUpdate.postNestedUpdate config.postRowsUrl rowId columnId parentValue childValue ) ( tableStateWithRowUpdate, cmd ) = case tableMsg of InputTable.Messages.SetCellValue columnId set rowId multipleValues value -> ( newTableState, postCellData columnId rowId value ) InputTable.Messages.SetBoolCellValue columnId set rowId value -> ( newTableState, postBoolCellData columnId rowId value ) InputTable.Messages.SelectDropdownParent rowId columnId parentValue set -> postNestedUpdate rowId columnId parentValue "" InputTable.Messages.SelectDropdownChild rowId columnId parentValue childValue set -> postNestedUpdate rowId columnId parentValue childValue InputTable.Messages.ToggleVisibleRowsCheckboxes _ -> ( newTableState, Decisions.Ports.sendRowsJson newTableState.rows ) InputTable.Messages.ToggleRowCheckbox _ -> ( newTableState, Decisions.Ports.sendRowsJson newTableState.rows ) InputTable.Messages.ToggleColumnVisibility id -> ( newTableState , PostVisibleColumns.post config.postVisibleColumnsUrl model.tableState.columns RecievePostNotification id ) _ -> ( newTableState, Cmd.none ) newBulkDecisionsText = rowsToBulkDecisionText tableStateWithRowUpdate.rows in ( { model | tableState = tableStateWithRowUpdate , bulkDecisionsText = newBulkDecisionsText } , Cmd.batch [ cmd, (Cmd.map Table tableCmd) ] ) SetDecisionFilter decisionFilter -> ( { model | decisionFilter = decisionFilter }, Cmd.none ) UpdateDataFromServer (Ok { headers, rows, stageId, bulkDecisionsOptions, hasBulkDecisions }) -> let tableState = model.tableState newTableState = { tableState | columns = List.map (makeColumnHeader stageId) headers , rows = List.map makeRow rows } in ( { model | tableState = newTableState , isLoadingInitialRows = False , hasBulkDecisions = hasBulkDecisions , bulkDecisionsOptions = bulkDecisionsOptions } , Navigation.modifyUrl (model.urlQuery) ) UpdateDataFromServer (Err errorMessage) -> ( { model | isLoadingInitialRows = False }, Cmd.none ) RecievePostNotification (Ok message) -> ( { model | postMessage = message }, Cmd.none ) RecievePostNotification (Err errorMessage) -> ( { model | postMessage = "error" }, Cmd.none ) ToggleShowBulkDecisions -> ( { model | showBulkDecisions = not model.showBulkDecisions , focussedBulkDecisionOption = Nothing , showBulkDecisionsDropdown = False } , Cmd.none ) SetBulkDecisionsText val -> let selectedRowIds = getBulkDescisionIds val newRows = model.tableState.rows |> List.map (\r -> if Set.member (getSerialNumber r) selectedRowIds then { r | checked = True } else { r | checked = False } ) tableState = model.tableState newTableState = { tableState | rows = newRows } in ( { model | bulkDecisionsText = val , tableState = newTableState } , Cmd.none ) ToggleBulkDecisionsDropdown -> ( { model | showBulkDecisionsDropdown = not model.showBulkDecisionsDropdown , focussedBulkDecisionOption = Nothing } , Cmd.none ) SelectBulkDecision decision subDecision -> let tableState = model.tableState bulkDecisionIds = getBulkDescisionIds model.bulkDecisionsText newTableState = { tableState | rows = tableState.rows |> List.map setRowDecision } setRowDecision row = if Set.member (getSerialNumber row) bulkDecisionIds then { row | data = updateDecision row.data } else row updateDecision rowData = { rowData | decision = decision , presentationType = subDecision } rowIds = tableState.rows |> List.filter (\r -> Set.member (getSerialNumber r) bulkDecisionIds) |> List.map .id ( tableStateDecisionUpdate, cmd ) = postDecisionUpdate config newTableState rowIds decision (Maybe.withDefault "" subDecision) in ( { model | tableState = tableStateDecisionUpdate , showBulkDecisionsDropdown = False , showBulkDecisions = False } , cmd ) ViewBulkDecisionDropdownChildren decision -> ( { model | focussedBulkDecisionOption = Just decision }, Cmd.none ) --called every time url changed HandleUrlQuery urlQuery -> let columnId = urlQuery |> String.split "=" |> List.Extra.getAt 1 |> Maybe.withDefault "0" filterValue = urlQuery |> String.split "=" |> List.Extra.getAt 2 oldTableState = model.tableState --only filter if there is actually a filter value in the url newTableState = case filterValue of Just value -> { oldTableState | columns = InputTable.Update.updateFilterText columnId value oldTableState.columns } Nothing -> oldTableState in ( { model | tableState = newTableState, urlQuery = urlQuery } , Cmd.none ) makeColumnHeader : Int -> HeaderData -> Column RowData makeColumnHeader stageId headerData = let description = Maybe.withDefault "" headerData.description subType = case headerData.subType of "TEXT_AREA" -> TextColumn (TextColumnProps (makeColumnGetter headerData.id) (makeColumnSetter headerData.id) "" True) "TEXT_INPUT" -> TextColumn (TextColumnProps (makeColumnGetter headerData.id) (makeColumnSetter headerData.id) "" False) "DROPDOWN_INPUT" -> DropdownColumn (DropdownColumnProps (makeColumnGetter headerData.id) (makeColumnSetter headerData.id) "" headerData.options ) "SUB_DROPDOWN_INPUT" -> (SubDropdownColumn (SubDropdownColumnProps (makeNestedColumnGetter headerData.id) (makeNestedColumnSetter headerData.id) "" headerData.nestedOptions Nothing Nothing ) ) "DECISIONS_INPUT" -> SubDropdownColumn (SubDropdownColumnProps (\rowData -> ( rowData.decision, rowData.presentationType )) (\rowData ( decision, presentationType ) -> { rowData | decision = decision, presentationType = presentationType } ) "" headerData.nestedOptions Nothing Nothing ) "CHECKBOX_INPUT" -> CheckboxColumn (CheckboxColumnProps (makeBoolColumnGetter headerData.id) (makeBoolColumnSetter headerData.id) Nothing ) "REVIEWS_COUNT" -> LinkColumn (LinkColumnProps (makeColumnGetter headerData.id) (makeReviewLinkGetter stageId headerData.id) "" ) "DATE_TIME" -> DisplayColumn (DisplayColumnProps (makeDateTimeGetter headerData.id) "" (Just (makeColumnGetter headerData.id)) ) "LINK_COLUMN" -> LinkColumn (LinkColumnProps (makeColumnGetter headerData.id) (makeLinkGetter headerData.id) "" ) _ -> DisplayColumn (DisplayColumnProps (makeColumnGetter headerData.id) "" Nothing) in Column headerData.id headerData.title headerData.visible headerData.hasNumericalValues subType description makeColumnGetter : ColumnId -> RowData -> String makeColumnGetter id = .stringDictData >> Dict.get id >> Maybe.map .value >> Maybe.withDefault "N/A" makeBoolColumnGetter : String -> RowData -> Bool makeBoolColumnGetter id = .boolDictData >> Dict.get id >> Maybe.withDefault False makeDateTimeGetter : String -> RowData -> String makeDateTimeGetter id = makeColumnGetter id >> Utils.displayTimeStamp makeReviewLinkGetter : Int -> ColumnId -> Row rowData -> String makeReviewLinkGetter stageId id row = "/stages/" ++ toString stageId ++ "/submissions/" ++ row.id ++ "/reviews/read-only" makeLinkGetter : String -> Row RowData -> String makeLinkGetter id = .data >> .stringDictData >> Dict.get id >> Maybe.andThen .link >> Maybe.withDefault "" makeNestedColumnGetter : ColumnId -> RowData -> ( String, Maybe String ) makeNestedColumnGetter id rowData = rowData |> .nestedStringDictData |> Dict.get id |> Maybe.withDefault (NestedCell "" Nothing) |> nestedColummnRender nestedColummnRender : NestedCell -> ( String, Maybe String ) nestedColummnRender { parent, child } = if parent == "" && (Maybe.withDefault "" child) == "" then ( "Choose Option", Nothing ) else ( parent, child ) makeColumnSetter : ColumnId -> (RowData -> String -> RowData) makeColumnSetter id row value = let update cell = { cell | value = value } in { row | stringDictData = Dict.update id (Maybe.map update) row.stringDictData } makeBoolColumnSetter : String -> RowData -> Bool -> RowData makeBoolColumnSetter id row value = { row | boolDictData = Dict.insert id value row.boolDictData } makeNestedColumnSetter : ColumnId -> (RowData -> ( String, Maybe String ) -> RowData) makeNestedColumnSetter id row ( parent, child ) = let valueAsRecord = { parent = parent, child = child } in { row | nestedStringDictData = Dict.insert id valueAsRecord row.nestedStringDictData } makeRow : ApiRowData -> Row RowData makeRow apiRowData = { id = apiRowData.id , data = { boolDictData = apiRowData.boolCells , decision = apiRowData.decision , nestedStringDictData = apiRowData.nestedCells , presentationType = apiRowData.presentationType , stringDictData = apiRowData.cells } , checked = False , disabledMsg = Nothing , checkboxDisabledMsg = Nothing , accordionRows = Nothing , accordionExpanded = False , rowFocusUrl = Nothing } getBulkDescisionIds : String -> Set.Set String getBulkDescisionIds bulkDecisionsText = bulkDecisionsText |> String.split "\n" |> List.filterMap (String.trim >> String.toInt >> Result.toMaybe) |> List.map toString |> Set.fromList rowsToBulkDecisionText : List (Row RowData) -> String rowsToBulkDecisionText rows = rows |> List.filter .checked |> List.map getSerialNumber |> String.join "\n" getSerialNumber : Row RowData -> String getSerialNumber row = Dict.get "0" row.data.stringDictData |> Maybe.map .value |> Maybe.withDefault "" postDecisionUpdate : Config -> TableState RowData Person -> List RowId -> String -> String -> ( TableState RowData Person, Cmd Msg ) postDecisionUpdate config tableState rowIds decision subDecision = let decisionData = { submissionIds = rowIds , decision = decision , subDecision = subDecision } rowsWithDisabledRow = if decision == "Advance" || decision == "Revert to submission's last stage" then List.map setToDisabledIfHasId tableState.rows else tableState.rows setToDisabledIfHasId row = if List.member row.id rowIds then { row | disabledMsg = Just "Submission has been moved to another stage" } else row tableStateWithRowUpdated = { tableState | rows = rowsWithDisabledRow } in ( tableStateWithRowUpdated, Decisions.PostCellUpdate.postDecisionUpdate config.postRowsUrl decisionData ) idToInt : String -> Int idToInt = String.toInt >> Result.withDefault -1