Files
sam-react-prod/src/components/pricing/PricingHistoryDialog.tsx
유병철 2639724f9f feat(WEB): 상태 뱃지 공통화 및 상세 페이지 훅 시스템 추가
공통화:
- status-config.ts 신규 추가 (상태 설정 중앙 관리)
- StatusBadge 컴포넌트 개선
- 뱃지 공통화 가이드 문서 추가

상세 페이지 훅 시스템:
- useDetailData, useDetailPageState, useDetailPermissions, useCRUDHandlers 훅 신규 추가
- hooks/index.ts 진입점 추가
- BillDetailV2 신규 컴포넌트 추가

리팩토링:
- 회계(매입/어음/거래처), 품목, 단가, 견적, 주문 상태 뱃지 공통화 적용
- 생산(작업지시서/대시보드/작업자화면), 품질(검사관리) 상태 뱃지 적용
- 공사관리(칸반/프로젝트카드) 상태 뱃지 적용
- 고객센터(문의관리), 인사(직원CSV업로드) 개선
- 리스트 페이지 공통화 현황 분석 문서 추가

상수 정리:
- lib/constants/ 디렉토리 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:57:49 +09:00

170 lines
6.4 KiB
TypeScript

/**
* 단가 이력 조회 다이얼로그
*/
'use client';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Badge } from '@/components/ui/badge';
import { getPresetStyle } from '@/lib/utils/status-config';
import { Separator } from '@/components/ui/separator';
import { History } from 'lucide-react';
import type { PricingData } from './types';
interface PricingHistoryDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
pricingData?: PricingData | null;
}
export function PricingHistoryDialog({
open,
onOpenChange,
pricingData,
}: PricingHistoryDialogProps) {
if (!pricingData) return null;
const hasRevisions = pricingData.revisions && pricingData.revisions.length > 0;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<History className="h-5 w-5" />
</DialogTitle>
<DialogDescription>
{pricingData.itemName} ({pricingData.itemCode}) .
</DialogDescription>
</DialogHeader>
{hasRevisions ? (
<div className="space-y-4">
{/* 현재 버전 */}
<div className="border-2 border-blue-200 rounded-lg p-4 bg-blue-50">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Badge className={getPresetStyle('info')}> </Badge>
<span className="font-semibold">
{pricingData.currentRevision}
</span>
</div>
<span className="text-sm text-muted-foreground">
{new Date(
pricingData.updatedAt || pricingData.createdAt
).toLocaleString('ko-KR')}
</span>
</div>
<div className="grid grid-cols-4 gap-3 text-sm">
<div>
<span className="text-muted-foreground">:</span>
<div className="font-semibold">
{pricingData.purchasePrice?.toLocaleString() || '-'}
</div>
</div>
<div>
<span className="text-muted-foreground">:</span>
<div className="font-semibold">
{pricingData.processingCost?.toLocaleString() || '-'}
</div>
</div>
<div>
<span className="text-muted-foreground">:</span>
<div className="font-semibold">
{pricingData.salesPrice?.toLocaleString() || '-'}
</div>
</div>
<div>
<span className="text-muted-foreground">:</span>
<div className="font-semibold">
{pricingData.marginRate?.toFixed(1) || '-'}%
</div>
</div>
</div>
</div>
{/* 이전 버전들 */}
{[...pricingData.revisions!].reverse().map((revision) => (
<div key={revision.revisionNumber} className="border rounded-lg p-4">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Badge variant="outline"> </Badge>
<span className="font-semibold">
{revision.revisionNumber}
</span>
{revision.revisionReason && (
<span className="text-sm text-muted-foreground">
({revision.revisionReason})
</span>
)}
</div>
<div className="text-right">
<div className="text-sm text-muted-foreground">
{new Date(revision.revisionDate).toLocaleString('ko-KR')}
</div>
<div className="text-xs text-muted-foreground">
by {revision.revisionBy}
</div>
</div>
</div>
<div className="grid grid-cols-4 gap-3 text-sm">
<div>
<span className="text-muted-foreground">:</span>
<div>
{revision.previousData?.purchasePrice?.toLocaleString() || '-'}
</div>
</div>
<div>
<span className="text-muted-foreground">:</span>
<div>
{revision.previousData?.processingCost?.toLocaleString() || '-'}
</div>
</div>
<div>
<span className="text-muted-foreground">:</span>
<div>
{revision.previousData?.salesPrice?.toLocaleString() || '-'}
</div>
</div>
<div>
<span className="text-muted-foreground">:</span>
<div>
{revision.previousData?.marginRate?.toFixed(1) || '-'}%
</div>
</div>
</div>
</div>
))}
{/* 최초 버전 */}
<div className="border rounded-lg p-4 bg-gray-50">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Badge variant="outline"> </Badge>
<span className="font-semibold"> </span>
</div>
<span className="text-sm text-muted-foreground">
{new Date(pricingData.createdAt).toLocaleString('ko-KR')}
</span>
</div>
</div>
</div>
) : (
<div className="text-center py-8 text-muted-foreground">
.
</div>
)}
</DialogContent>
</Dialog>
);
}
export default PricingHistoryDialog;