elm-pages-v3-beta/examples/pokedex/app/Route/Form.elm

275 lines
7.8 KiB
Elm
Raw Normal View History

2022-05-03 21:51:32 +03:00
module Route.Form exposing (ActionData, Data, Model, Msg, route)
2022-01-01 23:50:03 +03:00
import DataSource exposing (DataSource)
2022-01-04 08:17:07 +03:00
import Date exposing (Date)
2022-07-02 19:05:50 +03:00
import Dict
2022-03-29 21:48:04 +03:00
import ErrorPage exposing (ErrorPage)
import Form.Value
2022-01-01 23:50:03 +03:00
import Head
import Head.Seo as Seo
2022-01-03 21:07:06 +03:00
import Html exposing (Html)
import Html.Attributes as Attr
2022-07-02 19:05:50 +03:00
import Html.Styled
import Html.Styled.Attributes as StyledAttr
import Pages.Field as Field
import Pages.FieldRenderer
import Pages.Form as Form
import Pages.Msg
2022-01-01 23:50:03 +03:00
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
2022-07-02 19:05:50 +03:00
import Route
2022-03-05 20:50:01 +03:00
import RouteBuilder exposing (StatelessRoute, StaticPayload)
import Server.Request as Request exposing (Parser)
2022-07-02 19:05:50 +03:00
import Server.Response
2022-01-01 23:50:03 +03:00
import Shared
2022-01-04 08:17:07 +03:00
import Time
2022-07-02 19:05:50 +03:00
import Validation
2022-01-01 23:50:03 +03:00
import View exposing (View)
type alias Model =
{}
type alias Msg =
()
2022-01-01 23:50:03 +03:00
type alias RouteParams =
{}
2022-07-02 19:05:50 +03:00
type alias ActionData =
{ user : User
}
2022-01-01 23:50:03 +03:00
type alias User =
{ first : String
, last : String
, username : String
, email : String
2022-01-04 08:17:07 +03:00
, birthDay : Date
2022-01-04 22:47:57 +03:00
, checkbox : Bool
2022-01-01 23:50:03 +03:00
}
defaultUser : User
defaultUser =
2022-01-02 05:35:36 +03:00
{ first = "Jane"
, last = "Doe"
, username = "janedoe"
, email = "janedoe@example.com"
2022-01-04 08:17:07 +03:00
, birthDay = Date.fromCalendarDate 1969 Time.Jul 20
2022-01-04 22:47:57 +03:00
, checkbox = False
2022-01-01 23:50:03 +03:00
}
2022-07-02 19:05:50 +03:00
form : Form.HtmlForm String User User Msg
form =
Form.init
(\first last username email dob check ->
Validation.succeed User
|> Validation.andMap first
|> Validation.andMap last
|> Validation.andMap username
|> Validation.andMap email
|> Validation.andMap dob
|> Validation.andMap check
2022-07-02 19:05:50 +03:00
)
(\formState firstName lastName username email dob check ->
let
errors field =
formState.errors
|> Form.errorsForField field
2022-07-02 19:05:50 +03:00
errorsView field =
case ( formState.submitAttempted, field |> errors ) of
( True, first :: rest ) ->
Html.div []
[ Html.ul
[ Attr.style "border" "solid red"
]
(List.map
(\error ->
Html.li []
[ Html.text error
]
)
(first :: rest)
)
2022-01-03 19:43:00 +03:00
]
2022-07-02 19:05:50 +03:00
_ ->
Html.div [] []
2022-01-03 19:43:00 +03:00
2022-07-02 19:05:50 +03:00
fieldView label field =
2022-01-03 18:40:45 +03:00
Html.div []
2022-07-02 19:05:50 +03:00
[ Html.label []
[ Html.text (label ++ " ")
, field |> Pages.FieldRenderer.input []
2022-01-03 18:40:45 +03:00
]
2022-07-02 19:05:50 +03:00
, errorsView field
2022-01-03 18:40:45 +03:00
]
2022-07-02 19:05:50 +03:00
in
[ fieldView "Name" firstName
, fieldView "Description" lastName
, fieldView "Price" username
, fieldView "Image" email
, fieldView "Image" dob
, Html.button []
[ Html.text
(if formState.isTransitioning then
"Updating..."
2022-07-02 19:05:50 +03:00
else
"Update"
)
]
]
2022-07-02 19:05:50 +03:00
)
|> Form.field "first"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.first >> Form.Value.string)
2022-01-01 23:50:03 +03:00
)
2022-07-02 19:05:50 +03:00
|> Form.field "last"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.last >> Form.Value.string)
2022-01-01 23:50:03 +03:00
)
2022-07-02 19:05:50 +03:00
|> Form.field "username"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.username >> Form.Value.string)
--|> Form.withServerValidation
-- (\username ->
-- if username == "asdf" then
-- DataSource.succeed [ "username is taken" ]
--
-- else
-- DataSource.succeed []
-- )
2022-01-01 23:50:03 +03:00
)
2022-07-02 19:05:50 +03:00
|> Form.field "email"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.email >> Form.Value.string)
)
|> Form.field "dob"
(Field.date
{ invalid = \_ -> "Invalid date"
}
2022-07-02 19:05:50 +03:00
|> Field.required "Required"
|> Field.withInitialValue (.birthDay >> Form.Value.date)
--|> Field.withMin (Date.fromCalendarDate 1900 Time.Jan 1 |> Form.Value.date)
--|> Field.withMax (Date.fromCalendarDate 2022 Time.Jan 1 |> Form.Value.date)
)
2022-07-02 19:05:50 +03:00
|> Form.field "checkbox" Field.checkbox
2022-01-01 23:50:03 +03:00
2022-05-03 21:51:32 +03:00
route : StatelessRoute RouteParams Data ActionData
route =
2022-03-05 20:50:01 +03:00
RouteBuilder.serverRender
2022-01-01 23:50:03 +03:00
{ head = head
, data = data
, action = action
2022-01-01 23:50:03 +03:00
}
2022-03-05 20:50:01 +03:00
|> RouteBuilder.buildNoState { view = view }
2022-01-01 23:50:03 +03:00
type alias Data =
{}
2022-01-01 23:50:03 +03:00
2022-07-02 19:05:50 +03:00
data : RouteParams -> Parser (DataSource (Server.Response.Response Data ErrorPage))
2022-01-01 23:50:03 +03:00
data routeParams =
2022-07-02 19:05:50 +03:00
Data
|> Server.Response.render
|> DataSource.succeed
|> Request.succeed
2022-01-01 23:50:03 +03:00
2022-07-02 19:05:50 +03:00
action : RouteParams -> Parser (DataSource (Server.Response.Response ActionData ErrorPage))
action routeParams =
Request.formParserResultNew [ form ]
|> Request.map
(\userResult ->
ActionData
(userResult
-- TODO nicer error handling
-- TODO wire up DataSource server-side validation errors
|> Result.withDefault defaultUser
)
|> Server.Response.render
|> DataSource.succeed
)
2022-01-01 23:50:03 +03:00
head :
2022-05-03 21:51:32 +03:00
StaticPayload Data ActionData RouteParams
2022-01-01 23:50:03 +03:00
-> List Head.Tag
head static =
2022-07-02 19:05:50 +03:00
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
2022-01-01 23:50:03 +03:00
view :
Maybe PageUrl
-> Shared.Model
2022-05-03 21:51:32 +03:00
-> StaticPayload Data ActionData RouteParams
-> View (Pages.Msg.Msg Msg)
view maybeUrl sharedModel app =
2022-01-01 23:50:03 +03:00
let
user : User
2022-01-01 23:50:03 +03:00
user =
app.action
2022-07-02 19:05:50 +03:00
|> Maybe.map .user
|> Maybe.withDefault defaultUser
2022-01-01 23:50:03 +03:00
in
{ title = "Form Example"
, body =
[ Html.pre []
[ app.action
|> Debug.toString
|> Html.text
]
, app.action
2022-07-02 19:05:50 +03:00
|> Maybe.map .user
2022-01-03 21:07:06 +03:00
|> Maybe.map
(\user_ ->
Html.p
[ Attr.style "padding" "10px"
, Attr.style "background-color" "#a3fba3"
]
[ Html.text <| "Successfully received user " ++ user_.first ++ " " ++ user_.last
]
2022-01-03 21:07:06 +03:00
)
|> Maybe.withDefault (Html.p [] [])
2022-01-03 21:07:06 +03:00
, Html.h1
[]
[ Html.text <| "Edit profile " ++ user.first ++ " " ++ user.last ]
, form
|> Form.toDynamicTransition "test1"
|> Form.renderHtml
[ Attr.style "display" "flex"
, Attr.style "flex-direction" "column"
, Attr.style "gap" "20px"
]
app
defaultUser
2022-01-01 23:50:03 +03:00
]
}