Format with purty.

[?]
Jan 25, 2021, 12:54 AM
QH4UB73NUR2XPHZQ2RGJBKKUBN43RKC7ZJBCFPP4ESUIIEDDR5XQC

Dependencies

  • [2] B4MTB6UO Persist project across pages.
  • [3] ZIG57EE6 Fix project selection, end log end on project switch.
  • [4] TKGBRIQT Login component now raises LoginComplete message.
  • [5] QMEYU4MW Add display for prior intervals.
  • [6] 5R2Z7FSX Initial rendering for signup controls.
  • [7] ARX7SHY5 Begin work on login UI.
  • [8] EA5BFM5G Split Login component into its own module.
  • [9] IR75ZMX3 Return actual events for interval ends, not just timestamps.
  • [10] OUR4PAOT Use local dates for display of intervals.
  • [11] ENNZIQJG Use live signup API for client.
  • [12] PT4276XC Add logout functionality.
  • [13] BFZN4SUA Make timeline component work.
  • [14] NJNMO72S Add zcash.com submodule and update client to modern halogen.
  • [15] TUA4HMUD Use real API capability for login.
  • [16] 2J37EVJM Check for an open interval on project switch.
  • [17] RSF6UAJK Break out api module for timeline.
  • [18] J6S23MDG Use server timestamps for interval start and end.
  • [19] HO2PFRAB Client login now handles response correctly.
  • [20] JXG3FCXY Upgrade ps + halogen versions.
  • [21] QAC2QJ32 Add project overview page to client.
  • [22] 3LMXT7Z6 preventDefault on login form submission.
  • [23] SAESJLLY Initial experiments in hash routing.
  • [24] U256ZALI Add captcha check to register route.
  • [25] 5IDB3IWS Integrate zcashd-based zaddr validation.
  • [26] QU5FW67R Add project selection to time tracker.
  • [27] AAALU5A2 Fix client routing
  • [28] QQXR7DTO Rework login component to use more appropriate Bootstrap theme.
  • [29] WRPIYG3E Use project listing functionality to check for whether we have a cookie.
  • [30] O2BZOX7M Add signup form, captcha check.
  • [*] RB2ETNIF Add skeletal PureScript client project.

