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

View File

@ -221,17 +221,17 @@ form user =
(Form.text
"first"
(textInput "First name")
|> Form.required "Required"
|> Form.withInitialValue user.first
|> Form.withClientValidation validateCapitalized
|> Form.required "Required"
)
|> Form.with
(Form.text
"last"
(textInput "Last name")
|> Form.required "Required"
|> Form.withInitialValue user.last
|> Form.withClientValidation validateCapitalized
|> Form.required "Required"
)
|> Form.with
(Form.text "username" usernameInput
@ -288,12 +288,12 @@ form user =
|> Form.required "Required"
)
|> Form.with
(Form.requiredDate
(Form.date
"dob"
{ missing = "Required"
, invalid = \_ -> "Invalid date"
{ invalid = \_ -> "Invalid date"
}
(textInput "Date of Birth")
|> Form.required "Required"
|> Form.withInitialValue (user.birthDay |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
@ -311,23 +311,23 @@ form user =
)
)
|> Form.with
(Form.requiredDate
(Form.date
"checkin"
{ missing = "Required"
, invalid = \_ -> "Invalid date"
{ invalid = \_ -> "Invalid date"
}
(textInput "Check-in")
|> Form.required "Required"
|> Form.withInitialValue (user.checkIn |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
)
|> Form.with
(Form.requiredDate
(Form.date
"checkout"
{ missing = "Required"
, invalid = \_ -> "Invalid date"
{ invalid = \_ -> "Invalid date"
}
(textInput "Check-out")
|> Form.required "Required"
|> Form.withInitialValue (user.checkOut |> Date.toIsoString)
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
@ -417,13 +417,20 @@ form user =
|> Form.wrap wrapNotificationsSections
)
|> Form.appendForm (\() rest -> rest)
(Form.succeed (\_ -> ())
(Form.succeed identity
|> Form.with
(Form.checkbox
"acceptTerms"
False
(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
@ -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
[ Tw.block
, Tw.text_sm
@ -1096,7 +1110,13 @@ wrapPushNotificationsSection ({ errors, submitStatus } as info) children =
[ Attr.attribute "role" "group"
, Attr.attribute "aria-labelledby" "label-notifications"
]
[ Html.div
[ Html.span
[ css
[ Tw.font_bold
]
]
[ Html.text (Debug.toString info.status) ]
, Html.div
[ css
[ Bp.sm
[ Tw.grid

View File

@ -9,7 +9,7 @@ module Form exposing
, withInitialValue
, checkbox, date, email, hidden, multiple, number, password, radio, range, telephone, text, url, floatRange, search
, submit
, required, requiredDate, requiredNumber, requiredRadio
, required, requiredNumber, requiredRadio
, validate
, withServerValidation
, 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
@docs required, requiredDate, requiredNumber, requiredRadio
@docs required, requiredNumber, requiredRadio
### Custom Client-Side Validations
@ -716,9 +716,10 @@ text :
->
Field
error
String
(Maybe String)
view
{ required : ()
, wasMapped : No
}
text name toHtmlFn =
Field
@ -732,7 +733,14 @@ text name toHtmlFn =
toHtmlFn (toInputRecord formInfo name Nothing info fieldInfo)
, decode =
\rawValue ->
Ok ( rawValue |> Maybe.withDefault "", [] )
Ok
( if rawValue == Just "" then
Nothing
else
rawValue
, []
)
, properties = []
}
@ -1148,7 +1156,16 @@ date :
(FieldRenderInfo error
-> 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 =
Field
{ 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 maybeRaw =
if (maybeRaw |> Maybe.withDefault "") == "" then
@ -1331,28 +1314,47 @@ withBoolProperty ( key, value ) (Field field) =
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) =
Field
{ field
| required = True
, decode =
if field.type_ == "checkbox" then
\rawValue ->
if rawValue == Just "on" then
field.decode rawValue
{ name = field.name
, initialValue = field.initialValue
, type_ = field.type_
, required = True
, serverValidation = field.serverValidation
, toHtml = field.toHtml
, decode =
\rawValue ->
case field.decode rawValue of
Ok ( Just decoded, errors ) ->
Ok ( decoded, errors )
else
Err [ missingError ]
Ok ( Nothing, errors ) ->
Err [ missingError ]
else
\rawValue ->
if rawValue == Nothing || rawValue == Just "" then
Err [ missingError ]
else
field.decode rawValue
Err errors ->
Err errors
, properties = field.properties
}
@ -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) =
Field
{ 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) =
Field
{ name = field.name