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> </CardContent>
</Card> </Card>
{history.length > 0 && (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>ama Geçmişi</CardTitle> <CardTitle>Akış Geçmişi</CardTitle>
<CardDescription>Tamamlanan aşamaların kaydı.</CardDescription> <CardDescription>
İşin aşama transition&apos;ları, kim yaptı ve hangi notla.
</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ol className="space-y-3"> {history.length === 0 ? (
{history.map((h) => ( <p className="text-muted-foreground text-sm">
<li key={h.$id} className="border-l-2 border-primary/30 pl-4"> 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"> <div className="flex flex-wrap items-baseline gap-2">
<span className="font-medium">{JOB_STEP_LABELS[h.step]}</span> <span className="font-medium">
<span className="text-muted-foreground text-xs"> {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))} {dateFormatter.format(new Date(h.completedAt))}
</span> </span>
</div> </div>
{h.note && ( {h.note && (
<p className="text-muted-foreground mt-1 whitespace-pre-wrap text-sm"> <p className="text-muted-foreground mt-1 whitespace-pre-wrap text-sm">
{h.note} {h.note.replace(/^\[Düzeltme talebi\]\s*/, "")}
</p> </p>
)} )}
</li> </li>
))} );
})}
</ol> </ol>
)}
</CardContent> </CardContent>
</Card> </Card>
)}
<div> <div>
<Button asChild variant="outline"> <Button asChild variant="outline">