-- | A builder for Slack blocks
--
-- @since 2.1.0.0
module Web.Slack.Experimental.Blocks.Builder where

import Control.Monad.Writer.Strict
import Web.Slack.Experimental.Blocks.Types (SlackAccessory (..), SlackAction, SlackActionList, SlackBlock (..), SlackBlockId, SlackContent, SlackContext (..), SlackPlainTextOnly (..), SlackSection (..), SlackText, slackSectionWithText)
import Web.Slack.Prelude

type BlockBuilder = WriterT [SlackBlock]

-- | Runs a block builder, yielding a result
runBlockBuilder :: (Monad m) => BlockBuilder m () -> m [SlackBlock]
runBlockBuilder :: forall (m :: * -> *).
Monad m =>
BlockBuilder m () -> m [SlackBlock]
runBlockBuilder = WriterT [SlackBlock] m () -> m [SlackBlock]
forall (m :: * -> *) w a. Monad m => WriterT w m a -> m w
execWriterT

-- | Header block.
--
-- The text is max 150 characters long.
--
-- <https://api.slack.com/reference/block-kit/blocks#header>
--
-- @since 2.1.0.0
headerBlock :: (Monad m) => SlackText -> BlockBuilder m ()
headerBlock :: forall (m :: * -> *). Monad m => SlackText -> BlockBuilder m ()
headerBlock = [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([SlackBlock] -> WriterT [SlackBlock] m ())
-> (SlackText -> [SlackBlock])
-> SlackText
-> WriterT [SlackBlock] m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SlackBlock -> [SlackBlock])
-> (SlackText -> SlackBlock) -> SlackText -> [SlackBlock]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackPlainTextOnly -> SlackBlock
SlackBlockHeader (SlackPlainTextOnly -> SlackBlock)
-> (SlackText -> SlackPlainTextOnly) -> SlackText -> SlackBlock
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackText -> SlackPlainTextOnly
SlackPlainTextOnly

-- | Section block. Similar in concept to a p or div tag in HTML.
--
-- <https://api.slack.com/reference/block-kit/blocks#section>
--
-- @since 2.1.0.0
sectionBlock :: (Monad m) => SlackText -> BlockBuilder m ()
sectionBlock :: forall (m :: * -> *). Monad m => SlackText -> BlockBuilder m ()
sectionBlock = [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([SlackBlock] -> WriterT [SlackBlock] m ())
-> (SlackText -> [SlackBlock])
-> SlackText
-> WriterT [SlackBlock] m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SlackBlock -> [SlackBlock])
-> (SlackText -> SlackBlock) -> SlackText -> [SlackBlock]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackSection -> SlackBlock
SlackBlockSection (SlackSection -> SlackBlock)
-> (SlackText -> SlackSection) -> SlackText -> SlackBlock
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackText -> SlackSection
slackSectionWithText

