{-# 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 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, Generic, NFData) instance HTML.ToMarkup EntityId where toMarkup i = i & unEntityId & HTML.toHtml instance Doc.ToInline EntityId where toInline i = i & unEntityId & show & Doc.toInline -} type family EntityOf (a :: Type) :: Type class GetEntity entId where getEntity :: entId -> Entity entId 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 class GetOrganization entId where getOrganization :: entId -> Organization entId 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 GetEntity entId => Doc.ToBlock (Organization entId) where toBlock org = Doc.classes ["org"] [ Doc.toBlock $ org & orgEntity & getEntity , 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