Use phantom builder for required checks.

This commit is contained in:
Dillon Kearns 2022-01-15 18:28:47 -08:00
parent fedee35e08
commit 69e8fc92f4
3 changed files with 102 additions and 76 deletions

View File

@ -88,6 +88,7 @@ form user =
, Html.input toInput [] , Html.input toInput []
] ]
) )
|> Form.required "Required"
|> Form.withInitialValue user.first |> Form.withInitialValue user.first
) )
|> Form.with |> Form.with
@ -102,6 +103,7 @@ form user =
, Html.input toInput [] , Html.input toInput []
] ]
) )
|> Form.required "Required"
|> Form.withInitialValue user.last |> Form.withInitialValue user.last
) )
|> Form.with |> Form.with
@ -116,6 +118,7 @@ form user =
, Html.input toInput [] , Html.input toInput []
] ]
) )
|> Form.required "Required"
|> Form.withInitialValue user.username |> Form.withInitialValue user.username
|> Form.withServerValidation |> Form.withServerValidation
(\username -> (\username ->
@ -138,13 +141,13 @@ form user =
, Html.input toInput [] , Html.input toInput []
] ]
) )
|> Form.required "Required"
|> Form.withInitialValue user.email |> Form.withInitialValue user.email
) )
|> Form.with |> Form.with
(Form.requiredDate (Form.date
"dob" "dob"
{ missing = "Required" { invalid = \_ -> "Invalid date"
, invalid = \_ -> "Invalid date"
} }
(\{ toInput, toLabel, errors } -> (\{ toInput, toLabel, errors } ->
Html.div [] Html.div []
@ -155,6 +158,7 @@ form user =
, Html.input toInput [] , Html.input toInput []
] ]
) )
|> Form.required "Required"
|> Form.withInitialValue (user.birthDay |> Date.toIsoString) |> Form.withInitialValue (user.birthDay |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1) |> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1) |> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)

View File

