All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m44s
- PePipelineStrip moi (mirror x2 app md5-identical): Duyet NCC | Ke hoach ky ket HD | Duyet hop dong | Hop dong cung — chen dau PeDetailTabs (GD1 active) - Menu 4-GD: rename 2 root (PurchaseEvaluations->Duyet NCC, Contracts->Duyet hop dong) + 2 root placeholder KeHoachKyKet/HopDongCung (ngoai MenuKeys.All, staticMap -> /dashboard) — prod da SQL truc tiep cung ngay, seeder+labelBackfill giu hoi tu (gotcha #11) - Danh so 01.-07. nhom HD: prod prepend-only 0-VN-over-wire (renamed=7), seeder typeLabels + labelBackfill 7 entry - Dong bo nhan 4-GD tren dashboard (3 title + 3 group aria) - reviewKeys += 2 placeholder CanRead-only; test 562 PASS; build fe x2 PASS Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
66 lines
2.9 KiB
TypeScript
66 lines
2.9 KiB
TypeScript
// PePipelineStrip — dải 4 giai đoạn toàn trình, đặt trên đầu detail phiếu Duyệt NCC.
|
||
// [S159 2026-07-29] Owner vẽ tab strip trực tiếp lên ảnh phiếu + chốt tên qua chat:
|
||
// "Duyệt NCC | Kế hoạch ký kết HĐ | Duyệt hợp đồng | Hợp đồng cứng"
|
||
// (2 chỉnh verbatim: "Trình ký Hợp đồng đổi thành Duyệt hợp đồng, ký cứng -> Hợp đồng cứng").
|
||
// MIRROR ×2 app BYTE-IDENTICAL (cùng họ PeDetailTabs md5-parity) — sửa file này
|
||
// thì sửa CẢ HAI, verify md5 trước commit.
|
||
// v1: phiếu PE ⇒ giai đoạn 1 active. GĐ2/GĐ4 chưa có module (badge "Sắp");
|
||
// GĐ3 có module HĐ nhưng CHƯA nối per-phiếu (cầu PE→KHKK→HĐ ship ở wave GĐ2)
|
||
// ⇒ mọi stage không-active đều KHÔNG click được — hiển thị lộ trình, không giả link.
|
||
import { Check } from 'lucide-react'
|
||
import { cn } from '@/lib/cn'
|
||
|
||
const STAGES = [
|
||
{ n: 1, label: 'Duyệt NCC', soon: false },
|
||
{ n: 2, label: 'Kế hoạch ký kết HĐ', soon: true },
|
||
{ n: 3, label: 'Duyệt hợp đồng', soon: false },
|
||
{ n: 4, label: 'Hợp đồng cứng', soon: true },
|
||
] as const
|
||
|
||
export function PePipelineStrip({ current = 1 }: { current?: number }) {
|
||
return (
|
||
<div
|
||
role="list"
|
||
aria-label="Toàn trình 4 giai đoạn"
|
||
className="flex items-stretch gap-1 overflow-x-auto rounded-t-lg border-b border-slate-200 bg-slate-50/70 px-2 py-1.5"
|
||
>
|
||
{STAGES.map((s, i) => {
|
||
const active = s.n === current
|
||
return (
|
||
<div key={s.n} role="listitem" className="flex min-w-0 flex-1 items-center gap-1">
|
||
<div
|
||
aria-current={active ? 'step' : undefined}
|
||
title={
|
||
active
|
||
? 'Giai đoạn hiện tại'
|
||
: s.soon
|
||
? 'Sắp triển khai'
|
||
: 'Sẽ nối khi giai đoạn trước hoàn tất'
|
||
}
|
||
className={cn(
|
||
'flex w-full min-w-0 items-center justify-center gap-1.5 rounded-md px-2 py-1.5 text-center text-[11px] font-medium leading-tight',
|
||
active
|
||
? 'bg-brand-600 text-white shadow-sm'
|
||
: 'border border-dashed border-slate-300 bg-white text-slate-500',
|
||
)}
|
||
>
|
||
{active && <Check aria-hidden className="h-3 w-3 shrink-0" />}
|
||
<span className="truncate">{s.label}</span>
|
||
{s.soon && !active && (
|
||
<span className="shrink-0 rounded bg-slate-100 px-1 text-[9px] font-semibold uppercase tracking-wide text-slate-400">
|
||
Sắp
|
||
</span>
|
||
)}
|
||
</div>
|
||
{i < STAGES.length - 1 && (
|
||
<span aria-hidden className="shrink-0 px-0.5 text-slate-300">
|
||
→
|
||
</span>
|
||
)}
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
)
|
||
}
|