Files
HarborForge.Frontend/src/pages/DashboardPage.tsx
zhi 41ebd36218 feat: code-first navigation — use resource codes in links and displays
- DashboardPage: show task_code instead of #id, link via code
- TasksPage: navigate to tasks via task_code
- MilestoneDetailPage: navigate to tasks/supports/meetings via codes
- MilestoneDetailPage: display codes in support/meeting tables
- Fix support/meeting state types to any[] for code property access
2026-03-21 21:38:14 +00:00

76 lines
2.6 KiB
TypeScript

import { useState, useEffect } from 'react'
import api from '@/services/api'
import type { DashboardStats, Task } from '@/types'
export default function DashboardPage() {
const [stats, setStats] = useState<DashboardStats | null>(null)
useEffect(() => {
api.get<DashboardStats>('/dashboard/stats').then(({ data }) => setStats(data))
}, [])
if (!stats) return <div className="loading">Loading...</div>
const statusColors: Record<string, string> = {
open: '#3b82f6', in_progress: '#f59e0b', resolved: '#10b981',
closed: '#6b7280', blocked: '#ef4444',
}
const priorityColors: Record<string, string> = {
low: '#6b7280', medium: '#3b82f6', high: '#f59e0b', critical: '#ef4444',
}
return (
<div className="dashboard">
<h2>📊 Dashboard</h2>
<div className="stats-grid">
<div className="stat-card total">
<span className="stat-number">{stats.total_tasks}</span>
<span className="stat-label">Total Tasks</span>
</div>
{Object.entries(stats.by_status || {}).map(([k, v]) => (
<div className="stat-card" key={k} style={{ borderLeftColor: statusColors[k] || '#ccc' }}>
<span className="stat-number">{v}</span>
<span className="stat-label">{k}</span>
</div>
))}
</div>
<div className="section">
<h3>By Priority</h3>
<div className="bar-chart">
{Object.entries(stats.by_priority || {}).map(([k, v]) => (
<div className="bar-row" key={k}>
<span className="bar-label">{k}</span>
<div className="bar" style={{
width: `${Math.max((v / stats.total_tasks) * 100, 5)}%`,
backgroundColor: priorityColors[k] || '#ccc',
}}>{v}</div>
</div>
))}
</div>
</div>
<div className="section">
<h3>Recent Tasks</h3>
<table>
<thead>
<tr><th>Code</th><th>Title</th><th>Status</th><th>Priority</th><th>Type</th><th>Subtype</th></tr>
</thead>
<tbody>
{(stats.recent_tasks || []).map((i) => (
<tr key={i.id}>
<td>{i.task_code || `#${i.id}`}</td>
<td><a href={`/tasks/${i.task_code || i.id}`}>{i.title}</a></td>
<td><span className={`badge status-${i.status}`}>{i.status}</span></td>
<td><span className={`badge priority-${i.priority}`}>{i.priority}</span></td>
<td>{i.task_type}</td><td>{i.task_subtype || "-"}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)
}