- 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
76 lines
2.6 KiB
TypeScript
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>
|
|
)
|
|
}
|