diff --git a/apps/web/src/app/(authenticated)/page.test.tsx b/apps/web/src/app/(authenticated)/page.test.tsx
index 4702f0d..98da381 100644
--- a/apps/web/src/app/(authenticated)/page.test.tsx
+++ b/apps/web/src/app/(authenticated)/page.test.tsx
@@ -1,85 +1,55 @@
import { describe, it, expect, vi } from "vitest";
-import { render, screen, waitFor } from "@testing-library/react";
+import { render, screen } from "@testing-library/react";
import DashboardPage from "./page";
-// Mock dashboard widgets
-vi.mock("@/components/dashboard/RecentTasksWidget", () => ({
- RecentTasksWidget: ({
- tasks,
- isLoading,
- }: {
- tasks: unknown[];
- isLoading: boolean;
- }): React.JSX.Element => (
-
- {isLoading ? "Loading tasks" : `${String(tasks.length)} tasks`}
-
+// Mock Phase 3 dashboard widgets
+vi.mock("@/components/dashboard/DashboardMetrics", () => ({
+ DashboardMetrics: (): React.JSX.Element => (
+ Dashboard Metrics
),
}));
-vi.mock("@/components/dashboard/UpcomingEventsWidget", () => ({
- UpcomingEventsWidget: ({
- events,
- isLoading,
- }: {
- events: unknown[];
- isLoading: boolean;
- }): React.JSX.Element => (
-
- {isLoading ? "Loading events" : `${String(events.length)} events`}
-
+vi.mock("@/components/dashboard/OrchestratorSessions", () => ({
+ OrchestratorSessions: (): React.JSX.Element => (
+ Orchestrator Sessions
),
}));
-vi.mock("@/components/dashboard/QuickCaptureWidget", () => ({
- QuickCaptureWidget: (): React.JSX.Element => Quick Capture
,
+vi.mock("@/components/dashboard/QuickActions", () => ({
+ QuickActions: (): React.JSX.Element => Quick Actions
,
}));
-vi.mock("@/components/dashboard/DomainOverviewWidget", () => ({
- DomainOverviewWidget: ({
- tasks,
- isLoading,
- }: {
- tasks: unknown[];
- isLoading: boolean;
- }): React.JSX.Element => (
-
- {isLoading ? "Loading overview" : `${String(tasks.length)} tasks overview`}
-
- ),
+vi.mock("@/components/dashboard/ActivityFeed", () => ({
+ ActivityFeed: (): React.JSX.Element => Activity Feed
,
+}));
+
+vi.mock("@/components/dashboard/TokenBudget", () => ({
+ TokenBudget: (): React.JSX.Element => Token Budget
,
}));
describe("DashboardPage", (): void => {
- it("should render the page title", (): void => {
+ it("should render the DashboardMetrics widget", (): void => {
render();
- expect(screen.getByRole("heading", { level: 1 })).toHaveTextContent("Dashboard");
+ expect(screen.getByTestId("dashboard-metrics")).toBeInTheDocument();
});
- it("should show loading state initially", (): void => {
+ it("should render the OrchestratorSessions widget", (): void => {
render();
- expect(screen.getByTestId("recent-tasks")).toHaveTextContent("Loading tasks");
- expect(screen.getByTestId("upcoming-events")).toHaveTextContent("Loading events");
- expect(screen.getByTestId("domain-overview")).toHaveTextContent("Loading overview");
+ expect(screen.getByTestId("orchestrator-sessions")).toBeInTheDocument();
});
- it("should render all widgets with data after loading", async (): Promise => {
+ it("should render the QuickActions widget", (): void => {
render();
- await waitFor((): void => {
- expect(screen.getByTestId("recent-tasks")).toHaveTextContent("4 tasks");
- expect(screen.getByTestId("upcoming-events")).toHaveTextContent("3 events");
- expect(screen.getByTestId("domain-overview")).toHaveTextContent("4 tasks overview");
- expect(screen.getByTestId("quick-capture")).toBeInTheDocument();
- });
+ expect(screen.getByTestId("quick-actions")).toBeInTheDocument();
});
- it("should have proper layout structure", (): void => {
- const { container } = render();
- const main = container.querySelector("main");
- expect(main).toBeInTheDocument();
+ it("should render the ActivityFeed widget", (): void => {
+ render();
+ expect(screen.getByTestId("activity-feed")).toBeInTheDocument();
});
- it("should render the welcome subtitle", (): void => {
+ it("should render the TokenBudget widget", (): void => {
render();
- expect(screen.getByText(/Welcome back/)).toBeInTheDocument();
+ expect(screen.getByTestId("token-budget")).toBeInTheDocument();
});
});
diff --git a/apps/web/src/components/dashboard/DomainOverviewWidget.tsx b/apps/web/src/components/dashboard/DomainOverviewWidget.tsx
deleted file mode 100644
index 577bf3c..0000000
--- a/apps/web/src/components/dashboard/DomainOverviewWidget.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import type { Task } from "@mosaic/shared";
-import { TaskStatus, TaskPriority } from "@mosaic/shared";
-
-interface DomainOverviewWidgetProps {
- tasks: Task[];
- isLoading: boolean;
-}
-
-export function DomainOverviewWidget({
- tasks,
- isLoading,
-}: DomainOverviewWidgetProps): React.JSX.Element {
- if (isLoading) {
- return (
-
-
-
-
Loading overview...
-
-
- );
- }
-
- const stats = {
- total: tasks.length,
- inProgress: tasks.filter((t) => t.status === TaskStatus.IN_PROGRESS).length,
- completed: tasks.filter((t) => t.status === TaskStatus.COMPLETED).length,
- highPriority: tasks.filter((t) => t.priority === TaskPriority.HIGH).length,
- };
-
- const StatCard = ({
- label,
- value,
- color,
- }: {
- label: string;
- value: number;
- color: string;
- }): React.JSX.Element => (
-
- );
-
- return (
-
-
Domain Overview
-
-
-
-
-
-
-
- );
-}
diff --git a/apps/web/src/components/dashboard/QuickCaptureWidget.tsx b/apps/web/src/components/dashboard/QuickCaptureWidget.tsx
deleted file mode 100644
index 96cac82..0000000
--- a/apps/web/src/components/dashboard/QuickCaptureWidget.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-"use client";
-
-import { useState } from "react";
-import { Button } from "@mosaic/ui";
-import { useRouter } from "next/navigation";
-import { ComingSoon } from "@/components/ui/ComingSoon";
-
-/**
- * Check if we're in development mode (runtime check for testability)
- */
-function isDevelopment(): boolean {
- return process.env.NODE_ENV === "development";
-}
-
-/**
- * Internal Quick Capture Widget implementation
- */
-function QuickCaptureWidgetInternal(): React.JSX.Element {
- const [idea, setIdea] = useState("");
- const router = useRouter();
-
- const handleSubmit = (e: React.SyntheticEvent): void => {
- e.preventDefault();
- if (!idea.trim()) return;
-
- // TODO: Implement quick capture API call
- // For now, just show a success indicator
- console.log("Quick capture:", idea);
- setIdea("");
- };
-
- const goToTasks = (): void => {
- router.push("/tasks");
- };
-
- return (
-
-
Quick Capture
-
Quickly jot down ideas or brain dumps
-
-
- );
-}
-
-/**
- * Quick Capture Widget (Dashboard version)
- *
- * In production: Shows Coming Soon placeholder
- * In development: Full widget functionality
- */
-export function QuickCaptureWidget(): React.JSX.Element {
- // In production, show Coming Soon placeholder
- if (!isDevelopment()) {
- return (
-
-
-
- );
- }
-
- // In development, show full widget functionality
- return ;
-}
diff --git a/apps/web/src/components/dashboard/RecentTasksWidget.tsx b/apps/web/src/components/dashboard/RecentTasksWidget.tsx
deleted file mode 100644
index 3c864de..0000000
--- a/apps/web/src/components/dashboard/RecentTasksWidget.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import type { Task } from "@mosaic/shared";
-import { TaskPriority } from "@mosaic/shared";
-import { formatDate } from "@/lib/utils/date-format";
-import { TaskStatus } from "@mosaic/shared";
-import Link from "next/link";
-
-interface RecentTasksWidgetProps {
- tasks: Task[];
- isLoading: boolean;
-}
-
-const statusIcons: Record = {
- [TaskStatus.NOT_STARTED]: "βͺ",
- [TaskStatus.IN_PROGRESS]: "π’",
- [TaskStatus.PAUSED]: "βΈοΈ",
- [TaskStatus.COMPLETED]: "β
",
- [TaskStatus.ARCHIVED]: "π€",
-};
-
-export function RecentTasksWidget({ tasks, isLoading }: RecentTasksWidgetProps): React.JSX.Element {
- if (isLoading) {
- return (
-
- );
- }
-
- const recentTasks = tasks.slice(0, 5);
-
- return (
-
-
-
Recent Tasks
-
- View all β
-
-
- {recentTasks.length === 0 ? (
-
No tasks yet
- ) : (
-
- {recentTasks.map((task) => (
- -
-
- {statusIcons[task.status]}
-
-
-
{task.title}
-
- {task.priority !== TaskPriority.LOW && (
-
- {task.priority}
-
- )}
- {task.dueDate && (
- {formatDate(task.dueDate)}
- )}
-
-
-
- ))}
-
- )}
-
- );
-}
diff --git a/apps/web/src/components/dashboard/UpcomingEventsWidget.tsx b/apps/web/src/components/dashboard/UpcomingEventsWidget.tsx
deleted file mode 100644
index d54a08d..0000000
--- a/apps/web/src/components/dashboard/UpcomingEventsWidget.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import type { Event } from "@mosaic/shared";
-import { formatTime, formatDate } from "@/lib/utils/date-format";
-import Link from "next/link";
-
-interface UpcomingEventsWidgetProps {
- events: Event[];
- isLoading: boolean;
-}
-
-export function UpcomingEventsWidget({
- events,
- isLoading,
-}: UpcomingEventsWidgetProps): React.JSX.Element {
- if (isLoading) {
- return (
-
- );
- }
-
- const upcomingEvents = events.slice(0, 4);
-
- return (
-
-
-
Upcoming Events
-
- View calendar β
-
-
- {upcomingEvents.length === 0 ? (
-
No upcoming events
- ) : (
-
- {upcomingEvents.map((event) => (
-
-
-
- {formatDate(event.startTime).split(",")[0]}
-
-
- {formatTime(event.startTime)}
-
-
-
-
{event.title}
- {event.location && (
-
π {event.location}
- )}
-
-
- ))}
-
- )}
-
- );
-}
diff --git a/apps/web/src/components/dashboard/__tests__/QuickCaptureWidget.test.tsx b/apps/web/src/components/dashboard/__tests__/QuickCaptureWidget.test.tsx
deleted file mode 100644
index 91cac92..0000000
--- a/apps/web/src/components/dashboard/__tests__/QuickCaptureWidget.test.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * QuickCaptureWidget (Dashboard) Component Tests
- * Tests environment-based behavior
- */
-
-import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
-import { render, screen } from "@testing-library/react";
-import { QuickCaptureWidget } from "../QuickCaptureWidget";
-
-// Mock next/navigation
-vi.mock("next/navigation", () => ({
- useRouter: (): { push: () => void } => ({
- push: vi.fn(),
- }),
-}));
-
-describe("QuickCaptureWidget (Dashboard)", (): void => {
- beforeEach((): void => {
- vi.clearAllMocks();
- });
-
- afterEach((): void => {
- vi.unstubAllEnvs();
- });
-
- describe("Development mode", (): void => {
- beforeEach((): void => {
- vi.stubEnv("NODE_ENV", "development");
- });
-
- it("should render the widget form in development", (): void => {
- render();
-
- // Should show the header
- expect(screen.getByText("Quick Capture")).toBeInTheDocument();
- // Should show the textarea
- expect(screen.getByRole("textbox")).toBeInTheDocument();
- // Should show the Save Note button
- expect(screen.getByRole("button", { name: /save note/i })).toBeInTheDocument();
- // Should show the Create Task button
- expect(screen.getByRole("button", { name: /create task/i })).toBeInTheDocument();
- // Should NOT show Coming Soon badge
- expect(screen.queryByText("Coming Soon")).not.toBeInTheDocument();
- });
-
- it("should have a placeholder for the textarea", (): void => {
- render();
-
- const textarea = screen.getByRole("textbox");
- expect(textarea).toHaveAttribute("placeholder", "What's on your mind?");
- });
- });
-
- describe("Production mode", (): void => {
- beforeEach((): void => {
- vi.stubEnv("NODE_ENV", "production");
- });
-
- it("should show Coming Soon placeholder in production", (): void => {
- render();
-
- // Should show Coming Soon badge
- expect(screen.getByText("Coming Soon")).toBeInTheDocument();
- // Should show feature name
- expect(screen.getByText("Quick Capture")).toBeInTheDocument();
- // Should NOT show the textarea
- expect(screen.queryByRole("textbox")).not.toBeInTheDocument();
- // Should NOT show the buttons
- expect(screen.queryByRole("button", { name: /save note/i })).not.toBeInTheDocument();
- expect(screen.queryByRole("button", { name: /create task/i })).not.toBeInTheDocument();
- });
-
- it("should show description in Coming Soon placeholder", (): void => {
- render();
-
- expect(screen.getByText(/jot down ideas for later organization/i)).toBeInTheDocument();
- });
- });
-
- describe("Test mode (non-development)", (): void => {
- beforeEach((): void => {
- vi.stubEnv("NODE_ENV", "test");
- });
-
- it("should show Coming Soon placeholder in test mode", (): void => {
- render();
-
- // Test mode is not development, so should show Coming Soon
- expect(screen.getByText("Coming Soon")).toBeInTheDocument();
- expect(screen.queryByRole("textbox")).not.toBeInTheDocument();
- });
- });
-});
diff --git a/docs/TASKS.md b/docs/TASKS.md
index ffa7e6d..05446b4 100644
--- a/docs/TASKS.md
+++ b/docs/TASKS.md
@@ -4,7 +4,7 @@
| id | status | milestone | description | pr | notes |
| --------- | ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------ | --- | ------------------------------------------------ |
-| MS-P1-001 | not-started | phase-1 | Fix broken test suites: Button.test.tsx (4 fails, old Tailwind classes) + page.test.tsx (5 fails, old widget refs) | β | issue #457, est 15K |
-| MS-P1-002 | not-started | phase-1 | Remove legacy unused dashboard widgets: DomainOverviewWidget, RecentTasksWidget, UpcomingEventsWidget, QuickCaptureWidget | β | issue #457, est 5K |
+| MS-P1-001 | in-progress | phase-1 | Fix broken test suites: Button.test.tsx (4 fails, old Tailwind classes) + page.test.tsx (5 fails, old widget refs) | β | issue #457, est 15K |
+| MS-P1-002 | in-progress | phase-1 | Remove legacy unused dashboard widgets: DomainOverviewWidget, RecentTasksWidget, UpcomingEventsWidget, QuickCaptureWidget | β | issue #457, est 5K |
| MS-P1-003 | not-started | phase-1 | Visual + theme polish: audit current vs design reference, fix gaps, verify dark/light across all components, responsive verification | β | issue #457, est 25K, depends MS-P1-001 MS-P1-002 |
| MS-P1-004 | not-started | phase-1 | Phase verification: all quality gates pass, visual verification dark+light, responsive all breakpoints | β | issue #457, est 5K, depends MS-P1-003 |
diff --git a/packages/ui/src/components/Button.test.tsx b/packages/ui/src/components/Button.test.tsx
index 2d2d9da..b9da87f 100644
--- a/packages/ui/src/components/Button.test.tsx
+++ b/packages/ui/src/components/Button.test.tsx
@@ -16,19 +16,21 @@ describe("Button", () => {
it("should apply primary variant styles by default", () => {
render();
const button = screen.getByRole("button");
- expect(button.className).toContain("bg-blue-600");
+ expect(button.style.background).toBe("var(--ms-blue-500)");
});
it("should apply secondary variant styles", () => {
render();
const button = screen.getByRole("button");
- expect(button.className).toContain("bg-gray-200");
+ expect(button.style.background).toBe("transparent");
+ expect(button.style.border).toBe("1px solid var(--border)");
});
it("should apply danger variant styles", () => {
render();
const button = screen.getByRole("button");
- expect(button.className).toContain("bg-red-600");
+ expect(button.style.background).toBe("rgba(229, 72, 77, 0.12)");
+ expect(button.style.color).toBe("var(--danger)");
});
});
@@ -81,6 +83,6 @@ describe("Button", () => {
render();
const button = screen.getByRole("button");
expect(button.className).toContain("custom-class");
- expect(button.className).toContain("bg-blue-600");
+ expect(button.style.background).toBe("var(--ms-blue-500)");
});
});