Update code for latest form API.

This commit is contained in:
Dillon Kearns 2023-05-10 09:50:37 -07:00
parent 61cd66d905
commit b33dd5a6c1
9 changed files with 154 additions and 159 deletions

View File

@ -1,10 +1,10 @@
module Effect exposing (Effect(..), batch, fromCmd, map, none, perform)
import Browser.Navigation
import Form.FormData exposing (FormData)
import Http
import Json.Decode as Decode
import Pages.Fetcher
import Pages.ProgramConfig exposing (FormData)
import Url exposing (Url)

View File

@ -7,12 +7,13 @@ import FatalError exposing (FatalError)
import Form
import Form.Field as Field
import Form.FieldView
import Form.Validation as Validation exposing (Combined)
import Form.Value
import Form.Handler
import Form.Validation as Validation
import Head
import Head.Seo as Seo
import Html exposing (Html)
import Html.Attributes as Attr
import Pages.Form
import Pages.Url
import PagesMsg exposing (PagesMsg)
import RouteBuilder exposing (App, StatelessRoute)
@ -37,7 +38,7 @@ type alias RouteParams =
type alias ActionData =
{ user : Maybe User
, formResponse : Form.Response String
, formResponse : Form.ServerResponse String
}
@ -62,9 +63,9 @@ defaultUser =
}
form : Form.HtmlForm String User User Msg
form : Form.HtmlForm String User User msg
form =
Form.init
Form.form
(\firstName lastName username email dob check ->
{ combine =
Validation.succeed User
@ -121,7 +122,7 @@ form =
, fieldView "Image" dob
, Html.button []
[ Html.text
(if formState.isTransitioning then
(if formState.submitting then
"Updating..."
else
@ -134,29 +135,29 @@ form =
|> Form.field "first"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.first >> Form.Value.string)
|> Field.withInitialValue .first
)
|> Form.field "last"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.last >> Form.Value.string)
|> Field.withInitialValue .last
)
|> Form.field "username"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.username >> Form.Value.string)
|> Field.withInitialValue .username
)
|> Form.field "email"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (.email >> Form.Value.string)
|> Field.withInitialValue .email
)
|> Form.field "dob"
(Field.date
{ invalid = \_ -> "Invalid date"
}
|> Field.required "Required"
|> Field.withInitialValue (.birthDay >> Form.Value.date)
|> Field.withInitialValue .birthDay
--|> Field.withMin (Date.fromCalendarDate 1900 Time.Jan 1 |> Form.Value.date)
--|> Field.withMax (Date.fromCalendarDate 2022 Time.Jan 1 |> Form.Value.date)
)
@ -187,16 +188,16 @@ data routeParams =
action : RouteParams -> Parser (BackendTask FatalError (Server.Response.Response ActionData ErrorPage))
action routeParams =
Request.formData (form |> Form.initCombined identity)
Request.formData (form |> Form.Handler.init identity)
|> Request.map
(\( response, userResult ) ->
(case userResult of
Ok user ->
Form.Valid user ->
{ user = Just user
, formResponse = response
}
Err error ->
Form.Invalid _ error ->
{ user = Nothing
, formResponse = response
}
@ -261,13 +262,15 @@ view app shared =
[]
[ Html.text <| "Edit profile " ++ user.first ++ " " ++ user.last ]
, form
|> Form.renderHtml "test1"
|> Pages.Form.renderHtml
[ Attr.style "display" "flex"
, Attr.style "flex-direction" "column"
, Attr.style "gap" "20px"
]
(.formResponse >> Just)
Pages.Form.Serial
(Form.options "test1"
|> Form.withInput defaultUser
)
app
defaultUser
]
}

View File

