255 lines
7.7 KiB
TypeScript
255 lines
7.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
ResizableDialog,
|
|
ResizableDialogContent,
|
|
ResizableDialogHeader,
|
|
ResizableDialogTitle,
|
|
ResizableDialogDescription,
|
|
ResizableDialogFooter,
|
|
} from "@/components/ui/resizable-dialog";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Loader2 } from "lucide-react";
|
|
|
|
interface TempMaterial {
|
|
id: number;
|
|
material_code: string;
|
|
material_name: string;
|
|
category: string;
|
|
unit: string;
|
|
default_color: string;
|
|
description: string;
|
|
}
|
|
|
|
interface MaterialAddModalProps {
|
|
isOpen: boolean;
|
|
material: TempMaterial | null;
|
|
onClose: () => void;
|
|
onAdd: (placementData: any) => Promise<void>;
|
|
}
|
|
|
|
export default function MaterialAddModal({ isOpen, material, onClose, onAdd }: MaterialAddModalProps) {
|
|
const [quantity, setQuantity] = useState("1");
|
|
const [positionX, setPositionX] = useState("0");
|
|
const [positionY, setPositionY] = useState("0");
|
|
const [positionZ, setPositionZ] = useState("0");
|
|
const [sizeX, setSizeX] = useState("5");
|
|
const [sizeY, setSizeY] = useState("5");
|
|
const [sizeZ, setSizeZ] = useState("5");
|
|
const [color, setColor] = useState("");
|
|
const [isAdding, setIsAdding] = useState(false);
|
|
|
|
// 모달이 열릴 때 기본값 설정
|
|
const handleOpen = (open: boolean) => {
|
|
if (open && material) {
|
|
setColor(material.default_color);
|
|
setQuantity("1");
|
|
setPositionX("0");
|
|
setPositionY("0");
|
|
setPositionZ("0");
|
|
setSizeX("5");
|
|
setSizeY("5");
|
|
setSizeZ("5");
|
|
}
|
|
};
|
|
|
|
// 자재 추가
|
|
const handleAdd = async () => {
|
|
if (!material) return;
|
|
|
|
setIsAdding(true);
|
|
try {
|
|
await onAdd({
|
|
external_material_id: `TEMP-${Date.now()}`,
|
|
material_code: material.material_code,
|
|
material_name: material.material_name,
|
|
quantity: parseInt(quantity) || 1,
|
|
unit: material.unit,
|
|
position_x: parseFloat(positionX) || 0,
|
|
position_y: parseFloat(positionY) || 0,
|
|
position_z: parseFloat(positionZ) || 0,
|
|
size_x: parseFloat(sizeX) || 5,
|
|
size_y: parseFloat(sizeY) || 5,
|
|
size_z: parseFloat(sizeZ) || 5,
|
|
color: color || material.default_color,
|
|
});
|
|
onClose();
|
|
} catch (error) {
|
|
console.error("자재 추가 실패:", error);
|
|
} finally {
|
|
setIsAdding(false);
|
|
}
|
|
};
|
|
|
|
if (!material) return null;
|
|
|
|
return (
|
|
<Dialog
|
|
open={isOpen}
|
|
onOpenChange={(open) => {
|
|
handleOpen(open);
|
|
if (!open) onClose();
|
|
}}
|
|
>
|
|
<ResizableDialogContent className="max-w-2xl">
|
|
<ResizableDialogHeader>
|
|
<ResizableDialogTitle>자재 배치 설정</ResizableDialogTitle>
|
|
</ResizableDialogHeader>
|
|
|
|
<div className="space-y-4">
|
|
{/* 자재 정보 */}
|
|
<div className="rounded-lg bg-muted p-4">
|
|
<div className="mb-2 text-sm font-medium text-foreground">선택한 자재</div>
|
|
<div className="flex items-center gap-4">
|
|
<div className="h-10 w-10 rounded border" style={{ backgroundColor: material.default_color }} />
|
|
<div>
|
|
<div className="font-medium">{material.material_name}</div>
|
|
<div className="text-sm text-foreground">{material.material_code}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 수량 */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="quantity">수량</Label>
|
|
<div className="flex items-center gap-2">
|
|
<Input
|
|
id="quantity"
|
|
type="number"
|
|
value={quantity}
|
|
onChange={(e) => setQuantity(e.target.value)}
|
|
min="1"
|
|
className="flex-1"
|
|
/>
|
|
<span className="text-sm text-foreground">{material.unit}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 3D 위치 */}
|
|
<div className="space-y-2">
|
|
<Label>3D 위치</Label>
|
|
<div className="grid grid-cols-3 gap-2">
|
|
<div>
|
|
<Label htmlFor="posX" className="text-xs text-foreground">
|
|
X (좌우)
|
|
</Label>
|
|
<Input
|
|
id="posX"
|
|
type="number"
|
|
value={positionX}
|
|
onChange={(e) => setPositionX(e.target.value)}
|
|
step="0.5"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="posY" className="text-xs text-foreground">
|
|
Y (높이)
|
|
</Label>
|
|
<Input
|
|
id="posY"
|
|
type="number"
|
|
value={positionY}
|
|
onChange={(e) => setPositionY(e.target.value)}
|
|
step="0.5"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="posZ" className="text-xs text-foreground">
|
|
Z (앞뒤)
|
|
</Label>
|
|
<Input
|
|
id="posZ"
|
|
type="number"
|
|
value={positionZ}
|
|
onChange={(e) => setPositionZ(e.target.value)}
|
|
step="0.5"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 3D 크기 */}
|
|
<div className="space-y-2">
|
|
<Label>3D 크기</Label>
|
|
<div className="grid grid-cols-3 gap-2">
|
|
<div>
|
|
<Label htmlFor="sizeX" className="text-xs text-foreground">
|
|
너비
|
|
</Label>
|
|
<Input
|
|
id="sizeX"
|
|
type="number"
|
|
value={sizeX}
|
|
onChange={(e) => setSizeX(e.target.value)}
|
|
min="1"
|
|
step="0.5"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="sizeY" className="text-xs text-foreground">
|
|
높이
|
|
</Label>
|
|
<Input
|
|
id="sizeY"
|
|
type="number"
|
|
value={sizeY}
|
|
onChange={(e) => setSizeY(e.target.value)}
|
|
min="1"
|
|
step="0.5"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="sizeZ" className="text-xs text-foreground">
|
|
깊이
|
|
</Label>
|
|
<Input
|
|
id="sizeZ"
|
|
type="number"
|
|
value={sizeZ}
|
|
onChange={(e) => setSizeZ(e.target.value)}
|
|
min="1"
|
|
step="0.5"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 색상 */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="color">색상</Label>
|
|
<div className="flex items-center gap-2">
|
|
<input
|
|
id="color"
|
|
type="color"
|
|
value={color}
|
|
onChange={(e) => setColor(e.target.value)}
|
|
className="h-10 w-20 cursor-pointer rounded border"
|
|
/>
|
|
<Input value={color} onChange={(e) => setColor(e.target.value)} className="flex-1" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<ResizableDialogFooter>
|
|
<Button variant="outline" onClick={onClose} disabled={isAdding}>
|
|
취소
|
|
</Button>
|
|
<Button onClick={handleAdd} disabled={isAdding}>
|
|
{isAdding ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
추가 중...
|
|
</>
|
|
) : (
|
|
"배치"
|
|
)}
|
|
</Button>
|
|
</ResizableDialogFooter>
|
|
</ResizableDialogContent>
|
|
</ResizableDialog>
|
|
);
|
|
}
|