packages feed

typed-admin-0.1.0.0: src/TypedAdmin/Extra.hs

{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TemplateHaskell            #-}
module TypedAdmin.Extra where

import           Control.Monad
import           Control.Monad.Trans.Class
import           Data.ByteString.Lazy      (toStrict)
import qualified Data.ByteString.UTF8      as BS
import           Data.Default.Class
import           Data.Maybe
import           Data.Text                 (pack)
import           Data.Text                 (Text)
import           Data.Text.Encoding        (decodeUtf8)
import           GHC.Generics
import           GHC.Int
import           Lucid
import           Text.Blaze.Renderer.Utf8  (renderMarkup)
import           Text.Heterocephalus
import           TypedAdmin.Class
import           TypedAdmin.Instance       ()
import           TypedAdmin.Util

newtype Image = Image { unImage :: String }
  deriving (Show)

instance ToDetailField Image where
  toDetailField (Image x) = do
    a_ [href_ (pack x), target_ "_blank"] $
      img_ [src_ (pack x)]

newtype HiddenField a = HiddenField { unHiddenField :: a }
  deriving (Generic, Show)

instance Monad m => FormField m (HiddenField String) where
  toFormField n x = input_ [type_ "hidden", name_ n, value_ (pack $ fromMaybe "" $ unHiddenField <$> x)]
  fromFormField ps k = pure $ fmap HiddenField $ memptyToNothing =<< BS.toString <$> join (lookup k ps)

instance Monad m => FormField m (HiddenField Int64) where
  toFormField n x = input_ [type_ "text", name_ n, value_ (pack $ fromMaybe "" $ show . unHiddenField <$> x)]
  fromFormField ps k = pure $ fmap HiddenField $ lookupMaybe k ps

data Anchor a = Anchor a Text

instance ToDetailField a => ToDetailField (Anchor a) where
  toDetailField (Anchor x url) = do
    a_ [href_ url] $ toDetailField x

newtype TextArea = TextArea { unTextArea :: String }
  deriving (Show, Default)

instance Monad m => FormField m TextArea where
  toFormField n x = textarea_ [name_ n] $
    toHtml $ fromMaybe "" $ unTextArea <$> x
  fromFormField ps k = pure $ fmap TextArea $ memptyToNothing =<< BS.toString <$> join (lookup k ps)

newtype RangeField a = RangeField { unRangeField :: a }
  deriving (Show, Default)

instance (Monad m, Bounded a, Enum a) => FormField m (RangeField a) where
  toFormField n x = input_ [ type_ "range", name_ n
                           , value_ (pack $ fromMaybe "" $ show . fromEnum . unRangeField <$> x)
                           , step_ "1"
                           , min_ (pack . show $ fromEnum (minBound :: a))
                           , max_ (pack . show $ fromEnum (maxBound :: a))]
  fromFormField ps k = pure $ fmap (RangeField . toEnum) $ lookupMaybe k ps


class GoogleApiEnv m where
  getKey :: m String

data GeoLocation = GeoLocation
  { lat :: Double
  , lon :: Double
  } deriving (Show, Generic)
instance Default GeoLocation

instance (Monad m, GoogleApiEnv m) => FormField m GeoLocation where
  toFormField n v = do
    let vlat = maybe "" (pack . show . lat) v
    input_ [type_ "text", id_ "locationLat", name_ (n <> "lat"), value_ vlat]
    let vlon = maybe "" (pack . show . lon) v
    input_ [type_ "text", id_ "locationLon", name_ (n <> "lon"), value_ vlon]
    div_ [id_ "map", style_ "height: 400px;"] ""
    script_ (decodeUtf8 $ toStrict $ renderMarkup $(compileTextFile "templates/javascript/map.js"))
    key <- lift $ getKey
    script_ [src_ ("https://maps.googleapis.com/maps/api/js?key=" <> pack key <> "&callback=initMap")] ("" :: String)
   -- async defer></script>
  fromFormField ps k = do
    lat <- fromFormField ps (k <> "lat")
    lon <- fromFormField ps (k <> "lon")
    return $ GeoLocation <$> lat <*> lon