7TQPQW3NPNUK6CMTOT5ZE4MDENJ5SUOJ2VF2M4JGKHLZHXVX4F3QC
GLQSD33YYNRDK23R7W2LEIXODI4N5JD3RHX5VMRR5WPMSVMS333QC
NAFJ6RB3KYDBSTSNB3WQSVUQEPUGG2RZCBWRF4XNT2UKSOXDNMDQC
Z5KNL332YCRMHKU3NG7YWNLUCNHKSLXBZ3O22FSS47MNVXU2FDLAC
PPW6ROC5U7FZCJCH2RX7UJ3PJYNPUMNEZ6KKO3375VFRUM4VT3VQC
QAC2QJ32ZLAK25KJ7SWT27WOZKD2MMDE7OZPHIRRFP2W2QZW7PBAC
QH4UB73NUR2XPHZQ2RGJBKKUBN43RKC7ZJBCFPP4ESUIIEDDR5XQC
B4MTB6UOH5VPZQ7KDQ23TZSR3CIFGVGVBEFL26LMFAQ5RL7CXPRQC
WRPIYG3EUHZR6N6T74ZXZDXATRMIRLXAQ24UNUNSVTVYGMT2VDSQC
QU5FW67RGCWOWT2YFM4NYMJFFHWIRPQANQBBAHBKZUY7UYMCSIMQC
JXG3FCXYBDKMUD77DOM7RCIJYKB7BILC43OHHDZBE7YQRGAMUCCAC
QMEYU4MWLTSWPWEEOFRLK2IKE64BY3V5X73323WPLCGPP3TPDYGAC
J6S23MDGHVSCVVIRB6XRNSY3EGTDNWFJHV7RYLIEHBUK5KU63CFQC
OUR4PAOTXXKXQPMAR5TIYX7MBRRJS2WVTZS7SN4SOGML7SPJIJGQC
O2BZOX7MS4JCDS3C6EJQXAWUEQV6HVDCIF2FIN2BCJNRLIU6ZVKAC
RB2ETNIFLQUA6OA66DAEOXZ25ENMQGNKX5CZRSKEYHTD6BQ6NTFQC
SAESJLLYCQJUIHKFYFV53AWHFOSGI5SKLVS7DPTQO6BKGITPYPUQC
other -> throwError $ Error { status: Just other, message: r.statusText }
parseDatedResponseMay ::
forall t.
Traversable t =>
DecodeJson (t String) =>
Either AJAX.Error (Response Json) ->
ExceptT APIError Effect (Maybe (t Instant))
parseDatedResponseMay = case _ of
Left err -> throwError $ Error { status: Nothing, message: printError err }
Right r -> case r.status of
StatusCode 403 -> throwError $ Forbidden
StatusCode 404 -> pure Nothing
StatusCode 200 -> withExceptT (ParseFailure r.body) $ Just <<< map fromDateTime <$> decodeDatedJson r.body
import Control.Monad.Except.Trans (ExceptT, runExceptT, except, withExceptT)
import Control.Monad.Error.Class (throwError)
import Data.Argonaut.Core (Json)
import Control.Monad.Except.Trans (runExceptT)
-- import Control.Monad.Except.Trans (ExceptT, runExceptT, except, withExceptT)
-- import Control.Monad.Error.Class (throwError)
-- import Data.Argonaut.Core (Json)
import Data.Rational (Rational)
import Data.Time.Duration (Hours, Days)
import Data.Traversable (traverse)
import Data.UUID (parseUUID)
import Effect (Effect)
import Data.Rational (Rational, (%))
import Data.Time.Duration (Hours(..), Days(..))
import Data.Traversable (class Traversable, traverse)
-- import Effect (Effect)
( APIError(..) )
import Aftok.Api.Json (parseDate)
( APIError )
import Aftok.Api.Json
( decompose
, parseDatedResponse
)
data DepreciationFn
= LinearDepreciation { undep :: Days, dep :: Days }
instance decodeDepreciationFn :: DecodeJson DepreciationFn where
decodeJson json = do
x <- decodeJson json
dtype <- x .: "type"
args <- x .: "arguments"
case dtype of
"LinearDepreciation" -> do
undep <- Days <$> args .: "undep"
dep <- Days <$> args .: "dep"
pure $ LinearDepreciation { undep, dep }
other -> Left $ "Unrecognized depreciation function: " <> other
derive instance newtypeProject :: Newtype (Project' a) _
derive instance projectNewtype :: Newtype (Project' a) _
derive instance projectFunctor :: Functor Project'
instance projectFoldable :: Foldable Project' where
foldr f b (Project' p) = f (p.inceptionDate) b
foldl f b (Project' p) = f b (p.inceptionDate)
foldMap = foldMapDefaultR
instance projectTraversable :: Traversable Project' where
traverse f (Project' p) = Project' <<< (\b -> p { inceptionDate = b }) <$> f (p.inceptionDate)
sequence = traverse identity
data DepreciationFn
= LinearDepreciation { undep :: Days, dep :: Days }
instance decodeJsonProject :: DecodeJson (Project' String) where
decodeJson json = do
x <- decodeJson json
project <- x .: "project"
projectId <- x .: "projectId"
projectName <- project .: "projectName"
inceptionDate <- project .: "inceptionDate"
initiator <- project .: "initiator"
depFn <- project .: "depreciationFn"
pure $ Project' { projectId, projectName, inceptionDate, initiator, depFn }
type ProjectUserData = ProjectUserData' DateTime
instance decodeJsonContributor :: DecodeJson (Contributor' String) where
decodeJson json = do
x <- decodeJson json
userId <- x .: "userId"
handle <- x .: "username"
joinedOn <- x .: "joinedOn"
timeDevoted <- Hours <$> x .: "timeDevoted"
revShareObj <- x .: "revenueShare"
num <- revShareObj .: "numerator"
den <- revShareObj .: "denominator"
let revShare = num % den
pure $ Contributor' { userId, handle, joinedOn, timeDevoted, revShare }
projectIdStr <- x .: "projectId"
projectId <- ProjectId <$> (note "Failed to decode project UUID" $ parseUUID projectIdStr)
projectName <- project .: "projectName"
inceptionDate <- project .: "inceptionDate"
initiatorStr <- project .: "initiator"
initiator <- UserId <$> (note "Failed to decode initiator UUID" $ parseUUID initiatorStr)
pure $ Project' { projectId, projectName, inceptionDate, initiator }
contributors <- x .: "contributors"
pure $ ProjectDetail' { project, contributors }
result <- get RF.json "/api/projects"
EC.liftEffect <<< runExceptT
$ case result of
Left err -> throwError $ Error { status: Nothing, message: printError err }
Right r -> case r.status of
StatusCode 403 -> throwError Forbidden
StatusCode 200 -> do
records <- except $ lmap (ParseFailure r.body) (decodeJson r.body)
traverse parseProject records
other -> throwError $ Error { status: Just other, message: r.statusText }
response <- get RF.json "/api/projects"
EC.liftEffect
<<< runExceptT
<<< map decompose
<<< map (map toDateTime)
$ parseDatedResponse response
parseProject :: Json -> ExceptT APIError Effect Project
parseProject json = do
Project' p <- except <<< lmap (ParseFailure json) $ decodeJson json
pdate <- withExceptT (ParseFailure json) $ parseDate p.inceptionDate
pure $ Project' (p { inceptionDate = pdate })
-- getProjectDetail :: ProjectId -> Aff (Maybe ProjectDetail)
-- getProjectDetail pid = do
-- response <- get RF.json ("/api/user/projects/" <> pidStr pid)
-- EC.liftEffect
-- <<< map (\dt -> ProjectDetail' {
-- project: dt.project,
-- contributors: M.fromFoldable $ map (\c -> (Tuple c.userId c)) dt.contributors
-- })
-- $ parsed
[ HH.slot _projectList unit (ProjectList.component system pcaps) st.selectedProject (Just <<< ProjectSelected) ]
[ HH.slot
_projectList
unit
(ProjectList.component system pcaps)
st.selectedProject
(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))
]
depreciationCols detail.depreciation <>
[ colmd2 ((\(ProjectUserData' p) -> p.userName) <$> M.lookup project.initiator detail.contributors)
depreciationCols project.depFn <>
[ colmd2 ((\(Contributor' p) -> p.handle) <$> M.lookup project.initiator detail.contributors)
contributorCols :: ProjectUserData -> H.ComponentHTML OverviewAction Slots m
contributorCols (ProjectUserData' pud) =
let pct = maybe "N/A" (\f -> F.toString (f * F.fromInt 100)) (F.fromNumber (R.toNumber pud.currentPayoutRatio) :: Maybe (F.Fixed F.P10000))
contributorCols :: Contributor' DateTime -> H.ComponentHTML OverviewAction Slots m
contributorCols (Contributor' pud) =
let pct = maybe "N/A" (\f -> F.toString (f * F.fromInt 100)) (F.fromNumber (R.toNumber pud.revShare) :: Maybe (F.Fixed F.P10000))
[ HH.slot _projectList unit (ProjectList.component system pcaps) st.selectedProject (Just <<< ProjectSelected) ]
[ HH.slot
_projectList
unit
(ProjectList.component system pcaps)
st.selectedProject
(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))
]
derive instance projectIdNewtype :: Newtype ProjectId _
instance projectIdDecodeJson :: DecodeJson ProjectId where
decodeJson json = do
uuidStr <- decodeJson json
ProjectId <$> (note "Failed to decode project UUID" $ parseUUID uuidStr)