-- | Section block. Similar in concept to a p or div tag in HTML.
--
-- <https://api.slack.com/reference/block-kit/blocks#section>
--
-- @since 2.1.0.0
sectionBlockWithFields :: (Monad m) => SlackText -> [SlackText] -> BlockBuilder m ()
sectionBlockWithFields :: forall (m :: * -> *).
Monad m =>
SlackText -> [SlackText] -> BlockBuilder m ()
sectionBlockWithFields SlackText
text [SlackText]
fields =
  [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell
    ([SlackBlock] -> WriterT [SlackBlock] m ())
-> [SlackBlock] -> WriterT [SlackBlock] m ()
forall a b. (a -> b) -> a -> b
$ SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (SlackBlock -> [SlackBlock]) -> SlackBlock -> [SlackBlock]
forall a b. (a -> b) -> a -> b
$ SlackSection -> SlackBlock
SlackBlockSection
    (SlackSection -> SlackBlock) -> SlackSection -> SlackBlock
forall a b. (a -> b) -> a -> b
$ SlackSection
      { slackSectionText :: Maybe SlackText
slackSectionText = SlackText -> Maybe SlackText
forall a. a -> Maybe a
Just SlackText
text
      , slackSectionBlockId :: Maybe SlackBlockId
slackSectionBlockId = Maybe SlackBlockId
forall a. Maybe a
Nothing
      , slackSectionFields :: Maybe [SlackText]
slackSectionFields = [SlackText] -> Maybe [SlackText]
forall a. a -> Maybe a
Just [SlackText]
fields
      , slackSectionAccessory :: Maybe SlackAccessory
slackSectionAccessory = Maybe SlackAccessory
forall a. Maybe a
Nothing
      }

-- | Section block. Similar in concept to a p or div tag in HTML.
--
-- <https://api.slack.com/reference/block-kit/blocks#section>
--
-- @since 2.1.0.0
sectionBlockWithAccessory ::
  (Monad m) =>
  SlackText ->
  SlackAction ->
  BlockBuilder m ()
sectionBlockWithAccessory :: forall (m :: * -> *).
Monad m =>
SlackText -> SlackAction -> BlockBuilder m ()
sectionBlockWithAccessory SlackText
t SlackAction
b =
  [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell
    ([SlackBlock] -> WriterT [SlackBlock] m ())
-> [SlackBlock] -> WriterT [SlackBlock] m ()
forall a b. (a -> b) -> a -> b
$ SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (SlackBlock -> [SlackBlock]) -> SlackBlock -> [SlackBlock]
forall a b. (a -> b) -> a -> b
$ SlackSection -> SlackBlock
SlackBlockSection
      SlackSection
        { slackSectionText :: Maybe SlackText
slackSectionText = SlackText -> Maybe SlackText
forall a. a -> Maybe a
Just SlackText
t
        , slackSectionBlockId :: Maybe SlackBlockId
slackSectionBlockId = Maybe SlackBlockId
forall a. Maybe a
Nothing
        , slackSectionFields :: Maybe [SlackText]
slackSectionFields = Maybe [SlackText]
forall a. Maybe a
Nothing
        , slackSectionAccessory :: Maybe SlackAccessory
slackSectionAccessory = SlackAccessory -> Maybe SlackAccessory
forall a. a -> Maybe a
Just (SlackAccessory -> Maybe SlackAccessory)
-> SlackAccessory -> Maybe SlackAccessory
forall a b. (a -> b) -> a -> b
$ SlackAction -> SlackAccessory
SlackButtonAccessory SlackAction
b
        }

-- | Horizontal line. Similar to an html @hr@ tag.
--
-- <https://api.slack.com/reference/block-kit/blocks#divider>
--
-- @since 2.1.0.0
dividerBlock :: (Monad m) => BlockBuilder m ()
dividerBlock :: forall (m :: * -> *). Monad m => BlockBuilder m ()
dividerBlock = [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([SlackBlock] -> WriterT [SlackBlock] m ())
-> (SlackBlock -> [SlackBlock])
-> SlackBlock
-> WriterT [SlackBlock] m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SlackBlock -> WriterT [SlackBlock] m ())
-> SlackBlock -> WriterT [SlackBlock] m ()
forall a b. (a -> b) -> a -> b
$ SlackBlock
SlackBlockDivider

-- | Context block: smaller, grey, text, and rendered inline. Like a @span@ in HTML.
--
-- <https://api.slack.com/reference/block-kit/blocks#context>
contextBlock :: (Monad m) => [SlackContent] -> BlockBuilder m ()
contextBlock :: forall (m :: * -> *).
Monad m =>
[SlackContent] -> BlockBuilder m ()
contextBlock = [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([SlackBlock] -> WriterT [SlackBlock] m ())
-> ([SlackContent] -> [SlackBlock])
-> [SlackContent]
-> WriterT [SlackBlock] m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SlackBlock -> [SlackBlock])
-> ([SlackContent] -> SlackBlock) -> [SlackContent] -> [SlackBlock]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackContext -> SlackBlock
SlackBlockContext (SlackContext -> SlackBlock)
-> ([SlackContent] -> SlackContext) -> [SlackContent] -> SlackBlock
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [SlackContent] -> SlackContext
SlackContext

-- | Inline container for interactive actions.
--
-- <https://api.slack.com/reference/block-kit/blocks#actions>
actionsBlock ::
  (Monad m) =>
  Maybe SlackBlockId ->
  SlackActionList ->
  BlockBuilder m ()
actionsBlock :: forall (m :: * -> *).
Monad m =>
Maybe SlackBlockId -> SlackActionList -> BlockBuilder m ()
actionsBlock Maybe SlackBlockId
a SlackActionList
b = [SlackBlock] -> WriterT [SlackBlock] m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell ([SlackBlock] -> WriterT [SlackBlock] m ())
-> (SlackBlock -> [SlackBlock])
-> SlackBlock
-> WriterT [SlackBlock] m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackBlock -> [SlackBlock]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SlackBlock -> WriterT [SlackBlock] m ())
-> SlackBlock -> WriterT [SlackBlock] m ()
forall a b. (a -> b) -> a -> b
$ Maybe SlackBlockId -> SlackActionList -> SlackBlock
SlackBlockActions Maybe SlackBlockId
a SlackActionList
b

-- | This is used for testing purposes so that you can paste these into the
-- Block Kit builder and have the expected format:
--
-- <https://app.slack.com/block-kit-builder>
--
-- @since 2.1.0.0
newtype BlockKitBuilderMessage = BlockKitBuilderMessage {BlockKitBuilderMessage -> [SlackBlock]
blocks :: [SlackBlock]}

instance ToJSON BlockKitBuilderMessage where
  toJSON :: BlockKitBuilderMessage -> Value
toJSON BlockKitBuilderMessage {[SlackBlock]
blocks :: BlockKitBuilderMessage -> [SlackBlock]
blocks :: [SlackBlock]
blocks} = [Pair] -> Value
object [(Key
"blocks", [SlackBlock] -> Value
forall a. ToJSON a => a -> Value
toJSON [SlackBlock]
blocks)]