packages feed

snelstart-import-1.0.0: src/SnelstartImport/Web/Handler.hs

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeFamilies #-}

-- | handlers
module SnelstartImport.Web.Handler
  ( getRootR
  , postRootR
  )
where

import Data.Vector(toList)
import qualified Data.ByteString.Lazy as LBS
import SnelstartImport.Convert
import SnelstartImport.ING
import SnelstartImport.Web.Routes
import SnelstartImport.N26
import Text.Blaze.Html(Html)
import Yesod.Form
import Yesod.Core.Widget
import Yesod.Core.Handler
import Data.Text(Text, pack)
import Data.Text.Encoding
import Data.ByteString.Base64
import Data.Base64.Types(extractBase64)
import qualified Data.Text as Text
import SnelstartImport.SepaDirectCoreScheme(readSepaDirectCoreScheme)
import SnelstartImport.Web.Layout(layout)
import Yesod.Core(lucius)
import SnelstartImport.Web.Message
import Data.Time
import Control.Monad.IO.Class(liftIO)


type Form a = Html -> MForm Handler (FormResult a, Widget)


data InputFileForm = InputFileForm {
  ifBank :: Text ,
  ifFileInfo :: FileInfo
  }

inputFileForm :: Form InputFileForm
inputFileForm csrf = do
  (bankRes, bankView) <- mreq textField "own bank account" Nothing
  (inputRes, inputView) <- mreq fileField "xml file" Nothing

  let view = do
       toWidget [lucius|
          form label {
            width: 100%;
            display: inline-block;
          }
          form input{
            margin-bottom: 1em;
          }
       |]
       [whamlet|
        ^{csrf}
        <div>
          <label for=#{fvId bankView}>_{MsgOwnBank}
          ^{fvInput bankView}
        <div>
          <label for=#{fvId bankView}>_{MsgXmlFile}
          ^{fvInput inputView}
        <div>
          <button type=submit >_{MsgConvert}
  |]
  pure $ (InputFileForm <$> bankRes <*> inputRes, view)

getRootR :: Handler Html
getRootR = do
  ((_res, form), enctype) <- runFormPost inputFileForm
  layout $ inputForm [] enctype form

inputForm :: [Text] -> Enctype -> Widget -> Widget
inputForm issues enctype form =
  let
    issuesWidget = if Prelude.null issues then "" else
      [whamlet|
        <ul>
          $forall issue <- issues
            <li> #{issue}
      |]
  in

  [whamlet|
<h1>_{MsgTitle}
^{issuesWidget}
<form method=post enctype=#{enctype}>
    ^{form}
|]

postRootR :: Handler Html
postRootR = do
  ((res, form), enctype) <- runFormPost inputFileForm

  case res of
    FormMissing     -> layout $ inputForm ["error - missing data"] enctype form
    FormFailure x   -> layout $ inputForm x enctype form
    FormSuccess formRes -> do
      contents <- fileSourceByteString $ ifFileInfo formRes
      let filename = fileName $ ifFileInfo formRes
      if Text.isSuffixOf "xml" filename then
        case readSepaDirectCoreScheme contents of
          Left err -> layout $ inputForm [pack $ show err] enctype form
          Right res' -> renderDownload formRes (sepaDirectCoreSchemeToING (ifBank formRes) <$> res')
      else case readN26BS $ LBS.fromStrict contents of
        Left err -> layout $ inputForm [pack err] enctype form
        Right n26 -> renderDownload formRes (n26ToING (ifBank formRes) <$> toList n26)

renderDownload :: InputFileForm -> [ING] -> Handler Html
renderDownload form ings =
          let
            csvOut  = (writeCsv ings)
            contentText = decodeUtf8 $ LBS.toStrict csvOut
            downloadText = "data:text/plain;base64," <> (extractBase64 $ encodeBase64 $ LBS.toStrict csvOut)
          in
          layout $ do
            curTime <- liftIO getCurrentTime
            let
                timeStr :: String
                timeStr = formatTime defaultTimeLocale "%F_%H-%M" curTime
                downloadFileName = "snelstart-import-" <> timeStr <> ".csv"
            toWidget [lucius|
                pre {
                  overflow: scroll;
                  width: 100%;
                  position: absolute;
                  left: 0;
                  background-color: lightgray;
                  padding: 1em;
                }
            |]
            [whamlet|
                <table>
                  <tr>
                    <th>_{MsgBank}
                    <td>#{ifBank form }
                  <tr>
                    <th>_{MsgFilename}
                    <td>#{fileName $ ifFileInfo form }

                <h2>_{MsgContents}
                <a href=#{downloadText} download=#{downloadFileName}>_{MsgDownload}
                <pre>
                  <code>
                    #{contentText}
                |]