feat(jobs): step-by-step timeline on the detail page

The job_status_history table was already being populated on every
transition; the detail page just rendered a flat list with date only.
Replaced it with a proper vertical timeline:

  - Card title moved from 'Aşama Geçmişi' to 'Akış Geçmişi' since we
    now include side-trips (revision requests), not just forward steps.
  - Vertical guide line with a coloured node per entry: emerald for
    a normal step completion, rose for a revision request. Spotting a
    bounced prova in the history is a glance.
  - Revision rows get an inline 'Düzeltme talebi' pill; the '[Düzeltme
    talebi]' prefix is stripped from the visible note so the actual
    feedback text reads cleanly.
  - Always rendered (with an empty-state line) so the card position
    doesn't move around as the case progresses.
This commit is contained in:
kovakmedya
2026-05-22 16:05:07 +03:00
parent 53e443b4f1
commit 94e9dffaef
+33 -11
View File
@@ -259,33 +259,55 @@ export default async function JobDetailPage({
</CardContent>
</Card>
{history.length > 0 && (
<Card>
<CardHeader>
<CardTitle>ama Geçmişi</CardTitle>
<CardDescription>Tamamlanan aşamaların kaydı.</CardDescription>
<CardTitle>Akış Geçmişi</CardTitle>
<CardDescription>
İşin aşama transition&apos;ları, kim yaptı ve hangi notla.
</CardDescription>
</CardHeader>
<CardContent>
<ol className="space-y-3">
{history.map((h) => (
<li key={h.$id} className="border-l-2 border-primary/30 pl-4">
{history.length === 0 ? (
<p className="text-muted-foreground text-sm">
Henüz aşama tamamlanmadı.
</p>
) : (
<ol className="relative space-y-4 border-l-2 border-border pl-6">
{history.map((h) => {
const isRevision = h.note?.startsWith("[Düzeltme talebi]");
return (
<li key={h.$id} className="relative">
<span
className={`absolute -left-[1.85rem] mt-1.5 size-3 rounded-full ring-2 ring-background ${
isRevision ? "bg-rose-500" : "bg-emerald-500"
}`}
aria-hidden
/>
<div className="flex flex-wrap items-baseline gap-2">
<span className="font-medium">{JOB_STEP_LABELS[h.step]}</span>
<span className="text-muted-foreground text-xs">
<span className="font-medium">
{JOB_STEP_LABELS[h.step]}
</span>
{isRevision && (
<span className="rounded bg-rose-100 px-1.5 py-0.5 text-xs font-medium text-rose-700 dark:bg-rose-950 dark:text-rose-300">
Düzeltme talebi
</span>
)}
<span className="text-muted-foreground text-xs tabular-nums">
{dateFormatter.format(new Date(h.completedAt))}
</span>
</div>
{h.note && (
<p className="text-muted-foreground mt-1 whitespace-pre-wrap text-sm">
{h.note}
{h.note.replace(/^\[Düzeltme talebi\]\s*/, "")}
</p>
)}
</li>
))}
);
})}
</ol>
)}
</CardContent>
</Card>
)}
<div>
<Button asChild variant="outline">