77 lines
2.9 KiB
TypeScript
77 lines
2.9 KiB
TypeScript
|
|
import type { PrintJob } from '../types'
|
||
|
|
import { Clock, FileText } from 'lucide-react'
|
||
|
|
|
||
|
|
interface RecentPrintsProps {
|
||
|
|
jobs: PrintJob[]
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function RecentPrints({ jobs }: RecentPrintsProps) {
|
||
|
|
if (jobs.length === 0) {
|
||
|
|
return (
|
||
|
|
<div className="rounded-xl border border-slate-700 bg-slate-800 p-6 text-center text-slate-400">
|
||
|
|
<FileText size={32} className="mx-auto mb-3 text-slate-500" />
|
||
|
|
<p>No recent print jobs</p>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
const statusColor = (status: string) => {
|
||
|
|
switch (status.toLowerCase()) {
|
||
|
|
case 'completed': return 'text-emerald-400 bg-emerald-500/10'
|
||
|
|
case 'in_progress': return 'text-sky-400 bg-sky-500/10'
|
||
|
|
case 'failed': return 'text-red-400 bg-red-500/10'
|
||
|
|
default: return 'text-slate-400 bg-slate-500/10'
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="rounded-xl border border-slate-700 bg-slate-800 overflow-hidden">
|
||
|
|
<div className="overflow-x-auto">
|
||
|
|
<table className="w-full text-left">
|
||
|
|
<thead>
|
||
|
|
<tr className="border-b border-slate-700">
|
||
|
|
<th className="px-4 py-3 text-sm font-medium text-slate-400">Name</th>
|
||
|
|
<th className="px-4 py-3 text-sm font-medium text-slate-400">Status</th>
|
||
|
|
<th className="px-4 py-3 text-sm font-medium text-slate-400">Duration</th>
|
||
|
|
<th className="px-4 py-3 text-sm font-medium text-slate-400">Filament</th>
|
||
|
|
<th className="px-4 py-3 text-sm font-medium text-slate-400">Cost</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
{jobs.map((job) => (
|
||
|
|
<tr key={job.id} className="border-b border-slate-700/50 last:border-0 hover:bg-slate-700/30 transition-colors">
|
||
|
|
<td className="px-4 py-3 text-sm text-slate-100 font-medium">{job.name}</td>
|
||
|
|
<td className="px-4 py-3">
|
||
|
|
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium ${statusColor(job.status)}`}>
|
||
|
|
{job.status}
|
||
|
|
</span>
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-3 text-sm text-slate-300">
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
<Clock size={14} />
|
||
|
|
{formatDuration(job.duration_seconds)}
|
||
|
|
</div>
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-3 text-sm text-slate-300">
|
||
|
|
{job.filament_used_grams?.toFixed(1) ?? '-'} g
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-3 text-sm text-slate-300">
|
||
|
|
${job.cost_usd?.toFixed(2) ?? '-'}
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
))}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatDuration(seconds: number): string {
|
||
|
|
if (!seconds) return '-'
|
||
|
|
const hrs = Math.floor(seconds / 3600)
|
||
|
|
const mins = Math.floor((seconds % 3600) / 60)
|
||
|
|
if (hrs > 0) return `${hrs}h ${mins}m`
|
||
|
|
return `${mins}m`
|
||
|
|
}
|