packages feed

hyperbole-0.5.0: src/Web/Hyperbole/Server/Options.hs

{-# LANGUAGE LambdaCase #-}

module Web.Hyperbole.Server.Options where

import Data.ByteString.Lazy qualified as BL
import Data.String.Conversions (cs)
import Data.Text (Text)
import Data.Text qualified as T
import Web.Hyperbole.Data.Encoded (Encoded, encodedToText)
import Web.Hyperbole.Types.Event
import Web.Hyperbole.Types.Response
import Web.Hyperbole.View
import Web.Atomic.CSS


data ServerOptions = ServerOptions
  { toDocument :: BL.ByteString -> BL.ByteString
  , serverError :: ResponseError -> ServerError
  }


defaultErrorMessage :: ResponseError -> Text
defaultErrorMessage = \case
  -- mask server errors
  ErrCustom e -> e.message
  NotFound -> "Not Found"
  ErrInternal -> "Internal Server Error"
  ErrServer m -> m
  e -> cs $ drop 3 $ show e


defaultErrorBody :: Text -> View Body ()
defaultErrorBody msg =
  el ~ bg (HexColor "#F00") . color (HexColor "#FFF") $ do
    text msg


defaultError :: ResponseError -> ServerError
defaultError = \case
  ErrCustom e -> e
  ErrNotHandled e -> errNotHandled e
  err -> 
    let msg = defaultErrorMessage err
    in ServerError msg (defaultErrorBody msg)
 where
  errNotHandled :: Event TargetViewId Encoded -> ServerError
  errNotHandled ev =
    ServerError "Action Not Handled" $ do
      el $ do
        text "No Handler for Event viewId: "
        text ev.viewId.text
        text " action: "
        text $ encodedToText ev.action
      el $ do
        text "Remember to add a `hyper` handler in your page function"
      pre $
        T.intercalate
          "\n"
          [ "page :: (Hyperbole :> es) => Page es Response"
          , "page = do"
          , "  handle contentsHandler"
          , "  load $ do"
          , "    pure $ hyper Contents contentsView"
          , "</pre>"
          ]