Add error reporting to signup form.

[?]
Jan 31, 2021, 2:08 AM
U7YAT2ZK6GMS7KVFFEQTDRFX6GIN7HVHNWGKIFDGJGE2G2IXSF6QC

Dependencies

  • [2] UD5T5B7A Update email invitation workflow.
  • [3] APOATM4X Add getProjectDetail call to project API
  • [4] RV7ZIULZ Update overview to have access to the real project detail capability.
  • [5] QMEYU4MW Add display for prior intervals.
  • [6] 7HPY3QPF Fix linting errors. (yay hlint!)
  • [7] NAFJ6RB3 Minor module reorg.
  • [8] Z5KNL332 Add skeleton of project overview HTML.
  • [9] A6HKMINB Attempting to improve JSON handling.
  • [10] OV5AKJHA Remove unused LogInterval type.
  • [11] 2G3GNDDU Event logging is now functioning in postgres.
  • [12] QMRKFEPG Refactor QDB to use a free monad algebra instead.
  • [13] 2XQD6KKK Add invitation logic and clean up DBProg error handling.
  • [14] EFSXYZPO Autoformat everything with brittany.
  • [15] Z7CQXTU7 Update login scripts, add script for XHR login interface.
  • [16] QU5FW67R Add project selection to time tracker.
  • [17] O2BZOX7M Add signup form, captcha check.
  • [18] NEDDHXUK Reformat via stylish-haskell
  • [19] B4MTB6UO Persist project across pages.
  • [20] POX3UAMT Enabling logging of time to contributor/project accounts
  • [21] PBD7LZYQ Postgres & auth are beginning to function.
  • [22] 5R2Z7FSX Initial rendering for signup controls.
  • [23] PPW6ROC5 Render project data
  • [24] GCVQD44V Create amends endpoint, switch to UUID primary keys
  • [25] GLQSD33Y Use mock capability for overview init.
  • [26] N4NDAZYT Initial implementation of payouts.
  • [27] PT4276XC Add logout functionality.
  • [28] 7TQPQW3N Begin adding parsing for project detail.
  • [29] UWMGUJOW Autoformat sources.
  • [30] O5FVTOM6 Undo JSON silliness, enable a couple more routes.
  • [31] BROSTG5K Beginning of modularization of server.
  • [32] WRPIYG3E Use project listing functionality to check for whether we have a cookie.
  • [33] CDHZL3RP Add a couple of other CLI utilities for interacing with the service.
  • [34] OUR4PAOT Use local dates for display of intervals.
  • [35] ENNZIQJG Use live signup API for client.
  • [36] X3ES7NUA Fine. I'll use ormolu. At least it doesn't break the code.
  • [37] 5SBSBFLS Bind log directories to local paths for development.
  • [38] XTBSG4C7 Adding serveJSON combinator to eliminate some boilerplate from handlers.
  • [39] IPG33FAW Add billing daemon
  • [40] G4BS4NND Add simple shell script demonstrating how to invite a companion.
  • [41] MU6WOCCJ Update auctions to permit zcash as a funding currency.
  • [42] BFZN4SUA Make timeline component work.
  • [43] M4PWY5RU Preliminary work to add support for Zcash payments.
  • [44] QAC2QJ32 Add project overview page to client.
  • [45] GMYPBCWE Make docker-compose work.
  • [46] JXG3FCXY Upgrade ps + halogen versions.
  • [47] NJNMO72S Add zcash.com submodule and update client to modern halogen.
  • [48] 2OIPAQCB Merge branch 'master' of github.com:nuttycom/ananke
  • [49] J6S23MDG Use server timestamps for interval start and end.
  • [50] RPAJLHMT Change to use UUIDs instead of ints for primary keys.
  • [51] HALRDT2F Added initial auction create route.
  • [52] DFOBMSAO Initial work on payments API
  • [53] 3GLHIR4F Add migrate script for prod system.
  • [54] 4QX5E5AC Initial compilation of payouts function succeeds.
  • [55] Y35QCWYW Minor improvement in WorkIndex type to eliminate duplicated information.
  • [56] GKGVYBZG Added JSON serialization to TimeLog
  • [57] NVOCQVAS Initial failing tests.
  • [58] NAS4BFL4 Trivial stylish-haskell reformat.
  • [59] QH4UB73N Format with purty.
  • [60] SFWL5626 Initial release of UI.
  • [61] 2J37EVJM Check for an open interval on project switch.
  • [62] IZEVQF62 Work in progress replacing sqlite with postgres.
  • [63] B6HWAPDP Modularize & update to recent haskoin.
  • [64] RSF6UAJK Break out api module for timeline.
  • [65] 4354Y4PE Add endpoint to list project contributors.
  • [66] HMDM3B55 Implement core of payments/billing infrastructure.
  • [67] I2KHGVD4 Require project permissions for access to most data.
  • [68] XA7SOE6J Dockerize reactclient.
  • [69] A2J7B4SC Initial impl of depreciation function.
  • [70] IR75ZMX3 Return actual events for interval ends, not just timestamps.
  • [71] AAALU5A2 Fix client routing
  • [72] 7KZP4RHZ Switch from Data.Time to Data.Thyme
  • [73] KEP5WUFJ Convert project to stack-based build.
  • [74] SAESJLLY Initial experiments in hash routing.
  • [*] RB2ETNIF Add skeletal PureScript client project.
  • [*] 64C6AWH6 Rename Ananke -> Quixotic, project reboot.
  • [*] U256ZALI Add captcha check to register route.
  • [*] ADMKQQGC Initial empty Snap project.

