QU5FW67RGCWOWT2YFM4NYMJFFHWIRPQANQBBAHBKZUY7UYMCSIMQC PT4276XCOP5NJ3GRFJLIBZKVNVAOATAY5PLWV7FWK6RZW5FTEP5AC NJNMO72S7VIUV22JXB4IFPZMHWTJAOTP6EC6Z4QSKYIROSXT52MQC EA5BFM5GMM7KNMDLTVOSUKVKMSIDD72TAFVHDVGEOUY5VELECU3QC WRPIYG3EUHZR6N6T74ZXZDXATRMIRLXAQ24UNUNSVTVYGMT2VDSQC JXG3FCXYBDKMUD77DOM7RCIJYKB7BILC43OHHDZBE7YQRGAMUCCAC BFZN4SUAGYNFFYVAP36BAX32DMO622PK4EPEVQQEAGC2IHTEAAPQC RB2ETNIFLQUA6OA66DAEOXZ25ENMQGNKX5CZRSKEYHTD6BQ6NTFQC CDHZL3RP2HGNSSBXD4VDSAW7M3SPBF7LBYB2BL6I3N6EI5URSOJAC UOG5H2TW5R3FSHQPJCEMNFDQZS5APZUP7OM54FIBQG7ZP4HASQ7QC NSRSSSTRMJPPUYQANYDWGI5D3NVM6RQEVZCDUUNQAOL3OWQTD27AC -- import Halogen as H-- import Halogen.HTML.Core (ClassName(..))-- import Halogen.HTML as HH-- import Halogen.HTML.CSS as CSS-- import Halogen.HTML.Events as E-- import Web.Event.Event as WE-- import Halogen.HTML.Properties as P
import Aftok.Types (APIError(..))import Halogen as Himport Halogen.HTML as HHimport Halogen.HTML.Events as Eimport Halogen.HTML.Properties as Pimport Effect.Class.Console (error)newtype ProjectId = ProjectId UUIDpidStr :: ProjectId -> StringpidStr (ProjectId uuid) = show uuid
data APIError= Forbidden| ParseFailure Json String| Error { status :: Maybe StatusCode, message :: String }
projectListComponent:: forall query input m. EC.MonadEffect m=> Capability m-> H.Component HH.HTML query input Project mprojectListComponent caps = H.mkComponent{ initialState, render, eval: H.mkEval $ H.defaultEval{ handleAction = eval, initialize = Just Initialize}} whereinitialState :: input -> ProjectCStateinitialState _ = { projects: [] }render :: forall slots. ProjectCState -> H.ComponentHTML ProjectAction slots mrender st =let renderOption (Project' p) =HH.option [P.value $ pidStr p.projectId] [HH.text p.projectName]in HH.select[E.onSelectedIndexChange (Just <<< Select)]([HH.option [P.selected true, P.disabled true] [HH.text "Select a project"]] <> map renderOption st.projects)eval :: ProjectAction -> H.HalogenM ProjectCState ProjectAction () Project m Uniteval = case _ ofInitialize -> dores <- lift caps.listProjectscase res ofLeft _ -> error "Could not retrieve project list."Right projects -> H.modify_ (_ { projects = projects })Select i -> doprojects <- H.gets (_.projects)traverse_ H.raise (index projects i)
projectName <- x .: "projectName"inceptionDate <- x .: "inceptionDate"initiatorStr <- x .: "initiator"initiator <- note "Failed to decode initiator UUID" $ parseUUID initiatorStrpure $ Project' { projectName, inceptionDate, initiator }
project <- x .: "project"projectIdStr <- x .: "projectId"projectId <- ProjectId <$> (note "Failed to decode project UUID" $ parseUUID projectIdStr)
component :: forall query input output. Capability Aff -> TimelineConfig -> H.Component HH.HTML query input output Affcomponent caps conf = H.mkComponent
component:: forall query input output. Capability Aff-> Project.Capability Aff-> H.Component HH.HTML query input output Affcomponent caps pcaps = H.mkComponent
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 "Today's project timeline"],lineHtml (intervalHtml conf st.limits <$> st.history <> fromMaybe st.active),HH.div_[HH.button[P.classes (ClassName <$> ["btn", "btn-primary", "float-left"]),E.onClick \_ -> Just Start][HH.text "Start Work"],HH.button[P.classes (ClassName <$> ["btn", "btn-primary", "float-right"]),E.onClick \_ -> Just Stop
let lineForm =[lineHtml (intervalHtml st.limits <$> st.history <> fromMaybe st.active),HH.div_[HH.button[P.classes (ClassName <$> ["btn", "btn-primary", "float-left"]),E.onClick \_ -> Just Start][HH.text "Start Work"],HH.button[P.classes (ClassName <$> ["btn", "btn-primary", "float-right"]),E.onClick \_ -> Just Stop][HH.text "Stop Work"]
]]
in HH.section[P.classes (ClassName <$> ["section-border", "border-primary"])]([HH.div[P.classes (ClassName <$> ["container-fluid", "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 "Today's project timeline"],HH.div_[HH.slot _projectList unit (Project.projectListComponent pcaps) unit (Just <<< ProjectSelected)]]] <> (if isJust st.selectedProject then lineForm else []))
t <- lift caps.logStartH.modify_ (start t)
let withProject (Project' p) = dologged <- lift $ caps.logStart p.projectIdcase logged ofLeft _ -> log "Failed to start timer."Right t -> H.modify_ (start t)project <- H.gets (_.selectedProject)log $ "Project selected? " <> show (isJust project)traverse_ withProject project
t <- lift caps.logEndH.modify_ (stop t)
let withProject (Project' p) = dologged <- lift $ caps.logEnd p.projectIdcase logged ofLeft _ -> log "Failed to stop timer."Right t -> H.modify_ (stop t)project <- H.gets (_.selectedProject)traverse_ withProject project
logStart :: ProjectId -> Aff (Either TimelineError Instant)logStart (ProjectId pid) = dolet requestBody = Just <<< RB.Json <<< encodeJson $ { schemaVersion: "2.0" }result <- post RF.json ("/api/projects/" <> UUID.toString pid <> "/logStart") requestBodycase result ofLeft err -> pure <<< Left <<< LogFailure $ Error { status: Nothing, message: printError err }Right r -> case r.status ofStatusCode 403 -> pure <<< Left <<< LogFailure $ ForbiddenStatusCode 200 -> Right <$> liftEffect nowother -> pure <<< Left <<< LogFailure $ Error { status: Just other, message: r.statusText }logEnd :: ProjectId -> Aff (Either TimelineError Instant)logEnd (ProjectId pid) = dolet requestBody = Just <<< RB.Json <<< encodeJson $ { schemaVersion: "2.0" }result <- post RF.json ("/api/projects/" <> UUID.toString pid <> "/logEnd") requestBodycase result ofLeft err -> pure <<< Left <<< LogFailure $ Error { status: Nothing, message: printError err }Right r -> case r.status ofStatusCode 403 -> pure <<< Left <<< LogFailure $ ForbiddenStatusCode 200 -> Right <$> liftEffect nowother -> pure <<< Left <<< LogFailure $ Error { status: Just other, message: r.statusText }apiCapability :: Capability AffapiCapability = { logStart, logEnd }
module Aftok.Types whereimport Data.Argonaut.Core (Json)import Data.Maybe (Maybe)import Affjax.StatusCode (StatusCode)data APIError= Forbidden| ParseFailure Json String| Error { status :: Maybe StatusCode, message :: String }