impls Item and Wealth updates

This commit is contained in:
2019-11-05 00:20:35 +01:00
parent a859e1fe8c
commit a61c721a2c
2 changed files with 221 additions and 145 deletions

268
main.js
View File

@@ -6509,8 +6509,8 @@ var $author$project$Main$ModeSwitched = function (a) {
return {$: 'ModeSwitched', a: a}; return {$: 'ModeSwitched', a: a};
}; };
var $author$project$Main$ApiResponse = F4( var $author$project$Main$ApiResponse = F4(
function (value, updates, notification, error) { function (value, notification, updates, errors) {
return {error: error, notification: notification, updates: updates, value: value}; return {errors: errors, notification: notification, updates: updates, value: value};
}); });
var $elm$json$Json$Decode$oneOf = _Json_oneOf; var $elm$json$Json$Decode$oneOf = _Json_oneOf;
var $elm$json$Json$Decode$maybe = function (decoder) { var $elm$json$Json$Decode$maybe = function (decoder) {
@@ -6596,15 +6596,82 @@ var $author$project$Main$apiResponseDecoder = A5(
$author$project$Main$ApiResponse, $author$project$Main$ApiResponse,
$elm$json$Json$Decode$maybe( $elm$json$Json$Decode$maybe(
A2($elm$json$Json$Decode$field, 'value', $elm$json$Json$Decode$string)), 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( $elm$json$Json$Decode$maybe(
A2( A2(
$elm$json$Json$Decode$field, $elm$json$Json$Decode$field,
'updates', 'updates',
$elm$json$Json$Decode$list($author$project$Main$updatesDecoder))), $elm$json$Json$Decode$list($author$project$Main$updatesDecoder))),
$elm$json$Json$Decode$maybe( $elm$json$Json$Decode$maybe(
A2($elm$json$Json$Decode$field, 'notification', $elm$json$Json$Decode$string)), A2($elm$json$Json$Decode$field, 'errors', $elm$json$Json$Decode$string)));
$elm$json$Json$Decode$maybe( var $elm$core$List$filter = F2(
A2($elm$json$Json$Decode$field, 'error', $elm$json$Json$Decode$string))); 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) { var $elm$core$Set$Set_elm_builtin = function (a) {
return {$: 'Set_elm_builtin', a: 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$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$json$Json$Encode$int = _Json_wrap;
var $elm$core$Maybe$map = F2( var $elm$core$Maybe$map = F2(
function (f, maybe) { function (f, maybe) {
@@ -6664,15 +6720,6 @@ var $elm$core$Set$member = F2(
var dict = _v0.a; var dict = _v0.a;
return A2($elm$core$Dict$member, key, dict); 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( var $author$project$Main$itemInSelection = F2(
function (selection, item) { function (selection, item) {
return A2( 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'), 'http://localhost:8088/api/players/' + ($elm$core$String$fromInt(model.player.id) + '/loot'),
'DELETE'); 'DELETE');
default: 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; var endpoint = _v1.a;
@@ -6938,7 +6987,7 @@ var $author$project$Main$update = F2(
} else { } else {
var href = urlRequest.a; var href = urlRequest.a;
return _Utils_Tuple2( 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); $elm$core$Platform$Cmd$none);
} }
case 'UrlChanged': case 'UrlChanged':
@@ -7102,13 +7151,12 @@ var $author$project$Main$update = F2(
default: default:
var response = msg.a; var response = msg.a;
if (response.$ === 'Ok') { if (response.$ === 'Ok') {
var r = response.a; var result = response.a;
return _Utils_Tuple2( var updates = A2($elm$core$Maybe$withDefault, _List_Nil, result.updates);
A2( return A2(
$author$project$Main$setError, $author$project$Main$update,
$elm$core$Debug$toString(r), $author$project$Main$ModeSwitched($elm$core$Maybe$Nothing),
model), A3($elm$core$List$foldl, $author$project$Main$applyUpdate, model, updates));
$elm$core$Platform$Cmd$none);
} else { } else {
var r = response.a; var r = response.a;
return _Utils_Tuple2( 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 $author$project$Main$UndoLastAction = {$: 'UndoLastAction'};
var $elm$html$Html$button = _VirtualDom_node('button'); var $elm$html$Html$button = _VirtualDom_node('button');
var $elm$json$Json$Encode$string = _Json_wrap; var $elm$json$Json$Encode$string = _Json_wrap;
@@ -7164,7 +7208,7 @@ var $author$project$Main$actionButton = F4(
$elm$html$Html$button, $elm$html$Html$button,
_List_fromArray( _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) $elm$html$Html$Events$onClick(msg)
]), ]),
_List_fromArray( _List_fromArray(
@@ -7195,7 +7239,70 @@ var $author$project$Main$actionButton = F4(
])); ]));
}); });
var $elm$html$Html$article = _VirtualDom_node('article'); 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 $elm$html$Html$hr = _VirtualDom_node('hr');
var $author$project$Main$renderId = function (item) { var $author$project$Main$renderId = function (item) {
return A2( return A2(
@@ -7231,6 +7338,7 @@ var $elm$html$Html$Attributes$boolProperty = F2(
$elm$json$Json$Encode$bool(bool)); $elm$json$Json$Encode$bool(bool));
}); });
var $elm$html$Html$Attributes$checked = $elm$html$Html$Attributes$boolProperty('checked'); 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$core$String$fromFloat = _String_fromNumber;
var $elm$html$Html$input = _VirtualDom_node('input'); var $elm$html$Html$input = _VirtualDom_node('input');
var $elm$json$Json$Decode$at = F2( var $elm$json$Json$Decode$at = F2(
@@ -7979,84 +8087,18 @@ var $author$project$Main$view = function (model) {
if (_v3.$ === 'Just') { if (_v3.$ === 'Just') {
var mode = _v3.a; var mode = _v3.a;
return _Utils_Tuple2( return _Utils_Tuple2(
_List_fromArray( $author$project$Main$controlsWhenModeActive(mode),
[
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')
]))
]),
$elm$core$Maybe$Just( $elm$core$Maybe$Just(
A2($author$project$Main$rowControlsForMode, mode, isSelected))); A2($author$project$Main$rowControlsForMode, mode, isSelected)));
} else { } else {
return _Utils_Tuple2( return _Utils_Tuple2(
A2( A2(
$elm$core$List$cons, $elm$core$List$cons,
A4($author$project$Main$actionButton, $author$project$Main$UndoLastAction, 'Annuler action', 'delete', 'danger'), A4($author$project$Main$actionButton, $author$project$Main$UndoLastAction, 'Annuler action', 'backspace', 'danger'),
function () { $author$project$Main$controlsWhenRoute(model.state.route)),
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')
]);
}
}()),
function () { function () {
var _v5 = model.state.route; var _v4 = model.state.route;
if (_v5.$ === 'GroupLoot') { if (_v4.$ === 'GroupLoot') {
return $elm$core$Maybe$Just($author$project$Main$renderId); return $elm$core$Maybe$Just($author$project$Main$renderId);
} else { } else {
return $elm$core$Maybe$Nothing; 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; var rowControls = _v2.b;
return { return {
body: _List_fromArray( body: _List_fromArray(
[ [
$author$project$Main$viewHeaderBar(model), $author$project$Main$viewHeaderBar(model),
A2($author$project$Main$viewPlayerBar, model.player, actionControls), A2($author$project$Main$viewPlayerBar, model.player, headerControls),
A2( A2(
$elm$html$Html$article, $elm$html$Html$article,
_List_fromArray( _List_fromArray(

View File

@@ -160,9 +160,9 @@ type alias HttpResult a = (Result Http.Error a)
type alias ApiResponse = type alias ApiResponse =
{ value : Maybe String { value : Maybe String
, updates : Maybe (List DbUpdate)
, notification : Maybe String , notification : Maybe String
, error : Maybe String , updates : Maybe (List DbUpdate)
, errors : Maybe String
} }
type Msg type Msg
@@ -184,10 +184,9 @@ update msg model =
case urlRequest of case urlRequest of
Browser.Internal url -> Browser.Internal url ->
( model, Nav.pushUrl model.state.navKey (Url.toString url) ) ( model, Nav.pushUrl model.state.navKey (Url.toString url) )
--( model, Cmd.none )
Browser.External href -> Browser.External href ->
( setError ("Invalid request '" ++ href ++ "'") model ( setError ("External request '" ++ href ++ "'") model
, Cmd.none ) , Cmd.none )
UrlChanged url -> UrlChanged url ->
@@ -240,7 +239,8 @@ update msg model =
state = model.state state = model.state
in in
( { model | state = ( { model | state =
{ state | selection = Debug.log "new selection" (switchSelectionState id state.selection) }} { state | selection = Debug.log "new selection"
<| switchSelectionState id state.selection }}
, Cmd.none ) , Cmd.none )
ModeSwitched newMode -> ModeSwitched newMode ->
@@ -277,9 +277,15 @@ update msg model =
GotActionResult response -> GotActionResult response ->
case response of 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) Err r -> (setError (Debug.toString r) model, Cmd.none)
targetItemsFor : ViewMode -> Model -> List Item targetItemsFor : ViewMode -> Model -> List Item
targetItemsFor mode model = targetItemsFor mode model =
case mode of case mode of
@@ -319,6 +325,30 @@ type DbUpdate
| ClaimAdded () | ClaimAdded ()
| ClaimRemoved () | 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 -- TODO: update server to produce better json
-- like an object with list of updates of the same type -- like an object with list of updates of the same type
-- { ItemRemoved : [..], Wealth : [ .. ], .. } -- { ItemRemoved : [..], Wealth : [ .. ], .. }
@@ -338,9 +368,9 @@ apiResponseDecoder : Decoder ApiResponse
apiResponseDecoder = apiResponseDecoder =
Json.Decode.map4 ApiResponse Json.Decode.map4 ApiResponse
(Json.Decode.maybe (field "value" string)) (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 "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 sendRequest : Maybe ViewMode -> Model -> Cmd Msg
@@ -363,7 +393,7 @@ sendRequest activeMode model =
, "DELETE" , "DELETE"
) )
Grab -> Grab ->
( "http://" ( "http://localhost:8088/api/players/" ++ (String.fromInt model.player.id) ++ "/claims"
, "POST") , "POST")
in in
Http.request Http.request
@@ -401,9 +431,9 @@ switchSelectionState : Int -> Maybe Selection -> Maybe Selection
switchSelectionState id selection = switchSelectionState id selection =
case selection of case selection of
Just s -> Just s ->
Just (case Set.member id s of Just <| case Set.member id s of
True -> Set.remove id s True -> Set.remove id s
False -> Set.insert id s) False -> Set.insert id s
Nothing -> Debug.log "ignore switchSelectionState" Nothing Nothing -> Debug.log "ignore switchSelectionState" Nothing
-- SUBSCRIPTIONS -- SUBSCRIPTIONS
@@ -432,12 +462,26 @@ canSelectIn mode =
Add -> False Add -> False
actionButton msg t icon color = actionButton msg t icon color =
button [ class <| "button is-" ++ color button [ class <| "button level-item is-" ++ color
, onClick msg ] , onClick msg ]
[ span [ class "icon" ] [ i [ Svg.Attributes.class <| "fas fa-" ++ icon ] [] ] [ span [ class "icon" ] [ i [ Svg.Attributes.class <| "fas fa-" ++ icon ] [] ]
, p [] [text t] , 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 -> Browser.Document Msg
view model = view model =
let let
@@ -453,28 +497,18 @@ view model =
NewLoot -> NewLoot ->
("Nouveau trésor :)", [] ) ("Nouveau trésor :)", [] )
{- Dynamic renderes to allow the use of ViewMode {- Dynamic renderers for ViewMode
ActionControls is inserted in the PlayerBar's right Header controls are inserted in the PlayerBar
and rowControls are inserted, to the right of every item rows and rowControls to the right side of every item rows
-} -}
(actionControls, rowControls) = (headerControls, rowControls) =
case model.state.activeMode of case model.state.activeMode of
Just mode -> -- When a mode is active Just mode ->
( [ div [ class "buttons has-addons"] ( controlsWhenModeActive mode, Just (rowControlsForMode mode isSelected))
[ actionButton (ConfirmAction) "Valider" "success" "primary"
, actionButton (ModeSwitched Nothing) "Annuler" "times" "danger"
]
]
, Just (rowControlsForMode mode isSelected)
)
Nothing -> -- Buttons to enter mode Nothing -> -- Buttons to enter mode
( actionButton UndoLastAction "Annuler action" "delete" "danger" ( actionButton UndoLastAction "Annuler action" "backspace" "danger"
:: case model.state.route of :: controlsWhenRoute model.state.route
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"]
-- Claim controls for Group chest -- Claim controls for Group chest
, case model.state.route of , case model.state.route of
GroupLoot -> Just renderId GroupLoot -> Just renderId
@@ -489,7 +523,7 @@ view model =
{ title = "Loot-a-lot in ELM" { title = "Loot-a-lot in ELM"
, body = , body =
[ viewHeaderBar model [ viewHeaderBar model
, viewPlayerBar model.player actionControls , viewPlayerBar model.player headerControls
, article [class "section container"] , article [class "section container"]
[ p [class "heading"] [text header] [ p [class "heading"] [text header]
, viewSearchBar , viewSearchBar