[CLAUDE] FE: HĐ move Lich su dieu chinh sang Panel 3 duoi Lich su duyet
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m55s

User request: 'cho hop dong dua cac thong tin lich su dieu chinh sang
duoi lich su duyet nhen'.

ContractDetailContent (Panel 2): xoa section 'Lich su dieu chinh' (cot
3/10 grid 7/3) → Chi tiet HD gio full-width. Remove import History +
ContractChangelogsTab.

WorkflowHistoryPanel (Panel 3): them section Lich su dieu chinh duoi
Lich su duyet. Import History icon + ContractChangelogsTab. Reuse same
component, chi doi vi tri render.

Mirror fe-admin + fe-user.
This commit is contained in:
pqhuy1987
2026-04-24 13:06:18 +07:00
parent d1090843a2
commit 8cf1fe214a
4 changed files with 50 additions and 51 deletions

View File

@ -1,16 +1,15 @@
// Reusable detail body — used by full-page ContractDetailPage AND embedded
// in ContractsListPage 3-panel layout (Panel 2). Admin variant include thêm
// Phòng ban + Bypass CCM trong Info section. Workflow + history live separately
// trong WorkflowHistoryPanel (Panel 3).
// in MyContractsPage 3-panel layout (Panel 2). Renders header (title + phase
// + actions) + Info + Comments + Attachments + transition Dialog. Workflow +
// approval history live separately in WorkflowHistoryPanel (Panel 3).
import { useState, type FormEvent } from 'react'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { ArrowLeft, CheckCircle2, MessageSquare, XCircle, ListChecks, History } from 'lucide-react'
import { ArrowLeft, CheckCircle2, MessageSquare, XCircle, ListChecks } from 'lucide-react'
import { toast } from 'sonner'
import { PhaseBadge } from '@/components/PhaseBadge'
import { SlaTimer } from '@/components/SlaTimer'
import { ContractAttachmentsSection } from '@/components/ContractAttachmentsSection'
import { ContractDetailsTab } from '@/components/contracts/ContractDetailsTab'
import { ContractChangelogsTab } from '@/components/contracts/ContractChangelogsTab'
import { Button } from '@/components/ui/Button'
import { Select } from '@/components/ui/Select'
import { Textarea } from '@/components/ui/Textarea'
@ -49,7 +48,7 @@ export function ContractDetailContent({
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['contract', c.id] })
qc.invalidateQueries({ queryKey: ['contracts'] })
qc.invalidateQueries({ queryKey: ['my-contracts'] })
qc.invalidateQueries({ queryKey: ['inbox'] })
toast.success('Đã chuyển phase')
setActionOpen(false)
@ -65,7 +64,7 @@ export function ContractDetailContent({
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['contract', c.id] })
setCommentInput('')
toast.success('Đã gửi comment')
toast.success('Đã gửi')
},
onError: err => toast.error(getErrorMessage(err)),
})
@ -84,7 +83,7 @@ export function ContractDetailContent({
return (
<div className="space-y-4">
{/* Header — sticky inside scroll container */}
{/* Header — sticky inside scroll container so actions luôn visible */}
<div className="sticky top-0 z-10 -mx-5 -mt-5 border-b border-slate-200 bg-white px-5 pt-5 pb-3 md:-mx-6 md:-mt-6 md:px-6 md:pt-6">
<div className="flex flex-wrap items-start justify-between gap-3">
<div className="min-w-0 flex-1">
@ -126,13 +125,11 @@ export function ContractDetailContent({
<div><dt className="text-slate-500">Giá trị</dt><dd>{fmtMoney(c.giaTri)}</dd></div>
<div><dt className="text-slate-500">NCC</dt><dd>{c.supplierName}</dd></div>
<div><dt className="text-slate-500">Dự án</dt><dd>{c.projectName}</dd></div>
<div><dt className="text-slate-500">Phòng ban</dt><dd>{c.departmentName ?? '—'}</dd></div>
<div><dt className="text-slate-500">Người soạn</dt><dd>{c.drafterName ?? '—'}</dd></div>
<div className="col-span-2">
<dt className="text-slate-500 mb-1">SLA</dt>
<dd><SlaTimer deadline={c.slaDeadline} createdAt={c.createdAt} variant="full" /></dd>
</div>
<div><dt className="text-slate-500">Bypass CCM</dt><dd>{c.bypassProcurementAndCCM ? 'Có (HĐ Chủ đầu tư)' : 'Không'}</dd></div>
</dl>
{c.noiDung && (
<div className="mt-3">
@ -176,23 +173,14 @@ export function ContractDetailContent({
<ContractAttachmentsSection contractId={c.id} attachments={c.attachments} />
{/* Chi tiết + Lịch sử điều chỉnh — 7/3 grid bên dưới */}
<div className="grid grid-cols-1 gap-4 lg:grid-cols-10">
<section className="rounded-lg border border-slate-200 bg-white p-5 lg:col-span-7">
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
<ListChecks className="h-4 w-4" />
Chi tiết ({ContractTypeLabel[c.type] ?? '—'})
</h2>
<ContractDetailsTab contract={c} />
</section>
<section className="rounded-lg border border-slate-200 bg-white p-5 lg:col-span-3">
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
<History className="h-4 w-4" />
Lịch sử điều chỉnh
</h2>
<ContractChangelogsTab contractId={c.id} />
</section>
</div>
{/* Chi tiết HĐ full-width — Lịch sử điều chỉnh đã move sang Panel 3 */}
<section className="rounded-lg border border-slate-200 bg-white p-5">
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
<ListChecks className="h-4 w-4" />
Chi tiết ({ContractTypeLabel[c.type] ?? '—'})
</h2>
<ContractDetailsTab contract={c} />
</section>
<Dialog
open={actionOpen}

View File

@ -1,8 +1,11 @@
// Panel 3 cho 3-panel layout — gom WorkflowSummaryCard (timeline policy) +
// approval history (ai/khi/quyết định gì) vào 1 stack.
import { ArrowRight, Clock } from 'lucide-react'
// approval history (ai/khi/quyết định gì) + ContractChangelogsTab (mọi thay
// đổi header/detail/comment/attachment/transition) vào 1 stack. Dùng cho cả
// MyContracts 3-panel và ContractDetailPage fullpage.
import { ArrowRight, Clock, History } from 'lucide-react'
import { PhaseBadge } from '@/components/PhaseBadge'
import { WorkflowSummaryCard } from '@/components/WorkflowSummaryCard'
import { ContractChangelogsTab } from '@/components/contracts/ContractChangelogsTab'
import type { ContractDetail } from '@/types/contracts'
const fmt = (s: string) => new Date(s).toLocaleString('vi-VN')
@ -40,6 +43,14 @@ export function WorkflowHistoryPanel({ contract: c }: { contract: ContractDetail
))}
</ol>
</section>
<section className="rounded-xl border border-slate-200 bg-white p-5 shadow-sm">
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
<History className="h-4 w-4" />
Lịch sử điều chỉnh
</h2>
<ContractChangelogsTab contractId={c.id} />
</section>
</div>
)
}