Files
solution-erp/fe-user/src/components/pe/PePipelineStrip.tsx
pqhuy1987 1a47a61c21
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m44s
[CLAUDE] FE-User: tab strip 4 giai doan tren phieu PE + menu 4-GD + danh so 01-07 nhom HD (UAT anh Kiet)
- 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>
2026-07-29 12:06:19 +07:00

66 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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>
)
}