[CLAUDE] FE: PE detail flat layout — Panel 2 gop 3 section, Panel 3 them approvals + history
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m59s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m59s
User request: 'cho tat ca cai nay the hien tren dung 1 man hinh nhe, cai duyet va lich su thi dua sang panel 3'. Panel 2 (PeDetailTabs): truoc 5 tab (Info/NCC/Items/Approvals/History). Sau bo tabs, flat render 3 section stack doc voi divider + title uppercase: Thong tin → NCC tham gia (N) → Hang muc + Bao gia (N) Panel 3 (PeWorkflowPanel): truoc chi workflow timeline + transition btn. Sau them 2 section ben duoi: Workflow timeline → Lich su duyet (PeApprovalsSection) → Lich su thay doi (PeHistorySection) Export PeApprovalsSection + PeHistorySection tu PeDetailTabs — reuse ApprovalsTab + HistoryTab logic cu, wrap them <h3> section title. Dong bo ca fe-admin + fe-user (copy identical file).
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
// Detail tabs cho 1 phiếu Duyệt NCC: Thông tin / NCC / Hạng mục + Báo giá /
|
||||
// Duyệt / Lịch sử. Inline action dialog để add NCC, add Detail, upsert Quote,
|
||||
// select winner.
|
||||
// Detail content cho 1 phiếu Duyệt NCC. Flat render (no tabs): Thông tin +
|
||||
// NCC + Hạng mục + Báo giá stack vertically trong 1 màn hình.
|
||||
// Duyệt history + Lịch sử thay đổi → moved to Panel 3 (xem PeWorkflowPanel
|
||||
// → PeApprovalsSection + PeHistorySection).
|
||||
import { useState } from 'react'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
@ -27,10 +28,10 @@ import {
|
||||
} from '@/types/purchaseEvaluation'
|
||||
import type { Supplier } from '@/types/master'
|
||||
|
||||
type TabKey = 'info' | 'suppliers' | 'items' | 'approvals' | 'history'
|
||||
|
||||
const fmtMoney = (v: number) => v.toLocaleString('vi-VN')
|
||||
|
||||
// Main detail content — flat render 3 section không tabs.
|
||||
// Tên giữ PeDetailTabs để không break callsite (rename gây churn).
|
||||
export function PeDetailTabs({
|
||||
evaluation,
|
||||
onBack,
|
||||
@ -40,7 +41,6 @@ export function PeDetailTabs({
|
||||
onBack: () => void
|
||||
onDelete: () => void
|
||||
}) {
|
||||
const [tab, setTab] = useState<TabKey>('info')
|
||||
const navigate = useNavigate()
|
||||
const isDraft = evaluation.phase === PurchaseEvaluationPhase.DangSoanThao
|
||||
|
||||
@ -83,42 +83,50 @@ export function PeDetailTabs({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav className="flex gap-1 border-b border-slate-200 px-3 pt-2">
|
||||
{(
|
||||
[
|
||||
['info', 'Thông tin'],
|
||||
['suppliers', `NCC (${evaluation.suppliers.length})`],
|
||||
['items', `Hạng mục (${evaluation.details.length})`],
|
||||
['approvals', `Duyệt (${evaluation.approvals.length})`],
|
||||
['history', 'Lịch sử'],
|
||||
] as const
|
||||
).map(([k, lbl]) => (
|
||||
<button
|
||||
key={k}
|
||||
onClick={() => setTab(k)}
|
||||
className={cn(
|
||||
'rounded-t-md border-b-2 px-3 py-1.5 text-xs font-medium transition',
|
||||
tab === k
|
||||
? 'border-brand-500 text-brand-700'
|
||||
: 'border-transparent text-slate-500 hover:text-slate-700',
|
||||
)}
|
||||
>
|
||||
{lbl}
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div className="p-5">
|
||||
{tab === 'info' && <InfoTab ev={evaluation} />}
|
||||
{tab === 'suppliers' && <SuppliersTab ev={evaluation} />}
|
||||
{tab === 'items' && <ItemsTab ev={evaluation} />}
|
||||
{tab === 'approvals' && <ApprovalsTab ev={evaluation} />}
|
||||
{tab === 'history' && <HistoryTab ev={evaluation} />}
|
||||
<div className="divide-y divide-slate-200">
|
||||
<Section title="Thông tin">
|
||||
<InfoTab ev={evaluation} />
|
||||
</Section>
|
||||
<Section title={`NCC tham gia (${evaluation.suppliers.length})`}>
|
||||
<SuppliersTab ev={evaluation} />
|
||||
</Section>
|
||||
<Section title={`Hạng mục + Báo giá (${evaluation.details.length})`}>
|
||||
<ItemsTab ev={evaluation} />
|
||||
</Section>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<section className="px-5 py-4">
|
||||
<h3 className="mb-3 text-xs font-semibold uppercase tracking-wide text-slate-500">{title}</h3>
|
||||
{children}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
// ===== Exports cho Panel 3 — Approvals history + Changelog =====
|
||||
|
||||
export function PeApprovalsSection({ ev }: { ev: PeDetailBundle }) {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="mb-2 text-sm font-semibold text-slate-900">Lịch sử duyệt ({ev.approvals.length})</h3>
|
||||
<ApprovalsTab ev={ev} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function PeHistorySection({ ev }: { ev: PeDetailBundle }) {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="mb-2 text-sm font-semibold text-slate-900">Lịch sử thay đổi</h3>
|
||||
<HistoryTab ev={ev} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ===== Tab: Thông tin =====
|
||||
function InfoTab({ ev }: { ev: PeDetailBundle }) {
|
||||
const canCreateContract = ev.phase === PurchaseEvaluationPhase.DaDuyet && !ev.contractId && ev.selectedSupplierId
|
||||
|
||||
Reference in New Issue
Block a user