Change contents

  • replacement in client/src/Aftok/Api/Account.purs at line 93
    [5.2809][5.2809:2832]()
    pure UsernameCheckOK
    [5.2809]
    [5.2832]
    result <- get RF.ignore ("/api/validate_username?username=" <> uname)
    pure
    $ case result of
    Left err -> UsernameCheckTaken
    Right r
    | r.status == StatusCode 200 -> UsernameCheckOK
    Right r -> UsernameCheckTaken
  • replacement in client/src/Aftok/Api/Account.purs at line 104
    [5.1318][5.521:644](),[5.521][5.521:644](),[5.644][5.1319:1401](),[5.1401][5.718:832](),[5.718][5.718:832]()
    case result of
    Left err -> do
    log ("ZAddr validation failed: " <> printError err)
    pure ZAddrCheckInvalid
    Right r
    | r.status == StatusCode 200 -> do
    pure ZAddrCheckValid
    Right r -> do
    log ("ZAddr was determined to be invalid: " <> r.statusText)
    pure ZAddrCheckInvalid
    [5.1318]
    [5.2922]
    pure
    $ case result of
    Left err -> ZAddrCheckInvalid
    Right r
    | r.status == StatusCode 200 -> ZAddrCheckValid
    Right r -> ZAddrCheckInvalid
  • edit in client/src/Aftok/Api/Json.purs at line 58
    [5.2130]
    [5.2130]
    type Decode a
    = Json -> Either String a
  • replacement in client/src/Aftok/Api/Json.purs at line 62
    [5.2131][5.2131:2309]()
    decodeDatedJson :: forall t. Traversable t => DecodeJson (t String) => Json -> ExceptT String Effect (t DateTime)
    decodeDatedJson json = do
    decoded <- except $ decodeJson json
    [5.2131]
    [5.2309]
    decodeDatedJson :: forall t. Traversable t => Decode (t String) -> Json -> ExceptT String Effect (t DateTime)
    decodeDatedJson decode json = do
    decoded <- except $ decode json
  • replacement in client/src/Aftok/Api/Json.purs at line 70
    [5.2392][5.2392:2419]()
    DecodeJson (t String) =>
    [5.2392]
    [5.2419]
    Decode (t String) ->
  • replacement in client/src/Aftok/Api/Json.purs at line 73
    [5.2496][5.2496:2527]()
    parseDatedResponse = case _ of
    [5.2496]
    [5.2527]
    parseDatedResponse decode = case _ of
  • replacement in client/src/Aftok/Api/Json.purs at line 77
    [5.2680][5.2680:2782]()
    StatusCode 200 -> withExceptT (ParseFailure r.body) $ map fromDateTime <$> decodeDatedJson r.body
    [5.2680]
    [5.5]
    StatusCode 200 -> withExceptT (ParseFailure r.body) $ map fromDateTime <$> decodeDatedJson decode r.body
  • replacement in client/src/Aftok/Api/Json.purs at line 83
    [5.140][5.140:167]()
    DecodeJson (t String) =>
    [5.140]
    [5.167]
    Decode (t String) ->
  • replacement in client/src/Aftok/Api/Json.purs at line 86
    [5.252][5.252:286]()
    parseDatedResponseMay = case _ of
    [5.252]
    [5.286]
    parseDatedResponseMay decode = case _ of
  • replacement in client/src/Aftok/Api/Json.purs at line 91
    [5.474][5.474:585]()
    StatusCode 200 -> withExceptT (ParseFailure r.body) $ Just <<< map fromDateTime <$> decodeDatedJson r.body
    [5.474]
    [5.2782]
    StatusCode 200 ->
    withExceptT (ParseFailure r.body)
    $ Just
    <<< map fromDateTime
    <$> decodeDatedJson decode r.body
  • replacement in client/src/Aftok/Api/Project.purs at line 7
    [5.763][5.763:799]()
    -- import Data.Argonaut.Core (Json)
    [5.763]
    [5.3103]
    import Data.Argonaut.Core (Json)
  • edit in client/src/Aftok/Api/Project.purs at line 9
    [5.3168][5.800:832]()
    -- import Data.Bifunctor (lmap)
  • replacement in client/src/Aftok/Api/Project.purs at line 17
    [3.296][5.963:1000](),[5.3333][5.963:1000]()
    import Data.Rational (Rational, (%))
    [3.296]
    [5.1000]
    import Data.Ratio (Ratio, (%))
  • edit in client/src/Aftok/Api/Project.purs at line 19
    [5.1048]
    [5.1048]
    import Data.Tuple (Tuple(..))
  • edit in client/src/Aftok/Api/Project.purs at line 24
    [5.3542]
    [5.1129]
    import Foreign.Object (Object)
  • replacement in client/src/Aftok/Api/Project.purs at line 33
    [5.3726][5.1176:1228]()
    ( APIError )
    import Aftok.Api.Json
    ( decompose
    [5.3726]
    [5.1228]
    (APIError)
    import Aftok.Api.Json
    ( Decode
    , decompose
  • edit in client/src/Aftok/Api/Project.purs at line 81
    [5.140]
    [5.2254]
    parseProject :: ProjectId -> Object Json -> Either String (Project' String)
    parseProject projectId pjson = do
    projectName <- pjson .: "projectName"
    inceptionDate <- pjson .: "inceptionDate"
    initiator <- pjson .: "initiator"
    depf <- pjson .: "depf"
    pure $ Project' { projectId, projectName, inceptionDate, initiator, depf }
  • replacement in client/src/Aftok/Api/Project.purs at line 92
    [5.2367][5.2367:2397]()
    project <- x .: "project"
    [5.2367]
    [5.2397]
    pjson <- x .: "project"
  • replacement in client/src/Aftok/Api/Project.purs at line 94
    [5.2431][5.2431:2563](),[5.2563][3.388:497]()
    projectName <- project .: "projectName"
    inceptionDate <- project .: "inceptionDate"
    initiator <- project .: "initiator"
    depf <- project .: "depf"
    pure $ Project' { projectId, projectName, inceptionDate, initiator, depf }
    [5.2431]
    [5.4014]
    parseProject projectId pjson
  • replacement in client/src/Aftok/Api/Project.purs at line 102
    [5.2796][5.2796:2821]()
    , revShare :: Rational
    [5.2796]
    [5.377]
    , revShare :: Ratio Number
  • replacement in client/src/Aftok/Api/Project.purs at line 115
    [3.875][3.875:975]()
    traverse f (Contributor' p) =
    Contributor' <<< (\b -> p { joinedOn = b }) <$> f (p.joinedOn)
    [3.875]
    [3.975]
    traverse f (Contributor' p) = Contributor' <<< (\b -> p { joinedOn = b }) <$> f (p.joinedOn)
  • replacement in client/src/Aftok/Api/Project.purs at line 125
    [5.3081][5.3081:3120]()
    revShareObj <- x .: "revenueShare"
    [5.3081]
    [5.3120]
    revShareObj <- x .: "revenureShare"
  • replacement in client/src/Aftok/Api/Project.purs at line 128
    [5.3198][5.3198:3227]()
    let revShare = num % den
    [5.3198]
    [5.3227]
    let
    revShare = num % den
  • replacement in client/src/Aftok/Api/Project.purs at line 138
    [3.1009][3.1009:1102]()
    projectDetail ::
    forall date.
    Project' date ->
    M.Map UserId (Contributor' date) ->
    [3.1009]
    [3.1102]
    projectDetail ::
    forall date.
    Project' date ->
    M.Map UserId (Contributor' date) ->
  • replacement in client/src/Aftok/Api/Project.purs at line 143
    [3.1124][3.1124:1205]()
    projectDetail project contributors =
    ProjectDetail' { project, contributors }
    [3.1124]
    [5.554]
    projectDetail project contributors = ProjectDetail' { project, contributors }
  • replacement in client/src/Aftok/Api/Project.purs at line 145
    [5.555][5.555:600]()
    type ProjectDetail = ProjectDetail' DateTime
    [5.555]
    [5.600]
    type ProjectDetail
    = ProjectDetail' DateTime
  • replacement in client/src/Aftok/Api/Project.purs at line 158
    [3.1683][3.1683:1835]()
    traverse f (ProjectDetail' p) =
    projectDetail <$> traverse f p.project
    <*> (map unwrap $ traverse f (Compose p.contributors))
    [3.1683]
    [3.1835]
    traverse f (ProjectDetail' p) =
    projectDetail <$> traverse f p.project
    <*> (map unwrap $ traverse f (Compose p.contributors))
  • replacement in client/src/Aftok/Api/Project.purs at line 163
    [5.4060][5.3469:3546](),[5.3546][5.4125:4203](),[5.4125][5.4125:4203](),[5.4203][5.3547:3639]()
    instance decodeJsonProjectDetail :: DecodeJson (ProjectDetail' String) where
    decodeJson json = do
    x <- decodeJson json
    project <- x .: "project"
    contributors <- x .: "contributors"
    pure $ ProjectDetail' { project, contributors }
    [5.4060]
    [5.4624]
    parseProjectDetail :: ProjectId -> Decode (ProjectDetail' String)
    parseProjectDetail pid json = do
    x <- decodeJson json
    project <- parseProject pid =<< x .: "project"
    (contribList :: Array (Contributor' String)) <- x .: "contributors"
    let
    contributors = M.fromFoldable $ map (\c@(Contributor' xs) -> Tuple xs.userId c) contribList
    pure $ ProjectDetail' { project, contributors }
  • replacement in client/src/Aftok/Api/Project.purs at line 175
    [5.3682][5.3682:3699]()
    EC.liftEffect
    [5.3682]
    [5.3699]
    EC.liftEffect
  • replacement in client/src/Aftok/Api/Project.purs at line 179
    [5.3769][5.3769:3803]()
    $ parseDatedResponse response
    [5.3769]
    [5.5349]
    $ parseDatedResponse decodeJson response
  • replacement in client/src/Aftok/Api/Project.purs at line 183
    [3.1970][3.1970:2183]()
    response <- get RF.json ("/api/user/projects/" <> pidStr pid <> "/detail")
    let parsed :: ExceptT APIError Effect (Maybe (ProjectDetail' Instant))
    parsed = parseDatedResponseMay response
    EC.liftEffect
    [3.1970]
    [3.2183]
    response <- get RF.json ("/api/projects/" <> pidStr pid <> "/detail")
    let
    parsed :: ExceptT APIError Effect (Maybe (ProjectDetail' Instant))
    parsed = parseDatedResponseMay (parseProjectDetail pid) response
    EC.liftEffect
  • edit in client/src/Aftok/Api/Project.purs at line 191
    [3.2250][5.5618:5619](),[5.4185][5.5618:5619](),[5.5618][5.5618:5619](),[5.5619][5.4186:4187]()
  • edit in client/src/Aftok/Api/Recaptcha.js at line 10
    [5.3248]
    exports.recaptchaRenderInternal = siteKey => elemId => () => {
    grecaptcha.render(
    document.getElementById(elemId),
    { 'sitekey': siteKey }
    );
    }
  • replacement in client/src/Aftok/Api/Recaptcha.purs at line 5
    [5.3352][5.3352:3391]()
    import Prelude (bind, (==), ($), pure)
    [5.3352]
    [5.3391]
    import Prelude (bind, (==), ($), pure, Unit)
  • edit in client/src/Aftok/Api/Recaptcha.purs at line 16
    [5.3725]
    [5.3725]
    recaptchaRender :: String -> String -> Effect Unit
    recaptchaRender = recaptchaRenderInternal
  • edit in client/src/Aftok/Api/Recaptcha.purs at line 20
    [5.3807]
    foreign import recaptchaRenderInternal :: String -> String -> Effect Unit
  • replacement in client/src/Aftok/Api/Timeline.purs at line 191
    [5.3077][5.3077:3145]()
    kev <- withExceptT LogFailure $ parseDatedResponse response
    [5.3077]
    [5.3145]
    kev <- withExceptT LogFailure $ parseDatedResponse decodeJson response
  • replacement in client/src/Aftok/Api/Timeline.purs at line 203
    [5.3415][5.3415:3483]()
    kev <- withExceptT LogFailure $ parseDatedResponse response
    [5.3415]
    [5.3483]
    kev <- withExceptT LogFailure $ parseDatedResponse decodeJson response
  • replacement in client/src/Aftok/Api/Timeline.purs at line 247
    [5.5507][5.4104:4138]()
    $ parseDatedResponse response
    [5.5507]
    [5.6498]
    $ parseDatedResponse decodeJson response
  • replacement in client/src/Aftok/Api/Timeline.purs at line 257
    [5.5660][5.4139:4173]()
    $ parseDatedResponse response
    [5.5660]
    $ parseDatedResponse decodeJson response
  • edit in client/src/Aftok/Api/Types.purs at line 18
    [5.6328][5.6328:6329]()
  • replacement in client/src/Aftok/Overview.purs at line 20
    [5.686][5.686:712]()
    import Data.Rational as R
    [5.686]
    [5.702]
    import Data.Ratio as R
  • replacement in client/src/Aftok/Overview.purs at line 63
    [4.71][5.873:899](),[5.315][5.873:899](),[5.849][5.873:899](),[5.6486][5.873:899](),[5.899][5.4228:4288]()
    import Aftok.Api.Project
    (Project, Project'(..), ProjectDetail, ProjectDetail'(..)
    [4.71]
    [5.986]
    import Aftok.Api.Project
    ( Project
    , Project'(..)
    , ProjectDetail
    , ProjectDetail'(..)
  • replacement in client/src/Aftok/Overview.purs at line 133
    [5.10644][5.1113:1491](),[5.1491][5.4427:4662]()
    [ P.classes (ClassName <$> [ "container", "pt-6" ]) ]
    [ HH.h1
    [ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ]
    [ HH.text "Project Overview" ]
    , HH.p
    [ P.classes (ClassName <$> [ "col-md-5", "text-muted", "text-center", "mx-auto" ]) ]
    [ HH.text "Your project details" ]
    , HH.div_
    [ HH.slot
    _projectList
    unit
    (ProjectList.component system pcaps)
    st.selectedProject
    (Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))
    [5.10644]
    [5.4662]
    [ P.classes (ClassName <$> [ "container", "pt-6" ]) ]
    [ HH.h1
    [ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ]
    [ HH.text "Project Overview" ]
    , HH.p
    [ P.classes (ClassName <$> [ "col-md-5", "text-muted", "text-center", "mx-auto" ]) ]
    [ HH.text "Your project details" ]
    , HH.div_
    [ HH.slot
    _projectList
    unit
    (ProjectList.component system pcaps)
    st.selectedProject
    (Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))
    ]
    , HH.div
    [ P.classes (ClassName <$> if isNothing st.selectedProject then [ "collapse" ] else []) ]
    (U.fromMaybe $ projectDetail <$> st.projectDetail)
  • edit in client/src/Aftok/Overview.purs at line 152
    [5.4674][5.1614:1731](),[5.1614][5.1614:1731](),[5.1731][5.1443:1504](),[5.1504][5.1790:1800](),[5.1790][5.1790:1800]()
    , HH.div
    [ P.classes (ClassName <$> if isNothing st.selectedProject then [ "collapse" ] else []) ]
    (U.fromMaybe $ projectDetail <$> st.projectDetail)
    ]
  • replacement in client/src/Aftok/Overview.purs at line 156
    [5.1929][5.1929:1973]()
    let (Project' project) = detail.project
    [5.1929]
    [5.1973]
    let
    (Project' project) = detail.project
  • replacement in client/src/Aftok/Overview.purs at line 161
    [5.2061][5.2061:2247](),[5.2247][5.1505:1546](),[5.1546][5.2315:2498](),[5.2315][5.2315:2498]()
    [ P.id_ "projectOverview", P.classes (ClassName <$> ["pt-3"]) ]
    [ HH.div
    -- header
    [ P.classes (ClassName <$> ["row", "pt-3", "font-weight-bold" ]) ]
    [ colmd2 (Just "Project Name")
    , colmd2 (Just "Undepreciated Period")
    , colmd2 (Just "Depreciation Duration")
    , colmd2 (Just "Originator")
    , colmd2 (Just "Origination Date")
    [5.2061]
    [5.3898]
    [ P.id_ "projectOverview", P.classes (ClassName <$> [ "pt-3" ]) ]
    [ HH.div
    -- header
    [ P.classes (ClassName <$> [ "row", "pt-3", "font-weight-bold" ]) ]
    [ colmd2 (Just "Project Name")
    , colmd2 (Just "Undepreciated Period")
    , colmd2 (Just "Depreciation Duration")
    , colmd2 (Just "Originator")
    , colmd2 (Just "Origination Date")
    ]
    , HH.div
    [ P.classes (ClassName <$> [ "row", "pt-3" ]) ]
    ( [ colmd2 (Just project.projectName) ]
    <> depreciationCols project.depf
    <> [ colmd2 ((\(Contributor' p) -> p.handle) <$> M.lookup project.initiator detail.contributors)
    , colmd2 (Just $ dateStr (date project.inceptionDate))
    ]
    )
  • edit in client/src/Aftok/Overview.purs at line 180
    [5.3910][5.2499:2516](),[5.2516][5.1547:1655](),[5.1655][3.2252:2296](),[3.2296][5.4720:4825](),[5.4720][5.4720:4825](),[5.4825][5.1656:1722](),[5.2822][5.1656:1722](),[5.1722][5.2878:2902](),[5.2878][5.2878:2902]()
    , HH.div
    [ P.classes (ClassName <$> ["row", "pt-3"]) ]
    ([ colmd2 (Just project.projectName) ] <>
    depreciationCols project.depf <>
    [ colmd2 ((\(Contributor' p) -> p.handle) <$> M.lookup project.initiator detail.contributors)
    , colmd2 (Just $ dateStr (date project.inceptionDate))
    ])
    ]
  • replacement in client/src/Aftok/Overview.purs at line 181
    [5.1742][5.1742:2177]()
    [ P.id_ "contributors" ]
    ([ HH.div
    -- header
    [ P.classes (ClassName <$> ["row", "pt-3", "font-weight-bold" ]) ]
    [ colmd2 (Just "Contributor")
    , colmd2 (Just "Joined")
    , colmd2 (Just "Contributed Hours")
    , colmd2 (Just "Current Revenue Share")
    ]
    ] <>
    (contributorCols <$> (L.toUnfoldable $ M.values detail.contributors))
    )
    [5.1742]
    [5.2902]
    [ P.id_ "contributors" ]
    ( [ HH.div
    -- header
    [ P.classes (ClassName <$> [ "row", "pt-3", "font-weight-bold" ]) ]
    [ colmd2 (Just "Contributor")
    , colmd2 (Just "Joined")
    , colmd2 (Just "Contributed Hours")
    , colmd2 (Just "Current Revenue Share")
    ]
    ]
    <> (contributorCols <$> (L.toUnfoldable $ M.values detail.contributors))
    )
  • replacement in client/src/Aftok/Overview.purs at line 203
    [5.4911][5.4911:5086](),[5.5086][5.2571:2647](),[5.2571][5.2571:2647](),[5.2647][5.5087:5120](),[5.5120][5.2682:2734](),[5.2682][5.2682:2734](),[5.2734][5.5121:5175](),[5.5175][5.2794:2829](),[5.2794][5.2794:2829](),[5.2829][5.11322:11330](),[5.3157][5.11322:11330](),[5.3910][5.11322:11330]()
    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))
    in HH.div
    [ P.classes (ClassName <$> ["row", "pt-3", "pb-2" ]) ]
    [ colmd2 (Just pud.handle)
    , colmd2 (Just $ dateStr (date pud.joinedOn))
    , colmd2 (Just $ show (unwrap pud.timeDevoted))
    , colmd2 (Just $ pct <> "%")
    ]
    [5.4911]
    [5.3158]
    contributorCols (Contributor' pud) =
    let
    shareFrac = R.numerator pud.revShare `div` R.denominator pud.revShare
    pct = maybe "N/A" (\f -> F.toString (f * F.fromInt 100)) (F.fromNumber shareFrac :: Maybe (F.Fixed F.P10000))
    in
    HH.div
    [ P.classes (ClassName <$> [ "row", "pt-3", "pb-2" ]) ]
    [ colmd2 (Just pud.handle)
    , colmd2 (Just $ dateStr (date pud.joinedOn))
    , colmd2 (Just $ show (unwrap pud.timeDevoted))
    , colmd2 (Just $ pct <> "%")
    ]
  • replacement in client/src/Aftok/Overview.purs at line 218
    [5.3226][5.2830:2925]()
    colmd2 xs = HH.div [ P.classes (ClassName <$> ["col-md-2"]) ] (U.fromMaybe $ HH.text <$> xs)
    [5.3226]
    [5.3319]
    colmd2 xs = HH.div [ P.classes (ClassName <$> [ "col-md-2" ]) ] (U.fromMaybe $ HH.text <$> xs)
  • replacement in client/src/Aftok/Overview.purs at line 220
    [5.5940][5.5940:10364](),[5.10364][5.3920:3921](),[5.11330][5.3920:3921](),[5.3920][5.3920:3921]()
    -- </section>
    -- <!-- Map payouts -->
    -- <div class="row font-weight-bold">
    -- <div class="col-md-2">
    -- </div>
    -- <div class="col-md-4">
    -- Payments
    -- </div>
    -- <div class="col-md-6">
    --
    -- </div>
    -- </div>
    -- <div class="row">
    -- <div class="col-md-2">
    -- </div>
    -- <div class="col-md-2">
    -- Oct 20 2020
    -- </div>
    -- <div class="col-md-2">
    -- 100 zec
    -- </div>
    -- <div class="col-md-2">
    -- Acme PaidUsRight
    -- </div>
    -- <div class="col-md-4">
    -- </div>
    -- </div>
    -- <!-- map payout creditTos-->
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Freuline Fred
    -- </div>
    -- <div class="col-md-2">
    -- 2.4 zec
    -- </div>
    -- <div class="col-md-2">
    -- 2.4 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div>
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Goobie Works A Lot
    -- </div>
    -- <div class="col-md-2">
    -- 50 zec
    -- </div>
    -- <div class="col-md-2">
    -- 50 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div> <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Average Fella
    -- </div>
    -- <div class="col-md-2">
    -- 25 zec
    -- </div>
    -- <div class="col-md-2">
    -- 25 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div> <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Cool Kid
    -- </div>
    -- <div class="col-md-2">
    -- 24.6 zec
    -- </div>
    -- <div class="col-md-2">
    -- 24.6 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div>
    --
    -- </section>
    --
    --
    -- <!-- New Project form-->
    -- <section id="addProject">
    --
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- <span class="float-right">Project Name</span>
    -- </div>
    -- <div class="col-md-4">
    -- <input type="text" id="projectName" name="projectName" />
    -- </div>
    -- </div>
    --
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- <span class="float-right">Undepreciated Period ( Months )</span>
    -- </div>
    -- <div class="col-md-4">
    -- <input type="text" id="undepreciatedPeriod" name="undepreciatedPeriod" />
    -- </div>
    -- </div>
    --
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- <span class="float-right">Depreciation Duration ( Months )</span>
    -- </div>
    -- <div class="col-md-4">
    -- <input type="text" id="depreciationDuration" name="depreciationDuration" />
    -- </div>
    -- </div>
    --
    -- <div class="row pt-3 pb-3">
    -- <div class="col-md-2">
    -- </div>
    -- <div class="col-md-10">
    -- <button class="btn btn-sm btn-primary lift ml-auto">Add Project</button>
    -- </div>
    -- </div>
    --
    -- </section>
    [5.3320]
    [5.5176]
    -- </section>
    -- <!-- Map payouts -->
    -- <div class="row font-weight-bold">
    -- <div class="col-md-2">
    -- </div>
    -- <div class="col-md-4">
    -- Payments
    -- </div>
    -- <div class="col-md-6">
    --
    -- </div>
    -- </div>
    -- <div class="row">
    -- <div class="col-md-2">
    -- </div>
    -- <div class="col-md-2">
    -- Oct 20 2020
    -- </div>
    -- <div class="col-md-2">
    -- 100 zec
    -- </div>
    -- <div class="col-md-2">
    -- Acme PaidUsRight
    -- </div>
    -- <div class="col-md-4">
    -- </div>
    -- </div>
    -- <!-- map payout creditTos-->
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Freuline Fred
    -- </div>
    -- <div class="col-md-2">
    -- 2.4 zec
    -- </div>
    -- <div class="col-md-2">
    -- 2.4 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div>
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Goobie Works A Lot
    -- </div>
    -- <div class="col-md-2">
    -- 50 zec
    -- </div>
    -- <div class="col-md-2">
    -- 50 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div> <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Average Fella
    -- </div>
    -- <div class="col-md-2">
    -- 25 zec
    -- </div>
    -- <div class="col-md-2">
    -- 25 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div> <div class="row pt-3">
    -- <div class="col-md-4">
    -- </div>
    -- <div class="col-md-2">
    -- Cool Kid
    -- </div>
    -- <div class="col-md-2">
    -- 24.6 zec
    -- </div>
    -- <div class="col-md-2">
    -- 24.6 %
    -- </div>
    -- <div class="col-md-2">
    -- </div>
    -- </div>
    --
    -- </section>
    --
    --
    -- <!-- New Project form-->
    -- <section id="addProject">
    --
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- <span class="float-right">Project Name</span>
    -- </div>
    -- <div class="col-md-4">
    -- <input type="text" id="projectName" name="projectName" />
    -- </div>
    -- </div>
    --
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- <span class="float-right">Undepreciated Period ( Months )</span>
    -- </div>
    -- <div class="col-md-4">
    -- <input type="text" id="undepreciatedPeriod" name="undepreciatedPeriod" />
    -- </div>
    -- </div>
    --
    -- <div class="row pt-3">
    -- <div class="col-md-4">
    -- <span class="float-right">Depreciation Duration ( Months )</span>
    -- </div>
    -- <div class="col-md-4">
    -- <input type="text" id="depreciationDuration" name="depreciationDuration" />
    -- </div>
    -- </div>
    --
    -- <div class="row pt-3 pb-3">
    -- <div class="col-md-2">
    -- </div>
    -- <div class="col-md-10">
    -- <button class="btn btn-sm btn-primary lift ml-auto">Add Project</button>
    -- </div>
    -- </div>
    --
    -- </section>
  • replacement in client/src/Aftok/Overview.purs at line 367
    [5.810][5.810:859](),[5.859][4.176:305]()
    detail <- lift $ caps.getProjectDetail pid
    case detail of
    Left err -> lift $ system.error (show err)
    Right d -> H.modify_ (_ { projectDetail = d })
    [5.810]
    [5.906]
    detail <- lift $ caps.getProjectDetail pid
    case detail of
    Left err -> lift $ system.error (show err)
    Right d -> H.modify_ (_ { projectDetail = d })
  • replacement in client/src/Aftok/Overview.purs at line 379
    [5.10399][5.950:1066](),[5.1066][4.346:394](),[4.394][5.1104:1255](),[5.1104][5.1104:1255](),[5.1255][3.2297:2372](),[3.2372][5.1255:1267](),[5.5512][5.1255:1267](),[5.1255][5.1255:1267](),[5.1267][5.5513:5619](),[5.5619][5.1436:1460](),[5.1436][5.1436:1460](),[5.1460][5.5620:5690](),[5.5690][5.1546:1568](),[5.1546][5.1546:1568]()
    { getProjectDetail: \pid -> do
    t <- liftEffect nowDateTime
    uid <- UserId <$> liftEffect genUUID
    pure <<< Right <<< Just $ ProjectDetail'
    { project: Project'
    { projectId: pid
    , projectName: "Fake Project"
    , inceptionDate: t
    , initiator: uid
    , depf: LinearDepreciation { undep: Days 30.0, dep: Days 300.0 }
    }
    , contributors: M.singleton uid $ Contributor'
    { userId: uid
    , handle: "Joe"
    , joinedOn: t
    , timeDevoted: Hours 100.0
    , revShare: 55 R.% 100
    }
    }
    [5.10399]
    [5.6985]
    { getProjectDetail:
    \pid -> do
    t <- liftEffect nowDateTime
    uid <- UserId <$> liftEffect genUUID
    pure <<< Right <<< Just
    $ ProjectDetail'
    { project:
    Project'
    { projectId: pid
    , projectName: "Fake Project"
    , inceptionDate: t
    , initiator: uid
    , depf: LinearDepreciation { undep: Days 30.0, dep: Days 300.0 }
    }
    , contributors:
    M.singleton uid
    $ Contributor'
    { userId: uid
    , handle: "Joe"
    , joinedOn: t
    , timeDevoted: Hours 100.0
    , revShare: 55.0 R.% 100.0
    }
    }
  • edit in client/src/Aftok/Signup.purs at line 9
    [5.5110]
    [5.5111]
    import Data.Map as M
    import Data.Tuple (Tuple(..))
  • edit in client/src/Aftok/Signup.purs at line 22
    [5.451][5.451:487]()
    import Web.UIEvent.MouseEvent as ME
  • edit in client/src/Aftok/Signup.purs at line 43
    [5.5575]
    [5.707]
    data SignupField
    = UsernameField
    | PasswordField
    | ConfirmField
    | EmailField
    | ZAddrField
    | CaptchaField
    | ErrField
    derive instance signupFieldEq :: Eq SignupField
    derive instance signupFieldOrd :: Ord SignupField
  • replacement in client/src/Aftok/Signup.purs at line 70
    [5.14711][5.14711:14751]()
    , signupErrors :: Array SignupError
    [5.14711]
    [5.14751]
    , signupErrors :: M.Map SignupField SignupError
  • edit in client/src/Aftok/Signup.purs at line 80
    [5.1255][5.1255:1280]()
    | Signin ME.MouseEvent
  • replacement in client/src/Aftok/Signup.purs at line 122
    [5.15690][5.15690:15713]()
    , signupErrors: []
    [5.15690]
    [5.15713]
    , signupErrors: M.empty
  • replacement in client/src/Aftok/Signup.purs at line 138
    [5.16356][5.16356:16471]()
    [ HH.text "You can use either an email address or zcash payment address for account recovery." ]
    [5.16356]
    [5.16471]
    [ HH.text "You can use either an email address or shielded zcash address for account recovery." ]
  • replacement in client/src/Aftok/Signup.purs at line 150
    [5.16989][5.16989:17654]()
    [ HH.label [ P.for "username" ] [ HH.text "Username" ]
    , HH.input
    [ P.type_ P.InputText
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "username"
    , P.placeholder "Choose a handle (username)"
    , P.required true
    , P.autofocus true
    , P.value (fromMaybe "" st.username)
    , E.onValueInput (Just <<< SetUsername)
    ]
    ]
    [5.16989]
    [5.17654]
    $ [ HH.label [ P.for "username" ] [ HH.text "Username" ]
    , HH.input
    [ P.type_ P.InputText
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "username"
    , P.placeholder "Choose a handle (username)"
    , P.required true
    , P.autofocus true
    , P.value (fromMaybe "" st.username)
    , E.onValueInput (Just <<< SetUsername)
    ]
    ]
    <> signupErrors UsernameField st
  • replacement in client/src/Aftok/Signup.purs at line 165
    [5.17758][5.17758:18901]()
    [ HH.label [ P.for "password" ] [ HH.text "Password" ]
    , HH.input
    [ P.type_ P.InputPassword
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "password"
    , P.placeholder "Enter a unique password"
    , P.required true
    , P.value (fromMaybe "" st.password)
    , E.onValueInput (Just <<< SetPassword)
    ]
    , HH.input
    [ P.type_ P.InputPassword
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "passwordConfirm"
    , P.placeholder "Enter a unique password"
    , P.required true
    , P.value (fromMaybe "" st.passwordConfirm)
    , E.onValueInput (Just <<< ConfirmPassword)
    ]
    ]
    [5.17758]
    [5.18901]
    $ [ HH.label [ P.for "password" ] [ HH.text "Password" ]
    , HH.input
    [ P.type_ P.InputPassword
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "password"
    , P.placeholder "Enter a unique password"
    , P.required true
    , P.value (fromMaybe "" st.password)
    , E.onValueInput (Just <<< SetPassword)
    ]
    ]
    <> signupErrors PasswordField st
    <> [ HH.input
    [ P.type_ P.InputPassword
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "passwordConfirm"
    , P.placeholder "Enter a unique password"
    , P.required true
    , P.value (fromMaybe "" st.passwordConfirm)
    , E.onValueInput (Just <<< ConfirmPassword)
    ]
    ]
    <> signupErrors ConfirmField st
  • replacement in client/src/Aftok/Signup.purs at line 220
    [5.20197][5.20197:20323]()
    Acc.UsernameCheckOK -> pure unit
    Acc.UsernameCheckTaken -> H.modify_ (_ { signupErrors = [ UsernameTaken ] })
    [5.20197]
    [5.20323]
    Acc.UsernameCheckOK -> H.modify_ (\st -> st { signupErrors = M.delete UsernameField st.signupErrors })
    Acc.UsernameCheckTaken -> H.modify_ (\st -> st { signupErrors = M.insert UsernameField UsernameTaken st.signupErrors })
  • replacement in client/src/Aftok/Signup.purs at line 225
    [5.20439][5.20439:20533]()
    when (any (notEq pass) confirm) (H.modify_ (_ { signupErrors = [ PasswordMismatch ] }))
    [5.20439]
    [5.20533]
    if (any (notEq pass) confirm) then
    (H.modify_ (\st -> st { signupErrors = M.insert ConfirmField PasswordMismatch st.signupErrors }))
    else
    (H.modify_ (\st -> st { signupErrors = M.delete ConfirmField st.signupErrors }))
  • replacement in client/src/Aftok/Signup.purs at line 231
    [5.20622][5.20622:20758]()
    password <- H.gets (_.password)
    when (any (notEq confirm) password) (H.modify_ (_ { signupErrors = [ PasswordMismatch ] }))
    [5.20622]
    [5.20758]
    pass <- H.gets (_.password)
    if (any (notEq confirm) pass) then
    (H.modify_ (\st -> st { signupErrors = M.insert ConfirmField PasswordMismatch st.signupErrors }))
    else
    (H.modify_ (\st -> st { signupErrors = M.delete ConfirmField st.signupErrors }))
  • replacement in client/src/Aftok/Signup.purs at line 238
    [5.20893][5.20893:21353]()
    SetRecoveryZAddr addr -> do
    lift $ system.log "Switching to signin..."
    zres <- lift $ caps.checkZAddr addr
    H.modify_ (_ { recoveryZAddr = Just addr })
    case zres of
    Acc.ZAddrCheckValid -> pure unit
    Acc.ZAddrCheckInvalid -> H.modify_ (_ { signupErrors = [ ZAddrInvalid ] })
    Signin ev -> do
    lift $ system.log "Switching to signin..."
    lift $ system.preventDefault (ME.toEvent ev)
    H.raise SigninNav
    [5.20893]
    [5.21353]
    SetRecoveryZAddr addr ->
    --lift $ system.log "Switching to signin..."
    when (addr /= "")
    $ do
    zres <- lift $ caps.checkZAddr addr
    H.modify_ (_ { recoveryZAddr = Just addr })
    case zres of
    Acc.ZAddrCheckValid -> H.modify_ (\st -> st { signupErrors = M.delete ZAddrField st.signupErrors })
    Acc.ZAddrCheckInvalid -> H.modify_ (\st -> st { signupErrors = M.insert ZAddrField ZAddrInvalid st.signupErrors })
  • replacement in client/src/Aftok/Signup.purs at line 258
    [5.22076][5.22076:22128]()
    lift $ system.log "Sending signup request..."
    [5.22076]
    [5.22128]
    --lift $ system.log "Sending signup request..."
  • replacement in client/src/Aftok/Signup.purs at line 271
    [5.22518][5.22518:22621]()
    lift $ system.log "Got signup HTTP error."
    H.modify_ (_ { signupErrors = errors })
    [5.22518]
    [5.22621]
    let
    errMap = M.fromFoldable $ map (\e -> Tuple (errField e) e) errors
    --lift $ system.log "Got signup HTTP error."
    H.modify_ (_ { signupErrors = errMap })
  • replacement in client/src/Aftok/Signup.purs at line 277
    [5.22690][5.22690:22762]()
    lift <<< system.log $ "Got signup response " <> show response
    [5.22690]
    [5.22762]
    --lift <<< system.log $ "Got signup response " <> show response
  • replacement in client/src/Aftok/Signup.purs at line 280
    [5.22857][5.22857:23215]()
    Acc.CaptchaInvalid -> H.modify_ (_ { signupErrors = [ CaptchaError ] })
    Acc.ZAddrInvalid -> H.modify_ (_ { signupErrors = [ ZAddrInvalid ] })
    Acc.UsernameTaken -> H.modify_ (_ { signupErrors = [ UsernameTaken ] })
    Acc.ServiceError c m -> H.modify_ (_ { signupErrors = [ APIError { status: c, message: m } ] })
    [5.22857]
    [5.7340]
    Acc.CaptchaInvalid -> H.modify_ (_ { signupErrors = M.singleton CaptchaField CaptchaError })
    Acc.ZAddrInvalid -> H.modify_ (_ { signupErrors = M.singleton ZAddrField ZAddrInvalid })
    Acc.UsernameTaken -> H.modify_ (_ { signupErrors = M.singleton UsernameField UsernameTaken })
    Acc.ServiceError c m -> H.modify_ (_ { signupErrors = M.singleton ErrField (APIError { status: c, message: m }) })
    errField :: SignupError -> SignupField
    errField = case _ of
    UsernameRequired -> UsernameField
    UsernameTaken -> UsernameField
    PasswordRequired -> PasswordField
    ConfirmRequired -> ConfirmField
    PasswordMismatch -> ConfirmField
    EmailRequired -> EmailField
    ZAddrRequired -> ZAddrField
    ZAddrInvalid -> ZAddrField
    CaptchaError -> CaptchaField
    APIError _ -> ErrField
    signupErrors :: forall i a. SignupField -> SignupState -> Array (HH.HTML i a)
    signupErrors field st = case M.lookup field st.signupErrors of
    (Just UsernameRequired) -> err "Username is required"
    (Just UsernameTaken) -> err "Username is already taken"
    (Just PasswordRequired) -> err "Password is required"
    (Just ConfirmRequired) -> err "Confirm your password"
    (Just PasswordMismatch) -> err "Passwords do not match"
    (Just EmailRequired) -> err "Email address is required"
    (Just ZAddrRequired) -> err "Zcash address is required"
    (Just ZAddrInvalid) -> err "Not a valid Zcash address"
    (Just CaptchaError) -> err "Captcha failed; please try again"
    _ -> []
    where
    err str = [ HH.div_ [ HH.span [ P.classes (ClassName <$> [ "badge", "badge-danger-soft" ]) ] [ HH.text str ] ] ]
  • replacement in client/src/Aftok/Signup.purs at line 328
    [5.23670][5.23670:23702]()
    [ HH.text "Email" ]
    [5.23670]
    [5.23702]
    $ [ HH.text "Email" ]
  • replacement in client/src/Aftok/Signup.purs at line 350
    [5.7363][5.7363:7426](),[5.7426][5.24447:24744](),[5.24744][5.7708:7716](),[5.7708][5.7708:7716]()
    [ HH.label [ P.for "email" ] [ HH.text "Email Address" ]
    , HH.input
    [ P.type_ P.InputEmail
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "email"
    , P.placeholder "name@address.com"
    , P.value (fromMaybe "" st.recoveryEmail)
    , E.onValueInput (Just <<< SetRecoveryEmail)
    ]
    ]
    [5.7363]
    [5.7716]
    $ [ HH.label [ P.for "email" ] [ HH.text "Email Address" ]
    , HH.input
    [ P.type_ P.InputEmail
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "email"
    , P.placeholder "name@address.com"
    , P.value (fromMaybe "" st.recoveryEmail)
    , E.onValueInput (Just <<< SetRecoveryEmail)
    ]
    ]
    <> signupErrors EmailField st
  • replacement in client/src/Aftok/Signup.purs at line 364
    [5.7779][5.24757:25082](),[5.25082][5.7975:7987](),[5.7975][5.7975:7987](),[5.7987][5.25083:25381](),[5.1342][5.8072:8084](),[5.25381][5.8072:8084](),[5.8072][5.8072:8084](),[5.8389][5.8389:8397]()
    [ HH.label
    [ P.for "zaddr" ]
    [ HH.text "Zcash Shielded Address"
    , HH.a
    [ P.attr (AttrName "data-toggle") "modal"
    , P.href "#modalAboutZAddr"
    ]
    [ HH.img [ P.src "/assets/img/icons/duotone-icons/Code/Info-circle.svg" ]
    ]
    ]
    , HH.input
    [ P.type_ P.InputText
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "email"
    , P.placeholder "Enter a Zcash shielded address"
    , P.value (fromMaybe "" st.recoveryZAddr)
    , E.onValueInput (Just <<< SetRecoveryZAddr)
    ]
    ]
    [5.7779]
    [5.2735]
    $ [ HH.label
    [ P.for "zaddr" ]
    [ HH.text "Zcash Shielded Address"
    , HH.a
    [ P.attr (AttrName "data-toggle") "modal"
    , P.href "#modalAboutZAddr"
    ]
    [ HH.img [ P.src "/assets/img/icons/duotone-icons/Code/Info-circle.svg" ]
    ]
    ]
    , HH.input
    [ P.type_ P.InputText
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "email"
    , P.placeholder "Enter a Zcash shielded address"
    , P.value (fromMaybe "" st.recoveryZAddr)
    , E.onValueInput (Just <<< SetRecoveryZAddr)
    ]
    ]
    <> signupErrors ZAddrField st
  • replacement in client/src/Aftok/Signup.purs at line 387
    [5.25398][5.2785:2835](),[5.2785][5.2785:2835]()
    { checkUsername: \_ -> pure Acc.UsernameCheckOK
    [5.25398]
    [5.2835]
    { checkUsername: Acc.checkUsername
  • replacement in client/src/Aftok/Timeline.purs at line 169
    [5.28037][5.6055:6314]()
    [ HH.slot
    _projectList
    unit
    (ProjectList.component system pcaps)
    st.selectedProject
    (Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))
    [5.28037]
    [5.6314]
    [ HH.slot
    _projectList
    unit
    (ProjectList.component system pcaps)
    st.selectedProject
    (Just <<< (\(ProjectList.ProjectChange p) -> ProjectSelected p))
  • edit in client/src/Aftok/Types.purs at line 86
    [5.8230]
    [5.8230]
    derive instance userIdEq :: Eq UserId
    derive instance userIdOrd :: Ord UserId
  • edit in client/src/Aftok/Types.purs at line 91
    [5.8231][5.8231:8270](),[5.8270][5.10401:10442]()
    derive instance userIdEq :: Eq UserId
    derive instance userIdOrd :: Ord UserId
  • replacement in client/src/Aftok/Types.purs at line 95
    [5.7038][5.7038:7070]()
    uuidStr <- decodeJson json
    [5.7038]
    [5.7070]
    uuidStr <- decodeJson json
  • edit in client/src/Aftok/Types.purs at line 102
    [5.5717]
    [5.7142]
  • edit in client/src/Aftok/Types.purs at line 104
    [5.7188]
    [5.7188]
  • replacement in client/src/Aftok/Types.purs at line 109
    [5.7327][5.7327:7359]()
    uuidStr <- decodeJson json
    [5.7327]
    [5.7359]
    uuidStr <- decodeJson json
  • edit in client/src/Aftok/Types.purs at line 112
    [5.11909][5.7437:7438]()
  • edit in client/src/Aftok/Types.purs at line 121
    [5.3198][5.37638:37639](),[5.37638][5.37638:37639]()
  • replacement in client/src/Main.purs at line 44
    [5.38720][5.1570:1611]()
    overview = Overview.mockCapability
    [5.38720]
    [5.1684]
    overview = Overview.apiCapability
  • replacement in client/src/Main.purs at line 170
    [5.41379][5.1612:1822]()
    pure $ case result of
    Acc.LoginForbidden -> VLogin
    Acc.LoginError _ -> VLogin
    _ -> case other of
    "timeline" -> VTimeline
    _ -> VOverview
    [5.41379]
    [5.41526]
    pure
    $ case result of
    Acc.LoginForbidden -> VLogin
    Acc.LoginError _ -> VLogin
    _ -> case other of
    "timeline" -> VTimeline
    _ -> VOverview
  • replacement in client/src/Main.purs at line 178
    [5.41550][5.41550:41615]()
    SignupAction (Signup.SignupComplete _) -> navigate VTimeline
    [5.41550]
    [5.41615]
    SignupAction (Signup.SignupComplete _) -> navigate VOverview
  • replacement in client/src/Main.purs at line 180
    [5.41670][5.41670:41732]()
    LoginAction (Login.LoginComplete _) -> navigate VTimeline
    [5.41670]
    [5.41732]
    LoginAction (Login.LoginComplete _) -> navigate VOverview
  • replacement in client/src/Main.purs at line 225
    [5.42931][5.42931:42959]()
    [ HH.text "Aftok" ]
    [5.42931]
    [5.42959]
    [ HH.a [ P.href "/" ] [ HH.text "Aftok" ] ]
  • edit in docker-compose.yml at line 31
    [5.9859][5.1372:1642]()
    target: /opt/aftok/client/dist-volume
    aftok-reactclient:
    image: aftok/aftok-reactclient:latest
    container_name: aftok-reactclient
    entrypoint: /opt/aftok/aftok-client-cp.sh build
    volumes:
    - type: volume
    source: v_aftok-reactclient
  • edit in docker-compose.yml at line 65
    [5.2106][5.1667:1757](),[5.1667][5.1667:1757](),[5.1757][5.2788:2812](),[5.2788][5.2788:2812]()
    - type: volume
    source: v_aftok-reactclient
    target: /opt/static/app2
    read_only: true
  • edit in docker-compose.yml at line 111
    [5.10513][5.1758:1781]()
    v_aftok-reactclient:
  • replacement in lib/Aftok/Billing.hs at line 10
    [5.8452][5.8452:8526]()
    import Data.Thyme.Clock as C
    import Data.Thyme.Time as T
    import Data.UUID
    [5.8452]
    [5.981]
    import qualified Data.Thyme.Clock as C
    import qualified Data.Thyme.Time as T
    import Data.UUID (UUID)
  • replacement in lib/Aftok/Billing.hs at line 62
    [5.5671][5.8977:9007](),[5.8977][5.8977:9007](),[5.9007][5.5672:5721]()
    _gracePeriod :: Days,
    _requestExpiryPeriod :: NominalDiffTime,
    [5.5671]
    [5.9064]
    _gracePeriod :: T.Days,
    _requestExpiryPeriod :: T.NominalDiffTime,
  • replacement in lib/Aftok/Billing.hs at line 87
    [5.9309][5.6030:6095]()
    _startTime :: UTCTime,
    _endTime :: Maybe UTCTime
    [5.9309]
    [5.9378]
    _startTime :: C.UTCTime,
    _endTime :: Maybe C.UTCTime
  • replacement in lib/Aftok/Database/PostgreSQL/Events.hs at line 26
    [5.34477][5.10556:10590]()
    KeyedLogEntry(KeyedLogEntry),
    [5.34477]
    [5.5021]
    KeyedLogEntry (KeyedLogEntry),
  • replacement in lib/Aftok/Database/PostgreSQL/Events.hs at line 54
    [5.34844][5.10677:10933]()
    import Aftok.TimeLog (
    WorkIndex,
    LogEntry(LogEntry),
    LogEvent(..),
    EventId(..),
    EventAmendment(..),
    AmendmentId(..),
    eventMeta,
    _ModTime,
    _EventId,
    _AmendmentId,
    creditTo,
    eventTime,
    event,
    workIndex,
    eventName,
    nameEvent,
    [5.34844]
    [5.10933]
    import Aftok.TimeLog
    ( AmendmentId (..),
    EventAmendment (..),
    EventId (..),
    LogEntry (LogEntry),
    LogEvent (..),
    WorkIndex,
    _AmendmentId,
    _EventId,
    _ModTime,
    creditTo,
    event,
    eventMeta,
    eventName,
    eventTime,
    nameEvent,
    workIndex,
  • edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 11
    [5.57438]
    [5.57438]
    findUserProjectDetail,
  • edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 27
    [5.57748]
    [5.57748]
    utcParser,
  • edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 33
    [5.57835]
    [5.57835]
    import qualified Data.Thyme.Clock as C
  • edit in lib/Aftok/Database/PostgreSQL/Users.hs at line 67
    [5.58835]
    [5.58835]
    findUserProjectDetail :: UserId -> ProjectId -> DBM (Maybe (User, C.UTCTime))
    findUserProjectDetail (UserId uid) (ProjectId pid) = do
    headMay
    <$> pquery
    ((,) <$> userParser <*> utcParser)
    [sql| SELECT u.handle, u.recovery_email, u.recovery_zaddr, p.joined_at
    FROM users u
    JOIN project_companions p on p.user_id = u.id
    WHERE u.id = ? AND p.project_id = ? |]
    (uid, pid)
  • edit in lib/Aftok/Database/PostgreSQL.hs at line 57
    [5.61899]
    [5.61899]
    (FindUserProjectDetail uid pid) -> Q.findUserProjectDetail uid pid
  • edit in lib/Aftok/Database.hs at line 30
    [5.64111]
    [5.64111]
    HasLogEntry,
  • edit in lib/Aftok/Database.hs at line 33
    [5.64140][5.16657:16674]()
    HasLogEntry,
  • replacement in lib/Aftok/Database.hs at line 57
    [5.16693][5.16693:16786]()
    data KeyedLogEntry = KeyedLogEntry {
    _workId :: !EventId,
    _logEntry :: !LogEntry
    }
    [5.16693]
    [5.16786]
    data KeyedLogEntry
    = KeyedLogEntry
    { _workId :: !EventId,
    _logEntry :: !LogEntry
    }
  • edit in lib/Aftok/Database.hs at line 77
    [5.27065]
    [5.27065]
    FindUserProjectDetail :: UserId -> ProjectId -> DBOp (Maybe (User, C.UTCTime))
  • edit in lib/Aftok/Database.hs at line 164
    [77.5045]
    [78.2715]
    findUserProjectDetail :: (MonadDB m) => UserId -> ProjectId -> MaybeT m (User, C.UTCTime)
    findUserProjectDetail uid pid = MaybeT . liftdb $ FindUserProjectDetail uid pid
  • replacement in lib/Aftok/Database.hs at line 273
    [5.17495][5.17495:17600]()
    in if uid' == uid
    then liftdb act
    else raiseOpForbidden uid UserNotEventLogger act
    [5.17495]
    [5.1146]
    in if uid' == uid
    then liftdb act
    else raiseOpForbidden uid UserNotEventLogger act
  • replacement in lib/Aftok/Payments/Util.hs at line 31
    [5.80386][5.80386:80411]()
    m TL.FractionalPayouts
    [5.80386]
    [5.80411]
    m TL.WorkShares
  • replacement in lib/Aftok/Payments/Util.hs at line 52
    [5.81142][5.81142:81168]()
    TL.FractionalPayouts ->
    [5.81142]
    [5.81168]
    TL.WorkShares ->
  • replacement in lib/Aftok/Payments/Util.hs at line 59
    [5.81401][5.6705:6766](),[5.6766][5.81478:81665](),[5.81478][5.81478:81665]()
    let scaled frac = note AmountInvalid $ cscale amt frac
    payoutFractions <- except $ traverse scaled (payouts ^. TL._Payouts)
    fromListWith (<>) . join <$> traverse (uncurry (getPayoutAmounts t currency mp)) (assocs payoutFractions)
    [5.81401]
    [5.81665]
    let scaled ws = note AmountInvalid $ cscale amt (ws ^. TL.wsShare)
    payoutFractions <- except $ traverse scaled (payouts ^. TL.creditToShares)
    fromListWith (<>) . join
    <$> traverse (uncurry (getPayoutAmounts t currency mp)) (assocs payoutFractions)
  • replacement in lib/Aftok/TimeLog/Serialization.hs at line 21
    [5.29760][5.50034:50082]()
    LinearDepreciation (Months up) (Months dp) ->
    [5.29760]
    [5.50082]
    LinearDepreciation undep dep ->
  • replacement in lib/Aftok/TimeLog/Serialization.hs at line 24
    [5.50143][5.50143:50202]()
    "arguments" .= object ["undep" .= up, "dep" .= dp]
    [5.50143]
    [5.50202]
    "arguments" .= object ["undep" .= undep, "dep" .= dep]
  • replacement in lib/Aftok/TimeLog/Serialization.hs at line 34
    [5.30220][5.30220:30269](),[5.30269][5.50248:50293]()
    let undep = Months <$> (args .: "undep")
    dep = Months <$> (args .: "dep")
    [5.30220]
    [5.50293]
    let undep = (args .: "undep")
    dep = (args .: "dep")
  • replacement in lib/Aftok/TimeLog.hs at line 6
    [5.4159][5.50409:50428](),[5.50428][5.19028:19050]()
    ( LogEntry (..),
    HasLogEntry (..),
    [5.4159]
    [5.50468]
    ( module Aftok.TimeLog,
  • edit in lib/Aftok/TimeLog.hs at line 11
    [5.50569][5.50569:50588](),[5.50588][5.19051:19082](),[5.19082][5.50588:50893](),[5.50588][5.50588:50893](),[5.50893][5.90213:90236](),[5.90236][5.50893:50930](),[5.50893][5.50893:50930]()
    LogEvent (..),
    _StartWork,
    _StopWork,
    eventName,
    nameEvent,
    eventTime,
    WorkIndex (WorkIndex),
    _WorkIndex,
    workIndex,
    DepF,
    toDepF,
    EventId (EventId),
    _EventId,
    ModTime (ModTime),
    _ModTime,
    EventAmendment (..),
    AmendmentId (AmendmentId),
    _AmendmentId,
    Payouts (..),
    _Payouts,
    FractionalPayouts,
    payouts,
    linearDepreciation,
  • replacement in lib/Aftok/TimeLog.hs at line 16
    [5.51001][5.51001:51021](),[5.51021][5.6807:6836]()
    import Control.Lens
    import Data.AdditiveGroup ()
    [5.50972]
    [5.51047]
    ( CreditTo (..),
    DepreciationFunction (..),
    _CreditToAccount,
    _CreditToProject,
    _CreditToUser,
    )
    import Control.Lens ((.~), (^.), makeClassy, makeLenses, makePrisms, view)
  • replacement in lib/Aftok/TimeLog.hs at line 24
    [5.51070][5.51070:51094](),[5.51183][5.51183:51209]()
    import Data.AffineSpace
    import Data.Foldable as F
    [5.51070]
    [5.19083]
    import Data.AffineSpace ((.-.))
    import qualified Data.Foldable as F
  • replacement in lib/Aftok/TimeLog.hs at line 27
    [5.19122][5.51506:51535](),[5.51506][5.51506:51535]()
    import Data.Thyme.Clock as C
    [5.19122]
    [5.19123]
    import qualified Data.Thyme.Clock as C
    import qualified Data.Thyme.Time as C
  • replacement in lib/Aftok/TimeLog.hs at line 99
    [5.5971][5.90533:90578]()
    newtype Payouts a = Payouts (Map CreditTo a)
    [5.5971]
    [5.52471]
    data WorkShare a
    = WorkShare
    { _wsLogged :: NDT,
    _wsDepreciated :: NDT,
    _wsShare :: a
    }
  • replacement in lib/Aftok/TimeLog.hs at line 106
    [5.5110][5.6021:6042](),[5.31997][5.6021:6042](),[5.52472][5.6021:6042](),[5.6021][5.6021:6042]()
    makePrisms ''Payouts
    [5.52472]
    [5.6042]
    makeLenses ''WorkShare
  • replacement in lib/Aftok/TimeLog.hs at line 108
    [5.6043][5.90579:90621]()
    type FractionalPayouts = Payouts Rational
    [5.6043]
    [5.90621]
    data WorkShares
    = WorkShares
    { _loggedTotal :: NDT,
    _creditToShares :: Map CreditTo (WorkShare Rational)
    }
    makeLenses ''WorkShares
  • replacement in lib/Aftok/TimeLog.hs at line 126
    [5.52577][5.52577:52658](),[5.52658][5.19567:19761]()
    -- - produce the total, depreciated length of work to be credited to an address.
    workCredit :: (Foldable f, HasLogEntry le) => DepF -> C.UTCTime -> f (Interval le) -> NDT
    workCredit df ptime ivals = getSum $ F.foldMap (Sum . df ptime . fmap (view $ event . eventTime)) ivals
    [5.52577]
    [5.1576]
    -- - produce the total length and depreciated length of work to be credited to an recipient.
    workCredit :: (Foldable f, HasLogEntry le) => DepF -> C.UTCTime -> f (Interval le) -> (NDT, NDT)
    workCredit depf ptime ivals =
    bimap getSum getSum $ F.foldMap ((Sum . ilen &&& Sum . depf ptime) . fmap (view $ event . eventTime)) ivals
  • replacement in lib/Aftok/TimeLog.hs at line 135
    [5.90753][5.19762:19859]()
    payouts :: forall le. (HasLogEntry le) => DepF -> C.UTCTime -> WorkIndex le -> FractionalPayouts
    [5.90753]
    [5.4834]
    payouts :: forall le. (HasLogEntry le) => DepF -> C.UTCTime -> WorkIndex le -> WorkShares
  • replacement in lib/Aftok/TimeLog.hs at line 137
    [5.4871][5.19860:19938]()
    let addIntervalDiff :: (Foldable f) => NDT -> f (Interval le) -> (NDT, NDT)
    [5.4871]
    [5.12318]
    let addIntervalDiff :: (Foldable f) => NDT -> f (Interval le) -> (NDT, WorkShare ())
  • replacement in lib/Aftok/TimeLog.hs at line 139
    [5.12354][5.52852:52908]()
    (^+^ total) &&& id $ workCredit dep ptime ivals
    [5.12354]
    [5.1333]
    let (logged, depreciated) = workCredit dep ptime ivals
    in (total ^+^ depreciated, WorkShare logged depreciated ())
  • replacement in lib/Aftok/TimeLog.hs at line 142
    [5.1402][5.52909:52977]()
    in Payouts $ fmap ((/ toSeconds totalTime) . toSeconds) keyTimes
    [5.1402]
    [5.1581]
    withShareFraction t = t & wsShare .~ (C.toSeconds (t ^. wsDepreciated) / C.toSeconds totalTime)
    in WorkShares totalTime (fmap withShareFraction keyTimes)
  • replacement in lib/Aftok/TimeLog.hs at line 203
    [5.53991][5.53991:54167]()
    -- | The number of initial months during which no depreciation occurs
    Months ->
    -- | The number of months over which each logged interval will be depreciated
    Months ->
    [5.53991]
    [5.54167]
    -- | The number of initial days during which no depreciation occurs
    C.Days ->
    -- | The number of days over which each logged interval will be depreciated
    C.Days ->
  • replacement in lib/Aftok/TimeLog.hs at line 210
    [5.5170][5.2404:2508](),[5.9933][5.2404:2508](),[5.2404][5.2404:2508]()
    let monthsLength :: Months -> NDT
    monthsLength (Months i) = fromSeconds $ 60 * 60 * 24 * 30 * i
    [5.5170]
    [5.2509]
    let daysLength :: C.Days -> NDT
    daysLength d = C.fromSeconds $ 60 * 60 * 24 * d
  • replacement in lib/Aftok/TimeLog.hs at line 213
    [5.2537][5.5171:5246]()
    maxDepreciable = monthsLength undepLength ^+^ monthsLength depLength
    [5.2537]
    [5.2614]
    maxDepreciable = daysLength undepLength ^+^ daysLength depLength
  • replacement in lib/Aftok/TimeLog.hs at line 216
    [5.54248][5.54248:54289]()
    if dt < monthsLength undepLength
    [5.54248]
    [5.54289]
    if dt < daysLength undepLength
  • replacement in lib/Aftok/TimeLog.hs at line 219
    [5.54321][5.54321:54420]()
    toSeconds (max zeroV (maxDepreciable ^-^ dt))
    / toSeconds maxDepreciable
    [5.54321]
    [5.54420]
    C.toSeconds (max zeroV (maxDepreciable ^-^ dt))
    / C.toSeconds maxDepreciable
  • replacement in lib/Aftok/Types.hs at line 10
    [5.54639][5.54639:54659](),[5.54689][5.54689:54735]()
    import Data.Eq (Eq)
    import Data.Ord (Ord)
    import Data.Text (Text)
    [5.54639]
    [5.54735]
    import qualified Data.Thyme.Time as C
  • edit in lib/Aftok/Types.hs at line 12
    [5.54759][5.54759:54808]()
    import Text.Show (Show)
    import Prelude (Integer)
  • replacement in lib/Aftok/Types.hs at line 63
    [5.33915][5.33915:33976]()
    data DepreciationFunction = LinearDepreciation Months Months
    [5.1037]
    [5.33976]
    data DepreciationFunction = LinearDepreciation C.Days C.Days
  • edit in lib/Aftok/Types.hs at line 65
    [5.33998][5.33998:34053]()
    newtype Months = Months Integer
    deriving (Eq, Show)
  • file move: list_project_contributors.sh (---r------)get_project_detail.sh (---r------)
    [5.1220]
    [5.907]
  • replacement in scripts/get_project_detail.sh at line 24
    [5.1213][5.1213:1268]()
    "https://$AFTOK_HOST/api/projects/$PID/contributors"
    [5.1213]
    "https://$AFTOK_HOST/api/projects/$PID/detail"
  • edit in server/Aftok/Snaplet/Projects.hs at line 3
    [5.2397]
    [5.2397]
    {-# LANGUAGE TupleSections #-}
    {-# LANGUAGE TypeApplications #-}
  • replacement in server/Aftok/Snaplet/Projects.hs at line 11
    [5.63460][5.1327:1356]()
    listContributorsHandler,
    [5.63460]
    [5.1356]
    projectDetailGetHandler,
  • edit in server/Aftok/Snaplet/Projects.hs at line 14
    [5.27435]
    [5.27435]
    payoutsHandler,
    payoutsJSON,
  • edit in server/Aftok/Snaplet/Projects.hs at line 17
    [5.27455]
    [5.52743]
    projectDetailJSON,
  • replacement in server/Aftok/Snaplet/Projects.hs at line 23
    [5.63503][5.27456:27509]()
    import Aftok.Json (idValue, identifiedJSON, obj, v1)
    [5.63503]
    [5.63503]
    import Aftok.Json (creditToJSON, idValue, identifiedJSON, obj, v1)
  • edit in server/Aftok/Snaplet/Projects.hs at line 28
    [5.63598]
    [5.63598]
    import Aftok.TimeLog
    ( WorkShare,
    WorkShares,
    creditToShares,
    payouts,
    toDepF,
    wsLogged,
    wsShare,
    )
  • replacement in server/Aftok/Snaplet/Projects.hs at line 40
    [5.63698][5.27510:27549]()
    import Control.Lens ((^.), _1, _2, to)
    [5.63698]
    [5.63718]
    import Control.Lens ((^.), _1, _2, makeLenses, to)
  • edit in server/Aftok/Snaplet/Projects.hs at line 45
    [5.63837]
    [5.1520]
    import qualified Data.Map.Strict as M
  • edit in server/Aftok/Snaplet/Projects.hs at line 54
    [5.64089]
    [5.2485]
    import Time.Types (Hours (..))
  • replacement in server/Aftok/Snaplet/Projects.hs at line 59
    [5.1651][5.34611:34636](),[5.4054][5.34611:34636]()
    parseJSON (Object v) =
    [5.1651]
    [5.53505]
    parseJSON (A.Object v) =
  • edit in server/Aftok/Snaplet/Projects.hs at line 63
    [5.2915]
    [5.18010]
    data Contributor
    = Contributor
    { _userId :: UserId,
    _handle :: UserName,
    _joinedOn :: C.UTCTime,
    _timeDevoted :: Hours,
    _revenueShare :: Rational
    }
    makeLenses ''Contributor
    data ProjectDetail
    = ProjectDetail
    { _pdProject :: Project,
    _pdContributors :: M.Map UserId Contributor
    }
    makeLenses ''ProjectDetail
  • replacement in server/Aftok/Snaplet/Projects.hs at line 103
    [5.1653][5.1653:1865]()
    contributorJSON :: (UserId, UserName, C.UTCTime) -> Value
    contributorJSON (uid, uname, t) =
    object
    [ "user_id" .= idValue _UserId uid,
    "username" .= (uname ^. _UserName),
    "joined_at" .= t
    ]
    [5.1653]
    [5.1865]
    projectDetailGetHandler :: S.Handler App App ProjectDetail
    projectDetailGetHandler = do
    uid <- requireUserId
    pid <- requireProjectId
    project <-
    fromMaybeT
    (snapError 404 $ "Project not found for id " <> show pid)
    (mapMaybeT snapEval $ findUserProject uid pid)
    widx <- snapEval $ readWorkIndex pid uid
    ptime <- liftIO $ C.getCurrentTime
    let p = payouts (toDepF $ project ^. depf) ptime widx
    toContributorRecord = \case
    (CreditToUser uid', ws) -> do
    (user, joinedOn') <-
    fromMaybeT
    (snapError 500 $ "No user record found for logged-in user.")
    (mapMaybeT snapEval $ findUserProjectDetail uid pid)
    pure . Just . (uid',) $
    Contributor
    { _userId = uid',
    _handle = user ^. username,
    _joinedOn = joinedOn',
    _timeDevoted = Hours . (`div` 360) . round . C.toSeconds' $ ws ^. wsLogged,
    _revenueShare = ws ^. wsShare
    }
    _ -> pure Nothing
    contributorRecords <-
    fmap (M.fromList . catMaybes)
    . traverse toContributorRecord
    $ M.assocs (p ^. creditToShares)
    pure $
    ProjectDetail
    { _pdProject = project,
    _pdContributors = contributorRecords
    }
  • replacement in server/Aftok/Snaplet/Projects.hs at line 139
    [5.1866][5.1866:1972]()
    listContributorsHandler :: S.Handler App App [(UserId, UserName, C.UTCTime)]
    listContributorsHandler = do
    [5.1866]
    [5.1972]
    payoutsHandler :: S.Handler App App WorkShares
    payoutsHandler = do
  • replacement in server/Aftok/Snaplet/Projects.hs at line 143
    [5.2021][5.2021:2066]()
    snapEval $ listProjectContributors pid uid
    [5.2021]
    [5.8936]
    project <-
    fromMaybeT
    (snapError 400 $ "Project not found for id " <> show pid)
    (mapMaybeT snapEval $ findUserProject uid pid)
    widx <- snapEval $ readWorkIndex pid uid
    ptime <- liftIO $ C.getCurrentTime
    pure $ payouts (toDepF $ project ^. depf) ptime widx
  • edit in server/Aftok/Snaplet/Projects.hs at line 209
    [5.65787]
    [5.27550]
    depfToJSON :: DepreciationFunction -> Value
    depfToJSON = \case
    LinearDepreciation undep dep ->
    object
    [ "type" .= ("LinearDepreciation" :: Text),
    "arguments" .= object ["undep" .= undep, "dep" .= dep]
    ]
  • replacement in server/Aftok/Snaplet/Projects.hs at line 218
    [5.27551][5.27551:27583]()
    projectJSON :: Project -> Value
    [5.27551]
    [5.27583]
    projectJSON :: Project -> A.Object
  • replacement in server/Aftok/Snaplet/Projects.hs at line 220
    [5.27599][5.27599:27766]()
    v1 $
    obj
    [ "projectName" .= (p ^. projectName),
    "inceptionDate" .= (p ^. inceptionDate),
    "initiator" .= (p ^. initiator . _UserId)
    ]
    [5.27599]
    [5.27766]
    obj
    [ "projectName" .= (p ^. projectName),
    "inceptionDate" .= (p ^. inceptionDate),
    "initiator" .= (p ^. initiator . _UserId),
    "depf" .= depfToJSON (p ^. depf)
    ]
  • replacement in server/Aftok/Snaplet/Projects.hs at line 228
    [5.27815][5.27815:27897]()
    qdbProjectJSON = identifiedJSON "project" (_1 . _ProjectId) (_2 . to projectJSON)
    [5.27815]
    qdbProjectJSON = identifiedJSON "project" (_1 . _ProjectId) (_2 . to (v1 . projectJSON))
    contributorJSON :: Contributor -> Value
    contributorJSON c =
    object
    [ "userId" .= idValue _UserId (c ^. userId),
    "username" .= (c ^. handle . _UserName),
    "joinedOn" .= (c ^. joinedOn),
    "timeDevoted" .= (c ^. timeDevoted . (to fromEnum)),
    "revenureShare"
    .= object
    [ "numerator" .= (c ^. revenueShare . (to numerator)),
    "denominator" .= (c ^. revenueShare . (to denominator))
    ]
    ]
    projectDetailJSON :: ProjectDetail -> A.Object
    projectDetailJSON detail =
    obj
    [ "project" .= Object (projectJSON $ detail ^. pdProject),
    "contributors" .= (M.elems $ fmap contributorJSON (detail ^. pdContributors))
    ]
    payoutsJSON :: WorkShares -> A.Object
    payoutsJSON ws =
    let payoutsRec :: (CreditTo, WorkShare Rational) -> Value
    payoutsRec (c, r) =
    object
    [ "creditTo" .= creditToJSON c,
    "payoutRatio" .= (r ^. wsShare),
    "payoutPercentage" .= (fromRational @Double (r ^. wsShare) * 100)
    ]
    in obj $ ["payouts" .= fmap payoutsRec (M.assocs (ws ^. creditToShares))]
  • edit in server/Aftok/Snaplet/Users.hs at line 8
    [5.65909]
    [5.65909]
    checkUsernameHandler,
  • replacement in server/Aftok/Snaplet/Users.hs at line 19
    [5.103472][2.1040:1116]()
    import Aftok.Database (acceptInvitation, createUser, findCurrentInvitation)
    [5.103472]
    [5.66138]
    import Aftok.Database
    ( acceptInvitation,
    createUser,
    findCurrentInvitation,
    findUserByName,
    )
  • edit in server/Aftok/Snaplet/Users.hs at line 128
    [5.4425]
    [5.103755]
    checkUsernameHandler :: S.Handler App App ()
    checkUsernameHandler = do
    params <- S.getParams
    uname <-
    maybe
    (snapError 400 "username parameter is required")
    (either (const $ snapError 400 "username must be valid UTF-8") (pure . UserName) . decodeUtf8')
    (listToMaybe =<< M.lookup "username" params)
    found <- snapEval (runMaybeT $ findUserByName uname)
    case found of
    Nothing -> pure ()
    Just _ -> snapError 400 "username is already taken"
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 14
    [5.70398][5.70398:70419]()
    import Aftok.Project
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 21
    [5.28122][5.28122:28145]()
    FractionalPayouts,
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 24
    [5.28202][5.28202:28220]()
    Payouts (..),
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 29
    [5.28302][5.28302:28327]()
    payouts,
    toDepF,
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 33
    [5.28366][5.28366:28378]()
    UserId,
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 34
    [5.28393]
    [5.28393]
    UserId,
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 38
    [5.70565][5.70565:70596]()
    import Aftok.Util (fromMaybeT)
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 39
    [5.28443][5.70623:70668](),[5.70623][5.70623:70668]()
    import Control.Monad.Trans.Maybe (mapMaybeT)
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 110
    [5.4950][5.15166:15167](),[5.15945][5.15166:15167](),[5.29601][5.15166:15167](),[5.15166][5.15166:15167](),[5.15167][5.104286:104340](),[5.18701][5.10183:10203](),[5.36147][5.10183:10203](),[5.104340][5.10183:10203](),[5.1704][5.10183:10203](),[5.10203][5.72174:72411](),[5.8682][5.3065:3102](),[5.13259][5.3065:3102](),[5.59528][5.3065:3102](),[5.72411][5.3065:3102](),[5.3780][5.3065:3102](),[5.3102][5.13260:13315]()
    payoutsHandler :: S.Handler App App FractionalPayouts
    payoutsHandler = do
    uid <- requireUserId
    pid <- requireProjectId
    project <-
    fromMaybeT
    (snapError 400 $ "Project not found for id " <> show pid)
    (mapMaybeT snapEval $ findUserProject uid pid)
    widx <- snapEval $ readWorkIndex pid uid
    ptime <- liftIO $ C.getCurrentTime
    pure $ payouts (toDepF $ project ^. depf) ptime widx
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 162
    [5.31028][5.31028:31385]()
    payoutsJSON :: FractionalPayouts -> Value
    payoutsJSON (Payouts m) =
    v1 $
    let payoutsRec :: (CreditTo, Rational) -> Value
    payoutsRec (c, r) =
    object ["creditTo" .= creditToJSON c,
    "payoutRatio" .= r,
    "payoutPercentage" .= (fromRational @Double r * 100)]
    in obj $ ["payouts" .= fmap payoutsRec (MS.assocs m)]
  • edit in server/Aftok/Snaplet/WorkLog.hs at line 181
    [5.31970][5.31970:31971]()
  • edit in server/Main.hs at line 80
    [5.76933]
    [5.76933]
    checkUsernameRoute = void $ method GET checkUsernameHandler
  • replacement in server/Main.hs at line 85
    [5.77224][5.2160:2268]()
    listContributorsRoute =
    serveJSON (fmap contributorJSON) $ method GET listContributorsHandler
    [5.77224]
    [5.77224]
    projectDetailRoute =
    serveJSON (v1 . projectDetailJSON) $ method GET projectDetailGetHandler
  • edit in server/Main.hs at line 134
    [5.105494]
    [5.105494]
    ("validate_username", checkUsernameRoute), -- check_username.sh
  • replacement in server/Main.hs at line 146
    [5.106406][5.2269:2368]()
    ("projects/:projectId/contributors", listContributorsRoute), -- list_project_contributors.sh
    [5.106406]
    [5.106406]
    ("projects/:projectId/detail", projectDetailRoute), -- list_project_contributors.sh