Skip to content

Instantly share code, notes, and snippets.

@nloomans
Created May 6, 2018 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nloomans/55671f404a6ea2dece35c6a0209cf4be to your computer and use it in GitHub Desktop.
Save nloomans/55671f404a6ea2dece35c6a0209cf4be to your computer and use it in GitHub Desktop.
Elm Code Review
module Main exposing (..)
import Html exposing (Html, div, form, input, button, br, text)
import Html.Events exposing (onSubmit, onClick, onInput)
import Html.Attributes exposing (type_, placeholder, value, style)
import Dict exposing (Dict)
main : Program Never Model Msg
main =
Html.beginnerProgram { model = model, view = view, update = update }
-- MODEL
type alias User =
{ username : String
, password : String
, fullName : String
, moto : String
}
type alias Users =
Dict String User
type LoginError
= InvalidUsername
| InvalidPassword
| NoError
type alias LoggedInState =
{ currentUsername : String }
type alias LoggedOutState =
{ usernameField : String
, passwordField : String
, error : LoginError
}
type State
= LoggedIn LoggedInState
| LoggedOut LoggedOutState
type alias Model =
{ state : State, users : Users }
model : Model
model =
{ state =
LoggedOut
{ usernameField = ""
, passwordField = ""
, error = NoError
}
, users =
Dict.empty
|> Dict.insert "nloomans"
(User
"nloomans"
"hunter2"
"Noah Loomans"
"Hi my name is Noah and I like to code stuff."
)
|> Dict.insert "foobar"
(User
"foobar"
"barfoo"
"Foo Baz Bar"
"Foo + Bar = Baz"
)
}
-- UPDATE
type Msg
= ToggleLogin
| UpdateUsernameField String
| UpdatePasswordField String
| UpdateMoto String String
update : Msg -> Model -> Model
update msg model =
case msg of
ToggleLogin ->
case model.state of
LoggedIn { currentUsername } ->
-- Log the user out
{ model
| state =
LoggedOut
{ usernameField = currentUsername
, passwordField = ""
, error = NoError
}
}
LoggedOut { usernameField, passwordField } ->
let
isUsernameCorrect =
model.users |> Dict.member usernameField
isPasswordCorrect =
case
model.users
|> Dict.get usernameField
of
Just user ->
user.password == passwordField
Nothing ->
False
in
if not isUsernameCorrect then
-- Invalid username, display an error
{ model
| state =
LoggedOut
{ usernameField = usernameField
, passwordField = ""
, error = InvalidUsername
}
}
else if not isPasswordCorrect then
-- Invalid password, display an error
{ model
| state =
LoggedOut
{ usernameField = usernameField
, passwordField = ""
, error = InvalidPassword
}
}
else
-- Log the user in
{ model
| state =
LoggedIn
{ currentUsername = usernameField }
}
UpdateUsernameField username ->
case model.state of
LoggedOut loggedOutState ->
{ model
| state =
LoggedOut
{ loggedOutState
| usernameField =
username
}
}
LoggedIn _ ->
Debug.crash "UpdateUsernameField is only valid when logged out"
UpdatePasswordField password ->
case model.state of
LoggedOut loggedOutState ->
{ model
| state =
LoggedOut
{ loggedOutState
| passwordField =
password
}
}
LoggedIn _ ->
Debug.crash "UpdatePasswordField is only valid when logged out"
UpdateMoto username moto ->
{ model
| users =
updateUser
username
(\user -> { user | moto = moto })
model.users
}
updateUser : String -> (User -> User) -> Users -> Users
updateUser username updater users =
Dict.update username (Maybe.map updater) users
-- VIEW
viewLoggedOut : LoggedOutState -> Html Msg
viewLoggedOut { usernameField, passwordField, error } =
div []
[ text "Hello there, please login to use our application!"
, br [] []
, form [ onSubmit (ToggleLogin) ]
[ input
[ type_ "text"
, placeholder "Username"
, value usernameField
, onInput UpdateUsernameField
]
[]
, br [] []
, input
[ type_ "password"
, placeholder "Password"
, value passwordField
, onInput UpdatePasswordField
]
[]
, br [] []
, button [] [ text "Login" ]
]
, case error of
InvalidUsername ->
div [ style [ ( "background-color", "red" ) ] ]
[ text "Invalid username!" ]
InvalidPassword ->
div [ style [ ( "background-color", "red" ) ] ]
[ text "Invalid password!" ]
NoError ->
div [] []
]
viewLoggedIn : User -> Html Msg
viewLoggedIn user =
div []
[ button [ onClick ToggleLogin ] [ text "Logout" ]
, br [] []
, text ("Hello there " ++ user.fullName)
, viewEditMoto user.username user.moto
]
viewEditMoto : String -> String -> Html Msg
viewEditMoto username moto =
div []
[ text "String: "
, input
[ type_ "text"
, value moto
, onInput (UpdateMoto username)
, style [ ( "width", "300px" ) ]
]
[]
]
view : Model -> Html Msg
view { state, users } =
case state of
LoggedIn { currentUsername } ->
case users |> Dict.get currentUsername of
Just user ->
viewLoggedIn user
Nothing ->
Debug.crash "We already checked if the user exists during the login, so this should never happen, right???"
LoggedOut loggedOutState ->
viewLoggedOut loggedOutState
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment