317 lines
11 KiB
TypeScript
317 lines
11 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { GanttChart, toGanttTasks } from "@/components/gantt";
|
|
import type { GanttTask } from "@/components/gantt";
|
|
import { TaskStatus, TaskPriority, type Task } from "@mosaic/shared";
|
|
|
|
/**
|
|
* Demo page for Gantt Chart component
|
|
*
|
|
* This page demonstrates the GanttChart component with sample data
|
|
* showing various task states, durations, and interactions.
|
|
*/
|
|
export default function GanttDemoPage(): React.ReactElement {
|
|
// Sample tasks for demonstration
|
|
const baseTasks: Task[] = [
|
|
{
|
|
id: "task-1",
|
|
workspaceId: "demo-workspace",
|
|
title: "Project Planning",
|
|
description: "Initial project planning and requirements gathering",
|
|
status: TaskStatus.COMPLETED,
|
|
priority: TaskPriority.HIGH,
|
|
dueDate: new Date("2026-02-10"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 0,
|
|
metadata: {
|
|
startDate: "2026-02-01",
|
|
},
|
|
completedAt: new Date("2026-02-09"),
|
|
createdAt: new Date("2026-02-01"),
|
|
updatedAt: new Date("2026-02-09"),
|
|
},
|
|
{
|
|
id: "task-2",
|
|
workspaceId: "demo-workspace",
|
|
title: "Design Phase",
|
|
description: "Create mockups and design system",
|
|
status: TaskStatus.IN_PROGRESS,
|
|
priority: TaskPriority.HIGH,
|
|
dueDate: new Date("2026-02-25"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 1,
|
|
metadata: {
|
|
startDate: "2026-02-11",
|
|
dependencies: ["task-1"],
|
|
},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-11"),
|
|
updatedAt: new Date("2026-02-15"),
|
|
},
|
|
{
|
|
id: "task-3",
|
|
workspaceId: "demo-workspace",
|
|
title: "Backend Development",
|
|
description: "Build API and database",
|
|
status: TaskStatus.NOT_STARTED,
|
|
priority: TaskPriority.MEDIUM,
|
|
dueDate: new Date("2026-03-20"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 2,
|
|
metadata: {
|
|
startDate: "2026-02-20",
|
|
dependencies: ["task-1"],
|
|
},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-01"),
|
|
updatedAt: new Date("2026-02-01"),
|
|
},
|
|
{
|
|
id: "task-4",
|
|
workspaceId: "demo-workspace",
|
|
title: "Frontend Development",
|
|
description: "Build user interface components",
|
|
status: TaskStatus.NOT_STARTED,
|
|
priority: TaskPriority.MEDIUM,
|
|
dueDate: new Date("2026-03-25"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 3,
|
|
metadata: {
|
|
startDate: "2026-02-26",
|
|
dependencies: ["task-2"],
|
|
},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-01"),
|
|
updatedAt: new Date("2026-02-01"),
|
|
},
|
|
{
|
|
id: "task-5",
|
|
workspaceId: "demo-workspace",
|
|
title: "Integration Testing",
|
|
description: "Test all components together",
|
|
status: TaskStatus.PAUSED,
|
|
priority: TaskPriority.HIGH,
|
|
dueDate: new Date("2026-04-05"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 4,
|
|
metadata: {
|
|
startDate: "2026-03-26",
|
|
dependencies: ["task-3", "task-4"],
|
|
},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-01"),
|
|
updatedAt: new Date("2026-03-15"),
|
|
},
|
|
{
|
|
id: "task-6",
|
|
workspaceId: "demo-workspace",
|
|
title: "Deployment",
|
|
description: "Deploy to production",
|
|
status: TaskStatus.NOT_STARTED,
|
|
priority: TaskPriority.HIGH,
|
|
dueDate: new Date("2026-04-10"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 5,
|
|
metadata: {
|
|
startDate: "2026-04-06",
|
|
dependencies: ["task-5"],
|
|
},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-02-01"),
|
|
updatedAt: new Date("2026-02-01"),
|
|
},
|
|
{
|
|
id: "task-7",
|
|
workspaceId: "demo-workspace",
|
|
title: "Documentation",
|
|
description: "Write user and developer documentation",
|
|
status: TaskStatus.IN_PROGRESS,
|
|
priority: TaskPriority.LOW,
|
|
dueDate: new Date("2026-04-08"),
|
|
assigneeId: null,
|
|
creatorId: "demo-user",
|
|
projectId: null,
|
|
parentId: null,
|
|
sortOrder: 6,
|
|
metadata: {
|
|
startDate: "2026-03-01",
|
|
},
|
|
completedAt: null,
|
|
createdAt: new Date("2026-03-01"),
|
|
updatedAt: new Date("2026-03-10"),
|
|
},
|
|
];
|
|
|
|
const ganttTasks = toGanttTasks(baseTasks);
|
|
const [selectedTask, setSelectedTask] = useState<GanttTask | null>(null);
|
|
const [showDependencies, setShowDependencies] = useState(false);
|
|
|
|
const handleTaskClick = (task: GanttTask): void => {
|
|
setSelectedTask(task);
|
|
};
|
|
|
|
const statusCounts = {
|
|
total: ganttTasks.length,
|
|
completed: ganttTasks.filter((t) => t.status === TaskStatus.COMPLETED).length,
|
|
inProgress: ganttTasks.filter((t) => t.status === TaskStatus.IN_PROGRESS).length,
|
|
notStarted: ganttTasks.filter((t) => t.status === TaskStatus.NOT_STARTED).length,
|
|
paused: ganttTasks.filter((t) => t.status === TaskStatus.PAUSED).length,
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 p-8">
|
|
<div className="max-w-7xl mx-auto">
|
|
{/* Header */}
|
|
<div className="mb-8">
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">
|
|
Gantt Chart Component Demo
|
|
</h1>
|
|
<p className="text-gray-600">
|
|
Interactive project timeline visualization with task dependencies
|
|
</p>
|
|
</div>
|
|
|
|
{/* Stats */}
|
|
<div className="grid grid-cols-5 gap-4 mb-6">
|
|
<div className="bg-white p-4 rounded-lg border border-gray-200">
|
|
<div className="text-2xl font-bold text-gray-900">{statusCounts.total}</div>
|
|
<div className="text-sm text-gray-600">Total Tasks</div>
|
|
</div>
|
|
<div className="bg-green-50 p-4 rounded-lg border border-green-200">
|
|
<div className="text-2xl font-bold text-green-700">{statusCounts.completed}</div>
|
|
<div className="text-sm text-green-600">Completed</div>
|
|
</div>
|
|
<div className="bg-blue-50 p-4 rounded-lg border border-blue-200">
|
|
<div className="text-2xl font-bold text-blue-700">{statusCounts.inProgress}</div>
|
|
<div className="text-sm text-blue-600">In Progress</div>
|
|
</div>
|
|
<div className="bg-gray-100 p-4 rounded-lg border border-gray-300">
|
|
<div className="text-2xl font-bold text-gray-700">{statusCounts.notStarted}</div>
|
|
<div className="text-sm text-gray-600">Not Started</div>
|
|
</div>
|
|
<div className="bg-yellow-50 p-4 rounded-lg border border-yellow-200">
|
|
<div className="text-2xl font-bold text-yellow-700">{statusCounts.paused}</div>
|
|
<div className="text-sm text-yellow-600">Paused</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Controls */}
|
|
<div className="bg-white p-4 rounded-lg border border-gray-200 mb-6">
|
|
<div className="flex items-center gap-4">
|
|
<label className="flex items-center gap-2 cursor-pointer">
|
|
<input
|
|
type="checkbox"
|
|
checked={showDependencies}
|
|
onChange={(e) => setShowDependencies(e.target.checked)}
|
|
className="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
|
|
/>
|
|
<span className="text-sm text-gray-700">
|
|
Show Dependencies (coming soon)
|
|
</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Gantt Chart */}
|
|
<div className="bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden mb-6">
|
|
<div className="p-4 border-b border-gray-200 bg-gray-50">
|
|
<h2 className="text-lg font-semibold text-gray-900">
|
|
Project Timeline
|
|
</h2>
|
|
</div>
|
|
<div className="p-4">
|
|
<GanttChart
|
|
tasks={ganttTasks}
|
|
onTaskClick={handleTaskClick}
|
|
height={500}
|
|
showDependencies={showDependencies}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Selected Task Details */}
|
|
{selectedTask && (
|
|
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
|
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
|
Selected Task Details
|
|
</h3>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<div className="text-sm font-medium text-gray-500 mb-1">Title</div>
|
|
<div className="text-gray-900">{selectedTask.title}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm font-medium text-gray-500 mb-1">Status</div>
|
|
<div className="text-gray-900">{selectedTask.status}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm font-medium text-gray-500 mb-1">Priority</div>
|
|
<div className="text-gray-900">{selectedTask.priority}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm font-medium text-gray-500 mb-1">Duration</div>
|
|
<div className="text-gray-900">
|
|
{Math.ceil(
|
|
(selectedTask.endDate.getTime() - selectedTask.startDate.getTime()) /
|
|
(1000 * 60 * 60 * 24)
|
|
)}{" "}
|
|
days
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm font-medium text-gray-500 mb-1">Start Date</div>
|
|
<div className="text-gray-900">
|
|
{selectedTask.startDate.toLocaleDateString()}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm font-medium text-gray-500 mb-1">End Date</div>
|
|
<div className="text-gray-900">
|
|
{selectedTask.endDate.toLocaleDateString()}
|
|
</div>
|
|
</div>
|
|
{selectedTask.description && (
|
|
<div className="col-span-2">
|
|
<div className="text-sm font-medium text-gray-500 mb-1">Description</div>
|
|
<div className="text-gray-900">{selectedTask.description}</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* PDA-Friendly Language Notice */}
|
|
<div className="mt-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
<h3 className="text-sm font-semibold text-blue-900 mb-2">
|
|
🌟 PDA-Friendly Design
|
|
</h3>
|
|
<p className="text-sm text-blue-800">
|
|
This component uses respectful, non-judgmental language. Tasks past their target
|
|
date show "Target passed" instead of "OVERDUE", and approaching deadlines show
|
|
"Approaching target" to maintain a positive, supportive tone.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|