@ -3,8 +3,6 @@ module Route.FormEvent exposing (ActionData, Data, Model, Msg, route)
import BackendTask exposing (BackendTask)
import Effect exposing (Effect)
import FatalError exposing (FatalError)
import Form.FormData exposing (FormData)
import FormDecoder
import Head
import Head.Seo as Seo
import Html exposing (Html)
@ -23,7 +21,7 @@ type alias Model =
type Msg
= OnSubmit FormData
= OnSubmit --FormData
type alias RouteParams =
@ -60,15 +58,18 @@ update :
-> ( Model, Effect Msg )
update app shared msg model =
case msg of
OnSubmit formAsString ->
( { model | formAsString = Just (toString formAsString) }, Effect.none )
OnSubmit ->
--( { model | formAsString = Just (toString formAsString) }, Effect.none )
( model, Effect.none )
toString : FormData -> String
toString formAsString =
formAsString.fields
|> List.map (\( key, value ) -> key ++ "=" ++ value)
|> String.join "\n"
--toString : FormData -> String
--toString formAsString =
-- formAsString.fields
-- |> List.map (\( key, value ) -> key ++ "=" ++ value)
-- |> String.join "\n"
--
subscriptions : RouteParams -> Path -> Shared.Model -> Model -> Sub Msg
@ -135,7 +136,7 @@ view app shared model =
exampleForm : Html (PagesMsg Msg)
exampleForm =
Html.form
[ FormDecoder.formDataOnSubmit
[--FormDecoder.formDataOnSubmit
]
[ Html.div []
[ Html.label []
@ -166,4 +167,7 @@ exampleForm =
]
[ Html.text "Submit" ]
]
|> Html.map (OnSubmit >> PagesMsg.fromMsg)
--|> Html.map (OnSubmit >> PagesMsg.fromMsg)

View File

@ -5,10 +5,11 @@ import ErrorPage exposing (ErrorPage)
import FatalError exposing (FatalError)
import Form
import Form.Field as Field
import Form.Handler
import Form.Validation as Validation
import Head
import Head.Seo as Seo
import Html as Html exposing (Html)
import Html exposing (Html)
import Html.Attributes as Attr
import MySession
import Pages.PageUrl exposing (PageUrl)
@ -56,7 +57,7 @@ type alias Data =
form =
Form.init
Form.form
(\bar ->
{ combine =
Validation.succeed identity
@ -70,7 +71,8 @@ form =
data : RouteParams -> Request.Parser (BackendTask FatalError (Response Data ErrorPage))
data routeParams =
Request.oneOf
[ Request.formData (form |> Form.initCombined identity)
[ Request.formData (form |> Form.Handler.init identity)
|> Request.map (Tuple.mapSecond (Form.toResult >> Result.mapError (\_ -> "Error")))
|> MySession.withSession
(\( formResponse, nameResult ) session ->
(nameResult

View File

@ -7,11 +7,13 @@ import FatalError exposing (FatalError)
import Form
import Form.Field as Field
import Form.FieldView
import Form.Validation as Validation exposing (Combined, Field)
import Form.Handler
import Form.Validation as Validation exposing (Field)
import Head
import Head.Seo as Seo
import Html exposing (Html)
import Html.Attributes as Attr
import Pages.Form
import Pages.Url
import PagesMsg exposing (PagesMsg)
import Path exposing (Path)
@ -99,13 +101,14 @@ list =
data : RouteParams -> Request.Parser (BackendTask FatalError (Response Data ErrorPage))
data routeParams =
Request.oneOf
[ Request.formData (form |> Form.initCombined identity)
[ Request.formData (form |> Form.Handler.init identity)
|> Request.map
(\( formResponse, formResult ) ->
BackendTask.succeed
(Response.render
{ results =
formResult
|> Form.toResult
|> Result.map
(\query ->
Just
@ -121,9 +124,9 @@ data routeParams =
]
form : Form.HtmlForm String String () Msg
form : Form.HtmlForm String String () msg
form =
Form.init
Form.form
(\query ->
{ combine =
Validation.succeed identity
@ -201,13 +204,12 @@ view static sharedModel model =
, body =
[ Html.h2 [] [ Html.text "Search" ]
, form
|> Form.withGetMethod
|> Form.renderHtml "test1"
|> Pages.Form.renderHtml
[]
Pages.Form.Serial
(Form.options "test1" |> Form.withGetMethod)
-- TODO pass in server data
(\_ -> Nothing)
static
()
, static.data.results
|> Maybe.map resultsView
|> Maybe.withDefault (Html.div [] [])

View File

@ -1,23 +1,20 @@
module Route.Signup exposing (ActionData, Data, Model, Msg, route)
import BackendTask exposing (BackendTask)
import Dict
import Effect exposing (Effect)
import ErrorPage exposing (ErrorPage)
import FatalError exposing (FatalError)
import Form
import Form.Field as Field
import Form.FieldView
import Form.Validation as Validation exposing (Combined, Field)
import Form.Value
import Form.Handler
import Form.Validation as Validation exposing (Field)
import Head
import Head.Seo as Seo
import Html exposing (Html)
import Html.Attributes as Attr
import Http
import MySession
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Pages.Form
import PagesMsg exposing (PagesMsg)
import Path exposing (Path)
import Route
@ -59,8 +56,9 @@ route =
action : RouteParams -> Request.Parser (BackendTask FatalError (Response ActionData ErrorPage))
action _ =
(Request.formData (form |> Form.initCombined identity)
(Request.formData (form |> Form.Handler.init identity)
|> Request.map Tuple.second
|> Request.map Form.toResult
|> Request.map (Result.mapError (\error -> "Errors"))
|> Request.andThen Request.fromResult
)
@ -154,7 +152,7 @@ errorsForField formState field =
form : Form.HtmlForm String ( String, String ) data msg
form =
Form.init
Form.form
(\first email ->
{ combine =
Validation.succeed Tuple.pair
@ -168,8 +166,8 @@ form =
]
}
)
|> Form.field "first" (Field.text |> required |> Field.withInitialValue (\_ -> Form.Value.string "Jane"))
|> Form.field "email" (Field.text |> required |> Field.withInitialValue (\_ -> Form.Value.string "jane@example.com"))
|> Form.field "first" (Field.text |> required |> Field.withInitialValue (\_ -> "Jane"))
|> Form.field "email" (Field.text |> required |> Field.withInitialValue (\_ -> "jane@example.com"))
required field =
@ -265,12 +263,12 @@ view app shared model =
]
, flashView app.data.flashMessage
, form
|> Form.renderHtml "test1"
|> Pages.Form.renderHtml
[]
Pages.Form.Serial
(Form.options "test1")
-- TODO pass in server data
(\_ -> Nothing)
app
()
]
}

View File

@ -9,15 +9,15 @@ import ErrorPage exposing (ErrorPage)
import FatalError exposing (FatalError)
import Form
import Form.Field as Field
import Form.FieldStatus as FieldStatus
import Form.FieldView
import Form.Validation as Validation exposing (Combined, Field)
import Form.Value
import Form.Handler
import Form.Validation as Validation exposing (Field, Validation)
import Head
import Head.Seo as Seo
import Html.Styled as Html exposing (Html)
import Html.Styled.Attributes as Attr exposing (css)
import Icon
import Pages.Form
import Pages.Url
import PagesMsg exposing (PagesMsg)
import RouteBuilder exposing (App, StatefulRoute, StatelessRoute)
@ -199,18 +199,21 @@ usernameInput formState field =
]
validateCapitalized : String -> ( Maybe String, List String )
validateCapitalized : String -> Result String String
validateCapitalized string =
if string |> String.toList |> List.head |> Maybe.withDefault 'a' |> Char.isUpper then
( Just string, [] )
Ok string
else
( Nothing, [ "Needs to be capitalized" ] )
Err "Needs to be capitalized"
--form : Form.DoneForm String (BackendTask FatalError (Validation String User Never Never)) data (List (Html (PagesMsg Msg))) Msg
form : Form.DoneForm String (BackendTask FatalError (Combined String User)) data (List (Html (PagesMsg Msg))) Msg
form =
Form.init
Form.form
(\first last username email dob checkin checkout rating password passwordConfirmation comments candidates offers pushNotifications acceptTerms ->
{ combine =
Validation.succeed User
@ -329,53 +332,47 @@ form =
|> Form.field "first"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (always defaultUser.first >> Form.Value.string)
|> Field.withClientValidation validateCapitalized
|> Field.withInitialValue (always defaultUser.first)
|> Field.validateMap validateCapitalized
)
|> Form.field "last"
(Field.text
|> Field.required "Required"
|> Field.withInitialValue (always defaultUser.last >> Form.Value.string)
|> Field.withClientValidation validateCapitalized
|> Field.withInitialValue (always defaultUser.last)
|> Field.validateMap validateCapitalized
)
|> Form.field "username"
(Field.text
|> Field.withInitialValue (always defaultUser.username >> Form.Value.string)
|> Field.withInitialValue (always defaultUser.username)
|> Field.required "Required"
|> Field.withClientValidation
|> Field.validateMap
(\username ->
( Just username
, if username |> String.contains "@" then
[ "Cannot contain @ symbol" ]
if username |> String.contains "@" then
Err "Cannot contain @ symbol"
else
[]
Ok username
)
)
|> Field.withClientValidation
|> Field.validateMap
(\username ->
( Just username
, if username |> String.contains "#" then
[ "Cannot contain # symbol" ]
if username |> String.contains "#" then
Err "Cannot contain # symbol"
else
[]
Ok username
)
)
|> Field.withClientValidation
|> Field.validateMap
(\username ->
( Just username
, if (username |> String.length) < 3 then
[ "Must be at least 3 characters long" ]
if (username |> String.length) < 3 then
Err "Must be at least 3 characters long"
else
[]
)
Ok username
)
)
|> Form.field "email"
(Field.text
|> Field.withInitialValue (always defaultUser.email >> Form.Value.string)
|> Field.withInitialValue (always defaultUser.email)
|> Field.email
|> Field.required "Required"
)
@ -383,31 +380,31 @@ form =
(Field.date
{ invalid = \_ -> "Invalid date" }
|> Field.required "Required"
|> Field.withMin (Date.fromCalendarDate 1900 Time.Jan 1 |> Form.Value.date) "Choose a later date"
|> Field.withMax (Date.fromCalendarDate 2022 Time.Jan 1 |> Form.Value.date) "Choose an earlier date"
|> Field.withInitialValue (always defaultUser.birthDay >> Form.Value.date)
|> Field.withMin (Date.fromCalendarDate 1900 Time.Jan 1) "Choose a later date"
|> Field.withMax (Date.fromCalendarDate 2022 Time.Jan 1) "Choose an earlier date"
|> Field.withInitialValue (always defaultUser.birthDay)
)
|> Form.field "checkin"
(Field.date
{ invalid = \_ -> "Invalid date" }
|> Field.required "Required"
|> Field.withInitialValue (always defaultUser.checkIn >> Form.Value.date)
|> Field.withInitialValue (always defaultUser.checkIn)
)
|> Form.field "checkout"
(Field.date
{ invalid = \_ -> "Invalid date" }
|> Field.required "Required"
|> Field.withInitialValue (always defaultUser.checkOut >> Form.Value.date)
|> Field.withInitialValue (always defaultUser.checkOut)
)
|> Form.field "rating"
(Field.int { invalid = \_ -> "Invalid number" }
|> Field.range
{ missing = "Required"
, invalid = \_ -> "Outside range"
, initial = \_ -> Form.Value.int 3
, min = Form.Value.int 1
, max = Form.Value.int 5
, min = 1
, max = 5
}
|> Field.withInitialValue (\_ -> 3)
)
|> Form.field "password"
(Field.text |> Field.password |> Field.required "Required")
@ -431,15 +428,13 @@ form =
)
|> Form.field "acceptTerms"
(Field.checkbox
|> Field.withClientValidation
|> Field.validateMap
(\checked ->
( Just ()
, if checked then
[]
if checked then
Ok ()
else
[ "Please agree to terms to proceed." ]
)
Err "Please agree to terms to proceed."
)
)
@ -545,7 +540,7 @@ route =
action : RouteParams -> Parser (BackendTask FatalError (Response ActionData ErrorPage))
action routeParams =
Request.formDataWithServerValidation (form |> Form.initCombined identity)
Request.formDataWithServerValidation (form |> Form.Handler.init identity)
|> Request.map
(\toBackendTask ->
toBackendTask
@ -590,7 +585,7 @@ type alias Data =
type alias ActionData =
{ user : User
, flashMessage : Result String String
, formResponse : Maybe (Form.Response String)
, formResponse : Maybe (Form.ServerResponse String)
}
@ -661,17 +656,6 @@ wrapSection children =
]
--formModelView formModel =
-- formModel
-- |> Debug.toString
-- |> Html.text
-- |> List.singleton
-- |> Html.pre
-- [ Attr.style "white-space" "break-spaces"
-- ]
view :
App Data ActionData RouteParams
-> Shared.Model
@ -717,13 +701,14 @@ view app model sharedModel =
|> Debug.toString
)
, form
|> Form.renderStyledHtml "test"
|> Pages.Form.renderStyledHtml
[]
--app.action
-- |> Maybe.andThen .formResponse
(\_ -> Nothing)
Pages.Form.Serial
(Form.options "test"
|> Form.withServerResponse
(app.action |> Maybe.andThen .formResponse)
)
app
()
]
]
|> Html.toUnstyled
@ -789,7 +774,7 @@ textInput info labelText field =
[ Html.text
(field
|> Validation.fieldStatus
|> FieldStatus.fieldStatusToString
|> Validation.fieldStatusToString
)
]
, Html.label
@ -1104,7 +1089,7 @@ wrapPushNotificationsSection formState field children =
[ Html.text
(field
|> Validation.fieldStatus
|> FieldStatus.fieldStatusToString
|> Validation.fieldStatusToString
)
]
, Html.div

View File

@ -17,8 +17,9 @@
"danyx23/elm-mimetype": "4.0.1",
"dillonkearns/elm-bcp47-language-tag": "1.0.1",
"dillonkearns/elm-date-or-date-time": "2.0.0",
"dillonkearns/elm-form": "2.0.2",
"dillonkearns/elm-graphql": "5.0.11",
"dillonkearns/elm-markdown": "6.0.1",
"dillonkearns/elm-markdown": "7.0.1",
"dillonkearns/elm-sitemap": "1.0.2",
"elm/browser": "1.0.2",
"elm/bytes": "1.0.8",
@ -36,13 +37,13 @@
"elm-community/result-extra": "2.4.0",
"jluckyiv/elm-utc-date-strings": "1.0.0",
"justinmimbs/date": "4.0.1",
"mdgriffith/elm-codegen": "2.1.0",
"mdgriffith/elm-codegen": "3.0.0",
"miniBill/elm-codec": "2.0.0",
"noahzgordon/elm-color-extra": "1.0.2",
"pablohirafuji/elm-syntax-highlight": "3.4.1",
"robinheghan/fnv1a": "1.0.0",
"robinheghan/murmur3": "1.0.0",
"rtfeldman/elm-css": "16.1.1",
"rtfeldman/elm-css": "18.0.0",
"rtfeldman/elm-iso8601-date-strings": "1.1.4",
"the-sett/elm-syntax-dsl": "6.0.2",
"tripokey/elm-fuzzy": "5.2.1",

View File

@ -27,32 +27,32 @@
},
"../..": {
"name": "elm-pages",
"version": "3.0.0-beta.33",
"version": "3.0.0-beta.38",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"busboy": "^1.6.0",
"chokidar": "^3.5.3",
"commander": "^10.0.0",
"commander": "^10.0.1",
"connect": "^3.7.0",
"cookie-signature": "^1.2.1",
"cross-spawn": "7.0.3",
"devcert": "^1.2.2",
"elm-doc-preview": "^5.0.5",
"elm-hot": "^1.1.6",
"esbuild": "^0.17.12",
"esbuild": "^0.17.18",
"fs-extra": "^11.1.1",
"globby": "13.1.3",
"globby": "13.1.4",
"gray-matter": "^4.0.3",
"jsesc": "^3.0.2",
"kleur": "^4.1.5",
"make-fetch-happen": "^11.0.3",
"memfs": "^3.4.13",
"make-fetch-happen": "^11.1.1",
"memfs": "^3.5.1",
"micromatch": "^4.0.5",
"serve-static": "^1.15.0",
"terser": "^5.16.8",
"vite": "^4.2.1",
"which": "^3.0.0"
"terser": "^5.17.1",
"vite": "^4.3.5",
"which": "^3.0.1"
},
"bin": {
"elm-pages": "generator/src/cli.js"
@ -62,19 +62,19 @@
"@types/fs-extra": "^11.0.1",
"@types/make-fetch-happen": "^10.0.1",
"@types/micromatch": "^4.0.2",
"@types/node": "^18.15.7",
"@types/node": "^20.1.0",
"@types/serve-static": "^1.15.1",
"cypress": "^12.8.1",
"cypress": "^12.11.0",
"elm-codegen": "^0.3.0",
"elm-optimize-level-2": "^0.3.5",
"elm-review": "^2.9.2",
"elm-test": "^0.19.1-revision11",
"elm-tooling": "^1.13.1",
"elm-review": "^2.10.2",
"elm-test": "^0.19.1-revision12",
"elm-tooling": "^1.14.0",
"elm-verify-examples": "^5.2.0",
"elmi-to-json": "^1.4.3",
"typescript": "^5.0.2",
"vite": "^4.2.1",
"vitest": "^0.29.7"
"typescript": "^5.0.4",
"vite": "^4.3.5",
"vitest": "^0.31.0"
}
},
"node_modules/@babel/code-frame": {
@ -4430,40 +4430,40 @@
"@types/fs-extra": "^11.0.1",
"@types/make-fetch-happen": "^10.0.1",
"@types/micromatch": "^4.0.2",
"@types/node": "^18.15.7",
"@types/node": "^20.1.0",
"@types/serve-static": "^1.15.1",
"busboy": "^1.6.0",
"chokidar": "^3.5.3",
"commander": "^10.0.0",
"commander": "^10.0.1",
"connect": "^3.7.0",
"cookie-signature": "^1.2.1",
"cross-spawn": "7.0.3",
"cypress": "^12.8.1",
"cypress": "^12.11.0",
"devcert": "^1.2.2",
"elm-codegen": "^0.3.0",
"elm-doc-preview": "^5.0.5",
"elm-hot": "^1.1.6",
"elm-optimize-level-2": "^0.3.5",
"elm-review": "^2.9.2",
"elm-test": "^0.19.1-revision11",
"elm-tooling": "^1.13.1",
"elm-review": "^2.10.2",
"elm-test": "^0.19.1-revision12",
"elm-tooling": "^1.14.0",
"elm-verify-examples": "^5.2.0",
"elmi-to-json": "^1.4.3",
"esbuild": "^0.17.12",
"esbuild": "^0.17.18",
"fs-extra": "^11.1.1",
"globby": "13.1.3",
"globby": "13.1.4",
"gray-matter": "^4.0.3",
"jsesc": "^3.0.2",
"kleur": "^4.1.5",
"make-fetch-happen": "^11.0.3",
"memfs": "^3.4.13",
"make-fetch-happen": "^11.1.1",
"memfs": "^3.5.1",
"micromatch": "^4.0.5",
"serve-static": "^1.15.0",
"terser": "^5.16.8",
"typescript": "^5.0.2",
"vite": "^4.2.1",
"vitest": "^0.29.7",
"which": "^3.0.0"
"terser": "^5.17.1",
"typescript": "^5.0.4",
"vite": "^4.3.5",
"vitest": "^0.31.0",
"which": "^3.0.1"
}
},
"elm-review": {