I have a Digestive Functors form that looks like this:
dateTimeForm :: Monad m => Maybe LocalTime -> Form Text m LocalTime
dateTimeForm t = LocalTime
<$> "date" .: stringRead "Must be a valid date" (localDay <$> t)
<*> "time" .: stringRead "Must be a valid time" (localTimeOfDay <$> t)
The input elements I'm using for this form are <input type="date" />
and <input type="time" />
. This works very well for the date portion of this form, but not so well on the time portion. Browsers that support the time input element only submit the hours and minutes (eg. "18:00"), but a TimeOfDay requires hours, minutes, and seconds. This causes stringRead to fail and Digestive Functors reports an error to the user ("Must be a valid time").
I tried working around this like so, but if the user submits an invalid time, they no longer get an attractive error from Digestive Functors (Prelude.read: no parse).
dateTimeForm :: Monad m => Maybe LocalTime -> Form Text m LocalTime
dateTimeForm t = toLocalTime
<$> "date" .: stringRead "Must be a valid date" (localDay <$> t)
<*> "time" .: string (show . localTimeOfDay <$> t)
where
toLocalTime d x = LocalTime d $ read $ if length x == 8 then x else x <> ":00"
I guess what I was looking for is the validate
function and a little help from maybeRead
. This appears to work:
dateTimeForm :: Monad m => Maybe LocalTime -> Form Text m LocalTime
dateTimeForm t = LocalTime
<$> "date" .: stringRead "Must be a valid date" (localDay <$> t)
<*> "time" .: validate validTime (string (show . localTimeOfDay <$> t))
where
-- the time input element only submits hours and minutes ("18:00"), which is 5 characters long
validTime x = case maybeRead (if length x == 5 then x <> ":00" else x) of
Just x' -> Success x'
_ -> Error "Must be a valid time"