229 lines
7.4 KiB
TypeScript
229 lines
7.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
} from "@/components/ui/alert-dialog";
|
|
import { Trash2 } from "lucide-react";
|
|
|
|
interface YardPlacement {
|
|
id: number;
|
|
external_material_id: string;
|
|
material_code: string;
|
|
material_name: string;
|
|
quantity: number;
|
|
unit: string;
|
|
position_x: number;
|
|
position_y: number;
|
|
position_z: number;
|
|
size_x: number;
|
|
size_y: number;
|
|
size_z: number;
|
|
color: string;
|
|
memo?: string;
|
|
}
|
|
|
|
interface MaterialEditPanelProps {
|
|
placement: YardPlacement | null;
|
|
onClose: () => void;
|
|
onUpdate: (id: number, updates: Partial<YardPlacement>) => void;
|
|
onRemove: (id: number) => void;
|
|
}
|
|
|
|
export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemove }: MaterialEditPanelProps) {
|
|
const [editData, setEditData] = useState<Partial<YardPlacement>>({});
|
|
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
|
|
|
// placement 변경 시 editData 초기화
|
|
useEffect(() => {
|
|
if (placement) {
|
|
setEditData({
|
|
size_x: placement.size_x,
|
|
size_y: placement.size_y,
|
|
size_z: placement.size_z,
|
|
color: placement.color,
|
|
memo: placement.memo,
|
|
});
|
|
}
|
|
}, [placement]);
|
|
|
|
if (!placement) return null;
|
|
|
|
// 변경사항 적용
|
|
const handleApply = () => {
|
|
onUpdate(placement.id, editData);
|
|
};
|
|
|
|
// 배치 해제
|
|
const handleRemove = () => {
|
|
onRemove(placement.id);
|
|
setIsDeleteDialogOpen(false);
|
|
};
|
|
|
|
return (
|
|
<div className="w-80 border-l bg-white p-4">
|
|
<div className="mb-4 flex items-center justify-between">
|
|
<h3 className="text-lg font-semibold">자재 정보</h3>
|
|
<Button variant="ghost" size="sm" onClick={onClose}>
|
|
닫기
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{/* 읽기 전용 정보 */}
|
|
<div className="space-y-3 rounded-lg bg-gray-50 p-3">
|
|
<div className="text-xs font-medium text-gray-500">자재 정보 (읽기 전용)</div>
|
|
<div>
|
|
<div className="text-xs text-gray-600">자재 코드</div>
|
|
<div className="mt-1 text-sm font-medium">{placement.material_code}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-xs text-gray-600">자재 이름</div>
|
|
<div className="mt-1 text-sm font-medium">{placement.material_name}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-xs text-gray-600">수량</div>
|
|
<div className="mt-1 text-sm font-medium">
|
|
{placement.quantity} {placement.unit}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 배치 정보 (편집 가능) */}
|
|
<div className="space-y-3">
|
|
<div className="text-xs font-medium text-gray-500">배치 정보 (편집 가능)</div>
|
|
|
|
{/* 3D 크기 */}
|
|
<div>
|
|
<Label className="text-xs">크기</Label>
|
|
<div className="grid grid-cols-3 gap-2">
|
|
<div>
|
|
<Label htmlFor="edit-sizeX" className="text-xs text-gray-600">
|
|
너비
|
|
</Label>
|
|
<Input
|
|
id="edit-sizeX"
|
|
type="number"
|
|
value={editData.size_x ?? placement.size_x}
|
|
onChange={(e) => setEditData({ ...editData, size_x: parseFloat(e.target.value) || 1 })}
|
|
min="1"
|
|
step="1"
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="edit-sizeY" className="text-xs text-gray-600">
|
|
높이
|
|
</Label>
|
|
<Input
|
|
id="edit-sizeY"
|
|
type="number"
|
|
value={editData.size_y ?? placement.size_y}
|
|
onChange={(e) => setEditData({ ...editData, size_y: parseFloat(e.target.value) || 1 })}
|
|
min="1"
|
|
step="1"
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="edit-sizeZ" className="text-xs text-gray-600">
|
|
깊이
|
|
</Label>
|
|
<Input
|
|
id="edit-sizeZ"
|
|
type="number"
|
|
value={editData.size_z ?? placement.size_z}
|
|
onChange={(e) => setEditData({ ...editData, size_z: parseFloat(e.target.value) || 1 })}
|
|
min="1"
|
|
step="1"
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 색상 */}
|
|
<div>
|
|
<Label htmlFor="edit-color" className="text-xs">
|
|
색상
|
|
</Label>
|
|
<div className="mt-1 flex items-center gap-2">
|
|
<input
|
|
id="edit-color"
|
|
type="color"
|
|
value={editData.color ?? placement.color}
|
|
onChange={(e) => setEditData({ ...editData, color: e.target.value })}
|
|
className="h-8 w-16 cursor-pointer rounded border"
|
|
/>
|
|
<Input
|
|
value={editData.color ?? placement.color}
|
|
onChange={(e) => setEditData({ ...editData, color: e.target.value })}
|
|
className="h-8 flex-1 text-xs"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 메모 */}
|
|
<div>
|
|
<Label htmlFor="edit-memo" className="text-xs">
|
|
메모
|
|
</Label>
|
|
<Textarea
|
|
id="edit-memo"
|
|
value={editData.memo ?? placement.memo ?? ""}
|
|
onChange={(e) => setEditData({ ...editData, memo: e.target.value })}
|
|
placeholder="메모를 입력하세요"
|
|
rows={3}
|
|
className="text-xs"
|
|
/>
|
|
</div>
|
|
|
|
{/* 적용 버튼 */}
|
|
<Button onClick={handleApply} className="w-full" size="sm">
|
|
변경사항 적용
|
|
</Button>
|
|
</div>
|
|
|
|
{/* 배치 해제 */}
|
|
<div className="border-t pt-4">
|
|
<Button variant="destructive" onClick={() => setIsDeleteDialogOpen(true)} className="w-full" size="sm">
|
|
<Trash2 className="mr-2 h-4 w-4" />
|
|
배치 해제
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 삭제 확인 모달 */}
|
|
<AlertDialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>배치 해제</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
정말로 이 자재를 배치 해제하시겠습니까?
|
|
<br />
|
|
"{placement.material_name}" ({placement.quantity} {placement.unit})
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>취소</AlertDialogCancel>
|
|
<AlertDialogAction onClick={handleRemove} className="bg-red-600 hover:bg-red-700">
|
|
해제
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</div>
|
|
);
|
|
}
|