packages feed

hyperbole-0.5.0: src/Web/Hyperbole/HyperView/ViewId.hs

{-# LANGUAGE DefaultSignatures #-}

module Web.Hyperbole.HyperView.ViewId where

import Data.Text (Text)
import Effectful
import Effectful.Reader.Dynamic
import GHC.Generics
import Web.Hyperbole.Data.Encoded as Encoded
import Web.Hyperbole.View (View, context)


{- | A unique identifier for a 'HyperView'

@
#EMBED Example/Page/Simple.hs data Message
@
-}
class ViewId a where
  toViewId :: a -> Encoded
  default toViewId :: (Generic a, GToEncoded (Rep a)) => a -> Encoded
  toViewId = genericToEncoded


  parseViewId :: Encoded -> Either String a
  default parseViewId :: (Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
  parseViewId = genericParseEncoded


{- | Access the 'viewId' in a 'View' or 'update'

@
#EMBED Example/Page/Concurrency.hs data LazyData

#EMBED Example/Page/Concurrency.hs instance (Debug :> es, GenRandom :> es) => HyperView LazyData es where
@
-}
class HasViewId m view where
  viewId :: m view


instance HasViewId (View ctx) ctx where
  viewId = context
instance HasViewId (Eff (Reader view : es)) view where
  viewId = ask


encodeViewId :: (ViewId id) => id -> Text
encodeViewId = encodedToText . toViewId


decodeViewId :: (ViewId id) => Text -> Maybe id
decodeViewId t = do
  case parseViewId =<< encodedParseText t of
    Left _ -> Nothing
    Right a -> pure a