diff --git a/main.js b/main.js index 8a8f9cc..078834f 100644 --- a/main.js +++ b/main.js @@ -6509,8 +6509,8 @@ var $author$project$Main$ModeSwitched = function (a) { return {$: 'ModeSwitched', a: a}; }; var $author$project$Main$ApiResponse = F4( - function (value, updates, notification, error) { - return {error: error, notification: notification, updates: updates, value: value}; + function (value, notification, updates, errors) { + return {errors: errors, notification: notification, updates: updates, value: value}; }); var $elm$json$Json$Decode$oneOf = _Json_oneOf; var $elm$json$Json$Decode$maybe = function (decoder) { @@ -6596,15 +6596,82 @@ var $author$project$Main$apiResponseDecoder = A5( $author$project$Main$ApiResponse, $elm$json$Json$Decode$maybe( A2($elm$json$Json$Decode$field, 'value', $elm$json$Json$Decode$string)), + $elm$json$Json$Decode$maybe( + A2($elm$json$Json$Decode$field, 'notification', $elm$json$Json$Decode$string)), $elm$json$Json$Decode$maybe( A2( $elm$json$Json$Decode$field, 'updates', $elm$json$Json$Decode$list($author$project$Main$updatesDecoder))), $elm$json$Json$Decode$maybe( - A2($elm$json$Json$Decode$field, 'notification', $elm$json$Json$Decode$string)), - $elm$json$Json$Decode$maybe( - A2($elm$json$Json$Decode$field, 'error', $elm$json$Json$Decode$string))); + A2($elm$json$Json$Decode$field, 'errors', $elm$json$Json$Decode$string))); +var $elm$core$List$filter = F2( + function (isGood, list) { + return A3( + $elm$core$List$foldr, + F2( + function (x, xs) { + return isGood(x) ? A2($elm$core$List$cons, x, xs) : xs; + }), + _List_Nil, + list); + }); +var $elm$core$Basics$neq = _Utils_notEqual; +var $elm$core$Maybe$withDefault = F2( + function (_default, maybe) { + if (maybe.$ === 'Just') { + var value = maybe.a; + return value; + } else { + return _default; + } + }); +var $author$project$Main$applyUpdate = F2( + function (u, model) { + switch (u.$) { + case 'ItemRemoved': + var item = u.a; + return _Utils_update( + model, + { + loot: $elm$core$Maybe$Just( + A2( + $elm$core$List$filter, + function (i) { + return !_Utils_eq(i.id, item.id); + }, + A2($elm$core$Maybe$withDefault, _List_Nil, model.loot))) + }); + case 'ItemAdded': + var item = u.a; + return _Utils_update( + model, + { + loot: $elm$core$Maybe$Just( + A2( + $elm$core$List$cons, + item, + A2($elm$core$Maybe$withDefault, _List_Nil, model.loot))) + }); + case 'WealthUpdated': + var diff = u.a; + var player = model.player; + var wealth = player.wealth; + return _Utils_update( + model, + { + player: _Utils_update( + player, + { + wealth: A4($author$project$Main$Wealth, wealth.cp + diff.cp, wealth.sp + diff.sp, wealth.gp + diff.gp, wealth.pp + diff.pp) + }) + }); + case 'ClaimAdded': + return model; + default: + return model; + } + }); var $elm$core$Set$Set_elm_builtin = function (a) { return {$: 'Set_elm_builtin', a: a}; }; @@ -6628,17 +6695,6 @@ var $author$project$Main$printError = function (error) { } }; var $elm$browser$Browser$Navigation$pushUrl = _Browser_pushUrl; -var $elm$core$List$filter = F2( - function (isGood, list) { - return A3( - $elm$core$List$foldr, - F2( - function (x, xs) { - return isGood(x) ? A2($elm$core$List$cons, x, xs) : xs; - }), - _List_Nil, - list); - }); var $elm$json$Json$Encode$int = _Json_wrap; var $elm$core$Maybe$map = F2( function (f, maybe) { @@ -6664,15 +6720,6 @@ var $elm$core$Set$member = F2( var dict = _v0.a; return A2($elm$core$Dict$member, key, dict); }); -var $elm$core$Maybe$withDefault = F2( - function (_default, maybe) { - if (maybe.$ === 'Just') { - var value = maybe.a; - return value; - } else { - return _default; - } - }); var $author$project$Main$itemInSelection = F2( function (selection, item) { return A2( @@ -6825,7 +6872,9 @@ var $author$project$Main$sendRequest = F2( 'http://localhost:8088/api/players/' + ($elm$core$String$fromInt(model.player.id) + '/loot'), 'DELETE'); default: - return _Utils_Tuple2('http://', 'POST'); + return _Utils_Tuple2( + 'http://localhost:8088/api/players/' + ($elm$core$String$fromInt(model.player.id) + '/claims'), + 'POST'); } }(); var endpoint = _v1.a; @@ -6938,7 +6987,7 @@ var $author$project$Main$update = F2( } else { var href = urlRequest.a; return _Utils_Tuple2( - A2($author$project$Main$setError, 'Invalid request \'' + (href + '\''), model), + A2($author$project$Main$setError, 'External request \'' + (href + '\''), model), $elm$core$Platform$Cmd$none); } case 'UrlChanged': @@ -7102,13 +7151,12 @@ var $author$project$Main$update = F2( default: var response = msg.a; if (response.$ === 'Ok') { - var r = response.a; - return _Utils_Tuple2( - A2( - $author$project$Main$setError, - $elm$core$Debug$toString(r), - model), - $elm$core$Platform$Cmd$none); + var result = response.a; + var updates = A2($elm$core$Maybe$withDefault, _List_Nil, result.updates); + return A2( + $author$project$Main$update, + $author$project$Main$ModeSwitched($elm$core$Maybe$Nothing), + A3($elm$core$List$foldl, $author$project$Main$applyUpdate, model, updates)); } else { var r = response.a; return _Utils_Tuple2( @@ -7120,10 +7168,6 @@ var $author$project$Main$update = F2( } } }); -var $author$project$Main$Buy = {$: 'Buy'}; -var $author$project$Main$ConfirmAction = {$: 'ConfirmAction'}; -var $author$project$Main$Grab = {$: 'Grab'}; -var $author$project$Main$Sell = {$: 'Sell'}; var $author$project$Main$UndoLastAction = {$: 'UndoLastAction'}; var $elm$html$Html$button = _VirtualDom_node('button'); var $elm$json$Json$Encode$string = _Json_wrap; @@ -7164,7 +7208,7 @@ var $author$project$Main$actionButton = F4( $elm$html$Html$button, _List_fromArray( [ - $elm$html$Html$Attributes$class('button is-' + color), + $elm$html$Html$Attributes$class('button level-item is-' + color), $elm$html$Html$Events$onClick(msg) ]), _List_fromArray( @@ -7195,7 +7239,70 @@ var $author$project$Main$actionButton = F4( ])); }); var $elm$html$Html$article = _VirtualDom_node('article'); -var $elm$html$Html$div = _VirtualDom_node('div'); +var $author$project$Main$ConfirmAction = {$: 'ConfirmAction'}; +var $author$project$Main$controlsWhenModeActive = function (mode) { + return _List_fromArray( + [ + A4($author$project$Main$actionButton, $author$project$Main$ConfirmAction, 'Valider', 'check', 'primary'), + A4( + $author$project$Main$actionButton, + $author$project$Main$ModeSwitched($elm$core$Maybe$Nothing), + 'Annuler', + 'times', + 'danger') + ]); +}; +var $author$project$Main$Buy = {$: 'Buy'}; +var $author$project$Main$Grab = {$: 'Grab'}; +var $author$project$Main$Sell = {$: 'Sell'}; +var $author$project$Main$controlsWhenRoute = function (route) { + switch (route.$) { + case 'PlayerChest': + return _List_fromArray( + [ + A4( + $author$project$Main$actionButton, + $author$project$Main$ModeSwitched( + $elm$core$Maybe$Just($author$project$Main$Sell)), + 'Vendre', + 'coins', + 'danger') + ]); + case 'GroupLoot': + return _List_fromArray( + [ + A4( + $author$project$Main$actionButton, + $author$project$Main$ModeSwitched( + $elm$core$Maybe$Just($author$project$Main$Grab)), + 'Demander', + 'praying-hands', + 'primary') + ]); + case 'Merchant': + return _List_fromArray( + [ + A4( + $author$project$Main$actionButton, + $author$project$Main$ModeSwitched( + $elm$core$Maybe$Just($author$project$Main$Buy)), + 'Acheter', + 'coins', + 'success') + ]); + default: + return _List_fromArray( + [ + A4( + $author$project$Main$actionButton, + $author$project$Main$ModeSwitched( + $elm$core$Maybe$Just($author$project$Main$Add)), + 'Nouveau loot', + 'plus', + 'primary') + ]); + } +}; var $elm$html$Html$hr = _VirtualDom_node('hr'); var $author$project$Main$renderId = function (item) { return A2( @@ -7231,6 +7338,7 @@ var $elm$html$Html$Attributes$boolProperty = F2( $elm$json$Json$Encode$bool(bool)); }); var $elm$html$Html$Attributes$checked = $elm$html$Html$Attributes$boolProperty('checked'); +var $elm$html$Html$div = _VirtualDom_node('div'); var $elm$core$String$fromFloat = _String_fromNumber; var $elm$html$Html$input = _VirtualDom_node('input'); var $elm$json$Json$Decode$at = F2( @@ -7979,84 +8087,18 @@ var $author$project$Main$view = function (model) { if (_v3.$ === 'Just') { var mode = _v3.a; return _Utils_Tuple2( - _List_fromArray( - [ - A2( - $elm$html$Html$div, - _List_fromArray( - [ - $elm$html$Html$Attributes$class('buttons has-addons') - ]), - _List_fromArray( - [ - A4($author$project$Main$actionButton, $author$project$Main$ConfirmAction, 'Valider', 'success', 'primary'), - A4( - $author$project$Main$actionButton, - $author$project$Main$ModeSwitched($elm$core$Maybe$Nothing), - 'Annuler', - 'times', - 'danger') - ])) - ]), + $author$project$Main$controlsWhenModeActive(mode), $elm$core$Maybe$Just( A2($author$project$Main$rowControlsForMode, mode, isSelected))); } else { return _Utils_Tuple2( A2( $elm$core$List$cons, - A4($author$project$Main$actionButton, $author$project$Main$UndoLastAction, 'Annuler action', 'delete', 'danger'), - function () { - var _v4 = model.state.route; - switch (_v4.$) { - case 'PlayerChest': - return _List_fromArray( - [ - A4( - $author$project$Main$actionButton, - $author$project$Main$ModeSwitched( - $elm$core$Maybe$Just($author$project$Main$Sell)), - 'Vendre', - 'coins', - 'danger') - ]); - case 'GroupLoot': - return _List_fromArray( - [ - A4( - $author$project$Main$actionButton, - $author$project$Main$ModeSwitched( - $elm$core$Maybe$Just($author$project$Main$Grab)), - 'Demander', - 'coins', - 'primary') - ]); - case 'Merchant': - return _List_fromArray( - [ - A4( - $author$project$Main$actionButton, - $author$project$Main$ModeSwitched( - $elm$core$Maybe$Just($author$project$Main$Buy)), - 'Acheter', - 'coins', - 'success') - ]); - default: - return _List_fromArray( - [ - A4( - $author$project$Main$actionButton, - $author$project$Main$ModeSwitched( - $elm$core$Maybe$Just($author$project$Main$Add)), - 'Nouveau loot', - 'plus', - 'primary') - ]); - } - }()), + A4($author$project$Main$actionButton, $author$project$Main$UndoLastAction, 'Annuler action', 'backspace', 'danger'), + $author$project$Main$controlsWhenRoute(model.state.route)), function () { - var _v5 = model.state.route; - if (_v5.$ === 'GroupLoot') { + var _v4 = model.state.route; + if (_v4.$ === 'GroupLoot') { return $elm$core$Maybe$Just($author$project$Main$renderId); } else { return $elm$core$Maybe$Nothing; @@ -8064,13 +8106,13 @@ var $author$project$Main$view = function (model) { }()); } }(); - var actionControls = _v2.a; + var headerControls = _v2.a; var rowControls = _v2.b; return { body: _List_fromArray( [ $author$project$Main$viewHeaderBar(model), - A2($author$project$Main$viewPlayerBar, model.player, actionControls), + A2($author$project$Main$viewPlayerBar, model.player, headerControls), A2( $elm$html$Html$article, _List_fromArray( diff --git a/src/Main.elm b/src/Main.elm index fc90b1c..aeca8a5 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -160,9 +160,9 @@ type alias HttpResult a = (Result Http.Error a) type alias ApiResponse = { value : Maybe String - , updates : Maybe (List DbUpdate) , notification : Maybe String - , error : Maybe String + , updates : Maybe (List DbUpdate) + , errors : Maybe String } type Msg @@ -184,10 +184,9 @@ update msg model = case urlRequest of Browser.Internal url -> ( model, Nav.pushUrl model.state.navKey (Url.toString url) ) - --( model, Cmd.none ) Browser.External href -> - ( setError ("Invalid request '" ++ href ++ "'") model + ( setError ("External request '" ++ href ++ "'") model , Cmd.none ) UrlChanged url -> @@ -240,7 +239,8 @@ update msg model = state = model.state in ( { model | state = - { state | selection = Debug.log "new selection" (switchSelectionState id state.selection) }} + { state | selection = Debug.log "new selection" + <| switchSelectionState id state.selection }} , Cmd.none ) ModeSwitched newMode -> @@ -277,9 +277,15 @@ update msg model = GotActionResult response -> case response of - Ok r -> (setError (Debug.toString r) model, Cmd.none) + Ok result -> + let + updates = Maybe.withDefault [] result.updates + in + List.foldl applyUpdate model updates + |> update (ModeSwitched Nothing) Err r -> (setError (Debug.toString r) model, Cmd.none) + targetItemsFor : ViewMode -> Model -> List Item targetItemsFor mode model = case mode of @@ -319,6 +325,30 @@ type DbUpdate | ClaimAdded () | ClaimRemoved () +-- DbUpdates always refer to the active player's loot +applyUpdate : DbUpdate -> Model -> Model +applyUpdate u model = + case u of + ItemRemoved item -> { model | loot = Just + <| List.filter (\i -> i.id /= item.id) + <| Maybe.withDefault [] model.loot } + ItemAdded item -> { model | loot = Just + <| item :: Maybe.withDefault [] model.loot } + WealthUpdated diff -> + let + player = model.player + wealth = player.wealth + in + { model | player = { player | wealth = + (Wealth + (wealth.cp + diff.cp) + (wealth.sp + diff.sp) + (wealth.gp + diff.gp) + (wealth.pp + diff.pp) + )}} + ClaimAdded _ -> model + ClaimRemoved _ -> model + -- TODO: update server to produce better json -- like an object with list of updates of the same type -- { ItemRemoved : [..], Wealth : [ .. ], .. } @@ -338,9 +368,9 @@ apiResponseDecoder : Decoder ApiResponse apiResponseDecoder = Json.Decode.map4 ApiResponse (Json.Decode.maybe (field "value" string)) - (Json.Decode.maybe (field "updates" (Json.Decode.list updatesDecoder))) (Json.Decode.maybe (field "notification" string)) - (Json.Decode.maybe (field "error" string)) + (Json.Decode.maybe (field "updates" (Json.Decode.list updatesDecoder))) + (Json.Decode.maybe (field "errors" string)) sendRequest : Maybe ViewMode -> Model -> Cmd Msg @@ -363,7 +393,7 @@ sendRequest activeMode model = , "DELETE" ) Grab -> - ( "http://" + ( "http://localhost:8088/api/players/" ++ (String.fromInt model.player.id) ++ "/claims" , "POST") in Http.request @@ -401,9 +431,9 @@ switchSelectionState : Int -> Maybe Selection -> Maybe Selection switchSelectionState id selection = case selection of Just s -> - Just (case Set.member id s of - True -> Set.remove id s - False -> Set.insert id s) + Just <| case Set.member id s of + True -> Set.remove id s + False -> Set.insert id s Nothing -> Debug.log "ignore switchSelectionState" Nothing -- SUBSCRIPTIONS @@ -432,12 +462,26 @@ canSelectIn mode = Add -> False actionButton msg t icon color = - button [ class <| "button is-" ++ color + button [ class <| "button level-item is-" ++ color , onClick msg ] [ span [ class "icon" ] [ i [ Svg.Attributes.class <| "fas fa-" ++ icon ] [] ] , p [] [text t] ] +controlsWhenModeActive : ViewMode -> List (Html Msg) +controlsWhenModeActive mode = + [ actionButton (ConfirmAction) "Valider" "check" "primary" + , actionButton (ModeSwitched Nothing) "Annuler" "times" "danger" + ] + +controlsWhenRoute : Route -> List (Html Msg) +controlsWhenRoute route = + case route of + PlayerChest -> [actionButton (ModeSwitched (Just Sell)) "Vendre" "coins" "danger"] + GroupLoot -> [actionButton (ModeSwitched (Just Grab)) "Demander" "praying-hands" "primary"] + Merchant -> [actionButton (ModeSwitched (Just Buy)) "Acheter" "coins" "success"] + NewLoot -> [actionButton (ModeSwitched (Just Add)) "Nouveau loot" "plus" "primary"] + view : Model -> Browser.Document Msg view model = let @@ -453,28 +497,18 @@ view model = NewLoot -> ("Nouveau trésor :)", [] ) - {- Dynamic renderes to allow the use of ViewMode + {- Dynamic renderers for ViewMode - ActionControls is inserted in the PlayerBar's right - and rowControls are inserted, to the right of every item rows + Header controls are inserted in the PlayerBar + and rowControls to the right side of every item rows -} - (actionControls, rowControls) = + (headerControls, rowControls) = case model.state.activeMode of - Just mode -> -- When a mode is active - ( [ div [ class "buttons has-addons"] - [ actionButton (ConfirmAction) "Valider" "success" "primary" - , actionButton (ModeSwitched Nothing) "Annuler" "times" "danger" - ] - ] - , Just (rowControlsForMode mode isSelected) - ) + Just mode -> + ( controlsWhenModeActive mode, Just (rowControlsForMode mode isSelected)) Nothing -> -- Buttons to enter mode - ( actionButton UndoLastAction "Annuler action" "delete" "danger" - :: case model.state.route of - PlayerChest -> [actionButton (ModeSwitched (Just Sell)) "Vendre" "coins" "danger"] - GroupLoot -> [actionButton (ModeSwitched (Just Grab)) "Demander" "coins" "primary"] - Merchant -> [actionButton (ModeSwitched (Just Buy)) "Acheter" "coins" "success"] - NewLoot -> [actionButton (ModeSwitched (Just Add)) "Nouveau loot" "plus" "primary"] + ( actionButton UndoLastAction "Annuler action" "backspace" "danger" + :: controlsWhenRoute model.state.route -- Claim controls for Group chest , case model.state.route of GroupLoot -> Just renderId @@ -489,7 +523,7 @@ view model = { title = "Loot-a-lot in ELM" , body = [ viewHeaderBar model - , viewPlayerBar model.player actionControls + , viewPlayerBar model.player headerControls , article [class "section container"] [ p [class "heading"] [text header] , viewSearchBar