cleans Actions API and modes

This commit is contained in:
2019-11-13 15:46:15 +01:00
parent ca1ff2c778
commit 18f661ddf3
2 changed files with 225 additions and 107 deletions

View File

@@ -1,10 +1,21 @@
module Api exposing (Update(..), Msg(..) module Api exposing
, HttpResult ( ActionMode(..)
, Player, Wealth, fetchPlayer, blankPlayer , Claim
, Item, Loot, fetchLoot , Claims
, Claim, Claims, fetchClaims , HttpResult
, ActionMode(..), confirmAction , Item
) , Loot
, Msg(..)
, Player
, RequestData(..)
, Update(..)
, Wealth
, blankPlayer
, confirmAction
, fetchClaims
, fetchLoot
, fetchPlayer
)
import Http import Http
import Json.Decode as D exposing (Decoder, field, int, string, succeed) import Json.Decode as D exposing (Decoder, field, int, string, succeed)
@@ -15,7 +26,10 @@ type alias HttpResult a =
Result Http.Error a Result Http.Error a
-- Format of the server's response -- Format of the server's response
type alias Response = type alias Response =
{ value : Maybe String { value : Maybe String
, notification : Maybe String , notification : Maybe String
@@ -110,11 +124,11 @@ fetchClaims toMsg playerId =
} }
-- PLAYERS -- PLAYERS
-- --
fetchPlayer : (Result Http.Error Player -> msg) -> Int -> Cmd msg fetchPlayer : (Result Http.Error Player -> msg) -> Int -> Cmd msg
fetchPlayer toMsg id = fetchPlayer toMsg id =
Http.get Http.get
@@ -153,6 +167,14 @@ itemDecoder =
(D.field "base_price" int) (D.field "base_price" int)
itemEncoder item =
E.object
[ ( "id", E.int item.id )
, ( "name", E.string item.name )
, ( "base_price", E.int item.base_price )
]
lootDecoder : Decoder Loot lootDecoder : Decoder Loot
lootDecoder = lootDecoder =
D.list itemDecoder D.list itemDecoder
@@ -168,10 +190,6 @@ fetchLoot url toMsg =
-- CLAIMS -- CLAIMS
-- API Response -- API Response
-- --
@@ -220,73 +238,86 @@ undoLastAction id =
} }
{- ACTIONS
Actions that can be taken on a selection of items
-}
type ActionMode type ActionMode
= Sell = View
| Sell
| Buy | Buy
| Grab | Grab
| Add | Add
| NoMode
buildPayload : ActionMode -> List Item -> E.Value
buildPayload mode items = type RequestData
case mode of = SellPayload Loot (Maybe Float) (List Float) (List Int)
Buy -> | BuyPayload Loot (Maybe Float) (List Float)
| GrabPayload Loot
| AddPayload String Loot
buildPayload : RequestData -> E.Value
buildPayload data =
case data of
BuyPayload items _ _ ->
E.object E.object
[ ( "items", items |> E.list (\i -> E.list identity [ E.int i.id, E.null ]) ) [ ( "items", items |> E.list (\i -> E.list identity [ E.int i.id, E.null ]) )
, ( "global_mod", E.null ) , ( "global_mod", E.null )
] ]
Sell -> SellPayload items _ _ _ ->
E.object E.object
[ ( "items", items |> E.list (\i -> E.list identity [ E.int i.id, E.null ]) ) [ ( "items", items |> E.list (\i -> E.list identity [ E.int i.id, E.null ]) )
, ( "global_mod", E.null ) , ( "global_mod", E.null )
, ( "players", E.null ) , ( "players", E.null )
] ]
-- API expects the list of claimed loot ids -- API expects the list of claimed items ids
Grab -> GrabPayload items ->
items |> E.list (\i -> E.int i.id) items |> E.list (\i -> E.int i.id)
Add -> AddPayload sourceName items ->
E.object E.object
[ ( "items", items |> E.list (\i -> E.int i.id) ) [ ( "items", items |> E.list itemEncoder )
, ( "source_name", E.string sourceName )
] ]
NoMode -> E.null
confirmAction : String -> RequestData -> Cmd Msg
confirmAction : ActionMode -> String -> List Item -> Cmd Msg confirmAction id data =
confirmAction mode id items =
let let
( endpoint, method ) = ( endpoint, method ) =
case mode of case data of
Add -> AddPayload _ _ ->
( "http://localhost:8088/api/players/" ++ id ++ "/loot" ( "http://localhost:8088/api/players/" ++ id ++ "/loot"
, "POST" , "POST"
) )
Buy -> BuyPayload _ _ _ ->
( "http://localhost:8088/api/players/" ++ id ++ "/loot" ( "http://localhost:8088/api/players/" ++ id ++ "/loot"
, "PUT" , "PUT"
) )
Sell -> SellPayload _ _ _ _ ->
( "http://localhost:8088/api/players/" ++ id ++ "/loot" ( "http://localhost:8088/api/players/" ++ id ++ "/loot"
, "DELETE" , "DELETE"
) )
Grab -> GrabPayload _ ->
( "http://localhost:8088/api/players/" ++ id ++ "/claims" ( "http://localhost:8088/api/players/" ++ id ++ "/claims"
, "POST" , "POST"
) )
-- TODO: ???
NoMode -> ("", "GET")
in in
Http.request Http.request
{ method = method { method = method
, headers = [] , headers = []
, url = endpoint , url = endpoint
, body = Http.jsonBody <| buildPayload mode items , body = Http.jsonBody <| buildPayload data
, expect = Http.expectJson GotActionResult apiResponseDecoder , expect = Http.expectJson GotActionResult apiResponseDecoder
, timeout = Nothing , timeout = Nothing
, tracker = Nothing , tracker = Nothing

View File

@@ -7,6 +7,7 @@ import Api
, HttpResult , HttpResult
, Item , Item
, Loot , Loot
, RequestData(..)
, Wealth , Wealth
, confirmAction , confirmAction
) )
@@ -29,8 +30,11 @@ type alias State =
, mode : ActionMode , mode : ActionMode
, error : Maybe String , error : Maybe String
, notification : Maybe String , notification : Maybe String
-- AddLoot
, autoComplete : Loot , autoComplete : Loot
, newItem : Maybe Item , newItem : Maybe Item
, sourceName : Maybe String
-- Fetched on init -- Fetched on init
, player : Api.Player , player : Api.Player
@@ -58,7 +62,20 @@ type alias Model =
init (Player navKey playerId) = init (Player navKey playerId) =
( Model ( Model
navKey navKey
(State False NoMode Nothing Nothing [] Nothing Api.blankPlayer [] [] [] []) (State
False
View
Nothing
Nothing
[]
Nothing
Nothing
Api.blankPlayer
[]
[]
[]
[]
)
Route.PlayerLoot Route.PlayerLoot
Nothing Nothing
"" ""
@@ -259,7 +276,7 @@ view model =
"Nouveau trésor :)" "Nouveau trésor :)"
shownItems = shownItems =
selectContent model.shown selectContent model
isSelected = isSelected =
itemInSelection model.selection itemInSelection model.selection
@@ -269,7 +286,7 @@ view model =
rowRenderer = rowRenderer =
case model.state.mode of case model.state.mode of
NoMode -> View ->
case model.shown of case model.shown of
GroupLoot -> GroupLoot ->
let let
@@ -284,21 +301,33 @@ view model =
activeMode -> activeMode ->
Just (rowRendererForMode activeMode) Just (rowRendererForMode activeMode)
filteredItems =
shownItems
|> List.filter
(\i -> String.toLower i.name |> String.contains (String.toLower model.searchText))
in in
[ viewHeaderBar "Mon coffre" model [ viewHeaderBar "Mon coffre" model
, viewPlayerBar model.state.player renderControls , viewPlayerBar model.state.player renderControls
, main_ , main_
[ class "container" ] [ class "container" ]
[ viewNotification model.state.notification [ viewNotification model.state.notification
, article
[ class "section" ]
(case model.state.mode of
Add ->
[ viewAddLoot model
, viewLoot rowRenderer canSelect isSelected shownItems
]
-- TODO: viewAddLoot when in Add mode _ ->
, case model.state.mode of [ div [ class "columns" ]
Add -> [ div [ class "column is-one-third" ] [ p [ class "title" ] [ text header ] ]
viewAddLoot model , div [ class "column" ] [ viewSearchBar model.searchText ]
]
_ -> , viewLoot rowRenderer canSelect isSelected filteredItems
text "" ]
, viewLoot header model.searchText rowRenderer canSelect isSelected <| shownItems model )
] ]
, hr [] [] , hr [] []
, section [ class "container" ] [ viewDebugSection model ] , section [ class "container" ] [ viewDebugSection model ]
@@ -334,25 +363,12 @@ view model =
-- VIEW LOOT -- VIEW LOOT
viewLoot : String -> String -> Maybe (Item -> Html Msg) -> Bool -> (Item -> Bool) -> Loot -> Html Msg viewLoot : Maybe (Item -> Html Msg) -> Bool -> (Item -> Bool) -> Loot -> Html Msg
viewLoot header searchText maybeRowRenderer canSelect isSelected items = viewLoot maybeRowRenderer canSelect isSelected items =
let table [ class "table is-fullwidth is-striped is-hoverable" ]
filteredItems = [ thead [ class "table-header" ]
List.filter [ th [] [ text "Nom" ] ]
(\i -> String.toLower i.name |> String.contains (String.toLower searchText)) , tbody [] <| List.map (viewItemTableRow isSelected canSelect maybeRowRenderer) items
items
in
article
[ class "section" ]
[ div [ class "columns" ]
[ div [ class "column is-one-third" ] [ p [ class "title" ] [ text header ] ]
, div [ class "column" ] [ viewSearchBar searchText ]
]
, table [ class "table is-fullwidth is-striped is-hoverable" ]
[ thead [ class "table-header" ]
[ th [] [ text "Nom" ] ]
, tbody [] <| List.map (viewItemTableRow isSelected canSelect maybeRowRenderer) filteredItems
]
] ]
@@ -406,9 +422,9 @@ rowRendererForMode mode item =
p [ class "level-item" ] [ text "Grab" ] p [ class "level-item" ] [ text "Grab" ]
Add -> Add ->
p [ class "level-item" ] [ text "New !" ] p [ class "level-item" ] [ text <| "Valeur : " ++ String.fromInt item.base_price ++ "po" ]
NoMode -> View ->
text "" text ""
@@ -514,6 +530,14 @@ viewAddLoot model =
Nothing -> Nothing ->
Item 0 "" 0 Item 0 "" 0
sourceName =
case model.state.sourceName of
Just name ->
name
Nothing ->
""
itemIsValid = itemIsValid =
if nameValid && priceValid then if nameValid && priceValid then
True True
@@ -540,6 +564,9 @@ viewAddLoot model =
[ input [ input
[ class "input" [ class "input"
, type_ "text" , type_ "text"
, name "source"
, value sourceName
, onInput SourceNameChanged
] ]
[] []
] ]
@@ -644,14 +671,14 @@ canSelectIn mode =
Add -> Add ->
False False
NoMode -> View ->
False False
viewControls : ActionMode -> ChestContent -> List (Html Msg) viewControls : ActionMode -> ChestContent -> List (Html Msg)
viewControls mode content = viewControls mode content =
case mode of case mode of
NoMode -> View ->
case content of case content of
PlayerLoot -> PlayerLoot ->
[ actionButton (ModeSwitched Sell) "Vendre" "coins" "danger" ] [ actionButton (ModeSwitched Sell) "Vendre" "coins" "danger" ]
@@ -667,7 +694,7 @@ viewControls mode content =
m -> m ->
[ actionButton ConfirmAction "Valider" "check" "primary" [ actionButton ConfirmAction "Valider" "check" "primary"
, actionButton (ModeSwitched NoMode) "Annuler" "times" "danger" , actionButton (ModeSwitched View) "Annuler" "times" "danger"
] ]
@@ -686,10 +713,13 @@ type Msg
| GotPlayer (HttpResult Api.Player) | GotPlayer (HttpResult Api.Player)
| SwitchSelectionState Int | SwitchSelectionState Int
| ModeSwitched ActionMode | ModeSwitched ActionMode
| OnModeEnter ActionMode
| OnModeExit ActionMode
| ConfirmAction | ConfirmAction
| NewItemAdded Item | NewItemAdded Item
| NewItemNameChanged String | NewItemNameChanged String
| NewItemPriceChanged String | NewItemPriceChanged String
| SourceNameChanged String
| SetNewItem Item | SetNewItem Item
@@ -715,6 +745,15 @@ update msg model =
in in
( { model | state = { state | newItem = Just item } }, Cmd.none ) ( { model | state = { state | newItem = Just item } }, Cmd.none )
SourceNameChanged name ->
let
state =
model.state
in
( { model | state = { state | sourceName = Just name } }
, Cmd.none
)
NewItemPriceChanged price -> NewItemPriceChanged price ->
case String.toInt price of case String.toInt price of
Just newPrice -> Just newPrice ->
@@ -769,13 +808,20 @@ update msg model =
List.foldl applyUpdate model updates List.foldl applyUpdate model updates
|> setNotification notification |> setNotification notification
|> setError errors |> setError errors
|> update (ModeSwitched NoMode) |> update (ModeSwitched View)
Err r -> Err r ->
( setError (Debug.toString r) model, Cmd.none ) ( setError (Debug.toString r) model, Cmd.none )
SetContent content -> SetContent content ->
( { model | shown = content }, Cmd.none ) if content == NewLoot then
{ model | shown = content }
|> update (ModeSwitched Add)
else
( { model | shown = content }
, Cmd.none
)
GotPlayer result -> GotPlayer result ->
case result of case result of
@@ -791,45 +837,86 @@ update msg model =
, Cmd.none , Cmd.none
) )
OnModeEnter mode ->
update
(SetSelection
(case ( mode, canSelectIn mode ) of
( _, False ) ->
Nothing
-- Currently claimed object are initially selected
( Grab, _ ) ->
Just (Set.fromList <| List.map (\c -> c.loot_id) model.claims)
( _, True ) ->
Just Set.empty
)
)
model
OnModeExit mode ->
if mode == Add then
-- Redirect to PlayerLoot view
( model, Nav.pushUrl model.navKey "/" )
else
( model, Cmd.none )
ModeSwitched newMode -> ModeSwitched newMode ->
let let
state = state =
model.state model.state
-- We chain exit old mode and enter new mode updates
( exit, exit_cmd ) =
update (OnModeExit model.state.mode) model
( entered, enter_cmd ) =
update (OnModeEnter newMode) exit
in in
{ model | state = { state | mode = newMode } } ( { entered | state = { state | mode = newMode } }
|> update , Cmd.batch [ exit_cmd, enter_cmd ]
(SetSelection )
(case newMode of
NoMode ->
Nothing
Grab ->
-- Currently claimed object are initially selected
Just (Set.fromList <| List.map (\c -> c.loot_id) model.claims)
others ->
Just Set.empty
)
)
ConfirmAction -> ConfirmAction ->
case model.state.mode of let
-- This should not happen, so we ignore it items =
NoMode -> getSelectedItems model
( model, Cmd.none )
mode -> maybeData =
let case model.state.mode of
items = Add ->
getSelected model.shown model Just <|
in Api.AddPayload
( model (Maybe.withDefault
, Cmd.map ApiMsg <| "nouveau loot"
model.state.sourceName
)
(selectContent model)
Buy ->
Just <| Api.BuyPayload items Nothing []
Sell ->
Just <| Api.SellPayload items Nothing [] []
Grab ->
Just <| Api.GrabPayload items
View ->
Nothing
in
( model
, case maybeData of
Just data ->
Cmd.map ApiMsg <|
Api.confirmAction Api.confirmAction
mode
(String.fromInt model.state.player.id) (String.fromInt model.state.player.id)
items data
)
Nothing ->
Cmd.none
)
ClearNotification -> ClearNotification ->
( setNotification Nothing model, Cmd.none ) ( setNotification Nothing model, Cmd.none )
@@ -976,9 +1063,9 @@ fetchLoot dest =
-- Get list of selected items -- Get list of selected items
getSelected : ChestContent -> Model -> Loot getSelectedItems : Model -> Loot
getSelected content model = getSelectedItems model =
selectContent content model selectContent model
|> List.filter (itemInSelection model.selection) |> List.filter (itemInSelection model.selection)
@@ -1009,9 +1096,9 @@ switchSelectionState id selection =
Debug.log "ignore switchSelectionState" Nothing Debug.log "ignore switchSelectionState" Nothing
selectContent : ChestContent -> Model -> List Item selectContent : Model -> List Item
selectContent content model = selectContent model =
case content of case model.shown of
NewLoot -> NewLoot ->
model.state.newLoot model.state.newLoot