elm-pages-v3-beta/examples/pokedex/app/Route/Form.elm
2022-07-08 17:40:01 -07:00

275 lines
7.8 KiB
Elm

module Route.Form exposing (ActionData, Data, Model, Msg, route)
import DataSource exposing (DataSource)
import Date exposing (Date)
import Dict
import ErrorPage exposing (ErrorPage)
import Form.Value
import Head
import Head.Seo as Seo
import Html exposing (Html)
import Html.Attributes as Attr
import Html.Styled
import Html.Styled.Attributes as StyledAttr
import Pages.Field as Field
import Pages.FieldView
import Pages.Form as Form
import Pages.Msg
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Route
import RouteBuilder exposing (StatelessRoute, StaticPayload)
import Server.Request as Request exposing (Parser)
import Server.Response
import Shared
import Time
import Validation
import View exposing (View)
type alias Model =
{}
type alias Msg =
()
type alias RouteParams =
{}
type alias ActionData =
{ user : User
}
type alias User =
{ first : String
, last : String
, username : String
, email : String
, birthDay : Date
, checkbox : Bool
}
defaultUser : User
defaultUser =
{ first = "Jane"
, last = "Doe"
, username = "janedoe"
, email = "janedoe@example.com"
, birthDay = Date.fromCalendarDate 1969 Time.Jul 20
, checkbox = False
}
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
)
(\formState firstName lastName username email dob check ->
let
errors field =
formState.errors
|> Form.errorsForField field
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)
)
]
_ ->
Html.div [] []
fieldView label field =
Html.div []
[ Html.label []
[ Html.text (label ++ " ")
, field |> Pages.FieldView.input []
]
, errorsView field
]
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..."
else
"Update"
)
]
]
)
|> Form.field "first"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.first >> Form.Value.string)
)
|> Form.field "last"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.last >> Form.Value.string)
)
|> 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 []
-- )
)
|> Form.field "email"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.email >> Form.Value.string)
)
|> Form.field "dob"
(Field.date
{ invalid = \_ -> "Invalid date"
}
|> 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)
)
|> Form.field "checkbox" Field.checkbox
route : StatelessRoute RouteParams Data ActionData
route =
RouteBuilder.serverRender
{ head = head
, data = data
, action = action
}
|> RouteBuilder.buildNoState { view = view }
type alias Data =
{}
data : RouteParams -> Parser (DataSource (Server.Response.Response Data ErrorPage))
data routeParams =
Data
|> Server.Response.render
|> DataSource.succeed
|> Request.succeed
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
)
head :
StaticPayload Data ActionData RouteParams
-> List Head.Tag
head static =
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
view :
Maybe PageUrl
-> Shared.Model
-> StaticPayload Data ActionData RouteParams
-> View (Pages.Msg.Msg Msg)
view maybeUrl sharedModel app =
let
user : User
user =
app.action
|> Maybe.map .user
|> Maybe.withDefault defaultUser
in
{ title = "Form Example"
, body =
[ Html.pre []
[ app.action
|> Debug.toString
|> Html.text
]
, app.action
|> Maybe.map .user
|> Maybe.map
(\user_ ->
Html.p
[ Attr.style "padding" "10px"
, Attr.style "background-color" "#a3fba3"
]
[ Html.text <| "Successfully received user " ++ user_.first ++ " " ++ user_.last
]
)
|> Maybe.withDefault (Html.p [] [])
, 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
]
}