diff --git a/src/Page/Chest.elm b/src/Page/Chest.elm index 94f51e2..20ed533 100644 --- a/src/Page/Chest.elm +++ b/src/Page/Chest.elm @@ -1,17 +1,24 @@ module Page.Chest exposing (..) +import Api + exposing + ( ActionMode(..) + , Claims + , HttpResult + , Item + , Loot + , Wealth + , confirmAction + ) import Browser.Navigation as Nav - -import Api exposing (ActionMode(..), confirmAction, HttpResult - , Wealth, Claims - , Item, Loot) import Html exposing (..) import Html.Attributes exposing (..) -import Html.Events exposing (onCheck, onClick) +import Html.Events exposing (onCheck, onClick, onInput) import Route exposing (ChestContent(..)) +import Session exposing (Session(..)) import Set exposing (Set) import Utils exposing (..) -import Session exposing (Session(..)) + -- MODEL @@ -22,6 +29,7 @@ type alias State = , mode : ActionMode , error : Maybe String , notification : Maybe String + -- Fetched on init , player : Api.Player , playerLoot : Loot @@ -40,22 +48,25 @@ type alias Model = , state : State , shown : Route.ChestContent , selection : Maybe Selection + , searchText : String , claims : Claims } + init (Player navKey playerId) = ( Model navKey (State False NoMode Nothing Nothing Api.blankPlayer [] [] [] []) Route.PlayerLoot Nothing + "" [] , Cmd.batch [ Api.fetchPlayer GotPlayer playerId , Api.fetchClaims GotClaims playerId , fetchLoot (OfPlayer playerId) - , fetchLoot (OfGroup) - , fetchLoot (OfShop) + , fetchLoot OfGroup + , fetchLoot OfShop ] ) @@ -100,7 +111,6 @@ stackedIcon name = ] - debugSandbox = [ stackedIcon "fas fa-coins" , stackedIcon "fab fa-d-and-d" @@ -127,7 +137,7 @@ viewHeaderBar title model = [ div [ class "navbar-brand" ] [ a [ class "navbar-item", href "/" ] [ renderIcon { icon = "fab fa-d-and-d", size = "medium", ratio = "2x" } - , span [] [ text model.state.player.name ] + , span [] [ text title ] ] , a [ class "navbar-burger is-active" ] [ span [ attribute "aria-hidden" "true" ] [] @@ -216,7 +226,6 @@ showWealthField name value = - -- VIEW @@ -246,6 +255,9 @@ view model = isSelected = itemInSelection model.selection + canSelect = + canSelectIn model.state.mode + rowRenderer = case model.state.mode of NoMode -> @@ -262,25 +274,16 @@ view model = Nothing activeMode -> - Just (rowRendererForMode isSelected activeMode) + Just (rowRendererForMode activeMode) in [ viewHeaderBar model.state.player.name model , viewPlayerBar model.state.player renderControls , main_ [ class "container" ] [ viewNotification model.state.notification - , article - [ class "section" ] - [ div [ class "columns" ] - [ div [ class "column is-one-third" ] [ p [ class "title" ] [ text header ] ] - , div [ class "column" ] [ viewSearchBar ] - ] - , table [ class "table is-fullwidth is-striped is-hoverable" ] - [ thead [ class "table-header" ] - [ th [] [ text "Nom" ] ] - , tbody [] <| List.map (viewItemTableRow isSelected rowRenderer) <| shownItems model - ] - ] + + -- TODO: viewAddLoot when in Add mode + , viewLoot header model.searchText rowRenderer canSelect isSelected <| shownItems model ] , hr [] [] , section [ class "container" ] [ viewDebugSection model ] @@ -288,9 +291,49 @@ view model = --- Renderers --- --- Item -> Html Msg +-- VIEW LOOT + + +viewLoot : String -> String -> Maybe (Item -> Html Msg) -> Bool -> (Item -> Bool) -> Loot -> Html Msg +viewLoot header searchText rowRenderer canSelect isSelected items = + let + filteredItems = + List.filter + (\i -> String.toLower i.name |> String.contains (String.toLower searchText) ) + 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 rowRenderer) filteredItems + ] + ] + + + +-- Search Bar + + +viewSearchBar : String -> Html Msg +viewSearchBar textValue = + div [ class "field" ] + [ p [ class "control has-icons-left" ] + [ input [ class "input" + , onInput SearchTextChanged + , value textValue ] [] + , span [ class "icon is-left" ] [ i [ class "fas fa-search" ] [] ] + ] + ] + + + +-- Renderers : Item -> Html Msg claimedItemRenderer : (Item -> Bool) -> Item -> Html Msg @@ -307,74 +350,56 @@ claimedItemRenderer isClaimed item = text "" -rowRendererForMode : (Item -> Bool) -> ActionMode -> Item -> Html Msg -rowRendererForMode isSelected mode item = +rowRendererForMode : ActionMode -> Item -> Html Msg +rowRendererForMode mode item = + case mode of + Buy -> + p [ class "level-item" ] [ text (String.fromInt item.base_price ++ "po") ] + + Sell -> + p [ class "level-item" ] [ text (String.fromFloat (toFloat item.base_price / 2) ++ "po") ] + + Grab -> + p [ class "level-item" ] [ text "Grab" ] + + Add -> + p [ class "level-item" ] [ text "New !" ] + + NoMode -> + text "" + + +viewItemTableRow : (Item -> Bool) -> Bool -> Maybe (Item -> Html Msg) -> Item -> Html Msg +viewItemTableRow isSelected canSelect rowRenderer item = let - canSelect = - canSelectIn mode + rightLevel = + div [ class "level-right" ] + [ case rowRenderer of + Just render -> + render item - renderInfo = - case mode of - Buy -> - p [ class "level-item" ] [ text (String.fromInt item.base_price ++ "po") ] - - Sell -> - p [ class "level-item" ] [ text (String.fromFloat (toFloat item.base_price / 2) ++ "po") ] - - Grab -> - p [ class "level-item" ] [ text "Grab" ] - - Add -> - p [ class "level-item" ] [ text "New !" ] - - NoMode -> - text "" - in - div [ class "level-right" ] <| - renderInfo - :: (if canSelect then - [ input + Nothing -> + text "" + , if canSelect then + input [ class "checkbox level-item" , type_ "checkbox" , checked <| isSelected item , onCheck (\v -> SwitchSelectionState item.id) ] [] - ] - else - [] - ) - - -viewItemTableRow : (Item -> Bool) -> Maybe (Item -> Html Msg) -> Item -> Html Msg -viewItemTableRow isSelected rowRenderer item = + else + text "" + ] + in tr [ classList [ ( "is-selected", isSelected item ) ] ] [ td [] - [ label [ class "level checkbox" ] <| - div [ class "level-left" ] + [ label [ class "level checkbox" ] + [ div [ class "level-left" ] [ p [ class "level-item" ] [ text item.name ] ] - :: (case rowRenderer of - Just render -> - List.singleton (render item) - - Nothing -> - [] - ) - ] - ] - - - --- Search Bar - - -viewSearchBar : Html Msg -viewSearchBar = - div [ class "field" ] - [ p [ class "control has-icons-left" ] - [ input [ class "input" ] [] - , span [ class "icon is-left" ] [ i [ class "fas fa-search" ] [] ] + , rightLevel + ] ] ] @@ -406,7 +431,7 @@ canSelectIn mode = viewControls : ActionMode -> ChestContent -> List (Html Msg) viewControls mode content = case mode of - NoMode -> + NoMode -> case content of PlayerLoot -> [ actionButton (ModeSwitched Sell) "Vendre" "coins" "danger" ] @@ -433,8 +458,9 @@ viewControls mode content = type Msg = ApiMsg Api.Msg | ClearNotification - | SetContent (ChestContent) + | SetContent ChestContent | SetSelection (Maybe Selection) + | SearchTextChanged String | GotLoot ToChest (HttpResult Loot) | GotClaims (HttpResult Claims) | GotPlayer (HttpResult Api.Player) @@ -443,9 +469,6 @@ type Msg | ConfirmAction --- UPDATE - - update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of @@ -476,36 +499,39 @@ update msg model = ( { model | shown = content }, Cmd.none ) GotPlayer result -> - case result of - Ok player -> - let - state = model.state - in - ( { model | state = { state | player = player }} , Cmd.none) + case result of + Ok player -> + let + state = + model.state + in + ( { model | state = { state | player = player } }, Cmd.none ) - Err error -> - ( setError ("Fetching player... " ++ Debug.toString error) model - , Cmd.none - ) + Err error -> + ( setError ("Fetching player... " ++ Debug.toString error) model + , Cmd.none + ) ModeSwitched newMode -> - let state = model.state in - { model | state = { state | mode = newMode }} - |> update - (SetSelection - (case newMode of - NoMode -> - Nothing + let + state = + model.state + in + { model | state = { state | mode = newMode } } + |> update + (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 - ) - ) + Grab -> + -- Currently claimed object are initially selected + Just (Set.fromList <| List.map (\c -> c.loot_id) model.claims) + others -> + Just Set.empty + ) + ) ConfirmAction -> case model.state.mode of @@ -535,31 +561,34 @@ update msg model = SetSelection new -> ( { model | selection = new }, Cmd.none ) - GotClaims (Ok claims )-> - ( { model | claims = claims } , Cmd.none ) + SearchTextChanged search -> + ( { model | searchText = search }, Cmd.none ) + + GotClaims (Ok claims) -> + ( { model | claims = claims }, Cmd.none ) GotClaims (Err error) -> ( setError (Debug.toString error) model, Cmd.none ) GotLoot dest (Ok loot) -> - ( - let - state = model.state - in - case dest of - OfPlayer _ -> - { model | state = { state | playerLoot = loot }} + ( let + state = + model.state + in + case dest of + OfPlayer _ -> + { model | state = { state | playerLoot = loot } } - OfGroup -> - { model | state = { state | groupLoot = loot }} + OfGroup -> + { model | state = { state | groupLoot = loot } } - OfShop -> - { model | state = { state | merchantLoot = loot }} - , Cmd.none - ) + OfShop -> + { model | state = { state | merchantLoot = loot } } + , Cmd.none + ) GotLoot _ (Err error) -> - ( setError (Debug.toString error) model, Cmd.none ) + ( setError (Debug.toString error) model, Cmd.none ) setNotification : Maybe String -> Model -> Model @@ -573,6 +602,8 @@ setNotification notification model = { state | notification = notification } } + + -- ERRORS @@ -595,15 +626,21 @@ setError error model = applyUpdate : Api.Update -> Model -> Model applyUpdate u model = let - state = model.state + state = + model.state in case u of Api.ItemRemoved item -> - { model | state = { state | playerLoot = - List.filter (\i -> i.id /= item.id) model.state.playerLoot }} + { model + | state = + { state + | playerLoot = + List.filter (\i -> i.id /= item.id) model.state.playerLoot + } + } Api.ItemAdded item -> - { model | state = { state | playerLoot = (item :: model.state.playerLoot) }} + { model | state = { state | playerLoot = item :: model.state.playerLoot } } Api.WealthUpdated diff -> let @@ -613,26 +650,28 @@ applyUpdate u model = wealth = player.wealth in - { model | state = { state - | player = - { player - | wealth = - Wealth - (wealth.cp + diff.cp) - (wealth.sp + diff.sp) - (wealth.gp + diff.gp) - (wealth.pp + diff.pp) + { model + | state = + { state + | player = + { player + | wealth = + Wealth + (wealth.cp + diff.cp) + (wealth.sp + diff.sp) + (wealth.gp + diff.gp) + (wealth.pp + diff.pp) + } } - }} + } Api.ClaimAdded claim -> - { model | claims = (claim :: model.claims) } + { model | claims = claim :: model.claims } Api.ClaimRemoved claim -> { model | claims = List.filter (\c -> c.id /= claim.id) model.claims } - type ToChest = OfPlayer Int | OfGroup