{-# LANGUAGE OverloadedLists #-} module Literate.Organization where import Country qualified import Country.Identifier qualified as Country import Data.Text qualified as Text import Literate.Document qualified as Doc import Literate.Document.HTML qualified as HTML import Literate.Prelude import Text.Printf qualified as Printf import Prelude qualified data EntityId = EntityId {unEntityId :: Natural} deriving (Eq, Ord, Show) instance HTML.ToMarkup EntityId where toMarkup i = i & unEntityId & HTML.toHtml instance Doc.ToInline EntityId where toInline i = i & unEntityId & show & Doc.toInline data URL = URL {unURL :: Text} deriving (Eq, Ord, Show) instance IsString URL where fromString = URL . fromString instance Doc.ToInline URL where toInline = unURL >>> Doc.Target >>> Doc.inlineLinkExplicit data Email = Email { emailLocal :: Text , emailServer :: Text } deriving (Eq, Ord, Show) instance IsString Email where fromString s = case s & fromString & Text.split (== '@') of [emailLocal, emailServer] -> Email{..} _ -> Prelude.error $ "IsString Email: " <> s instance Doc.ToBlock Email where toBlock = Doc.toBlock . Doc.toInline instance Doc.ToInline Email where toInline eml = Doc.InlineLink { Doc.inlineLinkText = [ eml & emailLocal & Doc.toInline , "\x200B@" , eml & emailServer & Doc.toInline ] & Doc.Inlines , Doc.inlineLinkTarget = Doc.Target $ "mailto:" <> mconcat [ eml & emailLocal , "@" , eml & emailServer ] } type Phone = Text type Role = Text -- newtype Organization = Organization (Tree.Tree (Role, Organization)) -- organization = Organization (Tree.Node ("", entity) []) data Organization = Organization { orgEntity :: Entity , orgParts :: [(Role, Organization)] } deriving (Eq, Ord, Show) organization = Organization { orgEntity = entity , orgParts = [] } data Entity = Entity { entityId :: EntityId , entityAddress :: Maybe Address , entityEmail :: Maybe Email , entityIBAN :: Maybe IBAN , entityName :: Maybe Text , entityPhone :: Maybe Phone , entitySIREN :: Maybe Text } deriving (Eq, Ord, Show) instance Doc.ToBlock Entity where toBlock ent = do Doc.classes ["entity"] [ Doc.toBlock $ Doc.Dict $ mconcat [ [ "Name" := addr & Doc.toBlock | addr <- ent & entityName & maybeToList ] , [ "Address" := addr & Doc.toBlock | addr <- ent & entityAddress & maybeToList ] , [ "SIREN" := siren & Doc.toBlock | siren <- ent & entitySIREN & maybeToList ] , [ "Email" := email & Doc.toBlock | email <- ent & entityEmail & maybeToList ] , [ "Phone" := phone & Doc.toBlock | phone <- ent & entityPhone & maybeToList ] , [ "IBAN" := iban & Doc.toBlock | iban <- ent & entityIBAN & maybeToList ] ] ] instance Doc.ToBlock Organization where toBlock org = Doc.classes ["org"] [ if (org & orgEntity) == entity then Doc.emptyBlock else Doc.toBlock $ org & orgEntity , Doc.toBlock $ Doc.Dict $ [ role & Doc.toInline := part & Doc.toBlock | (role, part) <- org & orgParts ] ] where scope role | Text.null role = "" :: Doc.Inline | otherwise = Doc.classes @Doc.Inline ["entity-role"] $ "(" <> Doc.toInline role <> ")" entity = Entity { entityId = EntityId 0 , entityAddress = Nothing , entityEmail = Nothing , entityIBAN = Nothing , entityName = Nothing , entityPhone = Nothing , entitySIREN = Nothing } data Address = Address { addressText :: [Text] , addressZipCode :: ZipCode , addressCity :: City , addressCountry :: Country.Country } deriving (Eq, Ord, Show) instance Doc.ToBlock Address where toBlock addr = Doc.classes ["address"] $ Doc.Blocks $ fromList [ t & Doc.toBlock | t <- addr & addressText ] <> [ Doc.classes ["address-bottom"] $ Doc.toBlock $ Doc.words $ [ addr & addressZipCode & Doc.toInline , addr & addressCity & Doc.toInline , addr & addressCountry & Country.encodeEnglish & Doc.toInline ] ] address = Address { addressText = [] , addressZipCode = "" , addressCity = "" , addressCountry = Country.france } type ZipCode = Text type City = Text -- | International Bank Account Number data IBAN = IBAN { ibanCountry :: Country.Country , ibanCheckDigits :: Natural , ibanBasicBankAccountNumber :: Text } deriving (Eq, Ord, Show) instance Doc.ToBlock IBAN where toBlock iban = [ iban & ibanCountry & Country.alphaTwoUpper & Doc.toInline , iban & ibanCheckDigits & (Printf.printf "%02d" :: _ -> String) & Doc.toInline , " " , iban & ibanBasicBankAccountNumber & Text.chunksOf 4 & Text.intercalate " " & Doc.toInline ] & Doc.Inlines & Doc.toBlock