Begin adding parsing for project detail.
[?]
Jan 30, 2021, 2:05 AM
7TQPQW3NPNUK6CMTOT5ZE4MDENJ5SUOJ2VF2M4JGKHLZHXVX4F3QCDependencies
- [2]
GLQSD33YUse mock capability for overview init. - [3]
QU5FW67RAdd project selection to time tracker. - [4]
JXG3FCXYUpgrade ps + halogen versions. - [5]
RSF6UAJKBreak out api module for timeline. - [6]
B4MTB6UOPersist project across pages. - [7]
Z5KNL332Add skeleton of project overview HTML. - [8]
QMEYU4MWAdd display for prior intervals. - [9]
WRPIYG3EUse project listing functionality to check for whether we have a cookie. - [10]
NJNMO72SAdd zcash.com submodule and update client to modern halogen. - [11]
IR75ZMX3Return actual events for interval ends, not just timestamps. - [12]
QH4UB73NFormat with purty. - [13]
OUR4PAOTUse local dates for display of intervals. - [14]
PPW6ROC5Render project data - [15]
QAC2QJ32Add project overview page to client. - [16]
ZIG57EE6Fix project selection, end log end on project switch. - [17]
NAFJ6RB3Minor module reorg. - [18]
SAESJLLYInitial experiments in hash routing. - [19]
O2BZOX7MAdd signup form, captcha check. - [20]
J6S23MDGUse server timestamps for interval start and end. - [*]
RB2ETNIFAdd skeletal PureScript client project.
Change contents
- edit in client/src/Aftok/Api/Json.purs at line 75
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 _ ofLeft err -> throwError $ Error { status: Nothing, message: printError err }Right r -> case r.status ofStatusCode 403 -> throwError $ ForbiddenStatusCode 404 -> pure NothingStatusCode 200 -> withExceptT (ParseFailure r.body) $ Just <<< map fromDateTime <$> decodeDatedJson r.body - replacement in client/src/Aftok/Api/Project.purs at line 4
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) - replacement in client/src/Aftok/Api/Project.purs at line 9
import Data.Bifunctor (lmap)-- import Data.Bifunctor (lmap) - replacement in client/src/Aftok/Api/Project.purs at line 11
import Data.Either (Either(..), note)import Data.Maybe (Maybe(..))import Data.DateTime.Instant (toDateTime)import Data.Either (Either(..))import Data.Foldable (class Foldable, foldMapDefaultR) - replacement in client/src/Aftok/Api/Project.purs at line 16[3.3333]→[3.3333:3365](∅→∅),[3.3365]→[3.27:67](∅→∅),[3.67]→[3.3399:3434](∅→∅),[3.3399]→[3.3399:3434](∅→∅),[3.3434]→[3.68:97](∅→∅),[3.97]→[3.3469:3492](∅→∅),[3.3469]→[3.3469:3492](∅→∅)
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) - replacement in client/src/Aftok/Api/Project.purs at line 22
import Affjax (get, printError)import Affjax.StatusCode (StatusCode(..))import Affjax (get) - replacement in client/src/Aftok/Api/Project.purs at line 25
( UserId(..), ProjectId(..)( UserId, ProjectId - replacement in client/src/Aftok/Api/Project.purs at line 29
( APIError(..) )import Aftok.Api.Json (parseDate)( APIError )import Aftok.Api.Json( decompose, parseDatedResponse)data DepreciationFn= LinearDepreciation { undep :: Days, dep :: Days }instance decodeDepreciationFn :: DecodeJson DepreciationFn wheredecodeJson json = dox <- decodeJson jsondtype <- x .: "type"args <- x .: "arguments"case dtype of"LinearDepreciation" -> doundep <- Days <$> args .: "undep"dep <- Days <$> args .: "dep"pure $ LinearDepreciation { undep, dep }other -> Left $ "Unrecognized depreciation function: " <> other - edit in client/src/Aftok/Api/Project.purs at line 56
, depFn :: DepreciationFn - replacement in client/src/Aftok/Api/Project.purs at line 59
derive instance newtypeProject :: Newtype (Project' a) _derive instance projectNewtype :: Newtype (Project' a) _derive instance projectFunctor :: Functor Project'instance projectFoldable :: Foldable Project' wherefoldr f b (Project' p) = f (p.inceptionDate) bfoldl f b (Project' p) = f b (p.inceptionDate)foldMap = foldMapDefaultRinstance projectTraversable :: Traversable Project' wheretraverse f (Project' p) = Project' <<< (\b -> p { inceptionDate = b }) <$> f (p.inceptionDate)sequence = traverse identity - replacement in client/src/Aftok/Api/Project.purs at line 75
data DepreciationFn= LinearDepreciation { undep :: Days, dep :: Days }instance decodeJsonProject :: DecodeJson (Project' String) wheredecodeJson json = dox <- decodeJson jsonproject <- x .: "project"projectId <- x .: "projectId"projectName <- project .: "projectName"inceptionDate <- project .: "inceptionDate"initiator <- project .: "initiator"depFn <- project .: "depreciationFn"pure $ Project' { projectId, projectName, inceptionDate, initiator, depFn } - replacement in client/src/Aftok/Api/Project.purs at line 86
newtype ProjectUserData' date= ProjectUserData'{ userName :: Stringnewtype Contributor' date= Contributor'{ userId :: UserId, handle :: String - replacement in client/src/Aftok/Api/Project.purs at line 91
, totalContribution :: Hours, currentPayoutRatio :: Rational, timeDevoted :: Hours, revShare :: Rational - replacement in client/src/Aftok/Api/Project.purs at line 95
type ProjectUserData = ProjectUserData' DateTimeinstance decodeJsonContributor :: DecodeJson (Contributor' String) wheredecodeJson json = dox <- decodeJson jsonuserId <- x .: "userId"handle <- x .: "username"joinedOn <- x .: "joinedOn"timeDevoted <- Hours <$> x .: "timeDevoted"revShareObj <- x .: "revenueShare"num <- revShareObj .: "numerator"den <- revShareObj .: "denominator"let revShare = num % denpure $ Contributor' { userId, handle, joinedOn, timeDevoted, revShare } - replacement in client/src/Aftok/Api/Project.purs at line 111
, depreciation :: DepreciationFn, contributors :: M.Map UserId (ProjectUserData' date), contributors :: M.Map UserId (Contributor' date) - replacement in client/src/Aftok/Api/Project.purs at line 116
data ProjectEvent= ProjectChange Projecttype ProjectDetailJson date ={ project :: Project' date, contributors :: Array (Contributor' date)} - replacement in client/src/Aftok/Api/Project.purs at line 121
instance decodeJsonProject :: DecodeJson (Project' String) whereinstance decodeJsonProjectDetail :: DecodeJson (ProjectDetail' String) where - replacement in client/src/Aftok/Api/Project.purs at line 125[3.4203]→[3.4203:4470](∅→∅),[3.4470]→[3.602:696](∅→∅),[3.696]→[3.4551:4624](∅→∅),[3.4551]→[3.4551:4624](∅→∅)
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 } - edit in client/src/Aftok/Api/Project.purs at line 128
newtype Member' date= Member'{ userId :: UserId, handle :: String, joinedOn :: date, timeDevoted :: Hours, revShareFrac :: Rational} - replacement in client/src/Aftok/Api/Project.purs at line 130
result <- get RF.json "/api/projects"EC.liftEffect <<< runExceptT$ case result ofLeft err -> throwError $ Error { status: Nothing, message: printError err }Right r -> case r.status ofStatusCode 403 -> throwError ForbiddenStatusCode 200 -> dorecords <- except $ lmap (ParseFailure r.body) (decodeJson r.body)traverse parseProject recordsother -> throwError $ Error { status: Just other, message: r.statusText }response <- get RF.json "/api/projects"EC.liftEffect<<< runExceptT<<< map decompose<<< map (map toDateTime)$ parseDatedResponse response - replacement in client/src/Aftok/Api/Project.purs at line 137
parseProject :: Json -> ExceptT APIError Effect ProjectparseProject json = doProject' p <- except <<< lmap (ParseFailure json) $ decodeJson jsonpdate <- withExceptT (ParseFailure json) $ parseDate p.inceptionDatepure $ 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 - edit in client/src/Aftok/Api/Project.purs at line 147[3.5619]
- replacement in client/src/Aftok/Overview.purs at line 13
import Data.DateTime (date)import Data.DateTime (DateTime, date) - replacement in client/src/Aftok/Overview.purs at line 63
(Project, Project'(..), ProjectEvent(..), ProjectDetail, ProjectDetail'(..)(Project, Project'(..), ProjectDetail, ProjectDetail'(..) - replacement in client/src/Aftok/Overview.purs at line 65
, ProjectUserData'(..), ProjectUserData, Contributor'(..) - replacement in client/src/Aftok/Overview.purs at line 86
= forall query. H.Slot query ProjectEvent id= forall query. H.Slot query ProjectList.Event id - replacement in client/src/Aftok/Overview.purs at line 104
H.Component HH.HTML query OverviewInput ProjectEvent mH.Component HH.HTML query OverviewInput ProjectList.Event m - replacement in client/src/Aftok/Overview.purs at line 136
[ HH.slot _projectList unit (ProjectList.component system pcaps) st.selectedProject (Just <<< ProjectSelected) ][ HH.slot_projectListunit(ProjectList.component system pcaps)st.selectedProject(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))] - replacement in client/src/Aftok/Overview.purs at line 168
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) - replacement in client/src/Aftok/Overview.purs at line 195
contributorCols :: ProjectUserData -> H.ComponentHTML OverviewAction Slots mcontributorCols (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 mcontributorCols (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)) - replacement in client/src/Aftok/Overview.purs at line 200
[ colmd2 (Just pud.userName)[ colmd2 (Just pud.handle) - replacement in client/src/Aftok/Overview.purs at line 202
, colmd2 (Just $ show (unwrap pud.totalContribution)), colmd2 (Just $ show (unwrap pud.timeDevoted)) - replacement in client/src/Aftok/Overview.purs at line 339
eval :: OverviewAction -> H.HalogenM OverviewState OverviewAction Slots ProjectEvent m Uniteval :: OverviewAction -> H.HalogenM OverviewState OverviewAction Slots ProjectList.Event m Unit - replacement in client/src/Aftok/Overview.purs at line 351
H.raise (ProjectChange p)H.raise (ProjectList.ProjectChange p) - replacement in client/src/Aftok/Overview.purs at line 355
setProjectDetail :: ProjectId -> H.HalogenM OverviewState OverviewAction Slots ProjectEvent m UnitsetProjectDetail :: ProjectId -> H.HalogenM OverviewState OverviewAction Slots ProjectList.Event m Unit - edit in client/src/Aftok/Overview.purs at line 376
, depFn: LinearDepreciation { undep: Days 30.0, dep: Days 300.0 } - replacement in client/src/Aftok/Overview.purs at line 378
, depreciation: LinearDepreciation { undep: Days 30.0, dep: Days 300.0 }, contributors: M.singleton uid $ ProjectUserData'{ userName: "Joe", contributors: M.singleton uid $ Contributor'{ userId: uid, handle: "Joe" - replacement in client/src/Aftok/Overview.purs at line 382
, totalContribution: Hours 100.0, currentPayoutRatio: 55 R.% 100, timeDevoted: Hours 100.0, revShare: 55 R.% 100 - replacement in client/src/Aftok/ProjectList.purs at line 33
type Output= Projectdata Event= ProjectChange Project - replacement in client/src/Aftok/ProjectList.purs at line 37
= forall query. H.Slot query Project id= forall query. H.Slot query Event id - replacement in client/src/Aftok/ProjectList.purs at line 57
H.Component HH.HTML query Input Output mH.Component HH.HTML query Input Event m - replacement in client/src/Aftok/ProjectList.purs at line 99
eval :: Action -> H.HalogenM CState Action () Project m Uniteval :: Action -> H.HalogenM CState Action () Event m Unit - replacement in client/src/Aftok/ProjectList.purs at line 109
traverse_ H.raise (index projects (i - 1))traverse_ (H.raise <<< ProjectChange) (index projects (i - 1)) - edit in client/src/Aftok/Timeline.purs at line 66
, ProjectEvent(..) - replacement in client/src/Aftok/Timeline.purs at line 113
= forall query. H.Slot query ProjectEvent id= forall query. H.Slot query ProjectList.Event id - replacement in client/src/Aftok/Timeline.purs at line 135
H.Component HH.HTML query Input ProjectEvent mH.Component HH.HTML query Input ProjectList.Event m - replacement in client/src/Aftok/Timeline.purs at line 169
[ HH.slot _projectList unit (ProjectList.component system pcaps) st.selectedProject (Just <<< ProjectSelected) ][ HH.slot_projectListunit(ProjectList.component system pcaps)st.selectedProject(Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))] - replacement in client/src/Aftok/Timeline.purs at line 198
eval :: TimelineAction -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Uniteval :: TimelineAction -> H.HalogenM TimelineState TimelineAction Slots ProjectList.Event m Unit - replacement in client/src/Aftok/Timeline.purs at line 212
H.raise (ProjectChange p)H.raise (ProjectList.ProjectChange p) - replacement in client/src/Aftok/Timeline.purs at line 228
logStart :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m UnitlogStart :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectList.Event m Unit - replacement in client/src/Aftok/Timeline.purs at line 235
logEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m UnitlogEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectList.Event m Unit - replacement in client/src/Aftok/Timeline.purs at line 245
setStateForProject :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m UnitsetStateForProject :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectList.Event m Unit - edit in client/src/Aftok/Types.purs at line 4
import Data.Argonaut.Decode (class DecodeJson, decodeJson) - edit in client/src/Aftok/Types.purs at line 8
import Data.Either (note) - replacement in client/src/Aftok/Types.purs at line 14
import Data.UUID (UUID, toString)import Data.UUID (UUID, toString, parseUUID) - edit in client/src/Aftok/Types.purs at line 89
derive instance userIdNewtype :: Newtype UserId _ - replacement in client/src/Aftok/Types.purs at line 91
derive instance userIdNewtype :: Newtype UserId _instance userIdDecodeJson :: DecodeJson UserId wheredecodeJson json = douuidStr <- decodeJson jsonUserId <$> (note "Failed to decode user UUID" $ parseUUID uuidStr) - edit in client/src/Aftok/Types.purs at line 100
derive instance projectIdOrd :: Ord ProjectIdderive instance projectIdNewtype :: Newtype ProjectId _ - replacement in client/src/Aftok/Types.purs at line 103
derive instance projectIdNewtype :: Newtype ProjectId _instance projectIdDecodeJson :: DecodeJson ProjectId wheredecodeJson json = douuidStr <- decodeJson jsonProjectId <$> (note "Failed to decode project UUID" $ parseUUID uuidStr) - edit in client/src/Aftok/Types.purs at line 108
- replacement in client/src/Main.purs at line 25
import Aftok.Api.Project (Project, ProjectEvent(ProjectChange))import Aftok.Api.Project (Project) - replacement in client/src/Main.purs at line 95
| ProjectAction ProjectEvent| ProjectAction ProjectList.Event - replacement in client/src/Main.purs at line 183
ProjectAction (ProjectChange p) -> H.modify_ (_ { selectedProject = Just p })ProjectAction (ProjectList.ProjectChange p) -> H.modify_ (_ { selectedProject = Just p })