More wiring for form integration prototype.

This commit is contained in:
Dillon Kearns 2023-04-02 11:27:49 -07:00
parent a3f9b98409
commit 8275f4e447
10 changed files with 309 additions and 162 deletions

View File

@ -237,7 +237,7 @@ otherFile routes phaseString =
}
view =
Elm.Declare.function "view"
[ ( "pageFormState", Gen.Pages.FormState.annotation_.pageFormState |> Just )
[ ( "pageFormState", Type.named [ "Form" ] "Model" |> Just )
, ( "fetchers"
, Gen.Dict.annotation_.dict Type.string
(Gen.Pages.Transition.annotation_.fetcherState (Type.named [] "ActionData"))
@ -914,7 +914,7 @@ otherFile routes phaseString =
}
update =
Elm.Declare.function "update"
[ ( "pageFormState", Type.named [ "Pages", "FormState" ] "PageFormState" |> Just )
[ ( "pageFormState", Type.named [ "Form" ] "Model" |> Just )
, ( "fetchers"
, Gen.Dict.annotation_.dict
Type.string

View File

@ -12,16 +12,17 @@ import Date exposing (Date)
import Effect
import ErrorPage
import FatalError
import Form
import Form exposing (Validated(..))
import Form.Field
import Form.FieldView
import Form.Handler
import Form.Validation
import Form.Value
import Head
import Html exposing (Html)
import Html.Attributes
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
import Pages.Form
import PagesMsg exposing (PagesMsg)
import Path
import Platform.Sub
@ -93,7 +94,7 @@ type alias Data =
type alias ActionData =
{ errors : Form.Response String }
{ errors : Form.ServerResponse String }
data :
@ -151,13 +152,21 @@ view app shared model =
, body =
[ Html.h2 [] [ Html.text "Form" ]
, form
|> Form.renderHtml "form" [] (Just << .errors) app app.data.post
|> Pages.Form.renderHtml "form"
[]
--(Just << .errors)
app
app.data.post
, if app.routeParams.slug == "new" then
Html.text ""
else
deleteForm
|> Form.renderHtml "delete" [] (\_ -> Nothing) app ()
|> Pages.Form.renderHtml "delete"
[]
--(\_ -> Nothing)
app
()
]
}
@ -169,7 +178,7 @@ action routeParams =
Server.Request.map
(\( formResponse, parsedForm ) ->
case parsedForm of
Ok Delete ->
Valid Delete ->
BackendTask.Custom.run "deletePost"
(Encode.object
[ ( "slug", Encode.string routeParams.slug )
@ -182,7 +191,7 @@ action routeParams =
Route.redirectTo Route.Index
)
Ok (CreateOrEdit okForm) ->
Valid (CreateOrEdit okForm) ->
let
createPost : Bool
createPost =
@ -214,7 +223,7 @@ action routeParams =
(Route.Admin__Slug_ { slug = okForm.slug })
)
Err invalidForm ->
Invalid _ invalidForm ->
BackendTask.succeed
(Server.Response.render
{ errors = formResponse }
@ -223,7 +232,10 @@ action routeParams =
(Server.Request.formData formHandlers)
form : Form.HtmlForm String Post Post Msg
--form : Form.HtmlForm String Post Post Msg
form =
(\title slug body publish ->
{ combine =
@ -253,25 +265,24 @@ form =
]
}
)
|> Form.init
|> Form.form
|> Form.hiddenKind ( "kind", "create-or-edit" ) "Expected create-or-edit"
|> Form.field "title"
(Form.Field.required "Required" Form.Field.text
|> Form.Field.withInitialValue (.title >> Form.Value.string)
|> Form.Field.withInitialValue .title
)
|> Form.field "slug"
(Form.Field.required "Required" Form.Field.text
|> Form.Field.withInitialValue (.slug >> Form.Value.string)
|> Form.Field.withInitialValue .slug
)
|> Form.field "body"
(Form.Field.required "Required" Form.Field.text
|> Form.Field.textarea { rows = Just 10, cols = Just 80 }
|> Form.Field.withInitialValue (.body >> Form.Value.string)
|> Form.Field.withInitialValue .body
)
|> Form.field "publish"
(Form.Field.date { invalid = \_ -> "Invalid date." }
|> Form.Field.withOptionalInitialValue
(.publish >> Maybe.map Form.Value.date)
|> Form.Field.withOptionalInitialValue .publish
)
@ -280,16 +291,19 @@ type Action
| CreateOrEdit Post
formHandlers : Form.ServerForms String Action
formHandlers : Form.Handler.Handler String Action
formHandlers =
deleteForm
|> Form.initCombined (\() -> Delete)
|> Form.combine CreateOrEdit form
|> Form.Handler.init (\() -> Delete)
|> Form.Handler.with CreateOrEdit form
--deleteForm : Form.HtmlForm String () input (PagesMsg Msg)
deleteForm : Form.HtmlForm String () input Msg
deleteForm =
Form.init
Form.form
{ combine = Form.Validation.succeed ()
, view =
\formState ->
@ -305,9 +319,9 @@ deleteForm =
|> Form.hiddenKind ( "kind", "delete" ) "Expected delete"
buttonWithTransition : List (Html.Attribute msg) -> String -> String -> { a | isTransitioning : Bool } -> Html msg
buttonWithTransition : List (Html.Attribute msg) -> String -> String -> { a | submitting : Bool } -> Html msg
buttonWithTransition attributes initialText transitioningText formState =
if formState.isTransitioning then
if formState.submitting then
Html.button
(attributes
++ [ Html.Attributes.disabled True

View File

@ -9,8 +9,8 @@ import FatalError exposing (FatalError)
import Form
import Form.Field as Field
import Form.FieldView as FieldView
import Form.Handler
import Form.Validation as Validation
import Form.Value
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Keyed as Keyed
@ -352,7 +352,7 @@ view app shared model =
_ ->
allForms
|> Form.runOneOfServerSide payload.fields
|> Form.Handler.run payload.fields
|> Tuple.first
)
@ -471,7 +471,7 @@ view app shared model =
(\( key, { status, payload } ) ->
case
( allForms
|> Form.runOneOfServerSide payload.fields
|> Form.Handler.run payload.fields
|> Tuple.first
, status
)
@ -531,20 +531,20 @@ view app shared model =
-- FORMS
allForms : Form.ServerForms String Action
allForms : Form.Handler.Handler String Action
allForms =
editItemForm
|> Form.initCombined UpdateEntry
|> Form.combine Add addItemForm
|> Form.combine Check checkItemForm
|> Form.combine Delete deleteItemForm
|> Form.combine (\_ -> DeleteComplete) clearCompletedForm
|> Form.combine CheckAll toggleAllForm
|> Form.Handler.init UpdateEntry
|> Form.Handler.with Add addItemForm
|> Form.Handler.with Check checkItemForm
|> Form.Handler.with Delete deleteItemForm
|> Form.Handler.with (\_ -> DeleteComplete) clearCompletedForm
|> Form.Handler.with CheckAll toggleAllForm
addItemForm : Form.HtmlForm String String (Maybe String) Msg
addItemForm =
Form.init
Form.form
(\description ->
{ combine =
Validation.succeed identity
@ -571,7 +571,7 @@ addItemForm =
editItemForm : Form.HtmlForm String ( String, String ) Entry Msg
editItemForm =
Form.init
Form.form
(\itemId description ->
{ combine =
Validation.succeed Tuple.pair
@ -603,7 +603,7 @@ editItemForm =
deleteItemForm : Form.HtmlForm String String Entry Msg
deleteItemForm =
Form.init
Form.form
(\todoId ->
{ combine =
Validation.succeed identity
@ -623,7 +623,7 @@ deleteItemForm =
toggleAllForm : Form.HtmlForm String Bool { allCompleted : Bool } Msg
toggleAllForm =
Form.init
Form.form
(\toggleTo ->
{ combine =
Validation.succeed identity
@ -656,7 +656,7 @@ toggleAllForm =
checkItemForm : Form.HtmlForm String ( Bool, String ) Entry Msg
checkItemForm =
Form.init
Form.form
(\todoId complete ->
{ combine =
Validation.succeed Tuple.pair
@ -688,7 +688,7 @@ checkItemForm =
clearCompletedForm : Form.HtmlForm String () { entriesCompleted : Int } Msg
clearCompletedForm =
Form.init
Form.form
{ combine = Validation.succeed ()
, view =
\formState ->

View File

@ -103,4 +103,14 @@ function find_anchor(node) {
return /** @type {HTMLAnchorElement} */ (node);
}
Object.defineProperty(SubmitEvent.prototype, "fields", {
get: function fields() {
let formData = new FormData(this.currentTarget);
if (this.submitter?.name) {
formData.append(this.submitter.name, this.submitter.value);
}
return [...formData.entries()];
},
});
setup();

View File

@ -13,6 +13,7 @@ module Form exposing
, Msg, Model, init, update
, Validated(..)
, ServerResponse
, map
, mapMsg
-- subGroup
@ -273,6 +274,8 @@ in the user's workflow to show validation errors.
@docs ServerResponse
@docs map
-}
import Dict exposing (Dict)
@ -741,13 +744,8 @@ hiddenKind ( name, value ) error_ (Internal.Form.Form options definitions parseF
|> myFn
)
(\input ->
case fieldParser.initialValue input of
Just initialValue ->
( name, Just initialValue )
:: toInitialValues input
Nothing ->
toInitialValues input
( name, Just value )
:: toInitialValues input
)
@ -870,8 +868,9 @@ unwrapValidation (Pages.Internal.Form.Validation _ _ ( maybeParsed, errors )) =
{-| -}
renderHtml :
String
-> List (Html.Attribute (Msg msg))
(Msg msg -> mappedMsg)
-> String
-> List (Html.Attribute mappedMsg)
->
{ submitting : Bool
, serverResponse : Maybe (ServerResponse error)
@ -882,14 +881,20 @@ renderHtml :
Form
error
{ combine : Form.Validation.Validation error parsed named constraints
, view : Context error input -> List (Html (Msg msg))
, view : Context error input -> List (Html mappedMsg)
}
parsed
input
msg
-> Html (Msg msg)
renderHtml formId attrs app input form_ =
Html.Lazy.lazy5 renderHelper formId attrs app input form_
mappedMsg
-> Html mappedMsg
renderHtml liftMsg formId attrs app input form_ =
Html.Lazy.lazy6 renderHelper
liftMsg
formId
attrs
app
input
form_
{-| -}
@ -930,7 +935,7 @@ withOnSubmit onSubmit (Internal.Form.Form options a b c) =
{-| -}
renderStyledHtml :
String
-> List (Html.Styled.Attribute (Msg msg))
-> List (Html.Styled.Attribute msg)
->
{ submitting : Bool
, serverResponse : Maybe (ServerResponse error)
@ -941,7 +946,7 @@ renderStyledHtml :
Form
error
{ combine : Form.Validation.Validation error parsed field constraints
, view : Context error input -> List (Html.Styled.Html (Msg msg))
, view : Context error input -> List (Html.Styled.Html msg)
}
parsed
input
@ -969,8 +974,9 @@ type alias ServerResponse error =
renderHelper :
String
-> List (Html.Attribute (Msg msg))
(Msg msg -> mappedMsg)
-> String
-> List (Html.Attribute mappedMsg)
---> (actionData -> Maybe (ServerResponse error))
-> AppContext error
-> input
@ -978,26 +984,26 @@ renderHelper :
Form
error
{ combine : Form.Validation.Validation error parsed named constraints
, view : Context error input -> List (Html (Msg msg))
, view : Context error input -> List (Html mappedMsg)
}
parsed
input
msg
-> Html (Msg msg)
renderHelper formId attrs formState input ((Internal.Form.Form options _ _ _) as form_) =
mappedMsg
-> Html mappedMsg
renderHelper liftMsg formId attrs formState input ((Internal.Form.Form options _ _ _) as form_) =
-- TODO Get transition context from `app` so you can check if the current form is being submitted
-- TODO either as a transition or a fetcher? Should be easy enough to check for the `id` on either of those?
let
{ hiddenInputs, children, parsed, fields, errors } =
helperValues formId toHiddenInput formState input form_
toHiddenInput : List (Html.Attribute (Msg msg)) -> Html (Msg msg)
toHiddenInput : List (Html.Attribute mappedMsg) -> Html mappedMsg
toHiddenInput hiddenAttrs =
Html.input hiddenAttrs []
in
Html.form
((Form.listeners formId
|> List.map (Attr.map Internal.FieldEvent.FormFieldEvent)
|> List.map (Attr.map (Internal.FieldEvent.FormFieldEvent >> liftMsg))
)
++ [ Attr.method (Internal.Form.methodToString options.method)
, Attr.novalidate True
@ -1012,22 +1018,24 @@ renderHelper formId attrs formState input ((Internal.Form.Form options _ _ _) as
-- TransitionStrategy ->
-- Pages.Internal.Msg.submitIfValid options.onSubmit formId (\_ -> isValid)
]
++ [ Internal.FieldEvent.formDataOnSubmit
++ [ let
-- TODO include this msg
maybeFormMsg formDataThing =
options.onSubmit
|> Maybe.map
(\onSubmit ->
onSubmit
{ fields = formDataThing.fields |> Maybe.withDefault fields
, parsed = ( parsed, errors )
}
--|> Internal.FieldEvent.UserMsg
)
in
Internal.FieldEvent.formDataOnSubmit
|> Attr.map
(\formDataThing ->
let
msgThing : Maybe msg
msgThing =
options.onSubmit
|> Maybe.map
(\onSubmit ->
onSubmit
{ fields = formDataThing.fields |> Maybe.withDefault fields
, parsed = ( parsed, errors )
}
)
in
Internal.FieldEvent.Submit formDataThing msgThing
Internal.FieldEvent.Submit formDataThing Nothing
|> liftMsg
)
]
++ attrs
@ -1037,14 +1045,14 @@ renderHelper formId attrs formState input ((Internal.Form.Form options _ _ _) as
renderStyledHelper :
String
-> List (Html.Styled.Attribute (Msg msg))
-> List (Html.Styled.Attribute msg)
-> AppContext error
-> input
->
Form
error
{ combine : Form.Validation.Validation error parsed field constraints
, view : Context error input -> List (Html.Styled.Html (Msg msg))
, view : Context error input -> List (Html.Styled.Html msg)
}
parsed
input
@ -1057,7 +1065,7 @@ renderStyledHelper formId attrs formState input ((Internal.Form.Form options _ _
{ hiddenInputs, children, parsed, fields, errors } =
helperValues formId toHiddenInput formState input form_
toHiddenInput : List (Html.Attribute (Msg msg)) -> Html.Styled.Html (Msg msg)
toHiddenInput : List (Html.Attribute msg) -> Html.Styled.Html msg
toHiddenInput hiddenAttrs =
Html.Styled.input (hiddenAttrs |> List.map StyledAttr.fromUnstyled) []
in
@ -1100,14 +1108,14 @@ renderStyledHelper formId attrs formState input ((Internal.Form.Form options _ _
)
|> StyledAttr.fromUnstyled
]
++ attrs
++ (attrs |> List.map (StyledAttr.map Internal.FieldEvent.UserMsg))
)
(hiddenInputs ++ children)
((hiddenInputs ++ children) |> List.map (Html.Styled.map Internal.FieldEvent.UserMsg))
helperValues :
String
-> (List (Html.Attribute (Msg msg)) -> view)
-> (List (Html.Attribute mappedMsg) -> view)
-> AppContext error
-> input
->
@ -1118,7 +1126,7 @@ helperValues :
}
parsed
input
msg
mappedMsg
-> { hiddenInputs : List view, children : List view, isValid : Bool, parsed : Maybe parsed, fields : List ( String, String ), errors : Dict String (List error) }
helperValues formId toHiddenInput formState input (Internal.Form.Form _ fieldDefinitions parser toInitialValues) =
let
@ -1309,7 +1317,7 @@ type alias HtmlForm error parsed input msg =
Form
error
{ combine : Combined error parsed
, view : Context error input -> List (Html (Msg msg))
, view : Context error input -> List (Html msg)
}
parsed
input
@ -1321,7 +1329,7 @@ type alias StyledHtmlForm error parsed input msg =
Form
error
{ combine : Combined error parsed
, view : Context error input -> List (Html.Styled.Html (Msg msg))
, view : Context error input -> List (Html.Styled.Html msg)
}
parsed
input
@ -1333,6 +1341,21 @@ type alias Form error combineAndView parsed input userMsg =
Internal.Form.Form error combineAndView parsed input userMsg
{-| -}
map : (msg -> mappedMsg) -> Form error combineAndView parsed input msg -> Form error combineAndView parsed input mappedMsg
map mapFn (Internal.Form.Form a b c d) =
Internal.Form.Form
{ method = a.method
, onSubmit =
Maybe.map
(\onSubmit -> onSubmit >> mapFn)
a.onSubmit
}
b
c
d
{-| -}
addErrorsInternal : String -> List error -> Dict String (List error) -> Dict String (List error)
addErrorsInternal name newErrors allErrors =

91
src/Pages/Form.elm Normal file
View File

@ -0,0 +1,91 @@
module Pages.Form exposing (renderHtml)
import Dict exposing (Dict)
import Form
import Form.Validation exposing (Validation)
import Html
import Pages.Internal.Msg
import Pages.Transition
import PagesMsg exposing (PagesMsg)
renderHtml :
String
-> List (Html.Attribute (PagesMsg userMsg))
->
--{ submitting : Bool, serverResponse : Maybe (Form.ServerResponse error), state : Form.Model }
{ --path : Path
--, url : Maybe PageUrl
--, action : Maybe action
app
| pageFormState : Form.Model
, transition : Maybe Pages.Transition.Transition
, fetchers : Dict String (Pages.Transition.FetcherState (Maybe action))
}
-> input
-> Form.Form error { combine : Validation error parsed named constraints, view : Form.Context error input -> List (Html.Html (PagesMsg userMsg)) } parsed input (PagesMsg userMsg)
-> Html.Html (PagesMsg userMsg)
renderHtml formId attrs app input form_ =
(form_
|> Form.withOnSubmit
(\{ fields, parsed } ->
case parsed of
Form.Valid _ ->
Pages.Internal.Msg.Submit
{ useFetcher = False
, fields = fields
, msg = Nothing
, id = formId
, valid = True
}
Form.Invalid _ _ ->
Pages.Internal.Msg.Submit
{ useFetcher = False
, fields = fields
, msg = Nothing
, id = formId
, valid = True
}
)
)
|> Form.renderHtml Pages.Internal.Msg.FormMsg
formId
attrs
{ state = app.pageFormState
, serverResponse = Nothing -- TODO
, submitting =
(case app.fetchers |> Dict.get formId of
Just { status } ->
case status of
Pages.Transition.FetcherComplete _ ->
False
Pages.Transition.FetcherSubmitting ->
True
Pages.Transition.FetcherReloading _ ->
True
Nothing ->
False
)
|| (case app.transition of
Just (Pages.Transition.Submitting formData) ->
formData.id == Just formId
Just (Pages.Transition.LoadAfterSubmit submitData _ _) ->
submitData.id == Just formId
Just (Pages.Transition.Loading _ _) ->
False
Nothing ->
False
)
}
input
-- TODO renderStyledHtml

View File

@ -14,6 +14,7 @@ module Pages.Internal.Msg exposing
import Form
import Html exposing (Attribute)
import Html.Attributes as Attr
import Internal.FieldEvent
import Json.Decode
@ -23,7 +24,7 @@ type Msg userMsg
| Submit { valid : Bool, fields : List ( String, String ), id : String, msg : Maybe userMsg, useFetcher : Bool }
--| SubmitIfValid String FormData Bool (Maybe userMsg)
--| SubmitFetcher String FormData Bool (Maybe userMsg)
| FormMsg (Form.Msg userMsg)
| FormMsg (Internal.FieldEvent.Msg userMsg)
| NoOp

View File

@ -510,10 +510,20 @@ update config appMsg model =
Just
( -- TODO remove hardcoded number
-1
, Pages.Transition.Submitting fields
, Pages.Transition.Submitting
{ fields = fields.fields
, method = Post -- TODO
, action = "" -- TODO
, id = Just fields.id
}
)
}
, Submit fields
, Submit
{ fields = fields.fields
, method = Post -- TODO
, action = "" -- TODO
, id = Just fields.id
}
)
--Pages.Internal.Msg.SubmitIfValid formId fields isValid maybeUserMsg ->
@ -1002,7 +1012,11 @@ perform config model effect =
startFetcher "TODO" -1 options model
, fromPageMsg = Pages.Internal.Msg.UserMsg >> UserMsg
, key = key
, setField = \info -> Task.succeed (SetField info) |> Task.perform identity
, setField =
\info ->
--Task.succeed (SetField info) |> Task.perform identity
-- TODO
Cmd.none
}
Nothing ->
@ -1017,16 +1031,7 @@ startFetcher fetcherKey transitionId options model =
let
encodedBody : String
encodedBody =
FormDecoder.encodeFormData
{ fields = options.fields
-- TODO remove hardcoding
, action = ""
-- TODO remove hardcoding
, method = Post
, id = Nothing
}
encodeFormData options.fields
formData : { method : Method, action : String, fields : List ( String, String ), id : Maybe String }
formData =
@ -1089,7 +1094,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
let
encodedBody : String
encodedBody =
FormDecoder.encodeFormData formData
encodeFormData formData.fields
in
-- TODO make sure that `actionData` isn't updated in Model for fetchers
Cmd.batch
@ -1150,7 +1155,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
-- TODO use formData.method to do either query params or POST body
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } -> Path.join [ path, "content.dat" ] |> Path.toAbsolute) |> Maybe.withDefault "/"
, method = formData.method |> FormDecoder.methodToString
, method = formData.method |> methodToString
, timeout = Nothing
}
]
@ -1185,7 +1190,7 @@ appendFormQueryParams fields =
)
++ (case fields.method of
Get ->
"?" ++ FormDecoder.encodeFormData fields
"?" ++ encodeFormData fields.fields
Post ->
""
@ -1309,7 +1314,7 @@ fetchRouteData transitionKey toMsg config url details =
|> Maybe.withDefault Get
in
Http.request
{ method = details |> Maybe.map (.method >> FormDecoder.methodToString) |> Maybe.withDefault "GET"
{ method = details |> Maybe.map (.method >> methodToString) |> Maybe.withDefault "GET"
, headers = []
, url =
"/"
@ -1332,7 +1337,7 @@ fetchRouteData transitionKey toMsg config url details =
Get ->
details
|> Maybe.map FormDecoder.encodeFormData
|> Maybe.map (.fields >> encodeFormData)
|> Maybe.map (\encoded -> "?" ++ encoded)
|> Maybe.withDefault ""
)
@ -1354,7 +1359,7 @@ fetchRouteData transitionKey toMsg config url details =
urlEncodedFields : Maybe String
urlEncodedFields =
details
|> Maybe.map FormDecoder.encodeFormData
|> Maybe.map (.fields >> encodeFormData)
in
urlEncodedFields
|> Maybe.map (\encoded -> Http.stringBody "application/x-www-form-urlencoded" encoded)
@ -1608,3 +1613,23 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
|> Url.toString
|> BrowserLoadUrl
)
methodToString : Method -> String
methodToString method =
case method of
Get ->
"GET"
Post ->
"POST"
encodeFormData : List ( String, String ) -> String
encodeFormData fields =
fields
|> List.map
(\( name, value ) ->
Url.percentEncode name ++ "=" ++ Url.percentEncode value
)
|> String.join "&"

View File

@ -1,7 +1,6 @@
module Pages.StaticHttpRequest exposing (Error(..), MockResolver, RawRequest(..), Status(..), cacheRequestResolution, mockResolve, toBuildError)
import BuildError exposing (BuildError)
import Dict
import Json.Encode
import Pages.StaticHttp.Request
import RequestsAndPending exposing (RequestsAndPending)

View File

@ -881,57 +881,49 @@ fileField_ name =
{-| -}
formDataWithServerValidation :
Form.Handler.Handler error (BackendTask FatalError (Validation.Validation error combined kind constraints))
-> Parser (BackendTask FatalError (Result (Form.Response error) ( Form.Response error, combined )))
-> Parser (BackendTask FatalError (Result (Form.ServerResponse error) ( Form.ServerResponse error, combined )))
formDataWithServerValidation formParsers =
rawFormData
|> andThen
(\rawFormData_ ->
let
( maybeDecoded, errors ) =
Form.Handler.run
rawFormData_
formParsers
in
case ( maybeDecoded, errors |> Dict.toList |> List.filter (\( _, value ) -> value |> List.isEmpty |> not) |> List.NonEmpty.fromList ) of
( Just decoded, Nothing ) ->
case Form.Handler.run rawFormData_ formParsers of
Form.Valid decoded ->
succeed
(decoded
|> BackendTask.map
-- TODO not sure how to migrate this
(\(Validation _ _ ( maybeParsed, errors2 )) ->
case ( maybeParsed, errors2 |> Dict.toList |> List.filter (\( _, value ) -> value |> List.isEmpty |> not) |> List.NonEmpty.fromList ) of
( Just decodedFinal, Nothing ) ->
Ok
( Pages.Internal.Form.Response
{ fields = rawFormData_
, errors = Dict.empty
, clientErrors = Dict.empty
}
( { persisted =
{ fields = Just rawFormData_
, clientSideErrors = Nothing
}
, serverSideErrors = Dict.empty
}
, decodedFinal
)
_ ->
Err
(Pages.Internal.Form.Response
{ fields = rawFormData_
, errors = errors2
, clientErrors = errors
{ persisted =
{ fields = Just rawFormData_
, clientSideErrors = Just errors2
}
)
, serverSideErrors = Dict.empty
}
)
)
( _, maybeErrors ) ->
Form.Invalid maybeValue errors ->
Err
(Pages.Internal.Form.Response
{ fields = rawFormData_
, errors =
maybeErrors
|> Maybe.map List.NonEmpty.toList
|> Maybe.withDefault []
|> Dict.fromList
, clientErrors = Dict.empty
{ persisted =
{ fields = Just rawFormData_
, clientSideErrors = Just errors
}
)
, serverSideErrors = Dict.empty
}
|> BackendTask.succeed
|> succeed
)
@ -940,39 +932,31 @@ formDataWithServerValidation formParsers =
{-| -}
formData :
Form.Handler.Handler error combined
-> Parser ( Form.Response error, Result { fields : List ( String, String ), errors : Dict String (List error), clientErrors : Dict String (List error) } combined )
-> Parser ( Form.ServerResponse error, Form.Validated error combined )
formData formParsers =
rawFormData
|> andThen
(\rawFormData_ ->
let
( maybeDecoded, errors ) =
Form.Handler.run
rawFormData_
formParsers
in
case ( maybeDecoded, errors |> Dict.toList |> List.filter (\( _, value ) -> value |> List.isEmpty |> not) |> List.NonEmpty.fromList ) of
( Just decoded, Nothing ) ->
( Pages.Internal.Form.Response { fields = [], errors = Dict.empty, clientErrors = Dict.empty }
, Ok decoded
case Form.Handler.run rawFormData_ formParsers of
(Form.Valid decoded) as validated ->
( { persisted =
{ fields = Just rawFormData_
, clientSideErrors = Just Dict.empty
}
, serverSideErrors = Dict.empty
}
, validated
)
|> succeed
( _, maybeErrors ) ->
let
record : { fields : List ( String, String ), errors : Dict String (List error), clientErrors : Dict String (List error) }
record =
{ fields = rawFormData_
, errors = Dict.empty
, clientErrors =
maybeErrors
|> Maybe.map List.NonEmpty.toList
|> Maybe.withDefault []
|> Dict.fromList
(Form.Invalid maybeDecoded maybeErrors) as validated ->
( { persisted =
{ fields = Just rawFormData_
, clientSideErrors = Just maybeErrors
}
in
( Pages.Internal.Form.Response record
, Err record
, serverSideErrors = Dict.empty
}
, validated
)
|> succeed
)