docspell/modules/webapp/src/main/elm/Comp/CalEventInput.elm
Eike Kettner b4e11a7264 Fixes a race condition when initializing the calendar-event field
The problem was that the field executes a request to validate its
state. This was initiated at the same time for two values. Then it was
undetermined which value comes back first.
2020-08-01 11:42:01 +02:00

268 lines
7.3 KiB
Elm
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module Comp.CalEventInput exposing
( Model
, Msg
, init
, initDefault
, update
, view
)
import Api
import Api.Model.CalEventCheck exposing (CalEventCheck)
import Api.Model.CalEventCheckResult exposing (CalEventCheckResult)
import Data.CalEvent exposing (CalEvent)
import Data.Flags exposing (Flags)
import Data.Validated exposing (Validated(..))
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import Http
import Util.Http
import Util.Maybe
import Util.Time
type alias Model =
{ checkResult : Maybe CalEventCheckResult
}
type Msg
= SetYear String
| SetMonth String
| SetDay String
| SetHour String
| SetMinute String
| SetWeekday String
| CheckInputMsg CalEvent (Result Http.Error CalEventCheckResult)
initDefault : Model
initDefault =
Model Nothing
init : Flags -> CalEvent -> ( Model, Cmd Msg )
init flags ev =
( Model Nothing, checkInput flags ev )
checkInput : Flags -> CalEvent -> Cmd Msg
checkInput flags ev =
let
eventStr =
Data.CalEvent.makeEvent ev
input =
CalEventCheck eventStr
in
Api.checkCalEvent flags input (CheckInputMsg ev)
withCheckInput : Flags -> CalEvent -> Model -> ( Model, Cmd Msg, Validated CalEvent )
withCheckInput flags ev model =
( model, checkInput flags ev, Unknown ev )
isCheckError : Model -> Bool
isCheckError model =
Maybe.map .success model.checkResult
|> Maybe.withDefault True
|> not
update : Flags -> CalEvent -> Msg -> Model -> ( Model, Cmd Msg, Validated CalEvent )
update flags ev msg model =
case msg of
SetYear str ->
withCheckInput flags { ev | year = str } model
SetMonth str ->
withCheckInput flags { ev | month = str } model
SetDay str ->
withCheckInput flags { ev | day = str } model
SetHour str ->
withCheckInput flags { ev | hour = str } model
SetMinute str ->
withCheckInput flags { ev | minute = str } model
SetWeekday str ->
withCheckInput flags { ev | weekday = Util.Maybe.fromString str } model
CheckInputMsg event (Ok res) ->
let
m =
{ model | checkResult = Just res }
in
( m
, Cmd.none
, if res.success then
Valid event
else
Invalid [ res.message ] event
)
CheckInputMsg event (Err err) ->
let
emptyResult =
Api.Model.CalEventCheckResult.empty
m =
{ model
| checkResult =
Just
{ emptyResult
| success = False
, message = Util.Http.errorToString err
}
}
in
( m, Cmd.none, Unknown event )
view : String -> CalEvent -> Model -> Html Msg
view extraClasses ev model =
let
yearLen =
Basics.max 4 (String.length ev.year)
otherLen str =
Basics.max 2 (String.length str)
in
div
[ classList
[ ( extraClasses, True )
]
]
[ div [ class "calevent-input" ]
[ div []
[ label [] [ text "Weekday" ]
, input
[ type_ "text"
, class "time-input"
, size
(Maybe.map otherLen ev.weekday
|> Maybe.withDefault 4
)
, Maybe.withDefault "" ev.weekday
|> value
, onInput SetWeekday
]
[]
]
, div []
[ label [] [ text "Year" ]
, input
[ type_ "text"
, class "time-input"
, size yearLen
, value ev.year
, onInput SetYear
]
[]
]
, div [ class "date separator" ]
[ text ""
]
, div []
[ label [] [ text "Month" ]
, input
[ type_ "text"
, class "time-input"
, size (otherLen ev.month)
, value ev.month
, onInput SetMonth
]
[]
]
, div [ class "date separator" ]
[ text ""
]
, div []
[ label [] [ text "Day" ]
, input
[ type_ "text"
, class "time-input"
, size (otherLen ev.day)
, value ev.day
, onInput SetDay
]
[]
]
, div [ class "datetime separator" ]
[ text " "
]
, div []
[ label [] [ text "Hour" ]
, input
[ type_ "text"
, class "time-input"
, size (otherLen ev.hour)
, value ev.hour
, onInput SetHour
]
[]
]
, div [ class "time separator" ]
[ text ":"
]
, div []
[ label [] [ text "Minute" ]
, input
[ type_ "text"
, class "time-input"
, size (otherLen ev.minute)
, value ev.minute
, onInput SetMinute
]
[]
]
]
, div
[ classList
[ ( "ui basic red pointing label", True )
, ( "hidden invisible", not (isCheckError model) )
]
]
[ text "Error: "
, Maybe.map .message model.checkResult
|> Maybe.withDefault ""
|> text
]
, div
[ classList
[ ( "ui message", True )
, ( "hidden invisible"
, model.checkResult == Nothing || isCheckError model
)
]
]
[ dl []
[ dt []
[ text "Schedule: "
]
, dd []
[ code []
[ Maybe.andThen .event model.checkResult
|> Maybe.withDefault ""
|> text
]
]
, dt []
[ text "Next: "
]
, dd []
(Maybe.map .next model.checkResult
|> Maybe.withDefault []
|> List.map Util.Time.formatDateTime
|> List.map text
|> List.intersperse (br [] [])
)
]
]
]