{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} module Main where import Control.Lens import Control.Monad import Control.Monad.IO.Class import Data.Default.Class import Data.Generics.Labels () import Data.Maybe import Data.Proxy import Data.Text as T import Database.Relational as R hiding (fromMaybe, list) import DataSource2 import Debug.Trace (trace) import qualified Entity.Beer as Beer import qualified Entity.Store as Store import GHC.Generics import GHC.Int import Lucid import Network.HTTP.Types (status404) import Network.Wai import Network.Wai.Handler.Warp (run) import Prelude hiding (id) import qualified Prelude (id) import TypedAdmin import TypedAdmin.Util instance Default Beer.Beer instance ToDetail Handler Beer.Beer instance ToForm Handler Beer.Beer data BeerDetail = BeerDetail { id :: Int64 , name :: String , ibu :: Maybe Int32 } deriving (Generic) data UpdateBeerParam = UpdateBeerParam { name :: String , ibu :: Maybe Int32 } deriving (Generic) instance ToForm Handler UpdateBeerParam data BeerSummary = BeerSummary { id :: Int64 , name :: String , images :: [Image] } deriving (Generic, Show) instance HasHeader BeerSummary instance ToDetail Handler BeerSummary where linkDetail x = pure $ Just $ "/beers/" <> tshow (x ^. #id) linkEdit x = pure $ Just $ "/beers/" <> tshow (x ^. #id) <> "/_edit" instance ToDetail Handler BeerDetail instance ToDetail Handler Store.Store instance HasHeader Store.Store data SearchBeerParam = SearchBeerParam { name :: Maybe String , ibu :: Maybe Int32 } deriving (Generic, Show) instance ToForm Handler SearchBeerParam instance ListConsole Handler BeerSummary SearchBeerParam where list p _ = do beers <- runQuery (relationalQuery' (f p) []) () return $ fmap r beers where f (param :: Maybe SearchBeerParam) = relation $ do x <- query Beer.beer whenJust (param ^? _Just . #name . _Just) $ \v -> wheres $ x ! Beer.name' .=. value v whenJust (param ^? _Just . #ibu . _Just) $ \v -> wheres $ x ! Beer.ibu' .=. just (value v) return x -- mock r x = BeerSummary { id = Beer.id x , name = Beer.name x , images = fmap Image ["https://source.unsplash.com/100x100/?beer"] } listSublayout _ _ b = do div_ [] $ a_ [href_ "/beers/_create"] "add new beer" div_ [] b instance ListConsole Handler Store.Store () where list x _ = runQuery (relationalQuery' Store.store []) () instance DetailConsole Handler Beer.Beer where type Ident Beer.Beer = Int64 detail i = one <$> runQuery Beer.selectBeer i instance CreateConsole Handler Beer.Beer Beer.Beer where create _ x = do insertM Beer.insertBeer x pure () createdRedirectPath _ _ = pure "/beers" detailForCreate _ _ = pure . Just $ def toDetailUrl x = "/beers/" `append` (pack . show $ Beer.id x) instance EditConsole Handler BeerDetail UpdateBeerParam where type EditIdent BeerDetail UpdateBeerParam = Int64 editedRedirectPath _ _ ident = pure $ "/beers/" <> tshow ident <> "/_edit" detailForEdit _ ident = do b <- one <$> runQuery Beer.selectBeer ident case b of Just b -> return $ Just $ BeerDetail (Beer.id b) (Beer.name b) (Beer.ibu b) Nothing -> return Nothing edit _ ident x = updateM f () where f :: Update () f = update $ \proj -> do Beer.name' <-# value (x ^. #name) Beer.ibu' <-# value (x ^. #ibu) wheres $ proj ! Beer.id' .=. value ident return unitPlaceHolder route :: [Route Handler] route = [ ListR "beers" (Proxy :: Proxy BeerSummary) (Proxy :: Proxy SearchBeerParam) , DetailR ("beers" var @Int64) (Proxy :: Proxy Beer.Beer) , CreateR "beers" (Proxy :: Proxy Beer.Beer) (Proxy :: Proxy Beer.Beer) , EditR ("beers" var @Int64) (Proxy :: Proxy BeerDetail) (Proxy :: Proxy UpdateBeerParam) , ListR "stores" (Proxy :: Proxy Store.Store) (Proxy :: Proxy ()) ] application :: forall b . Request -> (Response -> IO b) -> IO b application req res = res $ responseLBS status404 [("Content-Type", "text/plain")] "not found" serve = do putStrLn "http://localhost:3000/beers" dic <- loadDictionary "i18n.yaml" run 3000 $ admin route Prelude.id Nothing (either (const Nothing) Just dic) application main = serve -- util memptyToNothing x = if x == mempty then Nothing else Just x one (x:_) = Just x one _ = Nothing debug lbl x = trace (lbl ++ ": " ++ show x) x tshow :: Show a => a -> Text tshow = pack . show