Change contents

  • edit in client/.gitignore at line 12
    [3.2069]
    [3.2069]
    .nvimrc
  • edit in client/package-lock.json at line 5856
    [3.232252]
    [3.232252]
    "purty": {
    "version": "6.3.0",
    "resolved": "https://registry.npmjs.org/purty/-/purty-6.3.0.tgz",
    "integrity": "sha512-l70uQyz+t5GvCPzOorUbIhRX3oQW9i8Kgwr0LvS6nUq+UM4rMJdYcHazuupcLVInvNsbd290EnpjaRgAITt0dw=="
    },
  • edit in client/package.json at line 17
    [3.345]
    [3.345]
    "purty": "^6.3.0",
  • edit in client/src/Aftok/Api/Account.purs at line 4
    [3.197][3.197:198]()
  • edit in client/src/Aftok/Api/Account.purs at line 8
    [3.342][3.342:343]()
  • replacement in client/src/Aftok/Api/Account.purs at line 15
    [3.858][3.858:921]()
    type LoginRequest = { username :: String, password :: String }
    [3.858]
    [3.921]
    type LoginRequest
    = { username :: String, password :: String }
  • replacement in client/src/Aftok/Api/Account.purs at line 27
    [3.1224][3.1224:1336]()
    result <- post RF.ignore "/api/login" (Just <<< RB.Json <<< encodeJson $ { username: user, password : pass })
    [3.1224]
    [3.1336]
    result <- post RF.ignore "/api/login" (Just <<< RB.Json <<< encodeJson $ { username: user, password: pass })
  • replacement in client/src/Aftok/Api/Account.purs at line 29
    [3.1353][3.1353:1743]()
    Left err -> log ("Login failed: " <> printError err)
    Right r -> log ("Login status: " <> show r.status)
    pure $ case result of
    Left err -> LoginError { status: Nothing, message: printError err }
    Right r -> case r.status of
    StatusCode 403 -> LoginForbidden
    StatusCode 200 -> LoginOK
    other -> LoginError { status: Just other, message: r.statusText }
    [3.1353]
    [3.1743]
    Left err -> log ("Login failed: " <> printError err)
    Right r -> log ("Login status: " <> show r.status)
    pure
    $ case result of
    Left err -> LoginError { status: Nothing, message: printError err }
    Right r -> case r.status of
    StatusCode 403 -> LoginForbidden
    StatusCode 200 -> LoginOK
    other -> LoginError { status: Just other, message: r.statusText }
  • replacement in client/src/Aftok/Api/Account.purs at line 46
    [3.1960][3.1960:2065]()
    pure $ case r.status of
    StatusCode 200 -> LoginOK
    StatusCode _ -> LoginForbidden
    [3.1960]
    [3.2065]
    pure
    $ case r.status of
    StatusCode 200 -> LoginOK
    StatusCode _ -> LoginForbidden
  • replacement in client/src/Aftok/Api/Account.purs at line 56
    [3.2171][3.2171:2198]()
    | RecoverByZAddr String
    [3.2171]
    [3.2198]
    | RecoverByZAddr String
  • replacement in client/src/Aftok/Api/Account.purs at line 58
    [3.2199][3.2199:2324]()
    type SignupRequest =
    { username :: String
    , password :: String
    , recoverBy :: RecoverBy
    , captchaToken :: String
    }
    [3.2199]
    [3.2324]
    type SignupRequest
    = { username :: String
    , password :: String
    , recoverBy :: RecoverBy
    , captchaToken :: String
    }
  • replacement in client/src/Aftok/Api/Account.purs at line 66
    [3.2399][3.2399:2507]()
    signupRequest username password recoverBy captchaToken =
    { username, password, recoverBy, captchaToken }
    [3.2399]
    [3.2507]
    signupRequest username password recoverBy captchaToken = { username, password, recoverBy, captchaToken }
  • replacement in client/src/Aftok/Api/Account.purs at line 97
    [3.2902][3.454:521]()
    result <- get RF.ignore ("/api/validate_zaddr?zaddr=" <> zaddr)
    [3.2902]
    [3.521]
    result <- get RF.ignore ("/api/validate_zaddr?zaddr=" <> zaddr)
  • replacement in client/src/Aftok/Api/Account.purs at line 102
    [3.644][3.644:718]()
    Right r | r.status == StatusCode 200 -> do
    pure ZAddrCheckValid
    [3.644]
    [3.718]
    Right r
    | r.status == StatusCode 200 -> do
    pure ZAddrCheckValid
  • replacement in client/src/Aftok/Api/Account.purs at line 111
    [3.2985][3.121:154](),[3.154][3.456:568](),[3.456][3.456:568](),[3.568][3.833:1189](),[3.1189][3.155:196](),[3.974][3.155:196](),[3.196][3.974:984](),[3.974][3.974:984]()
    let signupJSON = encodeJson $
    { username: req.username
    , password: req.password
    , recoveryType: case req.recoverBy of
    RecoverByEmail _ -> "email"
    RecoverByZAddr _ -> "zaddr"
    , recoveryEmail: case req.recoverBy of
    RecoverByEmail email -> Just email
    RecoverByZAddr _ -> Nothing
    , recoveryZAddr: case req.recoverBy of
    RecoverByEmail _ -> Nothing
    RecoverByZAddr zaddr -> Just zaddr
    , captchaToken: req.captchaToken
    }
    [3.2985]
    [3.1190]
    let
    signupJSON =
    encodeJson
    $ { username: req.username
    , password: req.password
    , recoveryType:
    case req.recoverBy of
    RecoverByEmail _ -> "email"
    RecoverByZAddr _ -> "zaddr"
    , recoveryEmail:
    case req.recoverBy of
    RecoverByEmail email -> Just email
    RecoverByZAddr _ -> Nothing
    , recoveryZAddr:
    case req.recoverBy of
    RecoverByEmail _ -> Nothing
    RecoverByZAddr zaddr -> Just zaddr
    , captchaToken: req.captchaToken
    }
  • replacement in client/src/Aftok/Api/Account.purs at line 136
    [3.1447][3.1447:1797]()
    Right r | r.status == StatusCode 200 -> do
    log "Registration succeeded!"
    pure SignupOK
    Right r | r.status == StatusCode 403 -> do
    log ("Registration failed: Capcha Invalid")
    pure CaptchaInvalid
    Right r | r.status == StatusCode 400 -> do
    log ("Registration failed: Z-Address Invalid")
    pure ZAddrInvalid
    [3.1447]
    [3.1797]
    Right r
    | r.status == StatusCode 200 -> do
    log "Registration succeeded!"
    pure SignupOK
    Right r
    | r.status == StatusCode 403 -> do
    log ("Registration failed: Capcha Invalid")
    pure CaptchaInvalid
    Right r
    | r.status == StatusCode 400 -> do
    log ("Registration failed: Z-Address Invalid")
    pure ZAddrInvalid
  • edit in client/src/Aftok/Api/Account.purs at line 151
    [3.1922][3.1922:1926](),[3.1926][3.422:423](),[3.422][3.422:423](),[3.423][3.3001:3004](),[3.984][3.3001:3004](),[3.3001][3.3001:3004]()
  • replacement in client/src/Aftok/Api/Recaptcha.purs at line 1
    [3.3287][3.3288:3316]()
    module Aftok.Api.Recaptcha
    [3.3287]
    [3.3316]
    module Aftok.Api.Recaptcha
  • replacement in client/src/Aftok/Api/Recaptcha.purs at line 13
    [3.3619][3.3619:3673]()
    Nothing -> getRecaptchaResponseInternal false ""
    [3.3619]
    [3.3673]
    Nothing -> getRecaptchaResponseInternal false ""
  • edit in client/src/Aftok/Api/Timeline.purs at line 4
    [3.67][3.67:68]()
  • edit in client/src/Aftok/Api/Timeline.purs at line 7
    [3.201][3.201:202]()
  • edit in client/src/Aftok/Api/Timeline.purs at line 22
    [3.717][3.717:718]()
  • edit in client/src/Aftok/Api/Timeline.purs at line 24
    [3.775][3.775:776]()
  • edit in client/src/Aftok/Api/Timeline.purs at line 27
    [3.869][3.869:870]()
  • edit in client/src/Aftok/Api/Timeline.purs at line 28
    [3.911][3.911:912]()
  • replacement in client/src/Aftok/Api/Timeline.purs at line 46
    [3.2170][3.2170:2190]()
    StopEvent t -> t
    [3.2170]
    [3.1300]
    StopEvent t -> t
  • replacement in client/src/Aftok/Api/Timeline.purs at line 67
    [3.2530][3.2530:2569]()
    StopEvent a -> StopEvent <$> f a
    [3.2530]
    [3.1733]
    StopEvent a -> StopEvent <$> f a
  • replacement in client/src/Aftok/Api/Timeline.purs at line 74
    [3.2742][3.2742:2916]()
    stop' <- traverse (_ .: "eventTime") =<< ev .:? "stop"
    note "Only 'stop' and 'start' events are supported." $
    (StartEvent <$> start') <|>
    (StopEvent <$> stop')
    [3.2742]
    [3.2916]
    stop' <- traverse (_ .: "eventTime") =<< ev .:? "stop"
    note "Only 'stop' and 'start' events are supported."
    $ (StartEvent <$> start')
    <|> (StopEvent <$> stop')
  • replacement in client/src/Aftok/Api/Timeline.purs at line 82
    [3.3025][3.3025:3059]()
    newtype KeyedEvent i = KeyedEvent
    [3.3025]
    [3.3059]
    newtype KeyedEvent i
    = KeyedEvent
  • replacement in client/src/Aftok/Api/Timeline.purs at line 113
    [3.2141][3.3933:3963]()
    newtype Interval i = Interval
    [3.2141]
    [3.2172]
    newtype Interval i
    = Interval
  • edit in client/src/Aftok/Api/Timeline.purs at line 120
    [3.4020]
    [3.4020]
  • replacement in client/src/Aftok/Api/Timeline.purs at line 126
    [3.158][3.4139:4176]()
    type TimeInterval = Interval Instant
    [3.158]
    [3.2356]
    type TimeInterval
    = Interval Instant
  • replacement in client/src/Aftok/Api/Timeline.purs at line 159
    [3.3075][3.3075:3110]()
    type TimeSpan = TimeSpan' DateTime
    [3.3075]
    [3.3110]
    type TimeSpan
    = TimeSpan' DateTime
  • edit in client/src/Aftok/Api/Timeline.purs at line 163
    [3.3164]
    [3.3164]
  • replacement in client/src/Aftok/Api/Timeline.purs at line 168
    [3.3292][3.3292:3314]()
    After a -> f a b
    [3.3292]
    [3.3314]
    After a -> f a b
  • replacement in client/src/Aftok/Api/Timeline.purs at line 172
    [3.3388][3.3388:3410]()
    After a -> f b a
    [3.3388]
    [3.3410]
    After a -> f b a
  • replacement in client/src/Aftok/Api/Timeline.purs at line 179
    [3.3595][3.3595:3625]()
    After a -> After <$> f a
    [3.3595]
    [3.3625]
    After a -> After <$> f a
  • replacement in client/src/Aftok/Api/Timeline.purs at line 184
    [3.3753][3.3753:3832]()
    let requestBody = Just <<< RB.Json <<< encodeJson $ { schemaVersion: "2.0" }
    [3.3753]
    [3.3832]
    let
    requestBody = Just <<< RB.Json <<< encodeJson $ { schemaVersion: "2.0" }
  • replacement in client/src/Aftok/Api/Timeline.purs at line 187
    [3.3931][3.3931:3964](),[3.3964][3.4799:5000]()
    liftEffect <<< runExceptT $ do
    kev <- withExceptT LogFailure $ parseDatedResponse response
    case event kev of
    StartEvent _ -> pure kev
    StopEvent _ -> throwError <<< Unexpected $ "Expected start event, got stop."
    [3.3931]
    [3.4162]
    liftEffect <<< runExceptT
    $ do
    kev <- withExceptT LogFailure $ parseDatedResponse response
    case event kev of
    StartEvent _ -> pure kev
    StopEvent _ -> throwError <<< Unexpected $ "Expected start event, got stop."
  • replacement in client/src/Aftok/Api/Timeline.purs at line 196
    [3.4255][3.4255:4334]()
    let requestBody = Just <<< RB.Json <<< encodeJson $ { schemaVersion: "2.0" }
    [3.4255]
    [3.4334]
    let
    requestBody = Just <<< RB.Json <<< encodeJson $ { schemaVersion: "2.0" }
  • replacement in client/src/Aftok/Api/Timeline.purs at line 199
    [3.4431][3.4431:4464](),[3.4464][3.5076:5162](),[3.5162][3.4548:4632](),[3.4548][3.4548:4632](),[3.4632][3.5163:5194]()
    liftEffect <<< runExceptT $ do
    kev <- withExceptT LogFailure $ parseDatedResponse response
    case event kev of
    StartEvent _ -> throwError <<< Unexpected $ "Expected stop event, got start."
    StopEvent _ -> pure kev
    [3.4431]
    [3.4661]
    liftEffect <<< runExceptT
    $ do
    kev <- withExceptT LogFailure $ parseDatedResponse response
    case event kev of
    StartEvent _ -> throwError <<< Unexpected $ "Expected stop event, got start."
    StopEvent _ -> pure kev
  • replacement in client/src/Aftok/Api/Timeline.purs at line 206
    [3.4662][3.4662:4718]()
    newtype ListIntervalsResponse a = ListIntervalsResponse
    [3.4662]
    [3.5195]
    newtype ListIntervalsResponse a
    = ListIntervalsResponse
  • edit in client/src/Aftok/Api/Timeline.purs at line 212
    [3.4858]
    [3.4858]
  • replacement in client/src/Aftok/Api/Timeline.purs at line 222
    [3.5287][3.5332:5508](),[3.5332][3.5332:5508]()
    let traverseCreditRow r' = ({ intervals: _ }) <$> traverse f r'.intervals
    in (ListIntervalsResponse <<< ({ workIndex: _ })) <$> traverse traverseCreditRow r.workIndex
    [3.5287]
    [3.5508]
    let
    traverseCreditRow r' = ({ intervals: _ }) <$> traverse f r'.intervals
    in
    (ListIntervalsResponse <<< ({ workIndex: _ })) <$> traverse traverseCreditRow r.workIndex
  • replacement in client/src/Aftok/Api/Timeline.purs at line 234
    [3.6006][3.6006:6040](),[3.6040][3.31:216]()
    let queryElements = case ts' of
    Before t -> ["before=" <> t, "limit=100"]
    During (Interval x) -> ["after=" <> x.start, "before=" <> x.end, "limit=100"]
    After t -> ["after=" <> t, "limit=100"]
    [3.6006]
    [3.6186]
    let
    queryElements = case ts' of
    Before t -> [ "before=" <> t, "limit=100" ]
    During (Interval x) -> [ "after=" <> x.start, "before=" <> x.end, "limit=100" ]
    After t -> [ "after=" <> t, "limit=100" ]
  • replacement in client/src/Aftok/Api/Timeline.purs at line 245
    [3.5507][3.6462:6498](),[3.6462][3.6462:6498]()
    $ parseDatedResponse response
    [3.5507]
    [3.6498]
    $ parseDatedResponse response
  • replacement in client/src/Aftok/Api/Timeline.purs at line 255
    [3.5660][3.495:534](),[3.495][3.495:534]()
    $ parseDatedResponse response
    [3.5660]
    $ parseDatedResponse response
  • edit in client/src/Aftok/Login.purs at line 4
    [3.295259][3.62:63](),[3.62][3.62:63]()
  • edit in client/src/Aftok/Login.purs at line 5
    [3.295300][3.96:97](),[3.96][3.96:97]()
  • edit in client/src/Aftok/Login.purs at line 6
    [3.127][3.295383:295384]()
  • edit in client/src/Aftok/Login.purs at line 7
    [3.160][3.154:155](),[3.295534][3.154:155](),[3.154][3.154:155]()
  • edit in client/src/Aftok/Login.purs at line 14
    [3.810][3.295567:295568]()
  • edit in client/src/Aftok/Login.purs at line 15
    [3.810][3.354:355](),[3.295602][3.354:355](),[3.354][3.354:355]()
  • edit in client/src/Aftok/Login.purs at line 16
    [3.295631][3.56:57]()
  • replacement in client/src/Aftok/Login.purs at line 20
    [3.3937][3.3937:3952]()
    = Forbidden
    [3.3937]
    [3.3952]
    = Forbidden
  • replacement in client/src/Aftok/Login.purs at line 23
    [3.269][3.295797:295815](),[3.295815][3.288:311](),[3.288][3.288:311](),[3.311][3.295816:295839](),[3.295839][3.3969:4004](),[3.4004][3.376:380](),[3.376][3.376:380]()
    type LoginState =
    { username :: String
    , password :: String
    , loginError :: Maybe LoginError
    }
    [3.269]
    [3.521]
    type LoginState
    = { username :: String
    , password :: String
    , loginError :: Maybe LoginError
    }
  • replacement in client/src/Aftok/Login.purs at line 34
    [3.596][3.177:195]()
    data LoginResult
    [3.596]
    [3.195]
    data LoginResult
  • replacement in client/src/Aftok/Login.purs at line 37
    [3.726][3.237:294]()
    type Slot id = forall query. H.Slot query LoginResult id
    [3.726]
    [3.832]
    type Slot id
    = forall query. H.Slot query LoginResult id
  • replacement in client/src/Aftok/Login.purs at line 40
    [3.833][3.296010:296080](),[3.296080][3.161:216](),[3.216][3.296080:296084](),[3.296080][3.296080:296084]()
    type Capability m =
    { login :: String -> String -> m LoginResponse
    , checkLogin :: m LoginResponse
    , logout :: m Unit
    }
    [3.833]
    [3.487]
    type Capability m
    = { login :: String -> String -> m LoginResponse
    , checkLogin :: m LoginResponse
    , logout :: m Unit
    }
  • replacement in client/src/Aftok/Login.purs at line 46
    [3.488][3.296085:296122](),[3.296122][3.86:132](),[3.132][3.295:346](),[3.346][3.133:171](),[3.296208][3.133:171](),[3.171][3.296239:296326](),[3.296239][3.296239:296326](),[3.296326][3.1092:1102](),[3.1092][3.1092:1102](),[3.1102][3.296327:296368](),[3.296368][3.4005:4078]()
    component
    :: forall query input m
    . Monad m
    => System m
    -> Capability m
    -> H.Component HH.HTML query input LoginResult m
    component system caps = H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = eval }
    } where
    initialState :: input -> LoginState
    initialState _ = { username: "", password: "", loginError: Nothing }
    [3.488]
    [3.296444]
    component ::
    forall query input m.
    Monad m =>
    System m ->
    Capability m ->
    H.Component HH.HTML query input LoginResult m
    component system caps =
    H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = eval }
    }
    where
    initialState :: input -> LoginState
    initialState _ = { username: "", password: "", loginError: Nothing }
  • replacement in client/src/Aftok/Login.purs at line 62
    [3.296446][3.193:271](),[3.271][3.296526:296580](),[3.296526][3.296526:296580](),[3.296580][3.4:79]()
    render :: forall slots. LoginState -> H.ComponentHTML LoginAction slots m
    render st =
    Card.component $
    HH.div
    [ P.classes (ClassName <$> ["row", "no-gutters", "container"]) ]
    [3.296445]
    [3.296642]
    render :: forall slots. LoginState -> H.ComponentHTML LoginAction slots m
    render st =
    Card.component
    $ HH.div
    [ P.classes (ClassName <$> [ "row", "no-gutters", "container" ]) ]
  • replacement in client/src/Aftok/Login.purs at line 68
    [3.296661][3.296661:297108]()
    [ P.classes (ClassName <$> ["col-12", "col-md-6", "bg-cover", "card-img-left"])
    , CSS.style $ backgroundImage (url "/assets/img/photos/latch.jpg")
    ]
    [
    HH.div
    [ P.classes (ClassName <$> ["shape", "shape-right", "shape-fluid-y", "svg-shim", "text-white", "d-none", "d-md-block"])]
    [ HH.img [ P.src "/assets/img/shapes/curves/curve-4.svg" ]]
    ]
    [3.296661]
    [3.297108]
    [ P.classes (ClassName <$> [ "col-12", "col-md-6", "bg-cover", "card-img-left" ])
    , CSS.style $ backgroundImage (url "/assets/img/photos/latch.jpg")
    ]
    [ HH.div
    [ P.classes (ClassName <$> [ "shape", "shape-right", "shape-fluid-y", "svg-shim", "text-white", "d-none", "d-md-block" ]) ]
    [ HH.img [ P.src "/assets/img/shapes/curves/curve-4.svg" ] ]
    ]
  • replacement in client/src/Aftok/Login.purs at line 76
    [3.297127][3.297127:297419](),[3.1102][3.997:998](),[3.297419][3.997:998](),[3.997][3.997:998](),[3.998][3.297420:297497](),[3.297497][3.105:151](),[3.151][3.297545:298308](),[3.297545][3.297545:298308]()
    [ P.classes (ClassName <$> ["col-12", "col-md-6"]) ]
    [ HH.div
    [ P.classes (ClassName <$> ["card-body"]) ]
    [ HH.h2
    [ P.classes (ClassName <$> ["mb-0", "font-weight-bold", "text-center"])]
    [ HH.text "Sign In"]
    , HH.form
    [ P.classes (ClassName <$> ["mb-6"])
    , E.onSubmit (Just <<< Login)
    ]
    [ HH.div
    [ P.classes (ClassName <$> ["form-group"])]
    [ HH.label
    [ P.classes (ClassName <$> ["sr-only"])
    , P.for "modalSigninHorizontalUsername"
    ]
    [ HH.text "Username" ]
    , HH.input
    [ P.type_ P.InputText
    , P.classes (ClassName <$> ["form-control"])
    , P.id_ "modalSigninHorizontalUsername"
    , P.placeholder "Username"
    , P.required true
    , P.autofocus true
    , P.value st.username
    , E.onValueInput (Just <<< SetUsername)
    ]
    [3.297127]
    [3.298308]
    [ P.classes (ClassName <$> [ "col-12", "col-md-6" ]) ]
    [ HH.div
    [ P.classes (ClassName <$> [ "card-body" ]) ]
    [ HH.h2
    [ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ]
    [ HH.text "Sign In" ]
    , HH.form
    [ P.classes (ClassName <$> [ "mb-6" ])
    , E.onSubmit (Just <<< Login)
    ]
    [ HH.div
    [ P.classes (ClassName <$> [ "form-group" ]) ]
    [ HH.label
    [ P.classes (ClassName <$> [ "sr-only" ])
    , P.for "modalSigninHorizontalUsername"
    ]
    [ HH.text "Username" ]
    , HH.input
    [ P.type_ P.InputText
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "modalSigninHorizontalUsername"
    , P.placeholder "Username"
    , P.required true
    , P.autofocus true
    , P.value st.username
    , E.onValueInput (Just <<< SetUsername)
    ]
    ]
    , HH.div
    [ P.classes (ClassName <$> [ "form-group" ]) ]
    [ HH.label
    [ P.classes (ClassName <$> [ "sr-only" ])
    , P.for "modalSigninHorizontalPassword"
    ]
    [ HH.text "Password" ]
    , HH.input
    [ P.type_ P.InputPassword
    , P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "modalSigninHorizontalPassword"
    , P.placeholder "Password"
    , P.required true
    , P.value st.password
    , E.onValueInput (Just <<< SetPassword)
    ]
    ]
    , case st.loginError of
    Nothing -> HH.div_ []
    Just err ->
    let
    message = case err of
    Forbidden -> "Login failed. Check your username and password."
    ServerError -> "Login failed due to an internal error. Please contact support."
    in
    HH.div
    [ P.classes (ClassName <$> [ "alert alert-danger" ]) ]
    [ HH.text message ]
    , HH.button
    [ P.classes (ClassName <$> [ "btn", "btn-block", "btn-primary" ]) ]
    [ HH.text "Sign in" ]
    ]
  • replacement in client/src/Aftok/Login.purs at line 137
    [3.298328][3.298328:299038]()
    , HH.div
    [ P.classes (ClassName <$> ["form-group"])]
    [ HH.label
    [ P.classes (ClassName <$> ["sr-only"])
    , P.for "modalSigninHorizontalPassword"
    ]
    [ HH.text "Password" ]
    , HH.input
    [ P.type_ P.InputPassword
    , P.classes (ClassName <$> ["form-control"])
    , P.id_ "modalSigninHorizontalPassword"
    , P.placeholder "Password"
    , P.required true
    , P.value st.password
    , E.onValueInput (Just <<< SetPassword)
    ]
    [3.298328]
    [3.299038]
    , HH.p
    [ P.classes (ClassName <$> [ "mb-0", "font-size-sm", "text-center", "text-muted" ]) ]
    [ HH.text "Need an account? "
    , HH.a
    [ P.href "#signup" ]
    [ HH.text "Sign up" ]
  • edit in client/src/Aftok/Login.purs at line 144
    [3.299058][3.4079:4119](),[3.4119][3.299101:299165](),[3.299101][3.299101:299165](),[3.299165][3.4120:4562](),[3.4562][3.299842:299871](),[3.299842][3.299842:299871](),[3.299871][3.4563:4647](),[3.4647][3.299973:300031](),[3.299973][3.299973:300031]()
    , case st.loginError of
    Nothing ->
    HH.div_ []
    Just err ->
    let message = case err of
    Forbidden -> "Login failed. Check your username and password."
    ServerError -> "Login failed due to an internal error. Please contact support."
    in HH.div
    [ P.classes (ClassName <$> ["alert alert-danger"]) ]
    [ HH.text message ]
    , HH.button
    [ P.classes (ClassName <$> ["btn", "btn-block", "btn-primary"]) ]
    [ HH.text "Sign in" ]
    ]
  • edit in client/src/Aftok/Login.purs at line 145
    [3.300047][3.347:541](),[3.541][3.4:43](),[3.43][3.582:640](),[3.582][3.582:640](),[3.640][3.300047:300061](),[3.300047][3.300047:300061]()
    , HH.p
    [ P.classes (ClassName <$> ["mb-0", "font-size-sm", "text-center", "text-muted"]) ]
    [ HH.text "Need an account? "
    , HH.a
    [ P.href "#signup" ]
    [ HH.text "Sign up" ]
    ]
    ]
  • replacement in client/src/Aftok/Login.purs at line 147
    [3.2139][3.641:724](),[3.724][3.300147:300288](),[3.300147][3.300147:300288](),[3.300288][3.152:173](),[3.173][3.172:212](),[3.212][3.300306:300426](),[3.218][3.300306:300426](),[3.300306][3.300306:300426](),[3.300482][3.300482:300507](),[3.300507][3.4648:4869]()
    eval :: LoginAction -> H.HalogenM LoginState LoginAction () LoginResult m Unit
    eval = case _ of
    SetUsername user -> H.modify_ (_ { username = user })
    SetPassword pass -> H.modify_ (_ { password = pass })
    Login ev -> do
    lift $ system.preventDefault ev
    user <- H.gets (_.username)
    pass <- H.gets (_.password)
    response <- lift (caps.login user pass)
    case response of
    LoginOK -> H.raise (LoginComplete { username: user })
    LoginForbidden -> H.modify_ (_ { loginError = Just Forbidden })
    LoginError _ -> H.modify_ (_ { loginError = Just ServerError })
    [3.2139]
    [3.3162]
    eval :: LoginAction -> H.HalogenM LoginState LoginAction () LoginResult m Unit
    eval = case _ of
    SetUsername user -> H.modify_ (_ { username = user })
    SetPassword pass -> H.modify_ (_ { password = pass })
    Login ev -> do
    lift $ system.preventDefault ev
    user <- H.gets (_.username)
    pass <- H.gets (_.password)
    response <- lift (caps.login user pass)
    case response of
    LoginOK -> H.raise (LoginComplete { username: user })
    LoginForbidden -> H.modify_ (_ { loginError = Just Forbidden })
    LoginError _ -> H.modify_ (_ { loginError = Just ServerError })
  • replacement in client/src/Aftok/Login.purs at line 165
    [3.493][3.1207:1225](),[3.1225][3.4870:4903]()
    mockCapability =
    { login: \_ _ -> pure LoginOK
    [3.493]
    [3.4903]
    mockCapability =
    { login: \_ _ -> pure LoginOK
  • edit in client/src/Aftok/Overview.purs at line 4
    [3.136][3.136:137]()
  • edit in client/src/Aftok/Overview.purs at line 27
    [3.1073][3.1073:1074]()
  • edit in client/src/Aftok/Overview.purs at line 32
    [3.1224][3.1224:1225]()
  • edit in client/src/Aftok/Overview.purs at line 35
    [3.1346][3.1346:1347]()
  • edit in client/src/Aftok/Overview.purs at line 40
    [3.1519][3.1519:1520]()
  • edit in client/src/Aftok/Overview.purs at line 44
    [3.1722][3.1722:1723]()
  • edit in client/src/Aftok/Overview.purs at line 58
    [3.2142][3.2142:2143]()
  • replacement in client/src/Aftok/Overview.purs at line 59
    [3.2144][3.2144:2179]()
    type OverviewInput = Maybe Project
    [3.2144]
    [3.2179]
    type OverviewInput
    = Maybe Project
  • replacement in client/src/Aftok/Overview.purs at line 62
    [3.2180][3.2180:2242]()
    type OverviewState =
    { selectedProject :: Maybe Project
    }
    [3.2180]
    [3.2242]
    type OverviewState
    = { selectedProject :: Maybe Project
    }
  • replacement in client/src/Aftok/Overview.purs at line 75
    [3.2396][3.2396:2454]()
    type Slot id = forall query. H.Slot query ProjectEvent id
    [3.2396]
    [3.2454]
    type Slot id
    = forall query. H.Slot query ProjectEvent id
  • replacement in client/src/Aftok/Overview.purs at line 78
    [3.2455][3.2455:2520]()
    type Slots =
    ( projectList :: Project.ProjectListSlot Unit
    )
    [3.2455]
    [3.2520]
    type Slots
    = ( projectList :: Project.ProjectListSlot Unit
    )
  • replacement in client/src/Aftok/Overview.purs at line 84
    [3.2568][3.2568:2615]()
    type Capability (m :: Type -> Type) =
    {
    }
    [3.2568]
    [3.2615]
    type Capability (m :: Type -> Type)
    = {
    }
  • replacement in client/src/Aftok/Overview.purs at line 88
    [3.2616][3.2616:3082]()
    component
    :: forall query m
    . Monad m
    => System m
    -> Capability m
    -> Project.Capability m
    -> H.Component HH.HTML query OverviewInput ProjectEvent m
    component system caps pcaps = H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval
    { handleAction = eval
    , initialize = Just Initialize
    }
    } where
    initialState :: OverviewInput -> OverviewState
    initialState input =
    { selectedProject: input
    }
    [3.2616]
    [3.3082]
    component ::
    forall query m.
    Monad m =>
    System m ->
    Capability m ->
    Project.Capability m ->
    H.Component HH.HTML query OverviewInput ProjectEvent m
    component system caps pcaps =
    H.mkComponent
    { initialState
    , render
    , eval:
    H.mkEval
    $ H.defaultEval
    { handleAction = eval
    , initialize = Just Initialize
    }
    }
    where
    initialState :: OverviewInput -> OverviewState
    initialState input =
    { selectedProject: input
    }
  • replacement in client/src/Aftok/Overview.purs at line 112
    [3.3083][3.3083:3651](),[3.3651][2.32:162](),[2.162][3.3767:3898](),[3.3767][3.3767:3898]()
    render :: OverviewState -> H.ComponentHTML OverviewAction Slots m
    render st =
    HH.section
    [P.classes (ClassName <$> ["section-border", "border-primary"])]
    [HH.div
    [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 timeline"]
    ,HH.div_
    [HH.slot _projectList unit (Project.projectListComponent system pcaps) st.selectedProject (Just <<< ProjectSelected)]
    ,HH.div
    [P.classes (ClassName <$> if isNothing st.selectedProject then ["collapse"] else [])]
    []
    [3.3083]
    [3.3898]
    render :: OverviewState -> H.ComponentHTML OverviewAction Slots m
    render st =
    HH.section
    [ P.classes (ClassName <$> [ "section-border", "border-primary" ]) ]
    [ HH.div
    [ 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 timeline" ]
    , HH.div_
    [ HH.slot _projectList unit (Project.projectListComponent system pcaps) st.selectedProject (Just <<< ProjectSelected) ]
    , HH.div
    [ P.classes (ClassName <$> if isNothing st.selectedProject then [ "collapse" ] else []) ]
    []
  • replacement in client/src/Aftok/Overview.purs at line 130
    [3.3910][3.3910:3920]()
    ]
    [3.3910]
    [3.3920]
    ]
  • replacement in client/src/Aftok/Overview.purs at line 132
    [3.3921][3.3921:4104]()
    eval :: OverviewAction -> H.HalogenM OverviewState OverviewAction Slots ProjectEvent m Unit
    eval action = do
    case action of
    Initialize -> do
    pure unit
    [3.3921]
    [3.4104]
    eval :: OverviewAction -> H.HalogenM OverviewState OverviewAction Slots ProjectEvent m Unit
    eval action = do
    case action of
    Initialize -> do
    pure unit
    Invite _ -> do
    pure unit
    ProjectSelected p -> do
    currentProject <- H.gets (_.selectedProject)
    when (all (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject)
    $ do
    H.raise (ProjectChange p)
    H.modify_ (_ { selectedProject = Just p })
  • edit in client/src/Aftok/Overview.purs at line 146
    [3.4105][3.4105:4247](),[3.4247][2.163:259](),[2.259][3.4343:4438](),[3.4343][3.4343:4438]()
    Invite _ -> do
    pure unit
    ProjectSelected p -> do
    currentProject <- H.gets (_.selectedProject)
    when (all (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) $ do
    H.raise (ProjectChange p)
    H.modify_ (_ { selectedProject = Just p })
  • replacement in client/src/Aftok/Overview.purs at line 147
    [3.4470][3.4470:4490]()
    apiCapability = { }
    [3.4470]
    [3.4490]
    apiCapability = {}
  • replacement in client/src/Aftok/Overview.purs at line 150
    [3.4524][3.4524:4545]()
    mockCapability = { }
    [3.4524]
    mockCapability = {}
  • edit in client/src/Aftok/Project.purs at line 4
    [3.576][3.576:577]()
  • edit in client/src/Aftok/Project.purs at line 7
    [3.727][3.727:728]()
  • edit in client/src/Aftok/Project.purs at line 15
    [3.259][3.1096:1097](),[3.1096][3.1096:1097]()
  • replacement in client/src/Aftok/Project.purs at line 21
    [3.1286][3.1286:1287](),[3.1287][3.4660:4680]()
    import Aftok.Types
    [3.1286]
    [3.4680]
    import Aftok.Types
  • edit in client/src/Aftok/Project.purs at line 29
    [3.127][3.216:217](),[3.313][3.216:217](),[3.4766][3.216:217](),[3.216][3.216:217]()
  • replacement in client/src/Aftok/Project.purs at line 35
    [3.1524][2.330:364]()
    type ProjectInput = Maybe Project
    [3.1524]
    [2.364]
    type ProjectInput
    = Maybe Project
  • replacement in client/src/Aftok/Project.purs at line 38
    [2.365][3.527:548](),[3.527][3.527:548](),[3.548][2.366:433](),[2.433][3.578:582](),[3.578][3.578:582]()
    type ProjectCState =
    { selectedProject :: Maybe Project
    , projects :: Array Project
    }
    [2.365]
    [3.582]
    type ProjectCState
    = { selectedProject :: Maybe Project
    , projects :: Array Project
    }
  • replacement in client/src/Aftok/Project.purs at line 43
    [3.583][3.583:603]()
    data ProjectAction
    [3.583]
    [3.603]
    data ProjectAction
  • replacement in client/src/Aftok/Project.purs at line 47
    [3.634][3.634:698]()
    type ProjectListSlot id = forall query. H.Slot query Project id
    [3.634]
    [3.1669]
    type ProjectListSlot id
    = forall query. H.Slot query Project id
  • replacement in client/src/Aftok/Project.purs at line 50
    [3.1670][3.1670:1750]()
    type Capability m =
    { listProjects :: m (Either APIError (Array Project))
    }
    [3.1670]
    [3.1750]
    type Capability m
    = { listProjects :: m (Either APIError (Array Project))
    }
  • replacement in client/src/Aftok/Project.purs at line 54
    [3.1751][3.699:746](),[3.746][3.412:458](),[3.458][2.434:488](),[2.488][3.459:509](),[3.834][3.459:509](),[3.509][3.876:1025](),[3.876][3.876:1025](),[3.1025][2.489:605]()
    projectListComponent
    :: forall query input m
    . Monad m
    => System m
    -> Capability m
    -> H.Component HH.HTML query ProjectInput Project m
    projectListComponent console caps = H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval
    { handleAction = eval
    , initialize = Just Initialize
    }
    } where
    initialState :: ProjectInput -> ProjectCState
    initialState input = { selectedProject: input, projects: [] }
    [3.1751]
    [3.1106]
    projectListComponent ::
    forall query input m.
    Monad m =>
    System m ->
    Capability m ->
    H.Component HH.HTML query ProjectInput Project m
    projectListComponent console caps =
    H.mkComponent
    { initialState
    , render
    , eval:
    H.mkEval
    $ H.defaultEval
    { handleAction = eval
    , initialize = Just Initialize
    }
    }
    where
    initialState :: ProjectInput -> ProjectCState
    initialState input = { selectedProject: input, projects: [] }
  • replacement in client/src/Aftok/Project.purs at line 75
    [3.1107][3.1107:1207](),[3.1207][2.606:739]()
    render :: forall slots. ProjectCState -> H.ComponentHTML ProjectAction slots m
    render st =
    HH.div
    [P.classes (ClassName <$> ["form-group"])]
    [ HH.label
    [ P.classes (ClassName <$> ["sr-only"])
    [3.1107]
    [2.739]
    render :: forall slots. ProjectCState -> H.ComponentHTML ProjectAction slots m
    render st =
    HH.div
    [ P.classes (ClassName <$> [ "form-group" ]) ]
    [ HH.label
    [ P.classes (ClassName <$> [ "sr-only" ])
  • replacement in client/src/Aftok/Project.purs at line 84
    [2.817][2.817:977]()
    , HH.select
    [P.classes (ClassName <$> ["form-control"])
    ,P.id_ "projectSelect"
    ,E.onSelectedIndexChange (Just <<< Select)
    [2.817]
    [2.977]
    , HH.select
    [ P.classes (ClassName <$> [ "form-control" ])
    , P.id_ "projectSelect"
    , E.onSelectedIndexChange (Just <<< Select)
  • replacement in client/src/Aftok/Project.purs at line 89
    [2.989][2.989:1148]()
    ( [HH.option [P.selected (isNothing st.selectedProject), P.disabled true] [HH.text "Select a project"]]
    <> map renderOption st.projects
    [2.989]
    [2.1148]
    ( [ HH.option [ P.selected (isNothing st.selectedProject), P.disabled true ] [ HH.text "Select a project" ] ]
    <> map renderOption st.projects
  • edit in client/src/Aftok/Project.purs at line 92
    [2.1160]
    [2.1160]
    ]
    where
    renderOption (Project' p) =
    HH.option
    [ P.selected (any (\(Project' p') -> p'.projectId == p.projectId) st.selectedProject)
    , P.value $ pidStr p.projectId
  • replacement in client/src/Aftok/Project.purs at line 99
    [2.1170][2.1170:1430]()
    where
    renderOption (Project' p) =
    HH.option
    [ P.selected (any (\(Project' p') -> p'.projectId == p.projectId) st.selectedProject)
    , P.value $ pidStr p.projectId
    ]
    [HH.text p.projectName]
    [2.1170]
    [3.1518]
    [ HH.text p.projectName ]
  • replacement in client/src/Aftok/Project.purs at line 101
    [3.1519][3.1519:1709](),[3.1709][3.510:592](),[3.592][3.1772:1840](),[3.1772][3.1772:1840]()
    eval :: ProjectAction -> H.HalogenM ProjectCState ProjectAction () Project m Unit
    eval = case _ of
    Initialize -> do
    res <- lift caps.listProjects
    case res of
    Left _ -> lift <<< console.error $ "Could not retrieve project list."
    Right projects -> H.modify_ (_ { projects = projects })
    [3.1519]
    [3.1840]
    eval :: ProjectAction -> H.HalogenM ProjectCState ProjectAction () Project m Unit
    eval = case _ of
    Initialize -> do
    res <- lift caps.listProjects
    case res of
    Left _ -> lift <<< console.error $ "Could not retrieve project list."
    Right projects -> H.modify_ (_ { projects = projects })
    Select i -> do
    projects <- H.gets (_.projects)
    lift <<< console.log $ "Selected project index " <> show i
    traverse_ H.raise (index projects (i - 1))
  • edit in client/src/Aftok/Project.purs at line 113
    [3.1841][3.1841:1902](),[3.1902][3.593:660](),[3.660][3.918:969](),[3.918][3.918:969](),[3.969][3.1869:1870](),[3.1947][3.1869:1870](),[3.1869][3.1869:1870]()
    Select i -> do
    projects <- H.gets (_.projects)
    lift <<< console.log $ "Selected project index " <> show i
    traverse_ H.raise (index projects (i - 1))
  • replacement in client/src/Aftok/Project.purs at line 115
    [3.2320][3.2320:2361](),[3.2361][3.2412:2460](),[3.2460][3.2406:2801](),[3.2406][3.2406:2801]()
    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 }
    [3.2320]
    [3.2801]
    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 }
  • edit in client/src/Aftok/Project.purs at line 137
    [3.3354][3.3354:3355]()
  • edit in client/src/Aftok/Signup.purs at line 4
    [3.44][3.44:45]()
  • edit in client/src/Aftok/Signup.purs at line 5
    [3.4974][3.88:89](),[3.88][3.88:89]()
  • edit in client/src/Aftok/Signup.purs at line 9
    [3.5110][3.130:131](),[3.130][3.130:131]()
  • edit in client/src/Aftok/Signup.purs at line 15
    [3.283][3.283:284]()
  • edit in client/src/Aftok/Signup.purs at line 23
    [3.552][3.552:553]()
  • edit in client/src/Aftok/Signup.purs at line 26
    [3.836][3.590:591](),[3.590][3.590:591]()
  • replacement in client/src/Aftok/Signup.purs at line 49
    [3.814][3.814:1028](),[3.1028][3.5576:5614](),[3.5614][3.1070:1074](),[3.1070][3.1070:1074]()
    type SignupState =
    { username :: Maybe String
    , password :: Maybe String
    , passwordConfirm :: Maybe String
    , recoveryType :: RecoveryType
    , recoveryEmail :: Maybe String
    , recoveryZAddr :: Maybe String
    , signupErrors :: Array SignupError
    }
    [3.814]
    [3.1074]
    type SignupState
    = { username :: Maybe String
    , password :: Maybe String
    , passwordConfirm :: Maybe String
    , recoveryType :: RecoveryType
    , recoveryEmail :: Maybe String
    , recoveryZAddr :: Maybe String
    , signupErrors :: Array SignupError
    }
  • replacement in client/src/Aftok/Signup.purs at line 69
    [3.1301][3.1301:1320](),[3.1320][3.5615:5642]()
    data SignupResult
    = SignupComplete String
    [3.1301]
    [3.5642]
    data SignupResult
    = SignupComplete String
  • replacement in client/src/Aftok/Signup.purs at line 73
    [3.1379][3.1379:1437]()
    type Slot id = forall query. H.Slot query SignupResult id
    [3.1379]
    [3.1437]
    type Slot id
    = forall query. H.Slot query SignupResult id
  • replacement in client/src/Aftok/Signup.purs at line 76
    [3.1438][3.1438:1459](),[3.1459][3.5657:5878](),[3.5878][3.1510:1514](),[3.1510][3.1510:1514]()
    type Capability m =
    { checkUsername :: String -> m Acc.UsernameCheckResponse
    , checkZAddr :: String -> m Acc.ZAddrCheckResponse
    , signup :: SignupRequest -> m SignupResponse
    , getRecaptchaResponse :: Maybe String -> m (Maybe String)
    }
    [3.1438]
    [3.1514]
    type Capability m
    = { checkUsername :: String -> m Acc.UsernameCheckResponse
    , checkZAddr :: String -> m Acc.ZAddrCheckResponse
    , signup :: SignupRequest -> m SignupResponse
    , getRecaptchaResponse :: Maybe String -> m (Maybe String)
    }
  • replacement in client/src/Aftok/Signup.purs at line 83
    [3.1515][3.1515:1560]()
    type Config =
    { recaptchaKey :: String
    }
    [3.1515]
    [3.1560]
    type Config
    = { recaptchaKey :: String
    }
  • replacement in client/src/Aftok/Signup.purs at line 87
    [3.1561][3.1561:2095](),[3.2095][3.5879:5904](),[3.5904][3.2126:2134](),[3.2126][3.2126:2134]()
    component
    :: forall query input m
    . Monad m
    => System m
    -> Capability m
    -> Config
    -> H.Component HH.HTML query input SignupResult m
    component system caps conf = H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = eval }
    } where
    initialState :: input -> SignupState
    initialState _ =
    { username: Nothing
    , password: Nothing
    , passwordConfirm: Nothing
    , recoveryType: RecoveryEmail
    , recoveryEmail: Nothing
    , recoveryZAddr: Nothing
    , signupErrors: []
    }
    [3.1561]
    [3.2134]
    component ::
    forall query input m.
    Monad m =>
    System m ->
    Capability m ->
    Config ->
    H.Component HH.HTML query input SignupResult m
    component system caps conf =
    H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = eval }
    }
    where
    initialState :: input -> SignupState
    initialState _ =
    { username: Nothing
    , password: Nothing
    , passwordConfirm: Nothing
    , recoveryType: RecoveryEmail
    , recoveryEmail: Nothing
    , recoveryZAddr: Nothing
    , signupErrors: []
    }
  • replacement in client/src/Aftok/Signup.purs at line 112
    [3.2135][3.2135:2420]()
    render :: forall slots. SignupState -> H.ComponentHTML SignupAction slots m
    render st =
    HH.section
    [ P.classes (ClassName <$> ["section-border", "border-primary"]) ]
    [ HH.div
    [ P.classes (ClassName <$> ["container", "d-flex", "flex-column"]) ]
    [3.2135]
    [3.2420]
    render :: forall slots. SignupState -> H.ComponentHTML SignupAction slots m
    render st =
    HH.section
    [ P.classes (ClassName <$> [ "section-border", "border-primary" ]) ]
    [ HH.div
    [ P.classes (ClassName <$> [ "container", "d-flex", "flex-column" ]) ]
  • replacement in client/src/Aftok/Signup.purs at line 119
    [3.2439][3.2439:2901]()
    [ P.classes (ClassName <$> ["align-items-center", "pt-6"]) ]
    [ HH.h1
    [ P.classes (ClassName <$> ["mb-0", "font-weight-bold", "text-center"]) ]
    [ HH.text "Sign up" ]
    , HH.p
    [ P.classes (ClassName <$> ["text-center", "text-muted", "col-md-5", "mx-auto"]) ]
    [ HH.text "You can use either an email address or zcash payment address for account recovery." ]
    ]
    [3.2439]
    [3.2901]
    [ P.classes (ClassName <$> [ "align-items-center", "pt-6" ]) ]
    [ HH.h1
    [ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ]
    [ HH.text "Sign up" ]
    , HH.p
    [ P.classes (ClassName <$> [ "text-center", "text-muted", "col-md-5", "mx-auto" ]) ]
    [ HH.text "You can use either an email address or zcash payment address for account recovery." ]
    ]
  • replacement in client/src/Aftok/Signup.purs at line 128
    [3.2920][3.837:949](),[3.949][3.3025:3157](),[3.3025][3.3025:3157](),[3.3157][3.5905:6024](),[3.6024][3.3212:4571](),[3.3212][3.3212:4571](),[3.4571][3.6025:6071](),[3.6071][3.4610:5087](),[3.4610][3.4610:5087](),[3.5087][3.6072:6148](),[3.6148][3.5159:5257](),[3.5159][3.5159:5257]()
    [ P.classes (ClassName <$> ["row", "align-items-center", "justify-content-center", "no-gutters"]) ]
    [ HH.div
    [ P.classes (ClassName <$> ["col-12", "col-lg-4", "py-8", "py-md-0"]) ]
    [ HH.form
    [ P.classes (ClassName <$> ["mb-6"])
    , E.onSubmit (Just <<< Signup)
    ]
    [ HH.div
    [ P.classes (ClassName <$> ["form-group"]) ]
    [ 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)
    ]
    ]
    , HH.div
    [ P.classes (ClassName <$> ["form-group"]) ]
    [ 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)
    ]
    ]
    , recoverySwitch st.recoveryType
    , recoveryField st
    , HH.div
    [ P.classes (ClassName <$> ["form-group", "mb-3"]) ]
    [ HH.div
    [ P.classes (ClassName <$> ["g-recaptcha", "mx-auto"])
    , P.attr (AttrName "data-sitekey") conf.recaptchaKey
    ] []
    [3.2920]
    [3.5257]
    [ P.classes (ClassName <$> [ "row", "align-items-center", "justify-content-center", "no-gutters" ]) ]
    [ HH.div
    [ P.classes (ClassName <$> [ "col-12", "col-lg-4", "py-8", "py-md-0" ]) ]
    [ HH.form
    [ P.classes (ClassName <$> [ "mb-6" ])
    , E.onSubmit (Just <<< Signup)
    ]
    [ HH.div
    [ P.classes (ClassName <$> [ "form-group" ]) ]
    [ 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)
    ]
    ]
    , HH.div
    [ P.classes (ClassName <$> [ "form-group" ]) ]
    [ 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)
    ]
    ]
    , recoverySwitch st.recoveryType
    , recoveryField st
    , HH.div
    [ P.classes (ClassName <$> [ "form-group", "mb-3" ]) ]
    [ HH.div
    [ P.classes (ClassName <$> [ "g-recaptcha", "mx-auto" ])
    , P.attr (AttrName "data-sitekey") conf.recaptchaKey
    ]
    []
    ]
    , HH.button
    [ P.classes (ClassName <$> [ "btn", "btn-block", "btn-primary" ]) ]
    [ HH.text "Sign up" ]
    ]
    , HH.p
    [ P.classes (ClassName <$> [ "mb-0", "font-size-sm", "text-center", "text-muted" ]) ]
    [ HH.text "Already have an account? "
    , HH.a
    [ P.href "#login" ]
    [ HH.text "Sign in" ]
    ]
  • edit in client/src/Aftok/Signup.purs at line 193
    [3.5277][3.5277:5570](),[3.5570][3.45:100](),[3.100][3.5624:5648](),[3.5624][3.5624:5648](),[3.5648][3.101:139](),[3.139][3.5710:5768](),[3.5710][3.5710:5768]()
    , HH.button
    [ P.classes (ClassName <$> ["btn", "btn-block", "btn-primary"]) ]
    [ HH.text "Sign up" ]
    ]
    , HH.p
    [ P.classes (ClassName <$> ["mb-0", "font-size-sm", "text-center", "text-muted"]) ]
    [ HH.text "Already have an account? "
    , HH.a
    [ P.href "#login" ]
    [ HH.text "Sign in" ]
    ]
  • edit in client/src/Aftok/Signup.purs at line 194
    [3.5784][3.5784:5798]()
    ]
  • replacement in client/src/Aftok/Signup.purs at line 195
    [3.5810][3.5810:5820]()
    ]
    [3.5810]
    [3.5820]
    ]
  • replacement in client/src/Aftok/Signup.purs at line 197
    [3.5821][3.5821:5929](),[3.5929][3.6149:6885](),[3.6885][3.950:1012](),[3.6059][3.950:1012](),[3.1012][3.6886:6997](),[3.6997][3.1928:1979](),[3.1979][3.6997:7114](),[3.6997][3.6997:7114](),[3.7114][3.1980:2023](),[3.2023][3.7154:7237](),[3.7154][3.7154:7237](),[3.7237][3.6156:6157](),[3.6156][3.6156:6157](),[3.6157][3.7238:7261](),[3.7261][3.2024:2075](),[3.2075][3.7261:7340](),[3.7261][3.7261:7340]()
    eval :: SignupAction -> H.HalogenM SignupState SignupAction () SignupResult m Unit
    eval = case _ of
    SetUsername user -> do
    ures <- lift $ caps.checkUsername user
    H.modify_ (_ { username = Just user })
    case ures of
    Acc.UsernameCheckOK -> pure unit
    Acc.UsernameCheckTaken -> H.modify_ (_ { signupErrors = [UsernameTaken] })
    SetPassword pass -> do
    H.modify_ (_ { password = Just pass })
    confirm <- H.gets (_.passwordConfirm)
    when (any (notEq pass) confirm) (H.modify_ (_ { signupErrors = [PasswordMismatch] }))
    ConfirmPassword confirm -> do
    H.modify_ (_ { passwordConfirm = Just confirm })
    password <- H.gets (_.password)
    when (any (notEq confirm) password) (H.modify_ (_ { signupErrors = [PasswordMismatch] }))
    SetRecoveryType t -> H.modify_ (_ { recoveryType = t })
    SetRecoveryEmail email -> H.modify_ (_ { recoveryEmail = Just email })
    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
    [3.5821]
    [3.7340]
    eval :: SignupAction -> H.HalogenM SignupState SignupAction () SignupResult m Unit
    eval = case _ of
    SetUsername user -> do
    ures <- lift $ caps.checkUsername user
    H.modify_ (_ { username = Just user })
    case ures of
    Acc.UsernameCheckOK -> pure unit
    Acc.UsernameCheckTaken -> H.modify_ (_ { signupErrors = [ UsernameTaken ] })
    SetPassword pass -> do
    H.modify_ (_ { password = Just pass })
    confirm <- H.gets (_.passwordConfirm)
    when (any (notEq pass) confirm) (H.modify_ (_ { signupErrors = [ PasswordMismatch ] }))
    ConfirmPassword confirm -> do
    H.modify_ (_ { passwordConfirm = Just confirm })
    password <- H.gets (_.password)
    when (any (notEq confirm) password) (H.modify_ (_ { signupErrors = [ PasswordMismatch ] }))
    SetRecoveryType t -> H.modify_ (_ { recoveryType = t })
    SetRecoveryEmail email -> H.modify_ (_ { recoveryEmail = Just email })
    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
    Signup ev -> do
    lift $ system.preventDefault ev
    recType <- H.gets (_.recoveryType)
    usernameV <- V <<< note [ UsernameRequired ] <$> H.gets (_.username)
    pwdFormV <- V <<< note [ PasswordRequired ] <$> H.gets (_.password)
    pwdConfV <- V <<< note [ ConfirmRequired ] <$> H.gets (_.passwordConfirm)
    recoveryType <- H.gets (_.recoveryType)
    recoveryV <- case recoveryType of
    RecoveryEmail -> V <<< note [ EmailRequired ] <<< map Acc.RecoverByEmail <$> H.gets (_.recoveryEmail)
    RecoveryZAddr -> V <<< note [ ZAddrRequired ] <<< map Acc.RecoverByZAddr <$> H.gets (_.recoveryZAddr)
    recapV <- lift $ V <<< note [ CaptchaError ] <$> caps.getRecaptchaResponse Nothing
    lift $ system.log "Sending signup request..."
    let
    reqV :: V (Array SignupError) Acc.SignupRequest
    reqV =
    signupRequest <$> usernameV
    <*> ( (eq <$> pwdFormV <*> pwdConfV)
    `andThen`
    (if _ then pwdFormV else invalid [ PasswordMismatch ])
    )
    <*> recoveryV
    <*> recapV
    case toEither reqV of
    Left errors -> do
    lift $ system.log "Got signup HTTP error."
    H.modify_ (_ { signupErrors = errors })
    Right req -> do
    response <- lift (caps.signup req)
    lift <<< system.log $ "Got signup response " <> show response
    case response of
    Acc.SignupOK -> H.raise (SignupComplete $ req.username)
    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 } ] })
  • edit in client/src/Aftok/Signup.purs at line 262
    [3.7341][3.7341:8103](),[3.8103][3.2076:2130](),[3.2130][3.8103:8503](),[3.8103][3.8103:8503](),[3.8503][3.2131:2214](),[3.2214][3.8529:8654](),[3.8529][3.8529:8654](),[3.8654][3.2215:2289](),[3.2289][3.8654:8683](),[3.8654][3.8654:8683](),[3.8683][3.2290:2734](),[3.2734][3.6157:6158](),[3.9003][3.6157:6158](),[3.6157][3.6157:6158]()
    Signup ev -> do
    lift $ system.preventDefault ev
    recType <- H.gets (_.recoveryType)
    usernameV <- V <<< note [UsernameRequired] <$> H.gets (_.username)
    pwdFormV <- V <<< note [PasswordRequired] <$> H.gets (_.password)
    pwdConfV <- V <<< note [ConfirmRequired ] <$> H.gets (_.passwordConfirm)
    recoveryType <- H.gets (_.recoveryType)
    recoveryV <- case recoveryType of
    RecoveryEmail ->
    V <<< note [EmailRequired] <<< map Acc.RecoverByEmail <$> H.gets (_.recoveryEmail)
    RecoveryZAddr ->
    V <<< note [ZAddrRequired] <<< map Acc.RecoverByZAddr <$> H.gets (_.recoveryZAddr)
    recapV <- lift $ V <<< note [CaptchaError] <$> caps.getRecaptchaResponse Nothing
    lift $ system.log "Sending signup request..."
    let reqV :: V (Array SignupError) Acc.SignupRequest
    reqV = signupRequest <$> usernameV
    <*> ((eq <$> pwdFormV <*> pwdConfV) `andThen`
    (if _ then pwdFormV else invalid [PasswordMismatch]))
    <*> recoveryV
    <*> recapV
    case toEither reqV of
    Left errors -> do
    lift $ system.log "Got signup HTTP error."
    H.modify_ (_ { signupErrors = errors })
    Right req -> do
    response <- lift (caps.signup req)
    lift <<< system.log $ "Got signup response " <> show response
    case response of
    Acc.SignupOK -> H.raise (SignupComplete $ req.username)
    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 }]})
  • replacement in client/src/Aftok/Signup.purs at line 263
    [3.6225][3.6225:6246]()
    recoverySwitch rt =
    [3.6225]
    [3.6246]
    recoverySwitch rt =
  • replacement in client/src/Aftok/Signup.purs at line 265
    [3.6255][3.6255:6407]()
    [ P.classes (ClassName <$> ["form-group", "mb-3"]) ]
    [ HH.label
    [ P.for "recoverySwitch" ]
    [ HH.text "Choose a recovery method" ]
    [3.6255]
    [3.6407]
    [ P.classes (ClassName <$> [ "form-group", "mb-3" ]) ]
    [ HH.label
    [ P.for "recoverySwitch" ]
    [ HH.text "Choose a recovery method" ]
  • replacement in client/src/Aftok/Signup.purs at line 270
    [3.6420][3.1013:1153](),[3.1153][3.6479:7015](),[3.6479][3.6479:7015](),[3.7015][3.1154:1257]()
    [ P.classes (ClassName <$> ["form-group", "mb-3"])
    , CSS.style do
    display flex
    flexFlow row nowrap
    ]
    [ HH.span
    [ P.classes (ClassName <$> [ if rt == RecoveryEmail then "text-success" else "text-muted"]) ]
    [ HH.text "Email" ]
    , HH.div
    [ P.classes (ClassName <$> ["custom-control", "custom-switch", "custom-switch-light", "mx-3"]) ]
    [ HH.input
    [ P.type_ P.InputCheckbox
    , P.classes (ClassName <$> ["custom-control-input"])
    , P.id_ "recoverySwitch"
    , E.onChecked (\b -> Just <<< SetRecoveryType $ if b then RecoveryZAddr else RecoveryEmail)
    ]
    , HH.label [ P.classes (ClassName <$> [ "custom-control-label" ]), P.for "recoverySwitch" ] []
    [3.6420]
    [3.7015]
    [ P.classes (ClassName <$> [ "form-group", "mb-3" ])
    , CSS.style do
    display flex
    flexFlow row nowrap
    ]
    [ HH.span
    [ P.classes (ClassName <$> [ if rt == RecoveryEmail then "text-success" else "text-muted" ]) ]
    [ HH.text "Email" ]
    , HH.div
    [ P.classes (ClassName <$> [ "custom-control", "custom-switch", "custom-switch-light", "mx-3" ]) ]
    [ HH.input
    [ P.type_ P.InputCheckbox
    , P.classes (ClassName <$> [ "custom-control-input" ])
    , P.id_ "recoverySwitch"
    , E.onChecked (\b -> Just <<< SetRecoveryType $ if b then RecoveryZAddr else RecoveryEmail)
    ]
    , HH.label [ P.classes (ClassName <$> [ "custom-control-label" ]), P.for "recoverySwitch" ] []
    ]
    , HH.span
    [ P.classes (ClassName <$> [ if rt == RecoveryZAddr then "text-success" else "text-muted" ]) ]
    [ HH.text "Z-Address" ]
  • edit in client/src/Aftok/Signup.purs at line 292
    [3.7025][3.7025:7184]()
    , HH.span
    [ P.classes (ClassName <$> [if rt == RecoveryZAddr then "text-success" else "text-muted"]) ]
    [ HH.text "Z-Address" ]
    ]
  • replacement in client/src/Aftok/Signup.purs at line 296
    [3.7299][3.7299:7331]()
    RecoveryEmail ->
    HH.div
    [3.7299]
    [3.7331]
    RecoveryEmail ->
    HH.div
  • replacement in client/src/Aftok/Signup.purs at line 300
    [3.7426][3.7426:7708]()
    , 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)
    ]
    [3.7426]
    [3.7708]
    , 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)
    ]
  • replacement in client/src/Aftok/Signup.purs at line 310
    [3.7735][3.7735:7747]()
    HH.div
    [3.7735]
    [3.7747]
    HH.div
  • replacement in client/src/Aftok/Signup.purs at line 312
    [3.7779][3.7779:7975]()
    [ HH.label
    [ P.for "zaddr" ]
    [ HH.text "Zcash Shielded Address"
    , HH.a
    [ P.attr (AttrName "data-toggle") "modal"
    , P.href "#modalAboutZAddr"
    [3.7779]
    [3.7975]
    [ 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" ]
    ]
  • replacement in client/src/Aftok/Signup.purs at line 322
    [3.7987][3.1258:1342]()
    [ HH.img [ P.src "/assets/img/icons/duotone-icons/Code/Info-circle.svg" ]
    [3.7987]
    [3.8072]
    , 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)
  • edit in client/src/Aftok/Signup.purs at line 330
    [3.8084][3.8084:8389]()
    ]
    , 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)
    ]
  • replacement in client/src/Aftok/Signup.purs at line 333
    [3.2768][3.2768:2785]()
    apiCapability =
    [3.2768]
    [3.2785]
    apiCapability =
  • replacement in client/src/Aftok/Signup.purs at line 337
    [3.2889][3.2889:2952]()
    , getRecaptchaResponse: liftEffect <<< getRecaptchaResponse
    [3.2889]
    [3.2952]
    , getRecaptchaResponse: liftEffect <<< getRecaptchaResponse
  • replacement in client/src/Aftok/Signup.purs at line 341
    [3.9037][3.1401:1419](),[3.1401][3.1401:1419]()
    mockCapability =
    [3.9037]
    [3.9038]
    mockCapability =
  • replacement in client/src/Aftok/Signup.purs at line 345
    [3.9168][3.9168:9231]()
    , getRecaptchaResponse: liftEffect <<< getRecaptchaResponse
    [3.9168]
    [3.1448]
    , getRecaptchaResponse: liftEffect <<< getRecaptchaResponse
  • edit in client/src/Aftok/Timeline.purs at line 4
    [3.2332][3.2332:2333]()
  • edit in client/src/Aftok/Timeline.purs at line 9
    [3.44][3.2520:2521](),[3.401][3.2520:2521](),[3.301277][3.2520:2521](),[3.2520][3.2520:2521]()
  • edit in client/src/Aftok/Timeline.purs at line 26
    [3.1266][3.2922:2923](),[3.2922][3.2922:2923]()
  • edit in client/src/Aftok/Timeline.purs at line 31
    [3.2873][3.2873:2874]()
  • edit in client/src/Aftok/Timeline.purs at line 34
    [3.301626][3.301626:301627]()
  • edit in client/src/Aftok/Timeline.purs at line 39
    [3.3220][3.301701:301702]()
  • edit in client/src/Aftok/Timeline.purs at line 43
    [3.301879][3.301879:301880]()
  • replacement in client/src/Aftok/Timeline.purs at line 44
    [3.6710][3.5764:5960]()
    import Aftok.Api.Timeline
    ( TimelineError,
    Event(..),
    Interval(..),
    TimeInterval,
    KeyedEvent,
    TimeSpan,
    start, end, interval,
    event, eventTime, keyedEvent
    )
    [3.6710]
    [3.2875]
    import Aftok.Api.Timeline
    ( TimelineError
    , Event(..)
    , Interval(..)
    , TimeInterval
    , KeyedEvent
    , TimeSpan
    , start
    , end
    , interval
    , event
    , eventTime
    , keyedEvent
    )
  • replacement in client/src/Aftok/Timeline.purs at line 59
    [3.2907][3.4768:4877]()
    import Aftok.Types
    ( System,
    ProjectEvent(..),
    Project,
    Project'(..),
    ProjectId
    )
    [3.2907]
    [3.3080]
    import Aftok.Types
    ( System
    , ProjectEvent(..)
    , Project
    , Project'(..)
    , ProjectId
    )
  • replacement in client/src/Aftok/Timeline.purs at line 67
    [3.3283][3.1101:1123](),[3.1123][3.5961:5989](),[3.4012][3.3327:3350](),[3.5989][3.3327:3350](),[3.301951][3.3327:3350](),[3.3327][3.3327:3350](),[3.301975][3.3417:3421](),[3.3417][3.3417:3421]()
    type TimelineLimits =
    { bounds :: TimeInterval
    , current :: Instant
    }
    [3.3081]
    [3.3421]
    type TimelineLimits
    = { bounds :: TimeInterval
    , current :: Instant
    }
  • replacement in client/src/Aftok/Timeline.purs at line 86
    [3.6387][3.990:1011](),[3.3422][3.990:1011](),[3.1011][3.6388:6472](),[3.6472][3.1075:1079](),[3.1075][3.1075:1079]()
    type DayIntervals =
    { dayBounds :: TimeInterval
    , loggedIntervals :: Array (Interval TimelineEvent)
    }
    [3.6387]
    [3.1079]
    type DayIntervals
    = { dayBounds :: TimeInterval
    , loggedIntervals :: Array (Interval TimelineEvent)
    }
  • replacement in client/src/Aftok/Timeline.purs at line 91
    [3.1080][3.1080:1119]()
    type History = M.Map Date DayIntervals
    [3.1080]
    [2.1432]
    type History
    = M.Map Date DayIntervals
  • replacement in client/src/Aftok/Timeline.purs at line 94
    [2.1433][2.1433:1468]()
    type TimelineInput = Maybe Project
    [2.1433]
    [3.1119]
    type TimelineInput
    = Maybe Project
  • replacement in client/src/Aftok/Timeline.purs at line 97
    [3.1120][3.1124:1145](),[3.3422][3.1124:1145](),[3.1145][3.1121:1197](),[3.1197][3.6473:6519](),[3.6519][3.1198:1243](),[3.302037][3.1198:1243](),[3.1243][3.3532:3536](),[3.3074][3.3532:3536](),[3.302037][3.3532:3536](),[3.3532][3.3532:3536]()
    type TimelineState =
    { selectedProject :: Maybe Project
    , history :: M.Map Date DayIntervals
    , active :: Maybe (Interval TimelineEvent)
    , activeHistory :: M.Map Date DayIntervals
    }
    [3.1120]
    [3.3536]
    type TimelineState
    = { selectedProject :: Maybe Project
    , history :: M.Map Date DayIntervals
    , active :: Maybe (Interval TimelineEvent)
    , activeHistory :: M.Map Date DayIntervals
    }
  • replacement in client/src/Aftok/Timeline.purs at line 111
    [3.3626][3.4907:4965]()
    type Slot id = forall query. H.Slot query ProjectEvent id
    [3.3626]
    [3.3687]
    type Slot id
    = forall query. H.Slot query ProjectEvent id
  • replacement in client/src/Aftok/Timeline.purs at line 114
    [3.3688][3.1146:1159](),[3.1159][3.3173:3225](),[3.3173][3.3173:3225]()
    type Slots =
    ( projectList :: Project.ProjectListSlot Unit
    )
    [3.3688]
    [3.3225]
    type Slots
    = ( projectList :: Project.ProjectListSlot Unit
    )
  • replacement in client/src/Aftok/Timeline.purs at line 120
    [3.3273][3.184:204](),[3.3688][3.184:204](),[3.204][3.4103:4145](),[3.4145][3.6520:6868](),[3.682][3.254:258](),[3.3396][3.254:258](),[3.4296][3.254:258](),[3.6868][3.254:258](),[3.254][3.254:258]()
    type Capability m =
    { timer :: EventSource m TimelineAction
    , logStart :: ProjectId -> m (Either TimelineError (KeyedEvent Instant))
    , logEnd :: ProjectId -> m (Either TimelineError (KeyedEvent Instant))
    , listIntervals :: ProjectId -> TimeSpan -> m (Either TimelineError (Array (Interval (KeyedEvent Instant))))
    , getLatestEvent :: ProjectId -> m (Either TimelineError (Maybe (KeyedEvent Instant)))
    }
    [3.3273]
    [3.258]
    type Capability m
    = { timer :: EventSource m TimelineAction
    , logStart :: ProjectId -> m (Either TimelineError (KeyedEvent Instant))
    , logEnd :: ProjectId -> m (Either TimelineError (KeyedEvent Instant))
    , listIntervals :: ProjectId -> TimeSpan -> m (Either TimelineError (Array (Interval (KeyedEvent Instant))))
    , getLatestEvent :: ProjectId -> m (Either TimelineError (Maybe (KeyedEvent Instant)))
    }
  • replacement in client/src/Aftok/Timeline.purs at line 128
    [3.259][3.1160:1170](),[3.1170][2.1469:1489](),[2.1489][3.4330:4401](),[3.4992][3.4330:4401](),[3.4330][3.4330:4401](),[3.4401][2.1490:1550](),[2.1550][3.4447:4491](),[3.5045][3.4447:4491](),[3.4447][3.4447:4491](),[3.415][3.302289:302306](),[3.1229][3.302289:302306](),[3.3574][3.302289:302306](),[3.4491][3.302289:302306](),[3.302289][3.302289:302306](),[3.302306][3.1230:1276](),[3.1276][3.302343:302371](),[3.302343][3.302343:302371](),[3.302371][3.1277:1314](),[3.1314][3.302409:302417](),[3.302409][3.302409:302417](),[3.302417][3.4419:4429](),[3.4419][3.4419:4429](),[3.4429][2.1551:1658](),[3.1277][3.4560:4585](),[2.1658][3.4560:4585](),[3.6944][3.4560:4585](),[3.4560][3.4560:4585](),[3.4585][3.3659:3683](),[3.3659][3.3659:3683](),[3.3683][3.1278:1309](),[3.1309][3.3716:3724](),[3.3716][3.3716:3724]()
    component
    :: forall query m
    . Monad m
    => System m
    -> Capability m
    -> Project.Capability m
    -> H.Component HH.HTML query TimelineInput ProjectEvent m
    component system caps pcaps = H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval
    { handleAction = eval
    , initialize = Just Initialize
    }
    } where
    initialState :: TimelineInput -> TimelineState
    initialState input =
    { selectedProject: input
    , history: M.empty
    , active: Nothing
    , activeHistory: M.empty
    }
    [3.259]
    [3.4429]
    component ::
    forall query m.
    Monad m =>
    System m ->
    Capability m ->
    Project.Capability m ->
    H.Component HH.HTML query TimelineInput ProjectEvent m
    component system caps pcaps =
    H.mkComponent
    { initialState
    , render
    , eval:
    H.mkEval
    $ H.defaultEval
    { handleAction = eval
    , initialize = Just Initialize
    }
    }
    where
    initialState :: TimelineInput -> TimelineState
    initialState input =
    { selectedProject: input
    , history: M.empty
    , active: Nothing
    , activeHistory: M.empty
    }
  • replacement in client/src/Aftok/Timeline.purs at line 155
    [3.4430][3.4586:4656](),[3.4656][3.1337:1766](),[3.3797][3.1337:1766](),[3.1766][3.4657:4703](),[3.4703][3.1815:1834](),[3.1815][3.1815:1834](),[3.1834][2.1659:1789](),[2.1789][3.1955:2071](),[3.4820][3.1955:2071](),[3.1955][3.1955:2071](),[3.2071][3.4821:4843](),[3.4843][3.3926:3951](),[3.3926][3.3926:3951](),[3.3951][3.4844:4932](),[3.4932][3.4031:4075](),[3.4031][3.4031:4075](),[3.4075][3.2072:2119]()
    render :: TimelineState -> H.ComponentHTML TimelineAction Slots m
    render st =
    HH.section
    [P.classes (ClassName <$> ["section-border", "border-primary"])]
    [HH.div
    [P.classes (ClassName <$> ["container", "pt-6"])]
    [HH.h1
    [P.classes (ClassName <$> ["mb-0", "font-weight-bold", "text-center"])]
    [HH.text "Time Tracker"]
    ,HH.p
    [P.classes (ClassName <$> ["col-md-5", "text-muted", "text-center", "mx-auto"])]
    [HH.text "Your project timeline"]
    ,HH.div_
    [HH.slot _projectList unit (Project.projectListComponent system pcaps) st.selectedProject (Just <<< ProjectSelected)]
    ,HH.div
    [P.classes (ClassName <$> if isNothing st.selectedProject then ["collapse"] else [])]
    ([HH.div_
    [HH.button
    [P.classes (ClassName <$> ["btn", "btn-primary", "float-left", "my-2"])
    ,E.onClick \_ -> Just Start
    ,P.disabled (isJust st.active)
    [3.4430]
    [3.4075]
    render :: TimelineState -> H.ComponentHTML TimelineAction Slots m
    render st =
    HH.section
    [ P.classes (ClassName <$> [ "section-border", "border-primary" ]) ]
    [ HH.div
    [ P.classes (ClassName <$> [ "container", "pt-6" ]) ]
    [ HH.h1
    [ P.classes (ClassName <$> [ "mb-0", "font-weight-bold", "text-center" ]) ]
    [ HH.text "Time Tracker" ]
    , HH.p
    [ P.classes (ClassName <$> [ "col-md-5", "text-muted", "text-center", "mx-auto" ]) ]
    [ HH.text "Your project timeline" ]
    , HH.div_
    [ HH.slot _projectList unit (Project.projectListComponent system pcaps) st.selectedProject (Just <<< ProjectSelected) ]
    , HH.div
    [ P.classes (ClassName <$> if isNothing st.selectedProject then [ "collapse" ] else []) ]
    ( [ HH.div_
    [ HH.button
    [ P.classes (ClassName <$> [ "btn", "btn-primary", "float-left", "my-2" ])
    , E.onClick \_ -> Just Start
    , P.disabled (isJust st.active)
    ]
    [ HH.text "Start Work" ]
    , HH.button
    [ P.classes (ClassName <$> [ "btn", "btn-primary", "float-right", "my-2" ])
    , E.onClick \_ -> Just Stop
    , P.disabled (isNothing st.active)
    ]
    [ HH.text "Stop Work" ]
    ]
  • replacement in client/src/Aftok/Timeline.purs at line 186
    [3.4093][3.4093:4157](),[3.4157][3.4933:5022](),[3.5022][3.4238:4281](),[3.4238][3.4238:4281](),[3.4281][3.2120:2170](),[3.2170][3.4281:4337](),[3.4281][3.4281:4337](),[3.4337][3.849:865](),[3.849][3.849:865](),[3.865][3.1310:1430]()
    [HH.text "Start Work"]
    ,HH.button
    [P.classes (ClassName <$> ["btn", "btn-primary", "float-right", "my-2"])
    ,E.onClick \_ -> Just Stop
    ,P.disabled (isNothing st.active)
    ]
    [HH.text "Stop Work"]
    ]
    ] <> (historyLine <$> reverse (M.toUnfoldable $ unionHistories st.history st.activeHistory))
    )
    [3.4093]
    [3.5176]
    <> (historyLine <$> reverse (M.toUnfoldable $ unionHistories st.history st.activeHistory))
    )
  • replacement in client/src/Aftok/Timeline.purs at line 189
    [3.5188][3.2171:2181](),[3.303581][3.2171:2181]()
    ]
    [3.5188]
    [3.4812]
    ]
  • replacement in client/src/Aftok/Timeline.purs at line 191
    [3.4813][3.5046:5142](),[3.5142][3.1431:1538](),[3.5279][3.1431:1538](),[3.1538][2.1790:1899](),[3.1016][3.5214:5215](),[3.1538][3.5214:5215](),[2.1899][3.5214:5215](),[3.304245][3.5214:5215](),[3.5214][3.5214:5215](),[3.5215][3.1539:1571](),[3.1571][3.683:735](),[3.735][3.1620:1675](),[3.1620][3.1620:1675](),[3.1675][3.736:810](),[3.810][3.5143:5252](),[3.5291][3.5291:5337](),[3.5337][3.915:916](),[3.1825][3.915:916](),[3.916][2.1900:1968](),[2.1968][3.1138:1139](),[3.6922][3.1138:1139](),[3.2377][3.1138:1139](),[3.2051][3.2671:2898](),[3.5265][3.2671:2898](),[3.2688][3.304322:304323](),[3.2898][3.304322:304323](),[3.5641][3.304322:304323](),[3.304322][3.304322:304323](),[3.304323][3.2899:2986](),[3.2782][3.304398:304399](),[3.2986][3.304398:304399](),[3.5953][3.304398:304399](),[3.304398][3.304398:304399](),[3.304399][3.2987:3233](),[3.3233][3.304477:304478](),[3.304477][3.304477:304478](),[3.304478][3.5338:5431](),[3.5431][3.2872:2973](),[3.6040][3.2872:2973](),[3.2872][3.2872:2973](),[3.2973][3.6041:6121](),[3.6121][3.3234:3279](),[3.3279][3.3059:3060](),[3.3059][3.3059:3060](),[3.3060][3.5432:5523](),[3.5523][3.3147:3244](),[3.6207][3.3147:3244](),[3.3147][3.3147:3244](),[3.3244][3.6208:6287](),[3.6287][3.3280:3429]()
    eval :: TimelineAction -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    eval action = do
    case action of
    Initialize -> do
    void $ H.subscribe caps.timer
    currentProject <- H.gets (_.selectedProject)
    traverse_ setStateForProject currentProject
    ProjectSelected p -> do
    oldActive <- isJust <$> H.gets (_.active)
    currentProject <- H.gets (_.selectedProject)
    -- End any active intervals when switching projects.
    when (oldActive && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject) $ do
    (traverse_ logEnd currentProject)
    H.raise (ProjectChange p)
    setStateForProject p
    Start -> do
    project <- H.gets (_.selectedProject)
    traverse_ logStart project
    Stop -> do
    currentProject <- H.gets (_.selectedProject)
    traverse_ logEnd currentProject
    Refresh -> do
    t <- lift $ system.now
    H.modify_ (refresh t)
    -- common updates, irrespective of action
    active <- H.gets (_.active)
    activeHistory <- lift <<< map (fromMaybe M.empty) <<< runMaybeT $ toHistory system (U.fromMaybe active)
    H.modify_ (_ { activeHistory = activeHistory })
    logStart :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    logStart (Project' p) = do
    logged <- lift $ caps.logStart p.projectId
    case logged of
    Left err -> lift <<< system.log $ "Failed to start timer: " <> show err
    Right t -> H.modify_ (updateStart t)
    logEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    logEnd (Project' p) = do
    logged <- lift $ caps.logEnd p.projectId
    case logged of
    Left err -> lift <<< system.log $ "Failed to stop timer: " <> show err
    Right t -> do
    currentState <- H.get
    updatedState <- lift $ updateStop system t currentState
    H.put updatedState
    [3.4813]
    [2.1969]
    eval :: TimelineAction -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    eval action = do
    case action of
    Initialize -> do
    void $ H.subscribe caps.timer
    currentProject <- H.gets (_.selectedProject)
    traverse_ setStateForProject currentProject
    ProjectSelected p -> do
    oldActive <- isJust <$> H.gets (_.active)
    currentProject <- H.gets (_.selectedProject)
    -- End any active intervals when switching projects.
    when (oldActive && any (\p' -> (unwrap p').projectId /= (unwrap p).projectId) currentProject)
    $ do
    (traverse_ logEnd currentProject)
    H.raise (ProjectChange p)
    setStateForProject p
    Start -> do
    project <- H.gets (_.selectedProject)
    traverse_ logStart project
    Stop -> do
    currentProject <- H.gets (_.selectedProject)
    traverse_ logEnd currentProject
    Refresh -> do
    t <- lift $ system.now
    H.modify_ (refresh t)
    -- common updates, irrespective of action
    active <- H.gets (_.active)
    activeHistory <- lift <<< map (fromMaybe M.empty) <<< runMaybeT $ toHistory system (U.fromMaybe active)
    H.modify_ (_ { activeHistory = activeHistory })
  • replacement in client/src/Aftok/Timeline.purs at line 221
    [2.1970][2.1970:2527]()
    setStateForProject :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    setStateForProject p = do
    timeSpan <- TL.Before <$> lift system.nowDateTime -- FIXME, should come from a form control
    intervals' <- lift $ caps.listIntervals (unwrap p).projectId timeSpan
    intervals <- lift $ case intervals' of
    Left err ->
    (system.log $ "Error occurred listing intervals" <> show err ) *>
    pure []
    Right ivals ->
    pure $ map (map LoggedEvent) ivals
    [2.1970]
    [2.2527]
    logStart :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    logStart (Project' p) = do
    logged <- lift $ caps.logStart p.projectId
    case logged of
    Left err -> lift <<< system.log $ "Failed to start timer: " <> show err
    Right t -> H.modify_ (updateStart t)
  • replacement in client/src/Aftok/Timeline.purs at line 228
    [2.2528][2.2528:2736]()
    history' <- lift <<< runMaybeT $ toHistory system intervals
    hist <- case history' of
    Nothing -> lift $ system.log "Project history was empty." *> pure M.empty
    Just h -> pure h
    [2.2528]
    [3.6288]
    logEnd :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    logEnd (Project' p) = do
    logged <- lift $ caps.logEnd p.projectId
    case logged of
    Left err -> lift <<< system.log $ "Failed to stop timer: " <> show err
    Right t -> do
    currentState <- H.get
    updatedState <- lift $ updateStop system t currentState
    H.put updatedState
  • replacement in client/src/Aftok/Timeline.purs at line 238
    [3.6289][2.2737:3161]()
    latestEventResponse <- lift $ caps.getLatestEvent (unwrap p).projectId
    now <- lift $ system.now
    active <- lift $ case latestEventResponse of
    Left err ->
    (system.log $ "Error occurred retrieving the latest event: " <> show err) *>
    pure Nothing
    Right latestEvent -> do
    let activeInterval :: TL.KeyedEvent Instant -> m (Maybe (Interval TimelineEvent))
    [3.6289]
    [2.3161]
    setStateForProject :: Project -> H.HalogenM TimelineState TimelineAction Slots ProjectEvent m Unit
    setStateForProject p = do
    timeSpan <- TL.Before <$> lift system.nowDateTime -- FIXME, should come from a form control
    intervals' <- lift $ caps.listIntervals (unwrap p).projectId timeSpan
    intervals <-
    lift
    $ case intervals' of
    Left err ->
    (system.log $ "Error occurred listing intervals" <> show err)
    *> pure []
    Right ivals -> pure $ map (map LoggedEvent) ivals
    history' <- lift <<< runMaybeT $ toHistory system intervals
    hist <- case history' of
    Nothing -> lift $ system.log "Project history was empty." *> pure M.empty
    Just h -> pure h
    latestEventResponse <- lift $ caps.getLatestEvent (unwrap p).projectId
    now <- lift $ system.now
    active <-
    lift
    $ case latestEventResponse of
    Left err ->
    (system.log $ "Error occurred retrieving the latest event: " <> show err)
    *> pure Nothing
    Right latestEvent -> do
    let
    activeInterval :: TL.KeyedEvent Instant -> m (Maybe (Interval TimelineEvent))
  • replacement in client/src/Aftok/Timeline.purs at line 265
    [2.3214][2.3214:3566]()
    TL.StartEvent i ->
    (system.log $ "Project has an open active interval starting " <> show i) *>
    (Just <<< interval (LoggedEvent ev) <<< PhantomEvent <$> system.now)
    TL.StopEvent _ ->
    pure Nothing
    join <$> traverse activeInterval latestEvent
    [2.3214]
    [2.3566]
    TL.StartEvent i ->
    (system.log $ "Project has an open active interval starting " <> show i)
    *> (Just <<< interval (LoggedEvent ev) <<< PhantomEvent <$> system.now)
    TL.StopEvent _ -> pure Nothing
    join <$> traverse activeInterval latestEvent
    H.modify_ (_ { selectedProject = Just p, history = hist, active = active })
  • replacement in client/src/Aftok/Timeline.purs at line 272
    [2.3567][2.3567:3651](),[2.3651][3.3430:3579](),[3.6289][3.3430:3579]()
    H.modify_ (_ { selectedProject = Just p, history = hist, active = active })
    historyLine
    :: forall w i
    . Tuple Date DayIntervals
    -> HH.HTML w i
    historyLine (Tuple d xs) =
    datedLine d xs.dayBounds xs.loggedIntervals
    [2.3567]
    [3.6540]
    historyLine ::
    forall w i.
    Tuple Date DayIntervals ->
    HH.HTML w i
    historyLine (Tuple d xs) = datedLine d xs.dayBounds xs.loggedIntervals
  • replacement in client/src/Aftok/Timeline.purs at line 278
    [3.6541][3.3580:3617](),[3.3617][3.7173:7228](),[3.7228][3.3633:3650](),[3.6596][3.3633:3650]()
    datedLine
    :: forall w i
    . Date
    -> TimeInterval
    -> Array (Interval TimelineEvent)
    -> HH.HTML w i
    [3.6541]
    [3.3650]
    datedLine ::
    forall w i.
    Date ->
    TimeInterval ->
    Array (Interval TimelineEvent) ->
    HH.HTML w i
  • replacement in client/src/Aftok/Timeline.purs at line 287
    [3.3698][3.3698:3723]()
    clear clearBoth
    [3.3698]
    [3.3723]
    clear clearBoth
  • replacement in client/src/Aftok/Timeline.purs at line 291
    [3.3743][3.3743:4021]()
    [ CSS.style do
    border solid (px 3.0) (rgb 0x00 0xFF 0x00)
    borderRadius px5 px5 px5 px5
    height (px $ 44.0)
    display flex
    , P.classes (ClassName <$> ["my-2"])
    ]
    (evalState (traverse (intervalHtml dateBounds) xs) 0.0)
    [3.3743]
    [3.7264]
    [ CSS.style do
    border solid (px 3.0) (rgb 0x00 0xFF 0x00)
    borderRadius px5 px5 px5 px5
    height (px $ 44.0)
    display flex
    , P.classes (ClassName <$> [ "my-2" ])
    ]
    (evalState (traverse (intervalHtml dateBounds) xs) 0.0)
  • replacement in client/src/Aftok/Timeline.purs at line 300
    [3.7270][3.4022:4048]()
    where
    px5 = px 5.0
    [3.7270]
    [3.7270]
    where
    px5 = px 5.0
  • replacement in client/src/Aftok/Timeline.purs at line 304
    [3.7297][3.7297:7436]()
    dateStr d = (show <<< fromEnum $ year d) <> "-"
    <> (show <<< fromEnum $ month d) <> "-"
    <> (show <<< fromEnum $ day d)
    [3.7297]
    [3.3328]
    dateStr d =
    (show <<< fromEnum $ year d) <> "-"
    <> (show <<< fromEnum $ month d)
    <> "-"
    <> (show <<< fromEnum $ day d)
  • replacement in client/src/Aftok/Timeline.purs at line 310
    [3.5481][3.3339:3352](),[3.3352][3.4049:4066](),[3.4066][3.7229:7275](),[3.7275][3.4067:4099](),[3.3387][3.4067:4099]()
    intervalHtml
    :: forall w i
    . TimeInterval
    -> Interval TimelineEvent
    -> State Number (HH.HTML w i)
    [3.3329]
    [3.4099]
    intervalHtml ::
    forall w i.
    TimeInterval ->
    Interval TimelineEvent ->
    State Number (HH.HTML w i)
  • replacement in client/src/Aftok/Timeline.purs at line 317
    [3.3412][3.1082:1128](),[3.4164][3.1082:1128](),[3.6001][3.1082:1128](),[3.7523][3.1082:1128](),[3.305031][3.1082:1128](),[3.1128][3.7276:7392](),[3.3487][3.3544:3565](),[3.7392][3.3544:3565](),[3.1204][3.3544:3565](),[3.3565][3.936:973]()
    let maxWidth = ilen limits.start limits.end
    ileft = ilen limits.start (tlEventTime i.start)
    iwidth = ilen (tlEventTime i.start) (tlEventTime i.end)
    px5 = px (5.0)
    toPct n = 100.0 * n / maxWidth
    [3.4164]
    [3.7393]
    let
    maxWidth = ilen limits.start limits.end
    ileft = ilen limits.start (tlEventTime i.start)
    iwidth = ilen (tlEventTime i.start) (tlEventTime i.end)
    px5 = px (5.0)
    toPct n = 100.0 * n / maxWidth
  • replacement in client/src/Aftok/Timeline.purs at line 328
    [3.7447][3.4247:4263](),[3.4247][3.4247:4263](),[3.4263][3.3488:3507](),[3.305233][3.3488:3507](),[3.305280][3.305280:305325](),[3.305325][3.4264:4312](),[3.4312][3.1007:1052](),[3.1007][3.1007:1052](),[3.1052][3.305417:305467](),[3.1346][3.305417:305467](),[3.305417][3.305417:305467]()
    pure $ HH.div
    [ CSS.style do
    backgroundColor (rgb 0xf0 0x98 0x18)
    marginLeft (pct $ toPct ileft - offset)
    width (pct $ max (toPct iwidth) 0.5)
    borderRadius px5 px5 px5 px5
    ]
    []
    [3.7447]
    [3.6097]
    pure
    $ HH.div
    [ CSS.style do
    backgroundColor (rgb 0xf0 0x98 0x18)
    marginLeft (pct $ toPct ileft - offset)
    width (pct $ max (toPct iwidth) 0.5)
    borderRadius px5 px5 px5 px5
    ]
    []
  • replacement in client/src/Aftok/Timeline.purs at line 339
    [3.305508][3.305508:305594](),[3.305594][3.3637:3678](),[3.3678][3.305634:305671](),[3.305634][3.305634:305671](),[3.305671][3.6221:6222](),[3.6221][3.6221:6222](),[3.6222][3.305672:305763](),[3.1936][3.6222:6223](),[3.305763][3.6222:6223](),[3.6222][3.6222:6223]()
    timer = EventSource.affEventSource \emitter -> do
    fiber <- Aff.forkAff $ forever do
    Aff.delay $ Aff.Milliseconds 10000.0
    EventSource.emit emitter Refresh
    pure $ EventSource.Finalizer do
    Aff.killFiber (error "Event source finalized") fiber
    [3.305508]
    [3.6223]
    timer =
    EventSource.affEventSource \emitter -> do
    fiber <-
    Aff.forkAff
    $ forever do
    Aff.delay $ Aff.Milliseconds 10000.0
    EventSource.emit emitter Refresh
    pure
    $ EventSource.Finalizer do
    Aff.killFiber (error "Event source finalized") fiber
  • replacement in client/src/Aftok/Timeline.purs at line 351
    [3.7516][3.7516:7646]()
    updateStart ev s =
    s { active = s.active <|> Just (TL.interval (LoggedEvent ev) (PhantomEvent <<< eventTime <<< event $ ev)) }
    [3.7516]
    [3.6387]
    updateStart ev s = s { active = s.active <|> Just (TL.interval (LoggedEvent ev) (PhantomEvent <<< eventTime <<< event $ ev)) }
  • replacement in client/src/Aftok/Timeline.purs at line 353
    [3.6388][3.4443:4497](),[3.4497][3.7647:7672](),[3.7672][3.4511:4552](),[3.4511][3.4511:4552]()
    updateStop
    :: forall m
    . Monad m
    => System m
    -> KeyedEvent Instant
    -> TimelineState
    -> m TimelineState
    [3.6388]
    [3.7673]
    updateStop ::
    forall m.
    Monad m =>
    System m ->
    KeyedEvent Instant ->
    TimelineState ->
    m TimelineState
  • replacement in client/src/Aftok/Timeline.purs at line 361
    [3.7702][3.7702:7796]()
    let updateHistory i = runMaybeT $ toHistory system [TL.interval (start i) (LoggedEvent ev)]
    [3.7702]
    [3.7796]
    let
    updateHistory i = runMaybeT $ toHistory system [ TL.interval (start i) (LoggedEvent ev) ]
  • replacement in client/src/Aftok/Timeline.purs at line 364
    [3.7854][3.4687:4873](),[3.4687][3.4687:4873]()
    pure { selectedProject: st.selectedProject
    , history: maybe st.history (unionHistories st.history) newHistory
    , active: Nothing
    , activeHistory: M.empty
    }
    [3.7854]
    [3.6585]
    pure
    { selectedProject: st.selectedProject
    , history: maybe st.history (unionHistories st.history) newHistory
    , active: Nothing
    , activeHistory: M.empty
    }
  • replacement in client/src/Aftok/Timeline.purs at line 373
    [3.3547][3.7855:7930]()
    s { active = map (\i -> TL.interval (start i) (PhantomEvent t)) s.active
    [3.3547]
    [3.306012]
    s
    { active = map (\i -> TL.interval (start i) (PhantomEvent t)) s.active
  • replacement in client/src/Aftok/Timeline.purs at line 379
    [3.3612][3.6813:6842](),[3.306039][3.6813:6842](),[3.6813][3.6813:6842](),[3.6842][3.4944:4992]()
    let n (Milliseconds x) = x
    in n (unInstant _end) - n (unInstant _start)
    [3.3612]
    [3.6889]
    let
    n (Milliseconds x) = x
    in
    n (unInstant _end) - n (unInstant _start)
  • replacement in client/src/Aftok/Timeline.purs at line 385
    [3.7270][3.10283:10300]()
    apiCapability =
    [3.7270]
    [3.10300]
    apiCapability =
  • replacement in client/src/Aftok/Timeline.purs at line 388
    [3.7362][3.7362:7388]()
    , logEnd: TL.apiLogEnd
    [3.7362]
    [3.7388]
    , logEnd: TL.apiLogEnd
  • replacement in client/src/Aftok/Timeline.purs at line 397
    [3.8009][3.8009:8086]()
    , logEnd: \_ -> Right <<< keyedEvent "" <<< StopEvent <$> liftEffect now
    [3.8009]
    [3.10470]
    , logEnd: \_ -> Right <<< keyedEvent "" <<< StopEvent <$> liftEffect now
  • replacement in client/src/Aftok/Timeline.purs at line 402
    [3.10517][3.8087:8128]()
    utcDayBounds :: Instant -> TimeInterval
    [3.10517]
    [3.5029]
    utcDayBounds :: Instant -> TimeInterval
  • replacement in client/src/Aftok/Timeline.purs at line 404
    [3.5046][3.5046:5272]()
    let startOfDay = DateTime (date $ toDateTime i) bottom
    endOfDay = DT.adjust (Days 1.0) startOfDay
    startInstant = fromDateTime startOfDay
    in TL.interval startInstant (maybe startInstant fromDateTime endOfDay)
    [3.5046]
    [3.10608]
    let
    startOfDay = DateTime (date $ toDateTime i) bottom
    endOfDay = DT.adjust (Days 1.0) startOfDay
  • replacement in client/src/Aftok/Timeline.purs at line 409
    [3.10609][3.5273:5344](),[3.5344][3.8129:8169]()
    localDayBounds
    :: forall m
    . Monad m
    => System m
    -> Instant
    -> MaybeT m (Tuple Date TimeInterval)
    [3.10609]
    [3.5380]
    startInstant = fromDateTime startOfDay
    in
    TL.interval startInstant (maybe startInstant fromDateTime endOfDay)
    localDayBounds ::
    forall m.
    Monad m =>
    System m ->
    Instant ->
    MaybeT m (Tuple Date TimeInterval)
  • replacement in client/src/Aftok/Timeline.purs at line 421
    [3.5471][3.8170:8314]()
    nextNoon <- MaybeT <<< pure $
    fromDateTime <$> (
    DT.adjust (Hours 12.0) <=< DT.adjust (Days 1.0) $
    (toDateTime start)
    )
    [3.5471]
    [3.8314]
    nextNoon <-
    MaybeT <<< pure
    $ fromDateTime
    <$> ( DT.adjust (Hours 12.0) <=< DT.adjust (Days 1.0)
    $ (toDateTime start)
    )
  • replacement in client/src/Aftok/Timeline.purs at line 430
    [3.5866][3.5866:5922](),[3.5922][3.8379:8408](),[3.8408][3.5937:5985](),[3.5937][3.5937:5985]()
    splitInterval
    :: forall m
    . Monad m
    => System m
    -> Interval TimelineEvent
    -> MaybeT m (Array (Tuple Date DayIntervals))
    [3.5866]
    [3.5985]
    splitInterval ::
    forall m.
    Monad m =>
    System m ->
    Interval TimelineEvent ->
    MaybeT m (Array (Tuple Date DayIntervals))
  • replacement in client/src/Aftok/Timeline.purs at line 441
    [3.8686][3.8686:8745]()
    split <- if tlEventTime (end i) < end bounds
    then do
    [3.8686]
    [3.8745]
    split <-
    if tlEventTime (end i) < end bounds then do
  • replacement in client/src/Aftok/Timeline.purs at line 444
    [3.8790][3.8790:8858]()
    pure [Tuple date { dayBounds: bounds, loggedIntervals: [i] }]
    [3.8790]
    [3.8858]
    pure [ Tuple date { dayBounds: bounds, loggedIntervals: [ i ] } ]
  • replacement in client/src/Aftok/Timeline.purs at line 446
    [3.8870][3.8870:9080]()
    let splitEvent = PhantomEvent (end bounds)
    currInterval = Tuple date { dayBounds: bounds, loggedIntervals: [interval (start i) splitEvent] }
    nextInterval = interval splitEvent (end i)
    [3.8870]
    [3.9080]
    let
    splitEvent = PhantomEvent (end bounds)
    currInterval = Tuple date { dayBounds: bounds, loggedIntervals: [ interval (start i) splitEvent ] }
    nextInterval = interval splitEvent (end i)
  • replacement in client/src/Aftok/Timeline.purs at line 457
    [3.6592][3.6592:6644](),[3.6644][3.9271:9307](),[3.9307][3.6665:6705](),[3.6665][3.6665:6705]()
    toHistory
    :: forall m
    . Monad m
    => System m
    -> Array (Interval TimelineEvent)
    -> MaybeT m (M.Map Date DayIntervals)
    [3.6592]
    [3.6705]
    toHistory ::
    forall m.
    Monad m =>
    System m ->
    Array (Interval TimelineEvent) ->
    MaybeT m (M.Map Date DayIntervals)
  • replacement in client/src/Aftok/Timeline.purs at line 468
    [3.6922][3.6922:6949]()
    unionDayIntervals d1 d2 =
    [3.6922]
    [3.6949]
    unionDayIntervals d1 d2 =
  • replacement in client/src/Aftok/Timeline.purs at line 470
    [3.7015][3.7015:7078]()
    , loggedIntervals: d1.loggedIntervals <> d2.loggedIntervals
    [3.7015]
    [3.7078]
    , loggedIntervals: d1.loggedIntervals <> d2.loggedIntervals
  • edit in client/src/Aftok/Timeline.purs at line 475
    [3.7178][3.7178:7179]()
  • edit in client/src/Aftok/Types.purs at line 4
    [3.3258][3.3258:3259]()
  • edit in client/src/Aftok/Types.purs at line 7
    [3.3351][3.7426:7427](),[3.7426][3.7426:7427]()
  • edit in client/src/Aftok/Types.purs at line 21
    [3.5636][3.3525:3526](),[3.7262][3.3525:3526](),[3.11251][3.3525:3526](),[3.7486][3.3525:3526]()
  • edit in client/src/Aftok/Types.purs at line 28
    [3.11447][3.11447:11448]()
  • replacement in client/src/Aftok/Types.purs at line 32
    [3.7525][3.11511:11606](),[3.11606][3.1480:1504](),[3.1504][3.141:173](),[3.173][3.11606:11677](),[3.1504][3.11606:11677](),[3.11606][3.11606:11677](),[3.11677][3.7263:7288](),[3.7288][3.11677:11681](),[3.11677][3.11677:11681]()
    type System m =
    { log :: String -> m Unit
    , error :: String -> m Unit
    , now :: m Instant
    , getHash :: m String
    , setHash :: String -> m Unit
    , nowDateTime :: m DateTime
    , preventDefault :: WE.Event -> m Unit
    , dateFFI :: DateFFI m
    }
    [3.7525]
    [3.11681]
    type System m
    = { log :: String -> m Unit
    , error :: String -> m Unit
    , now :: m Instant
    , getHash :: m String
    , setHash :: String -> m Unit
    , nowDateTime :: m DateTime
    , preventDefault :: WE.Event -> m Unit
    , dateFFI :: DateFFI m
    }
  • replacement in client/src/Aftok/Types.purs at line 44
    [3.11707][3.11707:11721]()
    liveSystem =
    [3.11707]
    [3.11721]
    liveSystem =
  • replacement in client/src/Aftok/Types.purs at line 55
    [3.7341][3.7341:7421](),[3.7421][3.11902:11906](),[3.11902][3.11902:11906]()
    type DateFFI m =
    { midnightLocal :: Instant -> m (Maybe (Tuple Date Instant))
    }
    [3.7341]
    [3.11906]
    type DateFFI m
    = { midnightLocal :: Instant -> m (Maybe (Tuple Date Instant))
    }
  • replacement in client/src/Aftok/Types.purs at line 60
    [3.7450][3.7450:7463]()
    jsDateFFI =
    [3.7450]
    [3.7463]
    jsDateFFI =
  • replacement in client/src/Aftok/Types.purs at line 66
    [3.7571][3.7571:7636]()
    let jsDate = JD.fromInstant i
    year <- JD.getFullYear jsDate
    [3.7571]
    [3.7636]
    let
    jsDate = JD.fromInstant i
    year <- JD.getFullYear jsDate
  • replacement in client/src/Aftok/Types.purs at line 70
    [3.7666][3.7666:7695]()
    day <- JD.getDate jsDate
    [3.7666]
    [3.7695]
    day <- JD.getDate jsDate
  • replacement in client/src/Aftok/Types.purs at line 72
    [3.7742][3.7742:7776]()
    let date = JD.toDate jsMidnight
    [3.7742]
    [3.7776]
    let
    date = JD.toDate jsMidnight
  • replacement in client/src/Aftok/Types.purs at line 77
    [3.7895][3.7895:8041]()
    midnightLocalJS year month day = JD.jsdateLocal
    { year
    , month
    , day
    , hour: 0.0
    , minute: 0.0
    , second: 0.0
    , millisecond: 0.0
    }
    [3.7895]
    [3.8041]
    midnightLocalJS year month day =
    JD.jsdateLocal
    { year
    , month
    , day
    , hour: 0.0
    , minute: 0.0
    , second: 0.0
    , millisecond: 0.0
    }
  • replacement in client/src/Aftok/Types.purs at line 89
    [3.8119][3.8119:8200]()
    hoistDateFFI nt ffi =
    { midnightLocal: \i -> nt (ffi.midnightLocal i)
    }
    [3.8119]
    [3.8200]
    hoistDateFFI nt ffi =
    { midnightLocal: \i -> nt (ffi.midnightLocal i)
    }
  • replacement in client/src/Aftok/Types.purs at line 93
    [3.8201][3.7525:7540](),[3.11907][3.7525:7540](),[3.7525][3.7525:7540]()
    data APIError
    [3.8201]
    [3.7540]
    data APIError
  • replacement in client/src/Aftok/Types.purs at line 101
    [3.3643][3.3643:3727]()
    ParseFailure js e -> "ParseFailure (" <> show (stringify js) <> ") " <> show e
    [3.3643]
    [3.3727]
    ParseFailure js e -> "ParseFailure (" <> show (stringify js) <> ") " <> show e
  • replacement in client/src/Aftok/Types.purs at line 104
    [3.5638][3.5638:5673]()
    newtype ProjectId = ProjectId UUID
    [3.5638]
    [3.5673]
    newtype ProjectId
    = ProjectId UUID
  • edit in client/src/Aftok/Types.purs at line 108
    [3.5717]
    [3.5717]
  • replacement in client/src/Aftok/Types.purs at line 114
    [3.5845][3.5845:5878]()
    newtype Project' date = Project'
    [3.5845]
    [3.5878]
    newtype Project' date
    = Project'
  • edit in client/src/Aftok/Types.purs at line 121
    [3.5983]
    [3.5983]
  • replacement in client/src/Aftok/Types.purs at line 124
    [3.6041][3.6041:6074]()
    type Project = Project' DateTime
    [3.6041]
    [3.6074]
    type Project
    = Project' DateTime
  • edit in client/src/Aftok/Types.purs at line 134
    [3.6263][3.6263:6264]()
  • replacement in client/src/Aftok/Types.purs at line 135
    [3.6301][3.6301:6446]()
    projectId <- ProjectId <$> (note "Failed to decode project UUID" $ parseUUID projectIdStr)
    projectName <- project .: "projectName"
    [3.6301]
    [3.6446]
    projectId <- ProjectId <$> (note "Failed to decode project UUID" $ parseUUID projectIdStr)
    projectName <- project .: "projectName"
  • replacement in client/src/Aftok/Types.purs at line 138
    [3.6494][3.6494:6623]()
    initiatorStr <- project .: "initiator"
    initiator <- note "Failed to decode initiator UUID" $ parseUUID initiatorStr
    [3.6494]
    [3.6623]
    initiatorStr <- project .: "initiator"
    initiator <- note "Failed to decode initiator UUID" $ parseUUID initiatorStr
  • replacement in client/src/Aftok/Types.purs at line 142
    [3.6697][3.11909:11965](),[3.11909][3.11909:11965]()
    newtype JsonCompose f g a = JsonCompose (Compose f g a)
    [3.6697]
    [3.11965]
    newtype JsonCompose f g a
    = JsonCompose (Compose f g a)
  • replacement in client/src/Aftok/Types.purs at line 167
    [3.3896][3.3896:3933]()
    str <- except $ decodeJson json
    [3.3896]
    [3.3933]
    str <- except $ decodeJson json
  • replacement in client/src/Aftok/Types.purs at line 173
    [3.8234][3.4059:4152](),[3.4059][3.4059:4152](),[3.4152][3.8235:8274]()
    except $ note ("Unable to convert date " <> show jsDate <> " to a valid DateTime value.")
    (JD.toDateTime jsDate)
    [3.8234]
    [3.12816]
    except
    $ note ("Unable to convert date " <> show jsDate <> " to a valid DateTime value.")
    (JD.toDateTime jsDate)
  • replacement in client/src/Aftok/Types.purs at line 182
    [3.4196][3.13025:13187]()
    parseDatedResponse
    :: forall t
    . Traversable t
    => DecodeJson (t String)
    => Either AJAX.Error (Response Json)
    -> ExceptT APIError Effect (t Instant)
    [3.4196]
    [3.13187]
    parseDatedResponse ::
    forall t.
    Traversable t =>
    DecodeJson (t String) =>
    Either AJAX.Error (Response Json) ->
    ExceptT APIError Effect (t Instant)
  • replacement in client/src/Aftok/Types.purs at line 189
    [3.13218][3.13218:13301]()
    Left err ->
    throwError $ Error { status: Nothing, message: printError err }
    [3.13218]
    [3.13301]
    Left err -> throwError $ Error { status: Nothing, message: printError err }
  • replacement in client/src/Aftok/Types.purs at line 191
    [3.13331][3.13331:13578]()
    StatusCode 403 ->
    throwError $ Forbidden
    StatusCode 200 ->
    withExceptT (ParseFailure r.body) $ map fromDateTime <$> decodeDatedJson r.body
    other ->
    throwError $ Error { status: Just other, message: r.statusText }
    [3.13331]
    StatusCode 403 -> throwError $ Forbidden
    StatusCode 200 -> withExceptT (ParseFailure r.body) $ map fromDateTime <$> decodeDatedJson r.body
    other -> throwError $ Error { status: Just other, message: r.statusText }
  • edit in client/src/Landkit/Card.purs at line 4
    [3.306160][3.306160:306161]()
  • replacement in client/src/Landkit/Card.purs at line 15
    [3.306419][3.306419:306474]()
    [ P.classes (ClassName <$> ["card", "card-row"]) ]
    [3.306419]
    [3.306474]
    [ P.classes (ClassName <$> [ "card", "card-row" ]) ]
  • edit in client/src/Landkit/Modal.purs at line 4
    [3.306568][3.306568:306569]()
  • replacement in client/src/Landkit/Modal.purs at line 16
    [3.306915][3.306915:306965]()
    [ P.classes (ClassName <$> ["modal", "fade"])
    [3.306915]
    [3.306965]
    [ P.classes (ClassName <$> [ "modal", "fade" ])
  • replacement in client/src/Landkit/Modal.purs at line 24
    [3.307197][3.307197:307417]()
    [ P.classes (ClassName <$> ["modal-dialog", "modal-lg", "modal-dialog-centered"])
    -- , P.role "document"
    ]
    [ HH.div
    [ P.classes (ClassName <$> ["modal-content"])]
    children
    ]
    [3.307197]
    [3.307417]
    [ P.classes (ClassName <$> [ "modal-dialog", "modal-lg", "modal-dialog-centered" ])
    -- , P.role "document"
    ]
    [ HH.div
    [ P.classes (ClassName <$> [ "modal-content" ]) ]
    children
    ]
  • edit in client/src/Main.purs at line 4
    [3.307475][3.3680:3681]()
  • edit in client/src/Main.purs at line 5
    [3.932][3.492:493](),[3.3721][3.492:493](),[3.6963][3.492:493](),[3.307475][3.492:493](),[3.492][3.492:493]()
  • edit in client/src/Main.purs at line 8
    [3.307565][3.961:962](),[3.3248][3.961:962]()
  • edit in client/src/Main.purs at line 11
    [3.308][3.1023:1024](),[3.307613][3.1023:1024](),[3.1023][3.1023:1024]()
  • edit in client/src/Main.purs at line 14
    [3.1340][3.1340:1341]()
  • edit in client/src/Main.purs at line 22
    [3.400][3.1094:1095](),[3.1158][3.1094:1095](),[3.1485][3.1094:1095](),[3.3360][3.1094:1095](),[3.7084][3.1094:1095](),[3.1094][3.1094:1095]()
  • replacement in client/src/Main.purs at line 31
    [3.307845][3.6849:6893](),[3.6893][3.1546:1583](),[3.307895][3.1546:1583]()
    main = runHalogenAff do
    body <- awaitBody
    let --login = Login.mockCapability
    [3.307845]
    [3.1583]
    main =
    runHalogenAff do
    body <- awaitBody
    let --login = Login.mockCapability
  • edit in client/src/Main.purs at line 36
    [3.1617]
    [3.3006]
  • edit in client/src/Main.purs at line 38
    [3.3042]
    [3.7682]
  • edit in client/src/Main.purs at line 40
    [3.7722]
    [3.3788]
  • edit in client/src/Main.purs at line 42
    [3.3826]
    [3.6894]
  • edit in client/src/Main.purs at line 44
    [3.6934][3.6934:7016](),[3.7016][3.401:446](),[3.1683][3.401:446]()
    mainComponent = component liveSystem login signup timeline project overview
    halogenIO <- runUI mainComponent unit body
  • replacement in client/src/Main.purs at line 45
    [3.1685][3.447:611]()
    void $ liftEffect $ matchesWith (match mainRoute) \oldMay new ->
    when (oldMay /= Just new) do
    launchAff_ <<< halogenIO.query <<< H.tell $ Navigate new
    [3.1685]
    [3.611]
    mainComponent = component liveSystem login signup timeline project overview
    halogenIO <- runUI mainComponent unit body
    void $ liftEffect
    $ matchesWith (match mainRoute) \oldMay new ->
    when (oldMay /= Just new) do
    launchAff_ <<< halogenIO.query <<< H.tell $ Navigate new
  • replacement in client/src/Main.purs at line 52
    [3.612][3.612:623]()
    data View
    [3.612]
    [3.1700]
    data View
  • replacement in client/src/Main.purs at line 57
    [3.7031][3.1736:1751](),[3.1736][3.1736:1751]()
    | VTimeline
    [3.7031]
    [3.624]
    | VTimeline
  • replacement in client/src/Main.purs at line 60
    [3.649][3.649:721](),[3.721][3.7032:7064](),[3.7064][3.721:757](),[3.721][3.721:757]()
    mainRoute = oneOf
    [ VSignup <$ lit "signup"
    , VLogin <$ lit "login"
    , VOverview <$ lit "overview"
    , VTimeline <$ lit "timeline"
    ]
    [3.649]
    [3.757]
    mainRoute =
    oneOf
    [ VSignup <$ lit "signup"
    , VLogin <$ lit "login"
    , VOverview <$ lit "overview"
    , VTimeline <$ lit "timeline"
    ]
  • edit in client/src/Main.purs at line 78
    [3.977]
    [3.977]
  • replacement in client/src/Main.purs at line 81
    [3.1014][3.1014:1049]()
    data MainQuery a = Navigate View a
    [3.1014]
    [3.1049]
    data MainQuery a
    = Navigate View a
  • replacement in client/src/Main.purs at line 84
    [3.1050][3.1752:1769](),[3.1117][3.1752:1769](),[3.1769][3.1051:1068](),[3.1068][3.1790:1818](),[3.1790][3.1790:1818](),[3.1818][3.7092:7129](),[3.7129][3.1818:1822](),[3.1818][3.1818:1822]()
    type MainState =
    { view :: View
    , config :: Signup.Config
    , selectedProject :: Maybe Project
    }
    [3.1050]
    [3.308063]
    type MainState
    = { view :: View
    , config :: Signup.Config
    , selectedProject :: Maybe Project
    }
  • replacement in client/src/Main.purs at line 97
    [3.1119][3.308119:308133](),[3.308133][3.1694:1723](),[3.1723][3.1912:1943](),[3.1943][3.7162:7197](),[3.1943][3.1723:1758](),[3.7197][3.1723:1758](),[3.1723][3.1723:1758](),[3.282][3.308197:308201](),[3.1758][3.308197:308201](),[3.308197][3.308197:308201]()
    type Slots =
    ( login :: Login.Slot Unit
    , signup :: Signup.Slot Unit
    , overview :: Overview.Slot Unit
    , timeline :: Timeline.Slot Unit
    )
    [3.1119]
    [3.308201]
    type Slots
    = ( login :: Login.Slot Unit
    , signup :: Signup.Slot Unit
    , overview :: Overview.Slot Unit
    , timeline :: Timeline.Slot Unit
    )
  • edit in client/src/Main.purs at line 105
    [3.308236]
    [3.1944]
  • edit in client/src/Main.purs at line 107
    [3.1980]
    [3.7198]
  • edit in client/src/Main.purs at line 109
    [3.7238]
    [3.308236]
  • replacement in client/src/Main.purs at line 112
    [3.1182][3.308277:308288](),[3.308288][3.1069:1096](),[3.1096][3.13721:13772](),[3.13721][3.13721:13772](),[3.13772][3.1981:2006](),[3.2006][3.13772:13825](),[3.13772][3.13772:13825](),[3.13825][3.7239:7266](),[3.7266][3.1097:1147](),[3.13825][3.1097:1147](),[3.1147][3.7267:7337](),[3.1831][3.308429:308458](),[3.2071][3.308429:308458](),[3.4028][3.308429:308458](),[3.7337][3.308429:308458](),[3.13925][3.308429:308458](),[3.308429][3.308429:308458](),[3.308458][3.4029:4065](),[3.4065][3.1148:1219](),[3.1219][3.4094:4140](),[3.4094][3.4094:4140](),[3.4140][3.1220:1224]()
    component
    :: forall input output m
    . Monad m
    => System m
    -> Login.Capability m
    -> Signup.Capability m
    -> Timeline.Capability m
    -> Project.Capability m
    -> Overview.Capability m
    -> H.Component HH.HTML MainQuery input output m
    component system loginCap signupCap tlCap pCap ovCap = H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval
    { handleAction = handleAction
    , handleQuery = handleQuery
    , initialize = Just Initialize
    }
    }
    [3.1182]
    [3.1224]
    component ::
    forall input output m.
    Monad m =>
    System m ->
    Login.Capability m ->
    Signup.Capability m ->
    Timeline.Capability m ->
    Project.Capability m ->
    Overview.Capability m ->
    H.Component HH.HTML MainQuery input output m
    component system loginCap signupCap tlCap pCap ovCap =
    H.mkComponent
    { initialState
    , render
    , eval:
    H.mkEval
    $ H.defaultEval
    { handleAction = handleAction
    , handleQuery = handleQuery
    , initialize = Just Initialize
    }
    }
  • replacement in client/src/Main.purs at line 135
    [3.1232][3.308528:308567](),[3.308528][3.308528:308567](),[3.308567][3.9266:9389](),[3.9389][3.7338:7371](),[3.7371][3.9389:9397](),[3.9389][3.9389:9397]()
    initialState :: input -> MainState
    initialState _ =
    { view: VLoading
    , config: { recaptchaKey: "6LdiA78ZAAAAAGGvDId_JmDbhalduIDZSqbuikfq" }
    , selectedProject: Nothing
    }
    [3.1232]
    [3.308598]
    initialState :: input -> MainState
    initialState _ =
    { view: VLoading
    , config: { recaptchaKey: "6LdiA78ZAAAAAGGvDId_JmDbhalduIDZSqbuikfq" }
    , selectedProject: Nothing
    }
  • replacement in client/src/Main.purs at line 142
    [3.308599][3.13926:13988](),[3.13988][3.2143:2193](),[3.2193][3.1631:1702](),[3.1631][3.1631:1702]()
    render :: MainState -> H.ComponentHTML MainAction Slots m
    render st = case st.view of
    VLoading ->
    HH.div [P.classes [ClassName "loader"]] [HH.text "Loading..."]
    [3.308599]
    [3.1702]
    render :: MainState -> H.ComponentHTML MainAction Slots m
    render st = case st.view of
    VLoading -> HH.div [ P.classes [ ClassName "loader" ] ] [ HH.text "Loading..." ]
    VSignup ->
    HH.div_
    [ HH.slot _signup unit (Signup.component system signupCap st.config) unit (Just <<< SignupAction) ]
    VLogin ->
    HH.div_
    [ HH.slot _login unit (Login.component system loginCap) unit (Just <<< LoginAction) ]
    VOverview ->
    withNavBar
    $ HH.div_
    [ HH.slot _overview unit (Overview.component system ovCap pCap) st.selectedProject (Just <<< ProjectAction) ]
    VTimeline ->
    withNavBar
    $ HH.div_
    [ HH.slot _timeline unit (Timeline.component system tlCap pCap) st.selectedProject (Just <<< ProjectAction) ]
  • replacement in client/src/Main.purs at line 160
    [3.1703][3.2194:2212](),[3.2212][3.1704:1721](),[3.308708][3.1704:1721](),[3.1721][3.2213:2323](),[3.2323][3.1812:1813](),[3.14087][3.1812:1813](),[3.1812][3.1812:1813](),[3.1813][3.2324:2454]()
    VSignup ->
    HH.div_
    [ HH.slot _signup unit (Signup.component system signupCap st.config) unit (Just <<< SignupAction) ]
    VLogin ->
    HH.div_
    [ HH.slot _login unit (Login.component system loginCap) unit (Just <<< LoginAction) ]
    [3.1703]
    [3.2454]
    handleAction :: MainAction -> H.HalogenM MainState MainAction Slots output m Unit
    handleAction = case _ of
    Initialize -> do
    route <- lift system.getHash
    nextView <- case route of
    "login" -> pure VLogin
    "signup" -> pure VSignup
    other -> do
    result <- lift loginCap.checkLogin
    case result of
    Acc.LoginForbidden -> pure VLogin
    Acc.LoginError _ -> pure VLogin
    _ -> pure VTimeline
    navigate nextView
    SignupAction (Signup.SignupComplete _) -> navigate VTimeline
    SignupAction (Signup.SigninNav) -> navigate VLogin
    LoginAction (Login.LoginComplete _) -> navigate VTimeline
    LogoutAction -> do
    lift loginCap.logout
    navigate VLogin
    ProjectAction (ProjectChange p) -> H.modify_ (_ { selectedProject = Just p })
  • replacement in client/src/Main.purs at line 182
    [3.2455][3.7372:7391](),[3.7391][2.3653:3683](),[2.3683][3.7408:7528](),[3.7408][3.7408:7528]()
    VOverview ->
    withNavBar $ HH.div_
    [ HH.slot _overview unit (Overview.component system ovCap pCap) st.selectedProject (Just <<< ProjectAction) ]
    [3.2455]
    [3.7528]
    handleQuery :: forall a. MainQuery a -> H.HalogenM MainState MainAction Slots output m (Maybe a)
    handleQuery = case _ of
    Navigate view a -> do
    currentView <- H.gets _.view
    when (currentView /= view) $ navigate view
    pure (Just a)
  • replacement in client/src/Main.purs at line 189
    [3.7529][3.2455:2475](),[3.2455][3.2455:2475](),[3.2475][3.1814:1844](),[3.308824][3.1814:1844](),[3.1844][2.3684:3804]()
    VTimeline ->
    withNavBar $ HH.div_
    [ HH.slot _timeline unit (Timeline.component system tlCap pCap) st.selectedProject (Just <<< ProjectAction) ]
    [3.7529]
    [3.308924]
    navigate :: View -> H.HalogenM MainState MainAction Slots output m Unit
    navigate view = do
    lift $ system.setHash (routeHash view)
    H.modify_ (_ { view = view })
  • edit in client/src/Main.purs at line 194
    [3.308925][3.1233:1348](),[3.1348][3.4241:4264](),[3.2509][3.4241:4264](),[3.309026][3.4241:4264](),[3.4264][3.2510:2747](),[3.2747][3.9398:9496](),[3.9496][3.2794:2830](),[3.2794][3.2794:2830](),[3.2830][3.1349:1375](),[3.1403][3.2081:2082](),[3.2962][3.2081:2082](),[3.4480][3.2081:2082](),[3.2082][3.2963:3011](),[3.3011][3.1404:1431](),[3.1431][3.3054:3055](),[3.3054][3.3054:3055](),[3.3055][3.9497:9538](),[3.9538][3.1432:1456](),[3.1456][3.7637:7711](),[3.1456][3.9578:9579](),[3.7711][3.9578:9579](),[3.9578][3.9578:9579](),[3.9579][3.3055:3080](),[3.3055][3.3055:3080](),[3.3080][3.2101:2130](),[3.2101][3.2101:2130](),[3.2130][3.1457:1482](),[3.1482][3.7712:7814](),[3.7814][3.1482:1749](),[3.1482][3.1482:1749](),[3.1749][3.3121:3122](),[3.3121][3.3121:3122](),[3.3122][3.1750:1930](),[3.1930][3.2154:2155](),[3.3122][3.2154:2155](),[3.2154][3.2154:2155]()
    handleAction :: MainAction -> H.HalogenM MainState MainAction Slots output m Unit
    handleAction = case _ of
    Initialize -> do
    route <- lift system.getHash
    nextView <- case route of
    "login" -> pure VLogin
    "signup" -> pure VSignup
    other -> do
    result <- lift loginCap.checkLogin
    case result of
    Acc.LoginForbidden -> pure VLogin
    Acc.LoginError _ -> pure VLogin
    _ -> pure VTimeline
    navigate nextView
    SignupAction (Signup.SignupComplete _) ->
    navigate VTimeline
    SignupAction (Signup.SigninNav) ->
    navigate VLogin
    LoginAction (Login.LoginComplete _) ->
    navigate VTimeline
    LogoutAction -> do
    lift loginCap.logout
    navigate VLogin
    ProjectAction (ProjectChange p) ->
    H.modify_ (_ { selectedProject = Just p })
    handleQuery :: forall a. MainQuery a -> H.HalogenM MainState MainAction Slots output m (Maybe a)
    handleQuery = case _ of
    Navigate view a -> do
    currentView <- H.gets _.view
    when (currentView /= view) $ navigate view
    pure (Just a)
    navigate :: View -> H.HalogenM MainState MainAction Slots output m Unit
    navigate view = do
    lift $ system.setHash (routeHash view)
    H.modify_ (_ { view = view })
  • replacement in client/src/Main.purs at line 196
    [3.2264][3.2264:2450](),[3.2450][3.7815:7936]()
    HH.div_
    [HH.nav
    [P.classes (ClassName <$> ["navbar", "navbar-expand-lg", "navbar-light", "bg-white"])]
    [HH.div
    [P.classes (ClassName <$> ["container-fluid"])]
    [ brand
    , HH.ul [P.classes (ClassName <$> ["navbar-nav", "ml-auto"])] (map navItem nav)
    , logout
    [3.2264]
    [3.7936]
    HH.div_
    [ HH.nav
    [ P.classes (ClassName <$> [ "navbar", "navbar-expand-lg", "navbar-light", "bg-white" ]) ]
    [ HH.div
    [ P.classes (ClassName <$> [ "container-fluid" ]) ]
    [ brand
    , HH.ul [ P.classes (ClassName <$> [ "navbar-nav", "ml-auto" ]) ] (map navItem nav)
    , logout
    ]
  • replacement in client/src/Main.purs at line 206
    [3.7946][3.2474:2505](),[3.2474][3.2474:2505]()
    ]
    ,body
    ]
    [3.7946]
    [3.2505]
    , body
    ]
  • replacement in client/src/Main.purs at line 210
    [3.7968][3.7968:8072]()
    nav = [ { label: "Overview", path: "overview" }
    , { label: "Timeline", path: "timeline" }
    ]
    [3.7968]
    [3.8072]
    nav =
    [ { label: "Overview", path: "overview" }
    , { label: "Timeline", path: "timeline" }
    ]
  • replacement in client/src/Main.purs at line 216
    [3.2551][3.2551:2701]()
    brand = HH.div
    [P.classes (ClassName <$> ["navbar-brand"])]
    [HH.h4
    [P.classes (ClassName <$> ["font-weight-bold"])]
    [HH.text "Aftok"]
    ]
    [3.2551]
    [3.2701]
    brand =
    HH.div
    [ P.classes (ClassName <$> [ "navbar-brand" ]) ]
    [ HH.h4
    [ P.classes (ClassName <$> [ "font-weight-bold" ]) ]
    [ HH.text "Aftok" ]
    ]
  • replacement in client/src/Main.purs at line 225
    [3.2755][3.2755:2869](),[3.2869][3.3123:3161](),[3.3161][3.2901:2926](),[3.2901][3.2901:2926]()
    logout = HH.button
    [P.classes (ClassName <$> ["btn", "navbar-btn", "btn-sm", "btn-primary", "lift", "ml-auto"])
    ,E.onClick \_ -> Just LogoutAction
    ]
    [HH.text "Logout"]
    [3.2755]
    [3.8074]
    logout =
    HH.button
    [ P.classes (ClassName <$> [ "btn", "navbar-btn", "btn-sm", "btn-primary", "lift", "ml-auto" ])
    , E.onClick \_ -> Just LogoutAction
    ]
    [ HH.text "Logout" ]
  • replacement in client/src/Main.purs at line 232
    [3.8075][3.8075:8141]()
    type NavTop =
    { label :: String
    , items :: Array NavItem
    }
    [3.8075]
    [3.2926]
    type NavTop
    = { label :: String
    , items :: Array NavItem
    }
  • replacement in client/src/Main.purs at line 237
    [3.2927][3.8142:8202]()
    type NavItem =
    { label :: String
    , path :: String
    }
    [3.2927]
    [3.8202]
    type NavItem
    = { label :: String
    , path :: String
    }
  • replacement in client/src/Main.purs at line 243
    [3.8261][3.8261:8275]()
    navItem ni =
    [3.8261]
    [3.8275]
    navItem ni =
  • replacement in client/src/Main.purs at line 245
    [3.8283][3.8283:8329]()
    [P.classes (ClassName <$> ["nav-item"]) ]
    [3.8283]
    [3.8329]
    [ P.classes (ClassName <$> [ "nav-item" ]) ]
  • replacement in client/src/Main.purs at line 247
    [3.8340][3.8340:8454]()
    [ P.classes (ClassName <$> ["nav-link"])
    , P.href ("#" <> ni.path)
    ]
    [ HH.text ni.label ]
    [3.8340]
    [3.8454]
    [ P.classes (ClassName <$> [ "nav-link" ])
    , P.href ("#" <> ni.path)
    ]
    [ HH.text ni.label ]