From c6b8b0f93bc73abe26316acf11d1d213092bbedf Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 10:48:19 -0600 Subject: [PATCH 01/17] Get working on 0.18 --- Main.elm | 6 ++-- elm-package.json | 9 +++--- src/Api.elm | 83 +++++++++++++++++++++++------------------------- src/Types.elm | 3 +- src/Update.elm | 25 +++++++++++---- src/View.elm | 31 ++++++++++-------- 6 files changed, 84 insertions(+), 73 deletions(-) diff --git a/Main.elm b/Main.elm index 87b9be4..ac4543a 100644 --- a/Main.elm +++ b/Main.elm @@ -1,7 +1,7 @@ module Main exposing (..) -import Html.App as App +import Html import Time exposing (second, every) import Model exposing (model) @@ -18,7 +18,7 @@ messageSubscription _ = every (5 * second) (always PollMessages) -main : Program Never +main : Program Never Chat Msg main = - App.program + Html.program { init = init, update = update, view = view, subscriptions = messageSubscription } diff --git a/elm-package.json b/elm-package.json index 20cec6d..48915cb 100644 --- a/elm-package.json +++ b/elm-package.json @@ -9,10 +9,9 @@ ], "exposed-modules": [], "dependencies": { - "circuithub/elm-html-shorthand": "11.0.0 <= v < 12.0.0", - "elm-lang/core": "4.0.5 <= v < 5.0.0", - "elm-lang/html": "1.1.0 <= v < 2.0.0", - "evancz/elm-http": "3.0.1 <= v < 4.0.0" + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0", + "elm-lang/http": "1.0.0 <= v < 2.0.0" }, - "elm-version": "0.17.0 <= v < 0.18.0" + "elm-version": "0.18.0 <= v < 0.19.0" } diff --git a/src/Api.elm b/src/Api.elm index c5a6e19..e902169 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -2,8 +2,8 @@ module Api exposing (pollMessages, sendMessage) import Dict -import Http exposing (Error, Response, RawError(RawNetworkError)) -import Json.Decode as Json exposing ((:=)) +import Http exposing (Error, Response, Request) +import Json.Decode as Json exposing (field) import Json.Encode exposing (Value, encode, object, string) import Task exposing (Task) @@ -20,48 +20,58 @@ endpoint = "http://localhost:3000/messages" -- GET -pollMessages : Cmd Msg -pollMessages = - Task.perform onError onReceive getMessages +pollMessages : (Result Error (List ChatMessage) -> Msg) -> Cmd Msg +pollMessages callback = + --Task.perform onError onReceive getMessages + Http.send callback getMessagesRequest +getMessagesRequest : Request (List ChatMessage) +getMessagesRequest = + Http.get endpoint incomingMessagesDecoder + --Http.get messagesDecoder endpoint -getMessages : Task Http.Error (List ChatMessage) -getMessages = - Http.get messagesDecoder endpoint - -messagesDecoder : Json.Decoder (List ChatMessage) -messagesDecoder = Json.list messageDecoder +incomingMessagesDecoder : Json.Decoder (List ChatMessage) +incomingMessagesDecoder = + Json.list messageDecoder messageDecoder : Json.Decoder ChatMessage messageDecoder = - Json.object2 (\name message -> { name = name, message = message }) - ("name" := Json.string) - ("message" := Json.string) + Json.map2 (\name message -> { name = name, message = message }) + (field "name" Json.string) + (field "message" Json.string) -- POST -sendMessage : ChatMessage -> Cmd Msg -sendMessage msg = - Task.perform onError onSent (postMessage msg) +sendMessage : (Result Error Json.Value -> Msg) -> ChatMessage -> Cmd Msg +sendMessage callback msg = + --Task.perform onError onSent (postMessage msg) + Http.send callback <| requestForPostMessage msg + +-- postMessage : ChatMessage -> Task RawError () +-- postMessage msg = +-- Http.send Http.defaultSettings +-- { verb = "POST" +-- , headers = [] +-- , url = endpoint +-- , body = +-- messageEncoder msg +-- |> encode 0 +-- |> Http.string +-- } +-- |> Task.andThen handlePostResponse -postMessage : ChatMessage -> Task RawError () -postMessage msg = - Http.send Http.defaultSettings - { verb = "POST" - , headers = [] - , url = endpoint - , body = - messageEncoder msg - |> encode 0 - |> Http.string - } - `Task.andThen` handlePostResponse +requestForPostMessage : ChatMessage -> Request Json.Value +requestForPostMessage msg = + Http.post endpoint (bodyForSending msg) Json.value +bodyForSending : ChatMessage -> Http.Body +bodyForSending msg = + Http.jsonBody <| messageEncoder msg messageEncoder : ChatMessage -> Json.Value messageEncoder msg = @@ -82,18 +92,3 @@ onError err = ShowError (toString err) -- we just refresh messages so the person posting can see their new message. onSent : () -> Msg onSent _ = PollMessages - - -handlePostResponse : Response -> Task RawError () -handlePostResponse resp = - case Dict.get "Location" resp.headers of - Nothing -> - Task.fail RawNetworkError - - Just _ -> - Task.succeed () - - -onReceive : List ChatMessage -> Msg -onReceive msgs = - Incoming msgs diff --git a/src/Types.elm b/src/Types.elm index 426b333..12727fd 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -1,12 +1,13 @@ module Types exposing (Msg(..), Chat, ChatMessage) +import Http import Array exposing (Array) type Msg = SendMessage ChatMessage - | Incoming (List ChatMessage) + | Incoming (Result Http.Error (List ChatMessage)) | Input String | NoOp | PollMessages diff --git a/src/Update.elm b/src/Update.elm index f5696ae..0f1b5ba 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -2,6 +2,7 @@ module Update exposing (..) import Api +import Http import Task import Types exposing (Msg(..), Chat, ChatMessage) @@ -11,17 +12,15 @@ update msg model = case msg of SendMessage msg -> ( { model | field = "" } - , Api.sendMessage msg + , Api.sendMessage (\_->PollMessages) msg ) - Incoming msgs -> - ( { model | messages = msgs, errorMessage = "" } - , Cmd.none - ) + Incoming msgsResult -> + handleIncoming model msgsResult PollMessages -> ( model - , Api.pollMessages + , Api.pollMessages Incoming ) Input say -> @@ -40,3 +39,17 @@ update msg model = ) NoOp -> (model, Cmd.none) + + +handleIncoming : Chat -> (Result Http.Error (List ChatMessage)) -> (Chat, Cmd Msg) +handleIncoming model msgsResult = + case msgsResult of + Ok msgs -> + ( { model | messages = msgs, errorMessage = "" } + , Cmd.none + ) + + Err err -> + ( { model | errorMessage = toString err } + , Cmd.none + ) diff --git a/src/View.elm b/src/View.elm index bccd513..11a2983 100644 --- a/src/View.elm +++ b/src/View.elm @@ -5,7 +5,6 @@ import Array import Html exposing (..) import Html.Attributes as A import Html.Events as E -import Html.Shorthand exposing (..) import Json.Decode as Json import Api @@ -24,7 +23,7 @@ view model = [] , img [A.src "images/joan.png"] [] - , h1_ "Can We Talk!?" + , h1 [] [ text "Can We Talk!?" ] , row_ [ displayErrors model ] , row_ [ inputControls model ] , row_ [ messageList model ] @@ -34,7 +33,7 @@ view model = inputControls : Chat -> Html Msg inputControls model = fieldset [] - [ legend_ "Add Message" + [ legend [] [ text "Add Message" ] , form [ A.class "form-horizontal" , A.action "#" @@ -75,7 +74,8 @@ inputControls model = displayErrors : Chat -> Html a -displayErrors model = p +displayErrors model = + p [ A.class "text-danger" ] [ text model.errorMessage ] @@ -95,20 +95,20 @@ sendMessageOnEnter key msg = messageList : Chat -> Html a messageList model = let msgRow msg = - tr_ - [ td_ [ em_ msg.name ] - , td_ [ text msg.message ] + tr [] + [ td [] [ em [] [ text msg.name ] ] + , td [] [ text msg.message ] ] in table [ A.class "table col-xs-10 table-striped" ] - [ thead_ - [ tr_ + [ thead [] + [ tr [] [ th [ A.class "col-xs-2" ] [ text "Name" ] - , th_ [ text "Message" ] + , th [] [ text "Message" ] ] ] - , tbody_ (List.map msgRow model.messages) + , tbody [] (List.map msgRow model.messages) ] @@ -124,15 +124,18 @@ stylesheet href = row_ : List (Html a) -> Html a -row_ = div [ A.class "row" ] +row_ = + div [ A.class "row" ] container_ : List (Html a) -> Html a -container_ = div [ A.class "container" ] +container_ = + div [ A.class "container" ] formGroup_ : List (Html a) -> Html a -formGroup_ = div [ A.class "form-group" ] +formGroup_ = + div [ A.class "form-group" ] btnPrimary_ : String -> a -> Html a From 147baaf4a301df8d532308eeb36316fc8b72442b Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 10:52:26 -0600 Subject: [PATCH 02/17] Genericize messages in Api --- src/Api.elm | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/src/Api.elm b/src/Api.elm index e902169..95a3100 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -1,16 +1,12 @@ module Api exposing (pollMessages, sendMessage) -import Dict import Http exposing (Error, Response, Request) import Json.Decode as Json exposing (field) import Json.Encode exposing (Value, encode, object, string) import Task exposing (Task) -import Types exposing - ( ChatMessage - , Msg(Incoming, PollMessages, ShowError) - ) +import Types exposing (ChatMessage) endpoint : String @@ -20,15 +16,13 @@ endpoint = "http://localhost:3000/messages" -- GET -pollMessages : (Result Error (List ChatMessage) -> Msg) -> Cmd Msg +pollMessages : (Result Error (List ChatMessage) -> msg) -> Cmd msg pollMessages callback = - --Task.perform onError onReceive getMessages Http.send callback getMessagesRequest getMessagesRequest : Request (List ChatMessage) getMessagesRequest = Http.get endpoint incomingMessagesDecoder - --Http.get messagesDecoder endpoint incomingMessagesDecoder : Json.Decoder (List ChatMessage) @@ -46,25 +40,11 @@ messageDecoder = -- POST -sendMessage : (Result Error Json.Value -> Msg) -> ChatMessage -> Cmd Msg +sendMessage : (Result Error Json.Value -> msg) -> ChatMessage -> Cmd msg sendMessage callback msg = - --Task.perform onError onSent (postMessage msg) Http.send callback <| requestForPostMessage msg --- postMessage : ChatMessage -> Task RawError () --- postMessage msg = --- Http.send Http.defaultSettings --- { verb = "POST" --- , headers = [] --- , url = endpoint --- , body = --- messageEncoder msg --- |> encode 0 --- |> Http.string --- } --- |> Task.andThen handlePostResponse - requestForPostMessage : ChatMessage -> Request Json.Value requestForPostMessage msg = Http.post endpoint (bodyForSending msg) Json.value @@ -79,16 +59,3 @@ messageEncoder msg = [ ("name", string msg.name) , ("message", string msg.message) ] - - --- Response handlers - - -onError : err -> Msg -onError err = ShowError (toString err) - - --- About the weird type... if we get here then the Http POST worked, now --- we just refresh messages so the person posting can see their new message. -onSent : () -> Msg -onSent _ = PollMessages From 0f864f75d1a512a8438d026a42d1c7a486aa92e4 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 11:15:18 -0600 Subject: [PATCH 03/17] Prefetch messages --- Main.elm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Main.elm b/Main.elm index ac4543a..dfef744 100644 --- a/Main.elm +++ b/Main.elm @@ -8,9 +8,16 @@ import Model exposing (model) import Update exposing (update) import View exposing (view) import Types exposing (Chat, Msg(PollMessages)) +import Task +prefetchMessages : Cmd Msg +prefetchMessages = + Task.perform + (\_->PollMessages) + (Task.succeed ()) -init = (model, Cmd.none) + +init = (model, prefetchMessages) messageSubscription : Chat -> Sub Msg From 47275a5ba6e02b5cbf4af731edbee1c2af6fd747 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 11:15:45 -0600 Subject: [PATCH 04/17] Clean up Api --- src/Api.elm | 32 ++++++++++++++++++-------------- src/Update.elm | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Api.elm b/src/Api.elm index 95a3100..090acce 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -1,13 +1,16 @@ -module Api exposing (pollMessages, sendMessage) +module Api exposing (fetchMessages, sendMessage) -import Http exposing (Error, Response, Request) +import Http exposing (Error, Response, Request, Body) import Json.Decode as Json exposing (field) import Json.Encode exposing (Value, encode, object, string) import Task exposing (Task) import Types exposing (ChatMessage) +type alias DontCare = Json.Value +dontCare : Json.Decoder DontCare +dontCare = Json.value endpoint : String endpoint = "http://localhost:3000/messages" @@ -15,13 +18,13 @@ endpoint = "http://localhost:3000/messages" -- GET +fetchMessages : (Result Error (List ChatMessage) -> msg) -> Cmd msg +fetchMessages callback = + Http.send callback fetchMessagesRequest -pollMessages : (Result Error (List ChatMessage) -> msg) -> Cmd msg -pollMessages callback = - Http.send callback getMessagesRequest -getMessagesRequest : Request (List ChatMessage) -getMessagesRequest = +fetchMessagesRequest : Request (List ChatMessage) +fetchMessagesRequest = Http.get endpoint incomingMessagesDecoder @@ -32,27 +35,28 @@ incomingMessagesDecoder = messageDecoder : Json.Decoder ChatMessage messageDecoder = - Json.map2 (\name message -> { name = name, message = message }) + Json.map2 (\name message -> ChatMessage name message) (field "name" Json.string) (field "message" Json.string) -- POST - sendMessage : (Result Error Json.Value -> msg) -> ChatMessage -> Cmd msg sendMessage callback msg = - Http.send callback <| requestForPostMessage msg + Http.send callback <| sendMessageRequest msg + +sendMessageRequest : ChatMessage -> Request DontCare +sendMessageRequest msg = + Http.post endpoint (bodyForSending msg) dontCare -requestForPostMessage : ChatMessage -> Request Json.Value -requestForPostMessage msg = - Http.post endpoint (bodyForSending msg) Json.value -bodyForSending : ChatMessage -> Http.Body +bodyForSending : ChatMessage -> Body bodyForSending msg = Http.jsonBody <| messageEncoder msg + messageEncoder : ChatMessage -> Json.Value messageEncoder msg = object diff --git a/src/Update.elm b/src/Update.elm index 0f1b5ba..e6148c8 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -20,7 +20,7 @@ update msg model = PollMessages -> ( model - , Api.pollMessages Incoming + , Api.fetchMessages Incoming ) Input say -> From 1c049387916c3d1efcfad5ced04f096d593f5d36 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 11:16:01 -0600 Subject: [PATCH 05/17] Fix Enter-pressing bug --- src/View.elm | 71 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/View.elm b/src/View.elm index 11a2983..8881c02 100644 --- a/src/View.elm +++ b/src/View.elm @@ -33,44 +33,44 @@ view model = inputControls : Chat -> Html Msg inputControls model = fieldset [] - [ legend [] [ text "Add Message" ] - , form - [ A.class "form-horizontal" - , A.action "#" - ] - [ formGroup_ - [ label - [ A.for "name" - , A.class "col-sm-1" - ] - [ text "Name" ] - , input - [ A.id "name" - , A.class "form-control" - , A.class "col-sm-2" - , A.placeholder "Your Name" - , E.onInput SetName - ] - [] + [ legend [] [ text "Add Message" ] + , form + [ A.class "form-horizontal" + , E.onSubmit (mkMessage model |> SendMessage) ] - , formGroup_ - [ label - [ A.for "say" - , A.class "col-sm-1" + [ formGroup_ + [ label + [ A.for "name" + , A.class "col-sm-1" + ] + [ text "Name" ] + , input + [ A.id "name" + , A.class "form-control" + , A.class "col-sm-2" + , A.placeholder "Your Name" + , E.onInput SetName + ] + [] ] - [ text "Say" ] - , input - [ A.id "say" - , A.class "col-sm-9" - , A.placeholder "Enter a message" - , A.value model.field - , E.onInput Input + , formGroup_ + [ label + [ A.for "say" + , A.class "col-sm-1" + ] + [ text "Say" ] + , input + [ A.id "say" + , A.class "col-sm-9" + , A.placeholder "Enter a message" + , A.value model.field + , E.onInput Input + ] + [] ] - [] + , btnPrimary_ "Send" ] - , btnPrimary_ "Send" (mkMessage model |> SendMessage) ] - ] displayErrors : Chat -> Html a @@ -138,11 +138,10 @@ formGroup_ = div [ A.class "form-group" ] -btnPrimary_ : String -> a -> Html a -btnPrimary_ label x = +btnPrimary_ : String -> Html a +btnPrimary_ label = button [ A.class "btn btn-primary" - , E.onClick x ] [ text label ] From 287d11c2c19f798b18dd8b934cd3e2989f3e2664 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 11:27:39 -0600 Subject: [PATCH 06/17] Simplify Main --- Main.elm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Main.elm b/Main.elm index dfef744..532f78f 100644 --- a/Main.elm +++ b/Main.elm @@ -13,13 +13,13 @@ import Task prefetchMessages : Cmd Msg prefetchMessages = Task.perform - (\_->PollMessages) + (always PollMessages) (Task.succeed ()) +init : (Chat, Cmd Msg) init = (model, prefetchMessages) - messageSubscription : Chat -> Sub Msg messageSubscription _ = every (5 * second) (always PollMessages) From e0ec69f809c967a979d87e84c7f5620e50d8538b Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 13:01:39 -0600 Subject: [PATCH 07/17] Extract common Api stuff --- src/Api.elm | 75 +++++++++++++++++++----------------------------- src/Api/Get.elm | 11 +++++++ src/Api/Post.elm | 18 ++++++++++++ src/Update.elm | 2 +- 4 files changed, 59 insertions(+), 47 deletions(-) create mode 100644 src/Api/Get.elm create mode 100644 src/Api/Post.elm diff --git a/src/Api.elm b/src/Api.elm index 090acce..78f1b96 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -1,65 +1,48 @@ module Api exposing (fetchMessages, sendMessage) - -import Http exposing (Error, Response, Request, Body) -import Json.Decode as Json exposing (field) -import Json.Encode exposing (Value, encode, object, string) -import Task exposing (Task) +import Http exposing (Error) +import Json.Decode as JD exposing (Decoder) +import Json.Encode as JE exposing (Value) import Types exposing (ChatMessage) -type alias DontCare = Json.Value -dontCare : Json.Decoder DontCare -dontCare = Json.value +import Api.Post +import Api.Get endpoint : String -endpoint = "http://localhost:3000/messages" +endpoint = "http://localhost:3000/" +get : String -> Decoder a -> (Result Error a -> msg) -> Cmd msg +get path = + Api.Get.get (endpoint ++ path) --- GET +post : String -> JD.Value -> (Result Error JD.Value -> msg) -> Cmd msg +post path = + Api.Post.post (endpoint ++ path) fetchMessages : (Result Error (List ChatMessage) -> msg) -> Cmd msg -fetchMessages callback = - Http.send callback fetchMessagesRequest - - -fetchMessagesRequest : Request (List ChatMessage) -fetchMessagesRequest = - Http.get endpoint incomingMessagesDecoder +fetchMessages = + get "messages" incomingMessagesDecoder - -incomingMessagesDecoder : Json.Decoder (List ChatMessage) +incomingMessagesDecoder : Decoder (List ChatMessage) incomingMessagesDecoder = - Json.list messageDecoder - - -messageDecoder : Json.Decoder ChatMessage -messageDecoder = - Json.map2 (\name message -> ChatMessage name message) - (field "name" Json.string) - (field "message" Json.string) - - --- POST - -sendMessage : (Result Error Json.Value -> msg) -> ChatMessage -> Cmd msg -sendMessage callback msg = - Http.send callback <| sendMessageRequest msg - + JD.list receiveDecoder -sendMessageRequest : ChatMessage -> Request DontCare -sendMessageRequest msg = - Http.post endpoint (bodyForSending msg) dontCare +receiveDecoder : Decoder ChatMessage +receiveDecoder = + JD.map2 (\name message -> ChatMessage name message) + (JD.field "name" JD.string) + (JD.field "message" JD.string) -bodyForSending : ChatMessage -> Body -bodyForSending msg = - Http.jsonBody <| messageEncoder msg +sendMessage : ChatMessage -> (Result Error JD.Value -> msg) -> Cmd msg +sendMessage chatMessage = + post "messages" (sendEncoder chatMessage) -messageEncoder : ChatMessage -> Json.Value -messageEncoder msg = - object - [ ("name", string msg.name) - , ("message", string msg.message) +sendEncoder : ChatMessage -> JE.Value +sendEncoder msg = + JE.object + [ ("name", JE.string msg.name) + , ("message", JE.string msg.message) ] diff --git a/src/Api/Get.elm b/src/Api/Get.elm new file mode 100644 index 0000000..4f74d2f --- /dev/null +++ b/src/Api/Get.elm @@ -0,0 +1,11 @@ +module Api.Get exposing (get) + +import Http exposing (Error) +import Json.Decode exposing (Decoder) + +-- GET + +get : String -> Decoder a -> (Result Error a -> msg) -> Cmd msg +get endpoint decoder callback = + Http.get endpoint decoder + |> Http.send callback diff --git a/src/Api/Post.elm b/src/Api/Post.elm new file mode 100644 index 0000000..7ee78e9 --- /dev/null +++ b/src/Api/Post.elm @@ -0,0 +1,18 @@ +module Api.Post exposing (post) + +import Http exposing (Error, Request) +import Json.Decode as Json exposing (Value) + +type alias DontCare = Json.Value +dontCare : Json.Decoder DontCare +dontCare = Json.value + +post : String -> Value -> (Result Error Value -> msg) -> Cmd msg +post endpoint msg callback = + sendMessageRequest endpoint msg + |> Http.send callback + + +sendMessageRequest : String -> Value -> Request DontCare +sendMessageRequest endpoint payload = + Http.post endpoint (Http.jsonBody payload) dontCare diff --git a/src/Update.elm b/src/Update.elm index e6148c8..3b65fd4 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -12,7 +12,7 @@ update msg model = case msg of SendMessage msg -> ( { model | field = "" } - , Api.sendMessage (\_->PollMessages) msg + , Api.sendMessage msg (\_->PollMessages) ) Incoming msgsResult -> From c9f290dcd527ace21339128da301b7bc4165bc32 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 13:31:59 -0600 Subject: [PATCH 08/17] Convert Result to WebData --- elm-package.json | 3 ++- src/Api.elm | 25 +++++++++++++++---------- src/Api/Get.elm | 8 ++++++-- src/Api/Post.elm | 8 ++++++-- src/Types.elm | 4 ++-- src/Update.elm | 23 +++++++++++++---------- 6 files changed, 44 insertions(+), 27 deletions(-) diff --git a/elm-package.json b/elm-package.json index 48915cb..fa5a6e4 100644 --- a/elm-package.json +++ b/elm-package.json @@ -11,7 +11,8 @@ "dependencies": { "elm-lang/core": "5.0.0 <= v < 6.0.0", "elm-lang/html": "2.0.0 <= v < 3.0.0", - "elm-lang/http": "1.0.0 <= v < 2.0.0" + "elm-lang/http": "1.0.0 <= v < 2.0.0", + "krisajenkins/remotedata": "4.0.0 <= v < 5.0.0" }, "elm-version": "0.18.0 <= v < 0.19.0" } diff --git a/src/Api.elm b/src/Api.elm index 78f1b96..bc8bbcc 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -4,6 +4,8 @@ import Http exposing (Error) import Json.Decode as JD exposing (Decoder) import Json.Encode as JE exposing (Value) +import RemoteData exposing (WebData) + import Types exposing (ChatMessage) import Api.Post @@ -12,15 +14,9 @@ import Api.Get endpoint : String endpoint = "http://localhost:3000/" -get : String -> Decoder a -> (Result Error a -> msg) -> Cmd msg -get path = - Api.Get.get (endpoint ++ path) +-- GET -post : String -> JD.Value -> (Result Error JD.Value -> msg) -> Cmd msg -post path = - Api.Post.post (endpoint ++ path) - -fetchMessages : (Result Error (List ChatMessage) -> msg) -> Cmd msg +fetchMessages : (WebData (List ChatMessage) -> msg) -> Cmd msg fetchMessages = get "messages" incomingMessagesDecoder @@ -28,14 +24,23 @@ incomingMessagesDecoder : Decoder (List ChatMessage) incomingMessagesDecoder = JD.list receiveDecoder - receiveDecoder : Decoder ChatMessage receiveDecoder = JD.map2 (\name message -> ChatMessage name message) (JD.field "name" JD.string) (JD.field "message" JD.string) -sendMessage : ChatMessage -> (Result Error JD.Value -> msg) -> Cmd msg +get : String -> Decoder a -> (WebData a -> msg) -> Cmd msg +get path = + Api.Get.get (endpoint ++ path) + +-- POST + +post : String -> JD.Value -> (WebData JD.Value -> msg) -> Cmd msg +post path = + Api.Post.post (endpoint ++ path) + +sendMessage : ChatMessage -> (WebData JD.Value -> msg) -> Cmd msg sendMessage chatMessage = post "messages" (sendEncoder chatMessage) diff --git a/src/Api/Get.elm b/src/Api/Get.elm index 4f74d2f..1d5afc1 100644 --- a/src/Api/Get.elm +++ b/src/Api/Get.elm @@ -3,9 +3,13 @@ module Api.Get exposing (get) import Http exposing (Error) import Json.Decode exposing (Decoder) +import RemoteData exposing (WebData) + -- GET -get : String -> Decoder a -> (Result Error a -> msg) -> Cmd msg +get : String -> Decoder a -> (WebData a -> msg) -> Cmd msg get endpoint decoder callback = Http.get endpoint decoder - |> Http.send callback + |> Http.toTask + |> RemoteData.asCmd + |> Cmd.map callback diff --git a/src/Api/Post.elm b/src/Api/Post.elm index 7ee78e9..71949f7 100644 --- a/src/Api/Post.elm +++ b/src/Api/Post.elm @@ -3,14 +3,18 @@ module Api.Post exposing (post) import Http exposing (Error, Request) import Json.Decode as Json exposing (Value) +import RemoteData exposing (WebData) + type alias DontCare = Json.Value dontCare : Json.Decoder DontCare dontCare = Json.value -post : String -> Value -> (Result Error Value -> msg) -> Cmd msg +post : String -> Value -> (WebData Value -> msg) -> Cmd msg post endpoint msg callback = sendMessageRequest endpoint msg - |> Http.send callback + |> Http.toTask + |> RemoteData.asCmd + |> Cmd.map callback sendMessageRequest : String -> Value -> Request DontCare diff --git a/src/Types.elm b/src/Types.elm index 12727fd..080a1a7 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -2,12 +2,12 @@ module Types exposing (Msg(..), Chat, ChatMessage) import Http -import Array exposing (Array) +import RemoteData exposing (WebData) type Msg = SendMessage ChatMessage - | Incoming (Result Http.Error (List ChatMessage)) + | Incoming (WebData (List ChatMessage)) | Input String | NoOp | PollMessages diff --git a/src/Update.elm b/src/Update.elm index 3b65fd4..87772a2 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -6,6 +6,7 @@ import Http import Task import Types exposing (Msg(..), Chat, ChatMessage) +import RemoteData exposing (WebData, RemoteData(..)) update : Msg -> Chat -> (Chat, Cmd Msg) update msg model = @@ -16,7 +17,7 @@ update msg model = ) Incoming msgsResult -> - handleIncoming model msgsResult + (handleIncoming model msgsResult) ! [] PollMessages -> ( model @@ -41,15 +42,17 @@ update msg model = NoOp -> (model, Cmd.none) -handleIncoming : Chat -> (Result Http.Error (List ChatMessage)) -> (Chat, Cmd Msg) +handleIncoming : Chat -> (WebData (List ChatMessage)) -> Chat handleIncoming model msgsResult = case msgsResult of - Ok msgs -> - ( { model | messages = msgs, errorMessage = "" } - , Cmd.none - ) + NotAsked -> + model - Err err -> - ( { model | errorMessage = toString err } - , Cmd.none - ) + Loading -> + model + + Success msgs -> + { model | messages = msgs, errorMessage = "" } + + Failure e -> + { model | errorMessage = toString e } From 453821b60039dda9c5014beb85b15f8a78d2fe33 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 13:39:34 -0600 Subject: [PATCH 09/17] Lift cmd up to top-level --- src/Api.elm | 5 +++-- src/Api/Get.elm | 7 +++---- src/Update.elm | 4 +++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Api.elm b/src/Api.elm index bc8bbcc..a9217a1 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -3,6 +3,7 @@ module Api exposing (fetchMessages, sendMessage) import Http exposing (Error) import Json.Decode as JD exposing (Decoder) import Json.Encode as JE exposing (Value) +import Task exposing (Task) import RemoteData exposing (WebData) @@ -16,7 +17,7 @@ endpoint = "http://localhost:3000/" -- GET -fetchMessages : (WebData (List ChatMessage) -> msg) -> Cmd msg +fetchMessages : Task Error (List ChatMessage) fetchMessages = get "messages" incomingMessagesDecoder @@ -30,7 +31,7 @@ receiveDecoder = (JD.field "name" JD.string) (JD.field "message" JD.string) -get : String -> Decoder a -> (WebData a -> msg) -> Cmd msg +get : String -> Decoder a -> Task Error a get path = Api.Get.get (endpoint ++ path) diff --git a/src/Api/Get.elm b/src/Api/Get.elm index 1d5afc1..42d36e1 100644 --- a/src/Api/Get.elm +++ b/src/Api/Get.elm @@ -2,14 +2,13 @@ module Api.Get exposing (get) import Http exposing (Error) import Json.Decode exposing (Decoder) +import Task exposing (Task) import RemoteData exposing (WebData) -- GET -get : String -> Decoder a -> (WebData a -> msg) -> Cmd msg -get endpoint decoder callback = +get : String -> Decoder a -> Task Error a +get endpoint decoder = Http.get endpoint decoder |> Http.toTask - |> RemoteData.asCmd - |> Cmd.map callback diff --git a/src/Update.elm b/src/Update.elm index 87772a2..f4ca0b0 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -21,7 +21,9 @@ update msg model = PollMessages -> ( model - , Api.fetchMessages Incoming + , Api.fetchMessages + |> RemoteData.asCmd + |> Cmd.map Incoming ) Input say -> From 6a2870b1a502f00228d99657266c855b4df51773 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 13:55:30 -0600 Subject: [PATCH 10/17] Push cmd up for Post --- src/Api.elm | 22 +++++----------------- src/Api/Base.elm | 4 ++++ src/Api/Get.elm | 12 ++++++------ src/Api/Post.elm | 16 +++++----------- src/Update.elm | 6 +++++- 5 files changed, 25 insertions(+), 35 deletions(-) create mode 100644 src/Api/Base.elm diff --git a/src/Api.elm b/src/Api.elm index a9217a1..6cd9743 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -1,23 +1,19 @@ module Api exposing (fetchMessages, sendMessage) -import Http exposing (Error) +import Http exposing (Error, Request) import Json.Decode as JD exposing (Decoder) import Json.Encode as JE exposing (Value) -import Task exposing (Task) import RemoteData exposing (WebData) import Types exposing (ChatMessage) -import Api.Post -import Api.Get - -endpoint : String -endpoint = "http://localhost:3000/" +import Api.Post exposing (post) +import Api.Get exposing (get) -- GET -fetchMessages : Task Error (List ChatMessage) +fetchMessages : Request (List ChatMessage) fetchMessages = get "messages" incomingMessagesDecoder @@ -31,17 +27,9 @@ receiveDecoder = (JD.field "name" JD.string) (JD.field "message" JD.string) -get : String -> Decoder a -> Task Error a -get path = - Api.Get.get (endpoint ++ path) - -- POST -post : String -> JD.Value -> (WebData JD.Value -> msg) -> Cmd msg -post path = - Api.Post.post (endpoint ++ path) - -sendMessage : ChatMessage -> (WebData JD.Value -> msg) -> Cmd msg +sendMessage : ChatMessage -> Request JD.Value sendMessage chatMessage = post "messages" (sendEncoder chatMessage) diff --git a/src/Api/Base.elm b/src/Api/Base.elm new file mode 100644 index 0000000..d036496 --- /dev/null +++ b/src/Api/Base.elm @@ -0,0 +1,4 @@ +module Api.Base exposing (baseUri) + +baseUri : String +baseUri = "http://localhost:3000/" diff --git a/src/Api/Get.elm b/src/Api/Get.elm index 42d36e1..0c1185a 100644 --- a/src/Api/Get.elm +++ b/src/Api/Get.elm @@ -1,14 +1,14 @@ module Api.Get exposing (get) -import Http exposing (Error) +import Http exposing (Error, Request) import Json.Decode exposing (Decoder) -import Task exposing (Task) import RemoteData exposing (WebData) +import Api.Base exposing (baseUri) + -- GET -get : String -> Decoder a -> Task Error a -get endpoint decoder = - Http.get endpoint decoder - |> Http.toTask +get : String -> Decoder a -> Request a +get path decoder = + Http.get (baseUri ++ path) decoder diff --git a/src/Api/Post.elm b/src/Api/Post.elm index 71949f7..ad180b3 100644 --- a/src/Api/Post.elm +++ b/src/Api/Post.elm @@ -5,18 +5,12 @@ import Json.Decode as Json exposing (Value) import RemoteData exposing (WebData) +import Api.Base exposing (baseUri) + type alias DontCare = Json.Value dontCare : Json.Decoder DontCare dontCare = Json.value -post : String -> Value -> (WebData Value -> msg) -> Cmd msg -post endpoint msg callback = - sendMessageRequest endpoint msg - |> Http.toTask - |> RemoteData.asCmd - |> Cmd.map callback - - -sendMessageRequest : String -> Value -> Request DontCare -sendMessageRequest endpoint payload = - Http.post endpoint (Http.jsonBody payload) dontCare +post : String -> Value -> Request DontCare +post path msg = + Http.post (baseUri ++ path) (Http.jsonBody msg) dontCare diff --git a/src/Update.elm b/src/Update.elm index f4ca0b0..69ba317 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -13,7 +13,10 @@ update msg model = case msg of SendMessage msg -> ( { model | field = "" } - , Api.sendMessage msg (\_->PollMessages) + , Api.sendMessage msg + |> Http.toTask + |> RemoteData.asCmd + |> Cmd.map (always PollMessages) ) Incoming msgsResult -> @@ -22,6 +25,7 @@ update msg model = PollMessages -> ( model , Api.fetchMessages + |> Http.toTask |> RemoteData.asCmd |> Cmd.map Incoming ) From f151cda67d9d395b0901cdef10a5fa04de351ff0 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 14:16:57 -0600 Subject: [PATCH 11/17] Actually use WebData --- src/Model.elm | 3 ++- src/Types.elm | 4 ++-- src/Update.elm | 26 +++++++++++++++----------- src/View.elm | 49 ++++++++++++++++++++++++++++++++++--------------- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/Model.elm b/src/Model.elm index 5025c7a..13b1535 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -1,12 +1,13 @@ module Model exposing (..) +import RemoteData exposing (RemoteData(..)) import Types exposing (Chat) model : Chat model = - { messages = [] + { messages = NotAsked , field = "" , name = "" , errorMessage = "" diff --git a/src/Types.elm b/src/Types.elm index 080a1a7..db8ea6a 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -3,7 +3,7 @@ module Types exposing (Msg(..), Chat, ChatMessage) import Http -import RemoteData exposing (WebData) +import RemoteData exposing (WebData, RemoteData) type Msg = SendMessage ChatMessage @@ -20,7 +20,7 @@ type alias ChatMessage type alias Chat = - { messages : List ChatMessage + { messages : WebData (List ChatMessage) , errorMessage : String , field : String , name : String diff --git a/src/Update.elm b/src/Update.elm index 69ba317..1bb32dd 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -2,21 +2,25 @@ module Update exposing (..) import Api -import Http +import Http exposing (Request) import Task import Types exposing (Msg(..), Chat, ChatMessage) import RemoteData exposing (WebData, RemoteData(..)) +requestMap : (WebData a -> Msg) -> Request a -> Cmd Msg +requestMap msg request = + request + |> Http.toTask + |> RemoteData.asCmd + |> Cmd.map msg + update : Msg -> Chat -> (Chat, Cmd Msg) update msg model = case msg of SendMessage msg -> ( { model | field = "" } - , Api.sendMessage msg - |> Http.toTask - |> RemoteData.asCmd - |> Cmd.map (always PollMessages) + , requestMap (always PollMessages) (Api.sendMessage msg) ) Incoming msgsResult -> @@ -24,10 +28,7 @@ update msg model = PollMessages -> ( model - , Api.fetchMessages - |> Http.toTask - |> RemoteData.asCmd - |> Cmd.map Incoming + , requestMap Incoming Api.fetchMessages ) Input say -> @@ -58,7 +59,10 @@ handleIncoming model msgsResult = model Success msgs -> - { model | messages = msgs, errorMessage = "" } + { model | messages = Success msgs, errorMessage = "" } Failure e -> - { model | errorMessage = toString e } + { model + | errorMessage = toString e + , messages = Failure e + } diff --git a/src/View.elm b/src/View.elm index 8881c02..3e8fa3b 100644 --- a/src/View.elm +++ b/src/View.elm @@ -6,6 +6,7 @@ import Html exposing (..) import Html.Attributes as A import Html.Events as E import Json.Decode as Json +import RemoteData exposing (WebData, RemoteData(..)) import Api import Types exposing (Msg(..), Chat, ChatMessage) @@ -94,23 +95,41 @@ sendMessageOnEnter key msg = messageList : Chat -> Html a messageList model = - let msgRow msg = - tr [] - [ td [] [ em [] [ text msg.name ] ] - , td [] [ text msg.message ] - ] - in - table - [ A.class "table col-xs-10 table-striped" ] - [ thead [] - [ tr [] - [ th [ A.class "col-xs-2" ] [ text "Name" ] - , th [] [ text "Message" ] - ] - ] - , tbody [] (List.map msgRow model.messages) + table + [ A.class "table col-xs-10 table-striped" ] + [ thead [] + [ tr [] + [ th [ A.class "col-xs-2" ] [ text "Name" ] + , th [] [ text "Message" ] ] + ] + , tbody [] (perhapsMessages model.messages) + ] + +msgRow : ChatMessage -> Html a +msgRow msg = + tr [] + [ td [] [ em [] [ text msg.name ] ] + , td [] [ text msg.message ] + ] + +perhapsMessages : WebData (List ChatMessage) -> List (Html a) +perhapsMessages msgs = + case msgs of + NotAsked -> + [ tr [] + [ td [] [ text "not loaded" ] ] + ] + Loading -> + [ tr [] + [ td [] [ text "loading" ] ] + ] + + Failure e -> + [] + Success messages -> + List.map msgRow messages stylesheet : String -> Html a stylesheet href = From ff98b5ad39124ca39d01bf39bf81633373ca9fc3 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 14:42:44 -0600 Subject: [PATCH 12/17] Simplify view --- src/View.elm | 127 +++++++++++++++++++++------------------------------ 1 file changed, 53 insertions(+), 74 deletions(-) diff --git a/src/View.elm b/src/View.elm index 3e8fa3b..223b716 100644 --- a/src/View.elm +++ b/src/View.elm @@ -3,82 +3,71 @@ module View exposing (..) import Array import Html exposing (..) -import Html.Attributes as A -import Html.Events as E -import Json.Decode as Json +import Html.Attributes exposing (..) +import Html.Events exposing (..) import RemoteData exposing (WebData, RemoteData(..)) import Api import Types exposing (Msg(..), Chat, ChatMessage) - view : Chat -> Html Msg view model = - container_ - [ stylesheet "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" - , stylesheet "css/style.css" - , node "link" - [ A.href "http://fonts.googleapis.com/css?family=Special+Elite" - , A.rel "stylesheet" + div [ class "container" ] + [ stylesheet "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" + , stylesheet "css/style.css" + , stylesheet "http://fonts.googleapis.com/css?family=Special+Elite" + , img [src "images/joan.png"] [] + , h1 [] [ text "Can We Talk!?" ] + , row_ [ displayErrors model.messages ] + , row_ [ inputControls model ] + , row_ [ messageList model ] ] - [] - , img [A.src "images/joan.png"] - [] - , h1 [] [ text "Can We Talk!?" ] - , row_ [ displayErrors model ] - , row_ [ inputControls model ] - , row_ [ messageList model ] - ] inputControls : Chat -> Html Msg inputControls model = fieldset [] [ legend [] [ text "Add Message" ] - , form - [ A.class "form-horizontal" - , E.onSubmit (mkMessage model |> SendMessage) + , Html.form + [ class "form-horizontal" + , onSubmit (mkMessage model |> SendMessage) ] - [ formGroup_ - [ label - [ A.for "name" - , A.class "col-sm-1" - ] - [ text "Name" ] - , input - [ A.id "name" - , A.class "form-control" - , A.class "col-sm-2" - , A.placeholder "Your Name" - , E.onInput SetName - ] - [] - ] - , formGroup_ - [ label - [ A.for "say" - , A.class "col-sm-1" - ] - [ text "Say" ] - , input - [ A.id "say" - , A.class "col-sm-9" - , A.placeholder "Enter a message" - , A.value model.field - , E.onInput Input - ] - [] - ] + [ formGroup_ ( labeledField "name" "Name" "Your Name" model.name SetName ) + , formGroup_ (labeledField "say" "Say" "Enter a message" model.field Input ) , btnPrimary_ "Send" ] ] +labeledField : String -> String -> String -> String -> (String -> Msg) -> List (Html Msg) +labeledField id_ text_ placeholder_ value_ msg_ = + [ label + [ for id_ + , class "col-sm-1" + ] + [ text text_ ] + , input + [ id id_ + , class "form-control col-sm-9" + , placeholder placeholder_ + , value value_ + , onInput msg_ + ] + [] + ] -displayErrors : Chat -> Html a -displayErrors model = - p - [ A.class "text-danger" ] - [ text model.errorMessage ] + +displayErrors : WebData a -> Html b +displayErrors messages = + let + content = + case messages of + NotAsked -> [] + Loading -> [] + Success _ -> [] + Failure e -> + [ text <| toString e ] + in + p [ class "text-danger" ] content mkMessage : Chat -> ChatMessage @@ -96,10 +85,10 @@ sendMessageOnEnter key msg = messageList : Chat -> Html a messageList model = table - [ A.class "table col-xs-10 table-striped" ] + [ class "table col-xs-10 table-striped" ] [ thead [] [ tr [] - [ th [ A.class "col-xs-2" ] [ text "Name" ] + [ th [ class "col-xs-2" ] [ text "Name" ] , th [] [ text "Message" ] ] ] @@ -132,10 +121,10 @@ perhapsMessages msgs = List.map msgRow messages stylesheet : String -> Html a -stylesheet href = +stylesheet href_ = node "link" - [ A.rel "stylesheet" - , A.href href + [ rel "stylesheet" + , href href_ ] [] @@ -144,27 +133,17 @@ stylesheet href = row_ : List (Html a) -> Html a row_ = - div [ A.class "row" ] - - -container_ : List (Html a) -> Html a -container_ = - div [ A.class "container" ] + div [ class "row" ] formGroup_ : List (Html a) -> Html a formGroup_ = - div [ A.class "form-group" ] + div [ class "form-group" ] btnPrimary_ : String -> Html a btnPrimary_ label = button - [ A.class "btn btn-primary" + [ class "btn btn-primary" ] [ text label ] - - -onKeyUp : (Int -> msg) -> Attribute msg -onKeyUp tagger = - E.on "keyup" (Json.map tagger E.keyCode) From 7c0605b744425089296d7093d2e7747dd8697785 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 16:29:21 -0600 Subject: [PATCH 13/17] Spiff up --- src/Model.elm | 2 +- src/Types.elm | 2 +- src/Update.elm | 4 ++-- src/View.elm | 9 ++++++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Model.elm b/src/Model.elm index 13b1535..a0c7296 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -8,7 +8,7 @@ import Types exposing (Chat) model : Chat model = { messages = NotAsked - , field = "" + , saying = "" , name = "" , errorMessage = "" } diff --git a/src/Types.elm b/src/Types.elm index db8ea6a..6f8d4e8 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -22,6 +22,6 @@ type alias ChatMessage type alias Chat = { messages : WebData (List ChatMessage) , errorMessage : String - , field : String + , saying : String , name : String } diff --git a/src/Update.elm b/src/Update.elm index 1bb32dd..4053fdc 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -19,7 +19,7 @@ update : Msg -> Chat -> (Chat, Cmd Msg) update msg model = case msg of SendMessage msg -> - ( { model | field = "" } + ( { model | saying = "" } , requestMap (always PollMessages) (Api.sendMessage msg) ) @@ -32,7 +32,7 @@ update msg model = ) Input say -> - ( { model | field = say } + ( { model | saying = say } , Cmd.none ) diff --git a/src/View.elm b/src/View.elm index 223b716..59897f4 100644 --- a/src/View.elm +++ b/src/View.elm @@ -33,7 +33,7 @@ inputControls model = , onSubmit (mkMessage model |> SendMessage) ] [ formGroup_ ( labeledField "name" "Name" "Your Name" model.name SetName ) - , formGroup_ (labeledField "say" "Say" "Enter a message" model.field Input ) + , formGroup_ (labeledField "say" "Say" "Enter a message" model.saying Input ) , btnPrimary_ "Send" ] ] @@ -73,7 +73,7 @@ displayErrors messages = mkMessage : Chat -> ChatMessage mkMessage m = { name = m.name - , message = m.field + , message = m.saying } @@ -118,7 +118,10 @@ perhapsMessages msgs = [] Success messages -> - List.map msgRow messages + messages + |> List.reverse + |> List.take 30 + |> List.map msgRow stylesheet : String -> Html a stylesheet href_ = From 68a13c329efc7ffbc34600ad5aac162363ebaf0d Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Tue, 22 Nov 2016 16:37:44 -0600 Subject: [PATCH 14/17] Simplify Api; Standardize Model name --- Main.elm | 9 +++++---- src/Api.elm | 19 ++++++++++++++++--- src/Api/Base.elm | 4 ---- src/Api/Get.elm | 14 -------------- src/Api/Post.elm | 16 ---------------- src/Model.elm | 14 +++++++++++--- src/Types.elm | 18 ++---------------- src/Update.elm | 7 ++++--- src/View.elm | 11 ++++++----- 9 files changed, 44 insertions(+), 68 deletions(-) delete mode 100644 src/Api/Base.elm delete mode 100644 src/Api/Get.elm delete mode 100644 src/Api/Post.elm diff --git a/Main.elm b/Main.elm index 532f78f..ad09d5b 100644 --- a/Main.elm +++ b/Main.elm @@ -7,7 +7,8 @@ import Time exposing (second, every) import Model exposing (model) import Update exposing (update) import View exposing (view) -import Types exposing (Chat, Msg(PollMessages)) +import Types exposing (Msg(PollMessages)) +import Model exposing (Model) import Task prefetchMessages : Cmd Msg @@ -17,15 +18,15 @@ prefetchMessages = (Task.succeed ()) -init : (Chat, Cmd Msg) +init : (Model, Cmd Msg) init = (model, prefetchMessages) -messageSubscription : Chat -> Sub Msg +messageSubscription : Model -> Sub Msg messageSubscription _ = every (5 * second) (always PollMessages) -main : Program Never Chat Msg +main : Program Never Model Msg main = Html.program { init = init, update = update, view = view, subscriptions = messageSubscription } diff --git a/src/Api.elm b/src/Api.elm index 6cd9743..e0fb966 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -6,13 +6,17 @@ import Json.Encode as JE exposing (Value) import RemoteData exposing (WebData) -import Types exposing (ChatMessage) +import Model exposing (ChatMessage) -import Api.Post exposing (post) -import Api.Get exposing (get) +baseUri : String +baseUri = "http://localhost:3000/" -- GET +get : String -> Decoder a -> Request a +get path decoder = + Http.get (baseUri ++ path) decoder + fetchMessages : Request (List ChatMessage) fetchMessages = get "messages" incomingMessagesDecoder @@ -29,6 +33,15 @@ receiveDecoder = -- POST +type alias DontCare = JD.Value +dontCare : JD.Decoder DontCare +dontCare = JD.value + +post : String -> JE.Value -> Request DontCare +post path msg = + Http.post (baseUri ++ path) (Http.jsonBody msg) dontCare + + sendMessage : ChatMessage -> Request JD.Value sendMessage chatMessage = post "messages" (sendEncoder chatMessage) diff --git a/src/Api/Base.elm b/src/Api/Base.elm deleted file mode 100644 index d036496..0000000 --- a/src/Api/Base.elm +++ /dev/null @@ -1,4 +0,0 @@ -module Api.Base exposing (baseUri) - -baseUri : String -baseUri = "http://localhost:3000/" diff --git a/src/Api/Get.elm b/src/Api/Get.elm deleted file mode 100644 index 0c1185a..0000000 --- a/src/Api/Get.elm +++ /dev/null @@ -1,14 +0,0 @@ -module Api.Get exposing (get) - -import Http exposing (Error, Request) -import Json.Decode exposing (Decoder) - -import RemoteData exposing (WebData) - -import Api.Base exposing (baseUri) - --- GET - -get : String -> Decoder a -> Request a -get path decoder = - Http.get (baseUri ++ path) decoder diff --git a/src/Api/Post.elm b/src/Api/Post.elm deleted file mode 100644 index ad180b3..0000000 --- a/src/Api/Post.elm +++ /dev/null @@ -1,16 +0,0 @@ -module Api.Post exposing (post) - -import Http exposing (Error, Request) -import Json.Decode as Json exposing (Value) - -import RemoteData exposing (WebData) - -import Api.Base exposing (baseUri) - -type alias DontCare = Json.Value -dontCare : Json.Decoder DontCare -dontCare = Json.value - -post : String -> Value -> Request DontCare -post path msg = - Http.post (baseUri ++ path) (Http.jsonBody msg) dontCare diff --git a/src/Model.elm b/src/Model.elm index a0c7296..d6c324c 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -1,11 +1,19 @@ module Model exposing (..) -import RemoteData exposing (RemoteData(..)) +import RemoteData exposing (RemoteData(..), WebData) -import Types exposing (Chat) +type alias ChatMessage + = { name: String, message: String } -model : Chat +type alias Model = + { messages : WebData (List ChatMessage) + , errorMessage : String + , saying : String + , name : String + } + +model : Model model = { messages = NotAsked , saying = "" diff --git a/src/Types.elm b/src/Types.elm index 6f8d4e8..efa5d15 100644 --- a/src/Types.elm +++ b/src/Types.elm @@ -1,9 +1,7 @@ -module Types exposing (Msg(..), Chat, ChatMessage) - - -import Http +module Types exposing (Msg(..)) import RemoteData exposing (WebData, RemoteData) +import Model exposing (ChatMessage) type Msg = SendMessage ChatMessage @@ -13,15 +11,3 @@ type Msg | PollMessages | SetName String | ShowError String - - -type alias ChatMessage - = { name: String, message: String } - - -type alias Chat = - { messages : WebData (List ChatMessage) - , errorMessage : String - , saying : String - , name : String - } diff --git a/src/Update.elm b/src/Update.elm index 4053fdc..cbb9e64 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -4,7 +4,8 @@ module Update exposing (..) import Api import Http exposing (Request) import Task -import Types exposing (Msg(..), Chat, ChatMessage) +import Types exposing (Msg(..)) +import Model exposing (Model, ChatMessage) import RemoteData exposing (WebData, RemoteData(..)) @@ -15,7 +16,7 @@ requestMap msg request = |> RemoteData.asCmd |> Cmd.map msg -update : Msg -> Chat -> (Chat, Cmd Msg) +update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of SendMessage msg -> @@ -49,7 +50,7 @@ update msg model = NoOp -> (model, Cmd.none) -handleIncoming : Chat -> (WebData (List ChatMessage)) -> Chat +handleIncoming : Model -> (WebData (List ChatMessage)) -> Model handleIncoming model msgsResult = case msgsResult of NotAsked -> diff --git a/src/View.elm b/src/View.elm index 59897f4..91dede5 100644 --- a/src/View.elm +++ b/src/View.elm @@ -8,9 +8,10 @@ import Html.Events exposing (..) import RemoteData exposing (WebData, RemoteData(..)) import Api -import Types exposing (Msg(..), Chat, ChatMessage) +import Types exposing (Msg(..)) +import Model exposing (Model, ChatMessage) -view : Chat -> Html Msg +view : Model -> Html Msg view model = div [ class "container" ] [ stylesheet "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" @@ -24,7 +25,7 @@ view model = ] -inputControls : Chat -> Html Msg +inputControls : Model -> Html Msg inputControls model = fieldset [] [ legend [] [ text "Add Message" ] @@ -70,7 +71,7 @@ displayErrors messages = p [ class "text-danger" ] content -mkMessage : Chat -> ChatMessage +mkMessage : Model -> ChatMessage mkMessage m = { name = m.name , message = m.saying @@ -82,7 +83,7 @@ sendMessageOnEnter key msg = if key == 13 then SendMessage msg else NoOp -messageList : Chat -> Html a +messageList : Model -> Html a messageList model = table [ class "table col-xs-10 table-striped" ] From 5d88c54f56c5a2c1a5279e47b288b9ea4220438b Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Wed, 23 Nov 2016 11:09:31 -0600 Subject: [PATCH 15/17] Simplify and format --- Main.elm | 27 ++++++------ Makefile | 2 +- css/style.css | 9 ++-- src/Api.elm | 45 ++++++++----------- src/Messages.elm | 10 +++++ src/Model.elm | 24 +++++----- src/Types.elm | 13 ------ src/Update.elm | 66 +++++----------------------- src/View.elm | 112 +++++++++++++++++++++-------------------------- 9 files changed, 122 insertions(+), 186 deletions(-) create mode 100644 src/Messages.elm delete mode 100644 src/Types.elm diff --git a/Main.elm b/Main.elm index ad09d5b..ab51d68 100644 --- a/Main.elm +++ b/Main.elm @@ -1,32 +1,33 @@ -module Main exposing (..) - +module Main exposing (main) import Html import Time exposing (second, every) -import Model exposing (model) +import Model exposing (Chat, model) import Update exposing (update) import View exposing (view) -import Types exposing (Msg(PollMessages)) -import Model exposing (Model) +import Messages exposing (Msg(PollMessages)) import Task +init : (Chat, Cmd Msg) +init = (model, prefetchMessages) + prefetchMessages : Cmd Msg prefetchMessages = Task.perform (always PollMessages) (Task.succeed ()) - -init : (Model, Cmd Msg) -init = (model, prefetchMessages) - -messageSubscription : Model -> Sub Msg -messageSubscription _ = +subscriptions : Chat -> Sub Msg +subscriptions _ = every (5 * second) (always PollMessages) -main : Program Never Model Msg +main : Program Never Chat Msg main = Html.program - { init = init, update = update, view = view, subscriptions = messageSubscription } + { init = init + , update = update + , view = view + , subscriptions = subscriptions + } diff --git a/Makefile b/Makefile index 5ee4f99..a409d7c 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ main = Main.elm sources = \ src/Api.elm \ src/Model.elm \ - src/Types.elm \ + src/Messages.elm \ src/Update.elm \ src/View.elm cc = elm make diff --git a/css/style.css b/css/style.css index 791fd29..99ed780 100644 --- a/css/style.css +++ b/css/style.css @@ -7,10 +7,8 @@ h1 { } img { - float: right; height: 135px; - position: absolute; - right: 30%; + width: auto; } .btn { @@ -18,13 +16,14 @@ img { margin-top: 25px; float: right; } + label { font-size: 18px; } + #say, #name { font-size: 16px; width: 90%; border-radius: 20px; height: 40px; - -} \ No newline at end of file +} diff --git a/src/Api.elm b/src/Api.elm index e0fb966..97c81db 100644 --- a/src/Api.elm +++ b/src/Api.elm @@ -1,51 +1,44 @@ module Api exposing (fetchMessages, sendMessage) -import Http exposing (Error, Request) +import Http exposing (Body) import Json.Decode as JD exposing (Decoder) import Json.Encode as JE exposing (Value) import RemoteData exposing (WebData) -import Model exposing (ChatMessage) +import Model exposing (ChatMessage, ChatList) +import Messages exposing (Msg) -baseUri : String -baseUri = "http://localhost:3000/" +endpoint : String +endpoint = "http://localhost:3000/messages" -- GET -get : String -> Decoder a -> Request a -get path decoder = - Http.get (baseUri ++ path) decoder - -fetchMessages : Request (List ChatMessage) -fetchMessages = - get "messages" incomingMessagesDecoder +fetchMessages : (ChatList -> Msg) -> Cmd Msg +fetchMessages callback = + Http.get endpoint incomingMessagesDecoder + |> Http.send (callback << RemoteData.fromResult) incomingMessagesDecoder : Decoder (List ChatMessage) incomingMessagesDecoder = - JD.list receiveDecoder + JD.list incomingMessageDecoder -receiveDecoder : Decoder ChatMessage -receiveDecoder = +incomingMessageDecoder : Decoder ChatMessage +incomingMessageDecoder = JD.map2 (\name message -> ChatMessage name message) (JD.field "name" JD.string) (JD.field "message" JD.string) -- POST -type alias DontCare = JD.Value -dontCare : JD.Decoder DontCare -dontCare = JD.value - -post : String -> JE.Value -> Request DontCare -post path msg = - Http.post (baseUri ++ path) (Http.jsonBody msg) dontCare - - -sendMessage : ChatMessage -> Request JD.Value -sendMessage chatMessage = - post "messages" (sendEncoder chatMessage) +sendMessage : ChatMessage -> (WebData JD.Value -> Msg) -> Cmd Msg +sendMessage chatMessage callback = + Http.post endpoint (bodyToSend chatMessage) JD.value + |> Http.send (callback << RemoteData.fromResult) +bodyToSend : ChatMessage -> Body +bodyToSend chatMessage = + Http.jsonBody <| sendEncoder chatMessage sendEncoder : ChatMessage -> JE.Value sendEncoder msg = diff --git a/src/Messages.elm b/src/Messages.elm new file mode 100644 index 0000000..3d70b8c --- /dev/null +++ b/src/Messages.elm @@ -0,0 +1,10 @@ +module Messages exposing (Msg(..)) + +import Model exposing (ChatMessage, ChatList) + +type Msg + = SendMessage ChatMessage + | Incoming ChatList + | Input String + | PollMessages + | SetName String diff --git a/src/Model.elm b/src/Model.elm index d6c324c..3d5a157 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -1,22 +1,24 @@ -module Model exposing (..) +module Model exposing (Chat, ChatList, ChatMessage, model) -import RemoteData exposing (RemoteData(..), WebData) +import RemoteData exposing (RemoteData(NotAsked), WebData) -type alias ChatMessage - = { name: String, message: String } - - -type alias Model = - { messages : WebData (List ChatMessage) - , errorMessage : String +type alias Chat = + { messages : ChatList , saying : String , name : String } -model : Model +model : Chat model = { messages = NotAsked , saying = "" , name = "" - , errorMessage = "" + } + +type alias ChatList = + WebData (List ChatMessage) + +type alias ChatMessage = + { name : String + , message : String } diff --git a/src/Types.elm b/src/Types.elm deleted file mode 100644 index efa5d15..0000000 --- a/src/Types.elm +++ /dev/null @@ -1,13 +0,0 @@ -module Types exposing (Msg(..)) - -import RemoteData exposing (WebData, RemoteData) -import Model exposing (ChatMessage) - -type Msg - = SendMessage ChatMessage - | Incoming (WebData (List ChatMessage)) - | Input String - | NoOp - | PollMessages - | SetName String - | ShowError String diff --git a/src/Update.elm b/src/Update.elm index cbb9e64..f0b428d 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -1,69 +1,23 @@ -module Update exposing (..) - +module Update exposing (update) import Api -import Http exposing (Request) -import Task -import Types exposing (Msg(..)) -import Model exposing (Model, ChatMessage) - -import RemoteData exposing (WebData, RemoteData(..)) - -requestMap : (WebData a -> Msg) -> Request a -> Cmd Msg -requestMap msg request = - request - |> Http.toTask - |> RemoteData.asCmd - |> Cmd.map msg +import Messages exposing (Msg(..)) +import Model exposing (Chat) -update : Msg -> Model -> (Model, Cmd Msg) +update : Msg -> Chat -> (Chat, Cmd Msg) update msg model = case msg of - SendMessage msg -> - ( { model | saying = "" } - , requestMap (always PollMessages) (Api.sendMessage msg) - ) + SendMessage message -> + ({ model | saying = "" }, Api.sendMessage message (always PollMessages)) Incoming msgsResult -> - (handleIncoming model msgsResult) ! [] + ({model | messages = msgsResult}, Cmd.none) PollMessages -> - ( model - , requestMap Incoming Api.fetchMessages - ) + (model, Api.fetchMessages Incoming) Input say -> - ( { model | saying = say } - , Cmd.none - ) + ({ model | saying = say }, Cmd.none) SetName name -> - ( { model | name = name } - , Cmd.none - ) - - ShowError err -> - ( { model | errorMessage = err } - , Cmd.none - ) - - NoOp -> (model, Cmd.none) - - -handleIncoming : Model -> (WebData (List ChatMessage)) -> Model -handleIncoming model msgsResult = - case msgsResult of - NotAsked -> - model - - Loading -> - model - - Success msgs -> - { model | messages = Success msgs, errorMessage = "" } - - Failure e -> - { model - | errorMessage = toString e - , messages = Failure e - } + ({ model | name = name }, Cmd.none) diff --git a/src/View.elm b/src/View.elm index 91dede5..3641117 100644 --- a/src/View.elm +++ b/src/View.elm @@ -1,31 +1,31 @@ -module View exposing (..) +module View exposing (view) -import Array import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) import RemoteData exposing (WebData, RemoteData(..)) -import Api -import Types exposing (Msg(..)) -import Model exposing (Model, ChatMessage) +import Messages exposing (Msg(SendMessage, Input, SetName)) +import Model exposing (Chat, ChatMessage, ChatList) -view : Model -> Html Msg +view : Chat -> Html Msg view model = div [ class "container" ] [ stylesheet "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" , stylesheet "css/style.css" , stylesheet "http://fonts.googleapis.com/css?family=Special+Elite" - , img [src "images/joan.png"] [] - , h1 [] [ text "Can We Talk!?" ] - , row_ [ displayErrors model.messages ] + , row_ + [ h1 [class "col-xs-7"] [ text "Can We Talk!?" ] + , div [class "col-xs-5"] [ img [src "images/joan.png"] [] ] + ] + , row_ [ errors model.messages ] , row_ [ inputControls model ] - , row_ [ messageList model ] + , row_ [ messageList model.messages ] ] -inputControls : Model -> Html Msg +inputControls : Chat -> Html Msg inputControls model = fieldset [] [ legend [] [ text "Add Message" ] @@ -33,7 +33,7 @@ inputControls model = [ class "form-horizontal" , onSubmit (mkMessage model |> SendMessage) ] - [ formGroup_ ( labeledField "name" "Name" "Your Name" model.name SetName ) + [ formGroup_ (labeledField "name" "Name" "Your Name" model.name SetName ) , formGroup_ (labeledField "say" "Say" "Enter a message" model.saying Input ) , btnPrimary_ "Send" ] @@ -57,8 +57,8 @@ labeledField id_ text_ placeholder_ value_ msg_ = ] -displayErrors : WebData a -> Html b -displayErrors messages = +errors : WebData a -> Html b +errors messages = let content = case messages of @@ -71,30 +71,34 @@ displayErrors messages = p [ class "text-danger" ] content -mkMessage : Model -> ChatMessage +mkMessage : Chat -> ChatMessage mkMessage m = { name = m.name , message = m.saying } -sendMessageOnEnter : Int -> ChatMessage -> Msg -sendMessageOnEnter key msg = - if key == 13 then SendMessage msg else NoOp - - -messageList : Model -> Html a -messageList model = - table - [ class "table col-xs-10 table-striped" ] - [ thead [] - [ tr [] - [ th [ class "col-xs-2" ] [ text "Name" ] - , th [] [ text "Message" ] - ] - ] - , tbody [] (perhapsMessages model.messages) - ] +messageList : ChatList -> Html a +messageList messages = + case messages of + NotAsked -> + notTable "Loading..." + Loading -> + notTable "Loading..." + Failure e -> + notTable "Loading failed" + Success s -> + let + messages_ = + s + |> List.reverse + |> List.take 30 + |> List.map msgRow + in + zebraTable + [ th [ class "col-xs-2" ] [ text "Name" ] + , th [] [ text "Message" ] + ] messages_ msgRow : ChatMessage -> Html a msgRow msg = @@ -103,34 +107,15 @@ msgRow msg = , td [] [ text msg.message ] ] -perhapsMessages : WebData (List ChatMessage) -> List (Html a) -perhapsMessages msgs = - case msgs of - NotAsked -> - [ tr [] - [ td [] [ text "not loaded" ] ] - ] - Loading -> - [ tr [] - [ td [] [ text "loading" ] ] - ] - - Failure e -> - [] - - Success messages -> - messages - |> List.reverse - |> List.take 30 - |> List.map msgRow - stylesheet : String -> Html a stylesheet href_ = - node "link" - [ rel "stylesheet" - , href href_ - ] [] + node "link" [ rel "stylesheet", href href_] [] +notTable : String -> Html a +notTable content = + div [ class "col-xs-12" ] + [ aside [] [ text content ] + ] -- From Bootstrap @@ -147,7 +132,12 @@ formGroup_ = btnPrimary_ : String -> Html a btnPrimary_ label = - button - [ class "btn btn-primary" - ] - [ text label ] + button [ class "btn btn-primary" ] [ text label ] + +zebraTable : List (Html a) -> List (Html a) -> Html a +zebraTable headers bodies = + table + [ class "table col-xs-10 table-striped" ] + [ thead [] [ tr [] headers ] + , tbody [] bodies + ] From 8dda748f23bf14d0a7175db65d6135a47369117b Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Wed, 23 Nov 2016 11:18:28 -0600 Subject: [PATCH 16/17] Use ChatMessage more appropriately --- src/Messages.elm | 4 ++-- src/Model.elm | 9 ++++++--- src/Update.elm | 9 ++++++--- src/View.elm | 17 +++++------------ 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Messages.elm b/src/Messages.elm index 3d70b8c..caf08ec 100644 --- a/src/Messages.elm +++ b/src/Messages.elm @@ -1,9 +1,9 @@ module Messages exposing (Msg(..)) -import Model exposing (ChatMessage, ChatList) +import Model exposing (..) type Msg - = SendMessage ChatMessage + = SendMessage Name Message | Incoming ChatList | Input String | PollMessages diff --git a/src/Model.elm b/src/Model.elm index 3d5a157..7c2ee24 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -1,4 +1,4 @@ -module Model exposing (Chat, ChatList, ChatMessage, model) +module Model exposing (..) import RemoteData exposing (RemoteData(NotAsked), WebData) @@ -18,7 +18,10 @@ model = type alias ChatList = WebData (List ChatMessage) +type alias Name = String +type alias Message = String + type alias ChatMessage = - { name : String - , message : String + { name : Name + , message : Message } diff --git a/src/Update.elm b/src/Update.elm index f0b428d..ad2e960 100644 --- a/src/Update.elm +++ b/src/Update.elm @@ -2,13 +2,16 @@ module Update exposing (update) import Api import Messages exposing (Msg(..)) -import Model exposing (Chat) +import Model exposing (Chat, ChatMessage) update : Msg -> Chat -> (Chat, Cmd Msg) update msg model = case msg of - SendMessage message -> - ({ model | saying = "" }, Api.sendMessage message (always PollMessages)) + SendMessage name saying -> + let + message = ChatMessage name saying + in + ({ model | saying = "" }, Api.sendMessage message (always PollMessages)) Incoming msgsResult -> ({model | messages = msgsResult}, Cmd.none) diff --git a/src/View.elm b/src/View.elm index 3641117..48e99e2 100644 --- a/src/View.elm +++ b/src/View.elm @@ -16,7 +16,7 @@ view model = , stylesheet "css/style.css" , stylesheet "http://fonts.googleapis.com/css?family=Special+Elite" , row_ - [ h1 [class "col-xs-7"] [ text "Can We Talk!?" ] + [ h1 [class "col-xs-7"] [ text "Can We Talk!?" ] , div [class "col-xs-5"] [ img [src "images/joan.png"] [] ] ] , row_ [ errors model.messages ] @@ -26,15 +26,15 @@ view model = inputControls : Chat -> Html Msg -inputControls model = +inputControls {name,saying} = fieldset [] [ legend [] [ text "Add Message" ] , Html.form [ class "form-horizontal" - , onSubmit (mkMessage model |> SendMessage) + , onSubmit <| SendMessage name saying ] - [ formGroup_ (labeledField "name" "Name" "Your Name" model.name SetName ) - , formGroup_ (labeledField "say" "Say" "Enter a message" model.saying Input ) + [ formGroup_ (labeledField "name" "Name" "Your Name" name SetName ) + , formGroup_ (labeledField "say" "Say" "Enter a message" saying Input ) , btnPrimary_ "Send" ] ] @@ -71,13 +71,6 @@ errors messages = p [ class "text-danger" ] content -mkMessage : Chat -> ChatMessage -mkMessage m = - { name = m.name - , message = m.saying - } - - messageList : ChatList -> Html a messageList messages = case messages of From dc6a08a023f242c15b6eef89b47fa5e6044f6201 Mon Sep 17 00:00:00 2001 From: Brad Grzesiak Date: Wed, 23 Nov 2016 11:21:03 -0600 Subject: [PATCH 17/17] Fix Joan --- css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/css/style.css b/css/style.css index 99ed780..c55cd9e 100644 --- a/css/style.css +++ b/css/style.css @@ -9,6 +9,7 @@ h1 { img { height: 135px; width: auto; + margin-bottom: -36px; } .btn {