module Loadable
  ( Loadable (..)
  , fromEvent
  , view
  ) where

import           Reflex.Dom   (MonadWidget)
import qualified Reflex.Dom   as R

import           Data.Functor (Functor)
import           Data.Text    (Text)
import           Reflex.Dom   (Dynamic, Event, MonadWidget)
import qualified Reflex.Dom   as R

data Loadable t
  = Loading
  | Error Text
  | Loaded t

instance Functor Loadable where
  fmap f Loading    = Loading
  fmap f (Error e)  = Error e
  fmap f (Loaded x) = Loaded (f x)

instance Applicative Loadable where
  pure x = Loaded x

  Loading <*> _ = Loading
  (Error e) <*> _ = Error e
  (Loaded f) <*> Loading = Loading
  (Loaded f) <*> (Error e) = Error e
  (Loaded f) <*> (Loaded x) = Loaded (f x)

instance Monad Loadable where
  Loading >>= f = Loading
  (Error e) >>= f = Error e
  (Loaded x) >>= f = f x

fromEvent :: forall t m a. MonadWidget t m => Event t (Either Text a) -> m (Dynamic t (Loadable a))
fromEvent =
  R.foldDyn
    (\res _ -> case res of
      Left err -> Error err
      Right t  -> Loaded t
    )
    Loading

view :: forall t m a. MonadWidget t m => (a -> m ()) -> Loadable a -> m ()
view _ (Loading)  = R.divClass "pageSpinner" $ R.divClass "spinner" $ R.blank
view _ (Error e)  = R.text e
view f (Loaded x) = f x