Files
sam-react-prod/src/components/production/WorkerScreen/MaterialInputModal.tsx

244 lines
7.1 KiB
TypeScript
Raw Normal View History

'use client';
/**
*
*
* - FIFO
* - (BOM )
* -
*/
import { useState } from 'react';
import { Package } from 'lucide-react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Checkbox } from '@/components/ui/checkbox';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import type { WorkOrder } from '../ProductionDashboard/types';
import type { MaterialInput } from './types';
// Mock 자재 데이터
const MOCK_MATERIALS: MaterialInput[] = [
{
id: '1',
materialCode: 'KD-RM-001',
materialName: 'SPHC-SD 1.6T',
unit: 'KG',
currentStock: 500,
fifoRank: 1,
},
{
id: '2',
materialCode: 'KD-RM-002',
materialName: 'EGI 1.55T',
unit: 'KG',
currentStock: 350,
fifoRank: 2,
},
{
id: '3',
materialCode: 'KD-SM-001',
materialName: '볼트 M6x20',
unit: 'EA',
currentStock: 1200,
fifoRank: 3,
},
];
interface MaterialInputModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
order: WorkOrder | null;
/** 전량완료 흐름에서 사용 - 투입 등록/취소 후 완료 처리 */
onComplete?: () => void;
/** 전량완료 흐름 여부 (취소 시에도 완료 처리) */
isCompletionFlow?: boolean;
/** 자재 투입 저장 콜백 */
onSaveMaterials?: (orderId: string, materials: MaterialInput[]) => void;
/** 이미 투입된 자재 목록 */
savedMaterials?: MaterialInput[];
}
export function MaterialInputModal({
open,
onOpenChange,
order,
onComplete,
isCompletionFlow = false,
onSaveMaterials,
savedMaterials = [],
}: MaterialInputModalProps) {
const [selectedMaterials, setSelectedMaterials] = useState<Set<string>>(new Set());
const [materials] = useState<MaterialInput[]>(MOCK_MATERIALS);
// 이미 투입된 자재가 있으면 선택 상태로 초기화
const hasSavedMaterials = savedMaterials.length > 0;
const handleToggleMaterial = (materialId: string) => {
setSelectedMaterials((prev) => {
const next = new Set(prev);
if (next.has(materialId)) {
next.delete(materialId);
} else {
next.add(materialId);
}
return next;
});
};
// 자재 투입 등록
const handleSubmit = () => {
if (!order) return;
// 선택된 자재 정보 추출
const selectedMaterialList = materials.filter((m) => selectedMaterials.has(m.id));
console.log('[자재투입] 저장:', order.id, selectedMaterialList);
// 자재 저장 콜백
if (onSaveMaterials) {
onSaveMaterials(order.id, selectedMaterialList);
}
setSelectedMaterials(new Set());
onOpenChange(false);
// 전량완료 흐름이면 완료 처리
if (isCompletionFlow && onComplete) {
onComplete();
}
};
// 건너뛰기 (자재 없이 완료) - 전량완료 흐름에서만 사용
const handleSkip = () => {
setSelectedMaterials(new Set());
onOpenChange(false);
// 전량완료 흐름이면 완료 처리
if (onComplete) {
onComplete();
}
};
// 취소 (모달만 닫기)
const handleCancel = () => {
setSelectedMaterials(new Set());
onOpenChange(false);
};
const getFifoRankBadge = (rank: number) => {
const colors = {
1: 'bg-red-100 text-red-800',
2: 'bg-orange-100 text-orange-800',
3: 'bg-gray-100 text-gray-800',
};
const labels = {
1: '최우선',
2: '차선',
3: '대기',
};
return (
<Badge className={colors[rank as 1 | 2 | 3] || colors[3]}>
{rank} ({labels[rank as 1 | 2 | 3] || labels[3]})
</Badge>
);
};
if (!order) return null;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Package className="h-5 w-5" />
</DialogTitle>
<DialogDescription>
{order.orderNo} .
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
{/* FIFO 순위 안내 */}
<div className="flex items-center gap-4 text-sm text-muted-foreground">
<span>FIFO :</span>
<span className="flex items-center gap-1">
<Badge className="bg-red-100 text-red-800">1</Badge>
</span>
<span className="flex items-center gap-1">
<Badge className="bg-orange-100 text-orange-800">2</Badge>
</span>
<span className="flex items-center gap-1">
<Badge className="bg-gray-100 text-gray-800">3+</Badge>
</span>
</div>
{/* 자재 테이블 */}
{materials.length === 0 ? (
<div className="py-8 text-center text-muted-foreground border rounded-lg">
.
</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-12"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
<TableHead>FIFO</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{materials.map((material) => (
<TableRow key={material.id}>
<TableCell>
<Checkbox
checked={selectedMaterials.has(material.id)}
onCheckedChange={() => handleToggleMaterial(material.id)}
/>
</TableCell>
<TableCell className="font-medium">{material.materialCode}</TableCell>
<TableCell>{material.materialName}</TableCell>
<TableCell>{material.unit}</TableCell>
<TableCell className="text-right">{material.currentStock.toLocaleString()}</TableCell>
<TableCell>{getFifoRankBadge(material.fifoRank)}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}
</div>
<DialogFooter className="flex-col sm:flex-row gap-2">
<Button variant="outline" onClick={handleCancel}>
</Button>
{isCompletionFlow && (
<Button variant="secondary" onClick={handleSkip}>
</Button>
)}
<Button onClick={handleSubmit} disabled={selectedMaterials.size === 0}>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}