← Back to task

Commit 30f6e16f

commit 30f6e16fe4fd3c9cbfcb39cd8053504ddd11167b
Author: Ben Sima <ben@bensima.com>
Date:   Wed Nov 26 06:42:52 2025

    The implementation is complete. Summary of what was implemented
    
    1. **POST /tasks/:id/status** endpoint accepting form data with
    'status' field (line 35) 2. **Status parsing** from form via `FromForm
    StatusForm` instance (lines 47-52) - handles Open, InProgress,
    Review, Approved, Done 3. **Calls TaskCore.updateTaskStatus**
    (line 337) 4. **Redirects** back to `/tasks/:id` with 303 status
    using `PostRedirect` type (line 26, 335-338) 5. **Error handling**
    for invalid status via `FromForm` returning `Left "Invalid status"`
    (line 52) which Servant converts to a 400 error
    
    Task-Id: t-1o2g8gugkr1.4

diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs
index 7416604b..beef8bb1 100644
--- a/Omni/Jr/Web.hs
+++ b/Omni/Jr/Web.hs
@@ -23,6 +23,8 @@ import Servant
 import qualified Servant.HTML.Lucid as Lucid
 import Web.FormUrlEncoded (FromForm (..), parseUnique)
 
+type PostRedirect = Verb 'POST 303 '[Lucid.HTML] (Headers '[Header "Location" Text] NoContent)
+
 defaultPort :: Warp.Port
 defaultPort = 8080
 
@@ -30,7 +32,7 @@ type API =
   Get '[Lucid.HTML] HomePage
     :<|> "tasks" :> Get '[Lucid.HTML] TaskListPage
     :<|> "tasks" :> Capture "id" Text :> Get '[Lucid.HTML] TaskDetailPage
-    :<|> "tasks" :> Capture "id" Text :> "status" :> ReqBody '[FormUrlEncoded] StatusForm :> Post '[Lucid.HTML] TaskDetailPage
+    :<|> "tasks" :> Capture "id" Text :> "status" :> ReqBody '[FormUrlEncoded] StatusForm :> PostRedirect
 
 newtype HomePage = HomePage ()
 
@@ -330,13 +332,10 @@ server = homeHandler :<|> taskListHandler :<|> taskDetailHandler :<|> taskStatus
         Nothing -> pure (TaskDetailNotFound tid)
         Just task -> pure (TaskDetailFound task tasks)
 
-    taskStatusHandler :: Text -> StatusForm -> Servant.Handler TaskDetailPage
+    taskStatusHandler :: Text -> StatusForm -> Servant.Handler (Headers '[Header "Location" Text] NoContent)
     taskStatusHandler tid (StatusForm newStatus) = do
       liftIO <| TaskCore.updateTaskStatus tid newStatus []
-      tasks <- liftIO TaskCore.loadTasks
-      case TaskCore.findTask tid tasks of
-        Nothing -> pure (TaskDetailNotFound tid)
-        Just task -> pure (TaskDetailFound task tasks)
+      pure <| addHeader ("/tasks/" <> tid) NoContent
 
 app :: Application
 app = serve api server