{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE UndecidableInstances #-} module Literate.Organization where import Country qualified import Country.Identifier qualified as Country import Data.Text qualified as Text import Text.Printf qualified as Printf import Prelude qualified import Literate.Database import Literate.Document qualified as Doc import Literate.Prelude data URL = URL {unURL :: Text} deriving (Eq, Ord, Show, Generic, NFData) 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, Generic, NFData) 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 data Entity entId = Entity { entityId :: entId , entityAddress :: Maybe Address , entityEmail :: Maybe Email , entityIBAN :: Maybe IBAN , entityName :: Maybe Text , entityPhone :: Maybe Phone , entitySIREN :: Maybe Text } deriving (Eq, Ord, Show, Generic, NFData) entity :: entId -> Entity entId entity entityId = Entity { entityId , entityAddress = Nothing , entityEmail = Nothing , entityIBAN = Nothing , entityName = Nothing , entityPhone = Nothing , entitySIREN = Nothing } type Role = Text data Organization entId = Organization { orgEntity :: entId , orgParts :: [(Role, Organization entId)] } deriving (Eq, Ord, Show, Generic, NFData) instance Doc.ToBlock (Entity entId) 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 Get (Entity entId) entId => Doc.ToBlock (Organization entId) where toBlock org = Doc.classes ["org"] [ Doc.toBlock $ org & orgEntity & get @(Entity entId) , 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 <> ")" data Address = Address { addressText :: [Text] , addressZipCode :: ZipCode , addressCity :: City , addressCountry :: Country.Country } deriving (Eq, Ord, Show, Generic, NFData) 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, Generic, NFData) 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