Add part7

This commit is contained in:
Richard Feldman
2018-05-05 04:54:47 -04:00
parent f6bef58e3d
commit 825dea437b
575 changed files with 79140 additions and 0 deletions

266
part7/src/Page/Settings.elm Normal file
View File

@@ -0,0 +1,266 @@
module Page.Settings exposing (ExternalMsg(..), Model, Msg, init, update, view)
import Data.Session exposing (Session)
import Data.User as User exposing (User)
import Data.UserPhoto as UserPhoto
import Html exposing (Html, button, div, fieldset, h1, input, text, textarea)
import Html.Attributes exposing (attribute, class, value, placeholder, type_)
import Html.Events exposing (onInput, onSubmit)
import Http
import Json.Decode as Decode exposing (Decoder, decodeString, field, list, string)
import Json.Decode.Pipeline exposing (decode, optional)
import Request.User exposing (storeSession)
import Route
import Util exposing (pair)
import Validate exposing (Validator, ifBlank, validate)
import Views.Form as Form
-- MODEL --
type alias Model =
{ errors : List Error
, image : Maybe String
, email : String
, bio : String
, username : String
, password : Maybe String
}
init : User -> Model
init user =
{ errors = []
, image = UserPhoto.toMaybeString user.image
, email = user.email
, bio = Maybe.withDefault "" user.bio
, username = User.usernameToString user.username
, password = Nothing
}
-- VIEW --
view : Session -> Model -> Html Msg
view session model =
div [ class "settings-page" ]
[ div [ class "container page" ]
[ div [ class "row" ]
[ div [ class "col-md-6 offset-md-3 col-xs-12" ]
[ h1 [ class "text-xs-center" ] [ text "Your Settings" ]
, Form.viewErrors model.errors
, viewForm model
]
]
]
]
viewForm : Model -> Html Msg
viewForm model =
Html.form [ onSubmit SubmitForm ]
[ fieldset []
[ Form.input
[ placeholder "URL of profile picture"
, value (Maybe.withDefault "" model.image)
, onInput SetImage
]
[]
, Form.input
[ class "form-control-lg"
, placeholder "Username"
, value model.username
, onInput SetUsername
]
[]
, Form.textarea
[ class "form-control-lg"
, placeholder "Short bio about you"
, attribute "rows" "8"
, value model.bio
, onInput SetBio
]
[]
, Form.input
[ class "form-control-lg"
, placeholder "Email"
, value model.email
, onInput SetEmail
]
[]
, Form.password
[ class "form-control-lg"
, placeholder "Password"
, value (Maybe.withDefault "" model.password)
, onInput SetPassword
]
[]
, button
[ class "btn btn-lg btn-primary pull-xs-right" ]
[ text "Update Settings" ]
]
]
-- UPDATE --
type Msg
= SubmitForm
| SetEmail String
| SetUsername String
| SetPassword String
| SetBio String
| SetImage String
| SaveCompleted (Result Http.Error User)
type ExternalMsg
= NoOp
| SetUser User
update : Session -> Msg -> Model -> ( ( Model, Cmd Msg ), ExternalMsg )
update session msg model =
case msg of
SubmitForm ->
case validate modelValidator model of
[] ->
( session.user
|> Maybe.map .token
|> Request.User.edit model
|> Http.send SaveCompleted
|> pair { model | errors = [] }
, NoOp
)
errors ->
( ( { model | errors = errors }
, Cmd.none
)
, NoOp
)
SetEmail email ->
( ( { model | email = email }
, Cmd.none
)
, NoOp
)
SetUsername username ->
( ( { model | username = username }
, Cmd.none
)
, NoOp
)
SetPassword passwordStr ->
let
password =
if String.isEmpty passwordStr then
Nothing
else
Just passwordStr
in
( ( { model | password = password }
, Cmd.none
)
, NoOp
)
SetBio bio ->
( ( { model | bio = bio }
, Cmd.none
)
, NoOp
)
SetImage imageStr ->
let
image =
if String.isEmpty imageStr then
Nothing
else
Just imageStr
in
( ( { model | image = image }
, Cmd.none
)
, NoOp
)
SaveCompleted (Err error) ->
let
errorMessages =
case error of
Http.BadStatus response ->
response.body
|> decodeString (field "errors" errorsDecoder)
|> Result.withDefault []
_ ->
[ "unable to save changes" ]
errors =
errorMessages
|> List.map (\errorMessage -> ( Form, errorMessage ))
in
( ( { model | errors = errors }
, Cmd.none
)
, NoOp
)
SaveCompleted (Ok user) ->
( ( model
, Cmd.batch [ storeSession user, Route.modifyUrl Route.Home ]
)
, SetUser user
)
-- VALIDATION --
type Field
= Form
| Username
| Email
| Password
| ImageUrl
| Bio
type alias Error =
( Field, String )
modelValidator : Validator Error Model
modelValidator =
Validate.all
[ ifBlank .username ( Username, "username can't be blank." )
, ifBlank .email ( Email, "email can't be blank." )
]
errorsDecoder : Decoder (List String)
errorsDecoder =
decode (\email username password -> List.concat [ email, username, password ])
|> optionalError "email"
|> optionalError "username"
|> optionalError "password"
optionalError : String -> Decoder (List String -> a) -> Decoder a
optionalError fieldName =
let
errorToString errorMessage =
String.join " " [ fieldName, errorMessage ]
in
optional fieldName (list (Decode.map errorToString string)) []