-
+ {error !== null ? (
+
+
{error}
+
+ ) : (
+
+ {/* Top row: Domain Overview and Quick Capture */}
+
+
+
-
-
+
+
-
-
+ )}
);
}
diff --git a/apps/web/src/app/(authenticated)/tasks/page.test.tsx b/apps/web/src/app/(authenticated)/tasks/page.test.tsx
index a317f18..a0c9966 100644
--- a/apps/web/src/app/(authenticated)/tasks/page.test.tsx
+++ b/apps/web/src/app/(authenticated)/tasks/page.test.tsx
@@ -1,5 +1,5 @@
import { describe, it, expect, vi } from "vitest";
-import { render, screen } from "@testing-library/react";
+import { render, screen, waitFor } from "@testing-library/react";
import TasksPage from "./page";
// Mock the TaskList component
@@ -15,9 +15,16 @@ describe("TasksPage", (): void => {
expect(screen.getByRole("heading", { level: 1 })).toHaveTextContent("Tasks");
});
- it("should render the TaskList component", (): void => {
+ it("should show loading state initially", (): void => {
render(
);
- expect(screen.getByTestId("task-list")).toBeInTheDocument();
+ expect(screen.getByTestId("task-list")).toHaveTextContent("Loading");
+ });
+
+ it("should render the TaskList with tasks after loading", async (): Promise
=> {
+ render();
+ await waitFor((): void => {
+ expect(screen.getByTestId("task-list")).toHaveTextContent("4 tasks");
+ });
});
it("should have proper layout structure", (): void => {
@@ -25,4 +32,9 @@ describe("TasksPage", (): void => {
const main = container.querySelector("main");
expect(main).toBeInTheDocument();
});
+
+ it("should render the subtitle text", (): void => {
+ render();
+ expect(screen.getByText("Organize your work at your own pace")).toBeInTheDocument();
+ });
});
diff --git a/apps/web/src/app/(authenticated)/tasks/page.tsx b/apps/web/src/app/(authenticated)/tasks/page.tsx
index 373409b..6873ce1 100644
--- a/apps/web/src/app/(authenticated)/tasks/page.tsx
+++ b/apps/web/src/app/(authenticated)/tasks/page.tsx
@@ -1,19 +1,40 @@
"use client";
+import { useState, useEffect } from "react";
import type { ReactElement } from "react";
import { TaskList } from "@/components/tasks/TaskList";
import { mockTasks } from "@/lib/api/tasks";
+import type { Task } from "@mosaic/shared";
export default function TasksPage(): ReactElement {
- // TODO: Replace with real API call when backend is ready
- // const { data: tasks, isLoading } = useQuery({
- // queryKey: ["tasks"],
- // queryFn: fetchTasks,
- // });
+ const [tasks, setTasks] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
- const tasks = mockTasks;
- const isLoading = false;
+ useEffect(() => {
+ void loadTasks();
+ }, []);
+
+ async function loadTasks(): Promise {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ // TODO: Replace with real API call when backend is ready
+ // const data = await fetchTasks();
+ await new Promise((resolve) => setTimeout(resolve, 300));
+ setTasks(mockTasks);
+ } catch (err) {
+ setError(
+ err instanceof Error
+ ? err.message
+ : "We had trouble loading your tasks. Please try again when you're ready."
+ );
+ } finally {
+ setIsLoading(false);
+ }
+ }
return (
@@ -21,7 +42,20 @@ export default function TasksPage(): ReactElement {
Tasks
Organize your work at your own pace