packages feed

todoist-sdk-0.1.2.1: src/Web/Todoist/Domain/Types.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE InstanceSigs #-}

{- |
Module      : Web.Todoist.Domain.Types
Description : Shared domain types and type classes
Copyright   : (c) 2025 Sam S. Almahri
License     : MIT
Maintainer  : sam.salmahri@gmail.com

This module provides shared types used across the Todoist SDK, including
newtype wrappers for IDs and common fields, as well as core enums and data types.

Most users will import "Web.Todoist" which re-exports these types rather than
importing this module directly.
-}
module Web.Todoist.Domain.Types
    ( Attachment
    , ViewStyle (..)
    , ProjectId (..)
    , TaskId (..)
    , Uid (..)
    , Name (..)
    , Color (..)
    , Order (..)
    , IsFavorite (..)
    , Description (..)
    , IsCollapsed (..)
    , Content (..)
    , ParentId (..)
    , parseViewStyle
      -- * Lenses
    , fileName
    , fileType
    , fileUrl
    , resourceType
    ) where

import Control.Monad (return)
import Data.Aeson
    ( FromJSON (..)
    , ToJSON (..)
    , Value
    , defaultOptions
    , fieldLabelModifier
    , genericParseJSON
    , genericToJSON
    , withObject
    , (.:)
    )
import Data.Aeson.Types (Parser)
import Data.Bool (Bool)
import Data.Eq (Eq)
import Data.Function (($))
import Data.Functor ((<$>))
import Data.Int (Int)
import qualified Data.List as L
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Base (undefined)
import GHC.Generics (Generic)
import Lens.Micro (to)
import Text.Show (Show)
import Web.Todoist.Lens (Getter)

{- | Visual display style for projects

Projects can be displayed as a list, board (Kanban-style), or calendar view.
-}
data ViewStyle = List | Board | Calendar deriving (Show, Eq)

instance ToJSON ViewStyle where
    toJSON :: ViewStyle -> Value
    toJSON List = toJSON ("list" :: Text)
    toJSON Board = toJSON ("board" :: Text)
    toJSON Calendar = toJSON ("calendar" :: Text)

instance FromJSON ViewStyle where
    parseJSON :: Value -> Parser ViewStyle
    parseJSON v = do
        str <- parseJSON v
        return $ parseViewStyle str

-- | Parse a Text string into ViewStyle, defaulting to undefined for unrecognized values
parseViewStyle :: Text -> ViewStyle
parseViewStyle txt = case T.toLower txt of
    "list" -> List
    "board" -> Board
    "calendar" -> Calendar
    _ -> undefined -- Default to undefined for unrecognized values

-- | Attachment metadata for comment
data Attachment = Attachment
    { _resource_type :: Text
    , _file_name :: Text
    , _file_type :: Text
    , _file_url :: Text
    }
    deriving (Show, Eq, Generic)

instance ToJSON Attachment where
    toJSON :: Attachment -> Value
    toJSON = genericToJSON defaultOptions {fieldLabelModifier = L.drop 1}

instance FromJSON Attachment where
    parseJSON :: Value -> Parser Attachment
    parseJSON = genericParseJSON defaultOptions {fieldLabelModifier = L.drop 1}

