module Web.Hyperbole.Effect.Client where

import Data.Aeson
import Data.Text (Text)
import Effectful
import Effectful.Dispatch.Dynamic
import Effectful.Reader.Dynamic
import Web.Hyperbole.Effect.Hyperbole
import Web.Hyperbole.HyperView
import Web.Hyperbole.Types.Client (clientSetPageTitle)
import Web.Hyperbole.Types.Event


{- | Trigger an action for an arbitrary 'HyperView'

▶️ [Advanced](https://hyperbole.live/advanced)

@
instance 'HyperView' Controls es where
  type Require Controls = '[Message]

  data 'Action' Controls = TriggerMessage
    deriving (Generic, 'ViewAction')

  'update' TriggerMessage = do
    trigger Message $ SetMessage \"Triggered!\"
    pure controlView
@
-}
trigger :: (HyperView id es, HyperViewHandled id view, Hyperbole :> es) => id -> Action id -> Eff (Reader view : es) ()
trigger :: forall id (es :: [Effect]) view.
(HyperView id es, HyperViewHandled id view, Hyperbole :> es) =>
id -> Action id -> Eff (Reader view : es) ()
trigger id
vid Action id
act = do
  Hyperbole (Eff (Reader view : es)) () -> Eff (Reader view : es) ()
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send (Hyperbole (Eff (Reader view : es)) ()
 -> Eff (Reader view : es) ())
-> Hyperbole (Eff (Reader view : es)) ()
-> Eff (Reader view : es) ()
forall a b. (a -> b) -> a -> b
$ TargetViewId -> Encoded -> Hyperbole (Eff (Reader view : es)) ()
forall (a :: * -> *). TargetViewId -> Encoded -> Hyperbole a ()
TriggerAction (Text -> TargetViewId
TargetViewId (Text -> TargetViewId) -> Text -> TargetViewId
forall a b. (a -> b) -> a -> b
$ id -> Text
forall id. ViewId id => id -> Text
encodeViewId id
vid) (Action id -> Encoded
forall a. ViewAction a => a -> Encoded
toAction Action id
act)


{- | Dispatch a custom javascript event. This is emitted on the current hyper view and bubbles up to the document

▶️ [Javascript](https://hyperbole.live/javascript)

@
instance 'HyperView' Message es where
  data 'Action' Message = AlertMe
    deriving (Generic, 'ViewAction')

  'update' AlertMe = do
    pushEvent @Text \"server-message\" \"hello\"
    pure \"Sent 'server-message' event\"
@

@
function listenServerEvents() {
  // you can listen on document instead, the event will bubble
  'Hyperbole'.hyperView(\"Message\").addEventListener(\"server-message\", function(e) {
    alert(\"Server Message: \" + e.detail)
  })
@
-}
pushEvent :: (ToJSON a, Hyperbole :> es) => Text -> a -> Eff es ()
pushEvent :: forall a (es :: [Effect]).
(ToJSON a, Hyperbole :> es) =>
Text -> a -> Eff es ()
pushEvent Text
nm a
a = do
  Hyperbole (Eff es) () -> Eff es ()
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send (Hyperbole (Eff es) () -> Eff es ())
-> Hyperbole (Eff es) () -> Eff es ()
forall a b. (a -> b) -> a -> b
$ Text -> Value -> Hyperbole (Eff es) ()
forall (a :: * -> *). Text -> Value -> Hyperbole a ()
TriggerEvent Text
nm (a -> Value
forall a. ToJSON a => a -> Value
toJSON a
a)


{- | Set the document title

@
page :: ('Hyperbole' :> es) => 'Page' es '[]
page = do
  pageTitle \"My 'Page' Title\"
  pure $ 'el' \"Hello World\"
@
-}
pageTitle :: (Hyperbole :> es) => Text -> Eff es ()
pageTitle :: forall (es :: [Effect]). (Hyperbole :> es) => Text -> Eff es ()
pageTitle Text
t = do
  Hyperbole (Eff es) () -> Eff es ()
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send (Hyperbole (Eff es) () -> Eff es ())
-> Hyperbole (Eff es) () -> Eff es ()
forall a b. (a -> b) -> a -> b
$ (Client -> Client) -> Hyperbole (Eff es) ()
forall (a :: * -> *). (Client -> Client) -> Hyperbole a ()
ModClient ((Client -> Client) -> Hyperbole (Eff es) ())
-> (Client -> Client) -> Hyperbole (Eff es) ()
forall a b. (a -> b) -> a -> b
$ Text -> Client -> Client
clientSetPageTitle Text
t