{-|
Module: IHP.FlashMessages
Description: Success and error messages for your application
Copyright: (c) digitally induced GmbH, 2020
-}
module IHP.FlashMessages where

import Prelude
import Data.Text (Text)
import Data.Maybe (fromMaybe)
import IHP.Controller.Session
import qualified Network.Wai.Middleware.FlashMessages as FlashMessages
import Network.Wai.Middleware.FlashMessages (FlashMessage (..))
import Network.Wai
import qualified Data.Vault.Lazy as Vault
import System.IO.Unsafe (unsafePerformIO)
import qualified Text.Blaze.Html5 as Html5
import IHP.ViewSupport
import IHP.View.Types

-- | Sets a flash messages. This is shown to the user when the next view is rendered.
--
-- Will be rendered in a bootstrap alert, with the @alert-success@ styling.
-- Take a look at https://getbootstrap.com/docs/4.5/components/alerts/ for how this will look like.
--
-- This requires 'IHP.ViewSupport.renderFlashMessages' to be placed somewhere in the layout or page of the next view.
-- For example:
--
-- > myLayout view = [hsx|
-- >     {renderFlashMessages}
-- >     <main>{view}</main>
-- > |]
setSuccessMessage :: (?request :: Request) => Text -> IO ()
setSuccessMessage :: (?request::Request) => Text -> IO ()
setSuccessMessage = SessionVaultKey -> Request -> Text -> IO ()
FlashMessages.setSuccessMessage SessionVaultKey
sessionVaultKey ?request::Request
Request
?request

-- | Sets a flash messages. This is shown to the user when the next view is rendered.
--
-- Will be rendered in a bootstrap alert, with the @alert-danger@ styling.
-- Take a look at https://getbootstrap.com/docs/4.5/components/alerts/ for how this will look like.
--
-- This requires 'IHP.ViewSupport.renderFlashMessages' to be placed somewhere in the layout or page of the next view.
-- For example:
--
-- > myLayout view = [hsx|
-- >     {renderFlashMessages}
-- >     <main>{view}</main>
-- > |]
setErrorMessage :: (?request :: Request) => Text -> IO ()
setErrorMessage :: (?request::Request) => Text -> IO ()
setErrorMessage = SessionVaultKey -> Request -> Text -> IO ()
FlashMessages.setErrorMessage SessionVaultKey
sessionVaultKey ?request::Request
Request
?request

-- | Returns the flash message currently set
getSuccessMessage :: (?request :: Request) => IO (Maybe Text)
getSuccessMessage :: (?request::Request) => IO (Maybe Text)
getSuccessMessage = SessionVaultKey -> Request -> IO (Maybe Text)
FlashMessages.getSuccessMessage SessionVaultKey
sessionVaultKey ?request::Request
Request
?request

-- | Removes the current flash message
clearSuccessMessage :: (?request :: Request) => IO ()
clearSuccessMessage :: (?request::Request) => IO ()
clearSuccessMessage = SessionVaultKey -> Request -> IO ()
FlashMessages.clearSuccessMessage SessionVaultKey
sessionVaultKey ?request::Request
Request
?request

flashVaultKey :: Vault.Key [FlashMessage]
flashVaultKey :: Key [FlashMessage]
flashVaultKey = IO (Key [FlashMessage]) -> Key [FlashMessage]
forall a. IO a -> a
unsafePerformIO IO (Key [FlashMessage])
forall a. IO (Key a)
Vault.newKey
{-# NOINLINE flashVaultKey #-}

consumeFlashMessagesMiddleware :: Middleware
consumeFlashMessagesMiddleware = SessionVaultKey -> Key [FlashMessage] -> Middleware
FlashMessages.consumeFlashMessagesMiddleware SessionVaultKey
sessionVaultKey Key [FlashMessage]
flashVaultKey

requestFlashMessages :: Request -> [FlashMessage]
requestFlashMessages :: Request -> [FlashMessage]
requestFlashMessages Request
request =
    [FlashMessage] -> Maybe [FlashMessage] -> [FlashMessage]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [FlashMessage] -> [FlashMessage])
-> Maybe [FlashMessage] -> [FlashMessage]
forall a b. (a -> b) -> a -> b
$ Key [FlashMessage] -> Request -> Maybe [FlashMessage]
FlashMessages.requestFlashMessages Key [FlashMessage]
flashVaultKey Request
request

-- | Displays the flash messages for the current request.
--
-- You can add a flash message to the next request by calling 'IHP.FlashMessages.setSuccessMessage' or 'IHP.FlashMessages.setErrorMessage':
--
-- > action CreateProjectAction = do
-- >     ...
-- >     setSuccessMessage "Your project has been created successfully"
-- >     redirectTo ShowProjectAction { .. }
--
--
-- > action CreateTeamAction = do
-- >     unless userOnPaidPlan do
-- >         setErrorMessage "This requires you to be on the paid plan"
-- >         redirectTo NewTeamAction
-- >
-- >     ...
--
-- For success messages, the text message is wrapped in a @<div class="alert alert-success">...</div>@, which is automatically styled by bootstrap.
-- Errors flash messages are wraped in @<div class="alert alert-danger">...</div>@.
renderFlashMessages :: (?request :: Request) => Html5.Html
renderFlashMessages :: (?request::Request) => Html
renderFlashMessages = [FlashMessage] -> Html
render [FlashMessage]
(?request::Request) => [FlashMessage]
theFlashMessages
    where
        render :: [FlashMessage] -> Html5.Html
        render :: [FlashMessage] -> Html
render = Proxy "styledFlashMessages" -> [FlashMessage] -> Html
forall (field :: Symbol) appliedFunction.
(?request::Request, KnownSymbol field,
 HasField field CSSFramework (CSSFramework -> appliedFunction)) =>
Proxy field -> appliedFunction
fromCSSFramework Proxy "styledFlashMessages"
#styledFlashMessages

theFlashMessages :: (?request :: Request) => [FlashMessage]
theFlashMessages :: (?request::Request) => [FlashMessage]
theFlashMessages = Request -> [FlashMessage]
requestFlashMessages ?request::Request
Request
?request