From 05724dbaab022bb355553340f67e23672df274df Mon Sep 17 00:00:00 2001 From: Paul Brinkmeier Date: Thu, 8 Dec 2022 22:42:10 +0100 Subject: [PATCH] Restructure client code --- elm/Main.elm | 156 ++++++++++++++++++++++++++++--------------------- static/jon.css | 8 +++ 2 files changed, 97 insertions(+), 67 deletions(-) diff --git a/elm/Main.elm b/elm/Main.elm index 188aab5..f089fa6 100644 --- a/elm/Main.elm +++ b/elm/Main.elm @@ -95,14 +95,14 @@ decodeOI = Dec.succeed OverviewItem |> requiredAt ["item", "bought"] Dec.string |> requiredAt ["overview", "activeMappings"] Dec.int -getSnacksByItemId : Int -> Cmd Msg -getSnacksByItemId itemId = rpc +getSnacksByItem : OverviewItem -> Cmd Msg +getSnacksByItem item = rpc { func = "getSnacksByItemId" , args = Enc.object - [ ("item", Enc.int itemId) + [ ("item", Enc.int item.id) ] , expect = Dec.list decodeSnack - } RcvSnacks + } (RcvSnacks item) type alias Snack = { id : Int @@ -136,82 +136,85 @@ type alias Location = , name : String } -type alias Model = - { state : State - } - -type State +type OuterState = LoadingLocations | LocationSelector (List Location) - | Overview - { location : Location - , selectedItems : Set Int + | Initialized { locations : List Location, location : Location } State + +type State + = Overview + { selectedItems : Set Int , desiredInventory : Dict Int Int , overviewItems : List OverviewItem } | SnacksEditor - { snacks : List Snack + { item : OverviewItem + , snacks : List Snack } type Msg - = SelectItem Int Bool + = SelectLocation Location + | SelectItem Int Bool + | ChangeLocation | SetDesiredInventory Int String - | SelectLocation Location | TransferInventory Int + | GoBack -- RPC calls | CallDisableItems (List Int) | CallAdjustInventory Int Int String - | CallGetSnacksById Int + | CallGetSnacksById OverviewItem -- Responses | RcvLocations (Result Http.Error (List Location)) | RcvOverview (Result Http.Error (List OverviewItem)) - | RcvSnacks (Result Http.Error (List Snack)) + | RcvSnacks OverviewItem (Result Http.Error (List Snack)) | RcvOther -init = ({ state = LoadingLocations }, getLocations) +init = (LoadingLocations, getLocations) -update msg global = case msg of - CallAdjustInventory item amount desc -> (global, adjustInventory item amount desc) - CallDisableItems items -> (global, disableItems items) - CallGetSnacksById itemId -> (global, getSnacksByItemId itemId) - _ -> - let - (newState, cmd) = stateMachine msg global global.state - in - ({ global | state = newState }, cmd) +update msg outerState = case msg of + CallAdjustInventory item amount desc -> (outerState, adjustInventory item amount desc) + CallDisableItems items -> (outerState, disableItems items) + CallGetSnacksById item -> (outerState, getSnacksByItem item) + _ -> case outerState of + LoadingLocations -> case msg of + RcvLocations (Ok locations) -> + (LocationSelector locations, Cmd.none) + _ -> + (outerState, Cmd.none) + LocationSelector locations -> case msg of + SelectLocation location -> + (Initialized { locations = locations, location = location } <| Overview + { selectedItems = Set.empty + , desiredInventory = Dict.empty + , overviewItems = [] + } + , getOverviewItems location.id + ) + _ -> + (outerState, Cmd.none) + Initialized global state -> case msg of + ChangeLocation -> + (LocationSelector global.locations, Cmd.none) + _ -> + let + (newState, cmd) = stateMachine msg global state + in + (Initialized global newState, cmd) stateMachine msg global state = case state of - LoadingLocations -> case msg of - RcvLocations (Ok locations) -> - (LocationSelector locations, Cmd.none) - _ -> - (state, Cmd.none) - LocationSelector locations -> case msg of - SelectLocation location -> - (Overview - { location = location - , selectedItems = Set.empty - , desiredInventory = Dict.empty - , overviewItems = [] - } - , getOverviewItems location.id - ) - _ -> - (state, Cmd.none) Overview model -> case msg of RcvOverview (Ok overviewItems) -> (Overview - { location = model.location - , selectedItems = Set.empty + { selectedItems = Set.empty , desiredInventory = Dict.empty , overviewItems = overviewItems } , Cmd.none ) - RcvSnacks (Ok snacks) -> - (SnacksEditor { snacks = snacks }, Cmd.none) + RcvSnacks item (Ok snacks) -> + (SnacksEditor { item = item, snacks = snacks }, Cmd.none) RcvOther -> - (state, getOverviewItems model.location.id) + (state, getOverviewItems global.location.id) SelectItem itemId selected -> (Overview { model | selectedItems = setSelect itemId selected model.selectedItems }, Cmd.none) SetDesiredInventory itemId invStr -> case String.toInt invStr of @@ -231,10 +234,13 @@ stateMachine msg global state = case state of (state, transferInventory transfers) _ -> (state, Cmd.none) - SnacksEditor { snacks } -> - (state, Cmd.none) + SnacksEditor { snacks } -> case msg of + GoBack -> + (Overview { selectedItems = Set.empty, desiredInventory = Dict.empty, overviewItems = [] }, getOverviewItems global.location.id) + _ -> + (state, Cmd.none) -view { state } = case state of +view outerState = case outerState of LoadingLocations -> progress [] [] LocationSelector locations -> let @@ -245,7 +251,17 @@ view { state } = case state of [ p [] [ text "Raum auswählen:" ] , div [] <| List.map viewLocationButton locations ] - Overview { location, selectedItems, desiredInventory, overviewItems } -> + Initialized global state -> + div [] + [ h2 [] + [ text <| "Inventar " ++ global.location.name ++ " " + , button [ onClick ChangeLocation ] [ text "Raum ändern" ] + ] + , viewState global state + ] + +viewState global state = case state of + Overview { selectedItems, desiredInventory, overviewItems } -> let header = tableCells th <| List.map text [ "", "ID", "Artikel", "Barcode", "Preis", "Kaufdatum", "Snackeinträge", "Soll-Inv.", "Ist-Inv.", "Aktionen" ] viewOverviewItem oi = @@ -277,7 +293,7 @@ view { state } = case state of , text <| String.fromInt oi.id , text oi.name , code [] [ text oi.barcode ] - , text <| String.fromFloat oi.price + , text <| showEuros oi.price , text <| Tuple.first <| splitAt 'T' oi.bought , text <| String.fromInt oi.activeMappings , text <| String.fromInt oi.unitsLeft @@ -303,31 +319,30 @@ view { state } = case state of then [ disabled True ] else [ onClick <| TransferInventory oi.id ]) [ text <| String.fromInt sumSelected ++ " Einheiten umbuchen" ] - , button - (if oi.activeMappings == 0 - then [ disabled True ] - else [ onClick <| CallGetSnacksById oi.id ]) - [ text "Snackeinträge bearbeiten" ] + , button [ onClick <| CallGetSnacksById oi ] [ text "Snackeinträge bearbeiten" ] ] ] in div [] - [ h2 [] [ text <| "Inventar " ++ location.name ] - , table [] <| [header] ++ List.map viewOverviewItem overviewItems + [ table [] <| [header] ++ List.map viewOverviewItem overviewItems ] - SnacksEditor { snacks } -> + SnacksEditor { item, snacks } -> let header = tableCells th <| List.map text [ "ID", "Artikel", "Barcode", "Brutto" ] viewSnack snack = tableCells td [ text <| String.fromInt snack.id , text snack.name , text snack.barcode - , text <| String.fromFloat snack.price + , text <| showEuros snack.price ] in - table [] - [ thead [] [ header ] - , tbody [] <| List.map viewSnack snacks + div [] + [ button [ onClick GoBack ] [ text "Zurück" ] + , p [] [ text <| "Snackeinträge für Inventareintrag " ++ String.fromInt item.id ++ " (" ++ showEuros item.price ++ " Netto)" ] + , table [] + [ thead [] [ header ] + , tbody [] <| List.map viewSnack snacks + ] ] -- utils @@ -354,4 +369,11 @@ splitAt delim str = firstOcc = locate delim str in - (String.slice 0 firstOcc str, String.slice firstOcc (String.length str) str) + (String.slice 0 firstOcc str, String.slice (firstOcc + 1) (String.length str) str) + +showEuros : Float -> String +showEuros x = + let + (whole, fractional) = splitAt '.' (String.fromFloat x) + in + whole ++ "," ++ String.slice 0 2 (fractional ++ "00") ++ "€" diff --git a/static/jon.css b/static/jon.css index dc5b6c2..162206c 100644 --- a/static/jon.css +++ b/static/jon.css @@ -1,3 +1,11 @@ +html { + font-size: 12px; +} + +button, input { + font-size: 0.8rem; +} + body { font-family: Arial, Helvetica, sans-serif; }