-- | Lenses for Attachment
fileName :: Getter Attachment Text
fileName = to _file_name
{-# INLINE fileName #-}

fileType :: Getter Attachment Text
fileType = to _file_type
{-# INLINE fileType #-}

fileUrl :: Getter Attachment Text
fileUrl = to _file_url
{-# INLINE fileUrl #-}

resourceType :: Getter Attachment Text
resourceType = to _resource_type
{-# INLINE resourceType #-}

-- | Unique identifier for a Todoist project
newtype ProjectId = ProjectId
    { getProjectId :: Text
    }
    deriving (Show, Eq, Generic)

-- Custom JSON instances for ProjectId - parse from {"id": "..."} object
instance FromJSON ProjectId where
    parseJSON :: Value -> Parser ProjectId
    parseJSON = withObject "ProjectId" $ \obj ->
        ProjectId <$> obj .: "id"

instance ToJSON ProjectId where
    toJSON :: ProjectId -> Value
    toJSON (ProjectId txt) = toJSON txt

-- | Unique identifier for a Todoist task
newtype TaskId = TaskId
    { getTaskId :: Text
    }
    deriving (Show, Eq, Generic)

instance FromJSON TaskId where
    parseJSON :: Value -> Parser TaskId
    parseJSON v = TaskId <$> parseJSON v

instance ToJSON TaskId where
    toJSON :: TaskId -> Value
    toJSON (TaskId txt) = toJSON txt

-- | User ID in Todoist system
newtype Uid = Uid {getUid :: Text} deriving (Show, Eq, Generic)

instance FromJSON Uid where
    parseJSON :: Value -> Parser Uid
    parseJSON v = Uid <$> parseJSON v

instance ToJSON Uid where
    toJSON :: Uid -> Value
    toJSON (Uid txt) = toJSON txt

-- | Display name for projects, tasks, or other entities
newtype Name = Name {getName :: Text} deriving (Show, Eq, Generic)

instance FromJSON Name where
    parseJSON :: Value -> Parser Name
    parseJSON v = Name <$> parseJSON v

instance ToJSON Name where
    toJSON :: Name -> Value
    toJSON (Name txt) = toJSON txt

-- | Color identifier for visual categorization (e.g., \"red\", \"blue\", \"green\")
newtype Color = Color {getColor :: Text} deriving (Show, Eq, Generic)

instance FromJSON Color where
    parseJSON :: Value -> Parser Color
    parseJSON v = Color <$> parseJSON v

instance ToJSON Color where
    toJSON :: Color -> Value
    toJSON (Color txt) = toJSON txt

-- | Sort order for items (lower numbers appear first)
newtype Order = Order {getOrder :: Int} deriving (Show, Eq, Generic)

instance FromJSON Order where
    parseJSON :: Value -> Parser Order
    parseJSON v = Order <$> parseJSON v

instance ToJSON Order where
    toJSON :: Order -> Value
    toJSON (Order txt) = toJSON txt

-- | Flag indicating whether an item is marked as favorite
newtype IsFavorite = IsFavorite {getIsFavorite :: Bool} deriving (Show, Eq, Generic)

instance FromJSON IsFavorite where
    parseJSON :: Value -> Parser IsFavorite
    parseJSON v = IsFavorite <$> parseJSON v

instance ToJSON IsFavorite where
    toJSON :: IsFavorite -> Value
    toJSON (IsFavorite txt) = toJSON txt

-- | Markdown-formatted description text
newtype Description = Description {getDescription :: Text} deriving (Show, Eq, Generic)

instance FromJSON Description where
    parseJSON :: Value -> Parser Description
    parseJSON v = Description <$> parseJSON v

instance ToJSON Description where
    toJSON :: Description -> Value
    toJSON (Description txt) = toJSON txt

-- | Flag indicating whether a section or project is collapsed in the UI
newtype IsCollapsed = IsCollapsed {getIsCollapsed :: Bool} deriving (Show, Eq, Generic)

instance FromJSON IsCollapsed where
    parseJSON :: Value -> Parser IsCollapsed
    parseJSON v = IsCollapsed <$> parseJSON v

instance ToJSON IsCollapsed where
    toJSON :: IsCollapsed -> Value
    toJSON (IsCollapsed txt) = toJSON txt

-- | Task or comment content text
newtype Content = Content {getContent :: Text} deriving (Show, Eq, Generic)

instance ToJSON Content where
    toJSON :: Content -> Value
    toJSON (Content txt) = toJSON txt

instance FromJSON Content where
    parseJSON :: Value -> Parser Content
    parseJSON v = Content <$> parseJSON v

-- | Parent project or task identifier for hierarchical relationships
newtype ParentId = ParentId
    { getParentId :: Text
    }
    deriving (Show, Eq, Generic)

instance FromJSON ParentId where
    parseJSON :: Value -> Parser ParentId
    parseJSON v = ParentId <$> parseJSON v

instance ToJSON ParentId where
    toJSON :: ParentId -> Value
    toJSON (ParentId txt) = toJSON txt