@ -221,17 +221,17 @@ form user =
(Form.text (Form.text
"first" "first"
(textInput "First name") (textInput "First name")
|> Form.required "Required"
|> Form.withInitialValue user.first |> Form.withInitialValue user.first
|> Form.withClientValidation validateCapitalized |> Form.withClientValidation validateCapitalized
|> Form.required "Required"
) )
|> Form.with |> Form.with
(Form.text (Form.text
"last" "last"
(textInput "Last name") (textInput "Last name")
|> Form.required "Required"
|> Form.withInitialValue user.last |> Form.withInitialValue user.last
|> Form.withClientValidation validateCapitalized |> Form.withClientValidation validateCapitalized
|> Form.required "Required"
) )
|> Form.with |> Form.with
(Form.text "username" usernameInput (Form.text "username" usernameInput
@ -288,12 +288,12 @@ form user =
|> Form.required "Required" |> Form.required "Required"
) )
|> Form.with |> Form.with
(Form.requiredDate (Form.date
"dob" "dob"
{ missing = "Required" { invalid = \_ -> "Invalid date"
, invalid = \_ -> "Invalid date"
} }
(textInput "Date of Birth") (textInput "Date of Birth")
|> Form.required "Required"
|> Form.withInitialValue (user.birthDay |> Date.toIsoString) |> Form.withInitialValue (user.birthDay |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1) |> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1) |> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
@ -311,23 +311,23 @@ form user =
) )
) )
|> Form.with |> Form.with
(Form.requiredDate (Form.date
"checkin" "checkin"
{ missing = "Required" { invalid = \_ -> "Invalid date"
, invalid = \_ -> "Invalid date"
} }
(textInput "Check-in") (textInput "Check-in")
|> Form.required "Required"
|> Form.withInitialValue (user.checkIn |> Date.toIsoString) |> Form.withInitialValue (user.checkIn |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1) |> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1) |> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
) )
|> Form.with |> Form.with
(Form.requiredDate (Form.date
"checkout" "checkout"
{ missing = "Required" { invalid = \_ -> "Invalid date"
, invalid = \_ -> "Invalid date"
} }
(textInput "Check-out") (textInput "Check-out")
|> Form.required "Required"
|> Form.withInitialValue (user.checkOut |> Date.toIsoString) |> Form.withInitialValue (user.checkOut |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1) |> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1) |> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
@ -417,13 +417,20 @@ form user =
|> Form.wrap wrapNotificationsSections |> Form.wrap wrapNotificationsSections
) )
|> Form.appendForm (\() rest -> rest) |> Form.appendForm (\() rest -> rest)
(Form.succeed (\_ -> ()) (Form.succeed identity
|> Form.with |> Form.with
(Form.checkbox (Form.checkbox
"acceptTerms" "acceptTerms"
False False
(checkboxInput { name = "Accept terms", description = "Please read the terms before proceeding." }) (checkboxInput { name = "Accept terms", description = "Please read the terms before proceeding." })
|> Form.required "Please agree to terms to proceed." |> Form.withClientValidation2
(\checked ->
if checked then
Ok ( (), [] )
else
Ok ( (), [ "Please agree to terms to proceed." ] )
)
) )
) )
|> Form.append |> Form.append
@ -784,7 +791,14 @@ textInput labelText ({ toInput, toLabel, errors, submitStatus } as info) =
] ]
] ]
] ]
[ Html.label [ --Html.text (Debug.toString submitStatus),
Html.span
[ css
[ Tw.font_bold
]
]
[ Html.text (Debug.toString info.status) ]
, Html.label
([ css ([ css
[ Tw.block [ Tw.block
, Tw.text_sm , Tw.text_sm
@ -1096,7 +1110,13 @@ wrapPushNotificationsSection ({ errors, submitStatus } as info) children =
[ Attr.attribute "role" "group" [ Attr.attribute "role" "group"
, Attr.attribute "aria-labelledby" "label-notifications" , Attr.attribute "aria-labelledby" "label-notifications"
] ]
[ Html.div [ Html.span
[ css
[ Tw.font_bold
]
]
[ Html.text (Debug.toString info.status) ]
, Html.div
[ css [ css
[ Bp.sm [ Bp.sm
[ Tw.grid [ Tw.grid

View File

@ -9,7 +9,7 @@ module Form exposing
, withInitialValue , withInitialValue
, checkbox, date, email, hidden, multiple, number, password, radio, range, telephone, text, url, floatRange, search , checkbox, date, email, hidden, multiple, number, password, radio, range, telephone, text, url, floatRange, search
, submit , submit
, required, requiredDate, requiredNumber, requiredRadio , required, requiredNumber, requiredRadio
, validate , validate
, withServerValidation , withServerValidation
, withMax, withMaxDate, withMin, withMinDate , withMax, withMaxDate, withMin, withMinDate
@ -84,7 +84,7 @@ A Date type can be entered with the native date picker UI of the user's browser,
### Required ### Required
@docs required, requiredDate, requiredNumber, requiredRadio @docs required, requiredNumber, requiredRadio
### Custom Client-Side Validations ### Custom Client-Side Validations
@ -716,9 +716,10 @@ text :
-> ->
Field Field
error error
String (Maybe String)
view view
{ required : () { required : ()
, wasMapped : No
} }
text name toHtmlFn = text name toHtmlFn =
Field Field
@ -732,7 +733,14 @@ text name toHtmlFn =
toHtmlFn (toInputRecord formInfo name Nothing info fieldInfo) toHtmlFn (toInputRecord formInfo name Nothing info fieldInfo)
, decode = , decode =
\rawValue -> \rawValue ->
Ok ( rawValue |> Maybe.withDefault "", [] ) Ok
( if rawValue == Just "" then
Nothing
else
rawValue
, []
)
, properties = [] , properties = []
} }
@ -1148,7 +1156,16 @@ date :
(FieldRenderInfo error (FieldRenderInfo error
-> view -> view
) )
-> Field error (Maybe Date) view { min : Date, max : Date } ->
Field
error
(Maybe Date)
view
{ min : Date
, max : Date
, required : ()
, wasMapped : No
}
date name toError toHtmlFn = date name toError toHtmlFn =
Field Field
{ name = name { name = name
@ -1176,40 +1193,6 @@ date name toError toHtmlFn =
} }
{-| -}
requiredDate :
String
-> { missing : error, invalid : String -> error }
->
(FieldRenderInfo error
-> view
)
-> Field error Date view { min : Date, max : Date }
requiredDate name toError toHtmlFn =
Field
{ name = name
, initialValue = Nothing
, type_ = "date"
, required = True
, serverValidation = \_ -> DataSource.succeed []
, toHtml =
\formInfo _ fieldInfo info ->
toHtmlFn (toInputRecord formInfo name Nothing info fieldInfo)
, decode =
\rawString ->
rawString
|> validateRequiredField toError
|> Result.andThen
(\rawDateString ->
Date.fromIsoString rawDateString
|> Result.mapError
(\_ -> toError.invalid rawDateString)
)
|> toFieldResult
, properties = []
}
validateRequiredField : { toError | missing : error } -> Maybe String -> Result error String validateRequiredField : { toError | missing : error } -> Maybe String -> Result error String
validateRequiredField toError maybeRaw = validateRequiredField toError maybeRaw =
if (maybeRaw |> Maybe.withDefault "") == "" then if (maybeRaw |> Maybe.withDefault "") == "" then
@ -1331,28 +1314,47 @@ withBoolProperty ( key, value ) (Field field) =
Field { field | properties = ( key, Encode.bool value ) :: field.properties } Field { field | properties = ( key, Encode.bool value ) :: field.properties }
type Yes
= Yes
type No
= No
{-| -} {-| -}
required : error -> Field error value view { constraints | required : () } -> Field error value view constraints required :
error
->
Field
error
(Maybe value)
view
{ constraints
| required : ()
, wasMapped : No
}
-> Field error value view { constraints | wasMapped : No }
required missingError (Field field) = required missingError (Field field) =
Field Field
{ field { name = field.name
| required = True , initialValue = field.initialValue
, decode = , type_ = field.type_
if field.type_ == "checkbox" then , required = True
\rawValue -> , serverValidation = field.serverValidation
if rawValue == Just "on" then , toHtml = field.toHtml
field.decode rawValue , decode =
\rawValue ->
case field.decode rawValue of
Ok ( Just decoded, errors ) ->
Ok ( decoded, errors )
else Ok ( Nothing, errors ) ->
Err [ missingError ] Err [ missingError ]
else Err errors ->
\rawValue -> Err errors
if rawValue == Nothing || rawValue == Just "" then , properties = field.properties
Err [ missingError ]
else
field.decode rawValue
} }
@ -1412,7 +1414,7 @@ withServerValidation serverValidation (Field field) =
{-| -} {-| -}
withClientValidation : (value -> Result error mapped) -> Field error value view constraints -> Field error mapped view constraints withClientValidation : (value -> Result error mapped) -> Field error value view constraints -> Field error mapped view { constraints | wasMapped : Yes }
withClientValidation mapFn (Field field) = withClientValidation mapFn (Field field) =
Field Field
{ name = field.name { name = field.name
@ -1437,7 +1439,7 @@ withClientValidation mapFn (Field field) =
{-| -} {-| -}
withClientValidation2 : (value -> Result (List error) ( mapped, List error )) -> Field error value view constraints -> Field error mapped view constraints withClientValidation2 : (value -> Result (List error) ( mapped, List error )) -> Field error value view constraints -> Field error mapped view { constraints | wasMapped : Yes }
withClientValidation2 mapFn (Field field) = withClientValidation2 mapFn (Field field) =
Field Field
{ name = field.name { name = field.name