module Component.Select ( SelectIn(..) , SelectOut(..) , select ) where import Data.Map (Map) import qualified Data.Map as M import qualified Data.Maybe as Maybe import Data.Text (Text) import qualified Data.Text as T import Data.Validation (Validation (Failure, Success)) import Reflex.Dom (Dynamic, Event, MonadWidget, Reflex) import qualified Reflex.Dom as R import qualified Common.Msg as Msg import qualified Util.Validation as ValidationUtil data (Reflex t) => SelectIn t a b c = SelectIn { _selectIn_label :: Text , _selectIn_initialValue :: a , _selectIn_value :: Event t a , _selectIn_values :: Dynamic t (Map a Text) , _selectIn_reset :: Event t b , _selectIn_isValid :: a -> Bool , _selectIn_validate :: Event t c } data SelectOut t a = SelectOut { _selectOut_value :: Dynamic t (Validation Text a) } select :: forall t m a b c. (Ord a, MonadWidget t m) => SelectIn t a b c -> m (SelectOut t a) select selectIn = do rec let containerAttr = R.ffor showedError (\e -> M.singleton "class" $ T.intercalate " " [ "selectInput" , if Maybe.isJust e then "error" else "" ]) validatedValue = R.ffor value (\v -> if _selectIn_isValid selectIn v then Success v else Failure (Msg.get Msg.Form_NonEmpty)) maybeError = fmap ValidationUtil.maybeError validatedValue showedError <- R.holdDyn Nothing $ R.leftmost [ const Nothing <$> _selectIn_reset selectIn , R.updated maybeError , R.attachWith const (R.current maybeError) (_selectIn_validate selectIn) ] value <- R.elDynAttr "div" containerAttr $ do R.el "label" $ R.text (_selectIn_label selectIn) let initialValue = _selectIn_initialValue selectIn let setValue = R.leftmost [ const initialValue <$> (_selectIn_reset selectIn) , _selectIn_value selectIn ] value <- R._dropdown_value <$> R.dropdown initialValue (_selectIn_values selectIn) (R.def { R._dropdownConfig_setValue = setValue }) R.divClass "errorMessage" . R.dynText $ R.ffor showedError (Maybe.fromMaybe "") return value return SelectOut { _selectOut_value = validatedValue }