Files
sam-react-prod/src/components/quotes/LocationEditModal.tsx
유병철 55e92bc7b4 fix(WEB): 모바일 반응형 UI 개선 및 개소 정보 수정 모달 추가
- CalendarHeader: 모바일에서 주/월 버튼 2줄 레이아웃으로 분리
- MobileCard: 제목 텍스트 overflow 시 truncate 적용
- DetailActions: 모바일 하단 sticky 버튼 바 overflow 수정
- OrderDetailForm: 모바일 하단 sticky 버튼 바 overflow 수정
- LocationDetailPanel: 오픈사이즈 옆 수정 버튼에 모달 연결
- LocationListPanel: 개소 목록에 수정/삭제 버튼 추가
- LocationEditModal: 개소 정보 수정 팝업 신규 생성

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 11:28:12 +09:00

283 lines
8.8 KiB
TypeScript

/**
* 개소 정보 수정 모달
*
* 발주 개소 목록에서 수정 버튼 클릭 시 표시
* - 개소 정보: 층, 부호
* - 오픈사이즈: 가로, 세로
* - 필수 설정: 가이드레일, 전원, 제어기
*/
"use client";
import { useState, useEffect } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "../ui/dialog";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
import { NumberInput } from "../ui/number-input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import type { LocationItem } from "./QuoteRegistrationV2";
// =============================================================================
// 상수
// =============================================================================
// 가이드레일 설치 유형
const GUIDE_RAIL_TYPES = [
{ value: "wall", label: "벽면형" },
{ value: "floor", label: "측면형" },
];
// 모터 전원
const MOTOR_POWERS = [
{ value: "single", label: "단상(220V)" },
{ value: "three", label: "삼상(380V)" },
];
// 연동제어기
const CONTROLLERS = [
{ value: "basic", label: "단독" },
{ value: "smart", label: "연동" },
{ value: "premium", label: "매립형-뒷박스포함" },
];
// =============================================================================
// Props
// =============================================================================
interface LocationEditModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
location: LocationItem | null;
onSave: (locationId: string, updates: Partial<LocationItem>) => void;
}
// =============================================================================
// 컴포넌트
// =============================================================================
export function LocationEditModal({
open,
onOpenChange,
location,
onSave,
}: LocationEditModalProps) {
// ---------------------------------------------------------------------------
// 상태
// ---------------------------------------------------------------------------
const [formData, setFormData] = useState({
floor: "",
code: "",
openWidth: 0,
openHeight: 0,
guideRailType: "wall",
motorPower: "single",
controller: "basic",
});
// location 변경 시 폼 데이터 초기화
useEffect(() => {
if (location) {
setFormData({
floor: location.floor,
code: location.code,
openWidth: location.openWidth,
openHeight: location.openHeight,
guideRailType: location.guideRailType,
motorPower: location.motorPower,
controller: location.controller,
});
}
}, [location]);
// ---------------------------------------------------------------------------
// 핸들러
// ---------------------------------------------------------------------------
const handleFieldChange = (field: string, value: string | number) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleSave = () => {
if (!location) return;
onSave(location.id, {
floor: formData.floor,
code: formData.code,
openWidth: formData.openWidth,
openHeight: formData.openHeight,
guideRailType: formData.guideRailType,
motorPower: formData.motorPower,
controller: formData.controller,
});
onOpenChange(false);
};
const handleCancel = () => {
onOpenChange(false);
};
// ---------------------------------------------------------------------------
// 렌더링
// ---------------------------------------------------------------------------
if (!location) return null;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle> </DialogTitle>
</DialogHeader>
<div className="space-y-6 py-4">
{/* 개소 정보 */}
<div className="space-y-3">
<h4 className="text-sm font-semibold text-gray-700"> </h4>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm text-gray-600 mb-1 block"></label>
<Input
value={formData.floor}
onChange={(e) => handleFieldChange("floor", e.target.value)}
placeholder="1층"
/>
</div>
<div>
<label className="text-sm text-gray-600 mb-1 block"></label>
<Input
value={formData.code}
onChange={(e) => handleFieldChange("code", e.target.value)}
placeholder="FSS-01"
/>
</div>
</div>
</div>
{/* 오픈사이즈 */}
<div className="space-y-3">
<h4 className="text-sm font-semibold text-gray-700"></h4>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm text-gray-600 mb-1 block"> (mm)</label>
<NumberInput
value={formData.openWidth}
onChange={(value) => handleFieldChange("openWidth", value ?? 0)}
placeholder="5000"
/>
</div>
<div>
<label className="text-sm text-gray-600 mb-1 block"> (mm)</label>
<NumberInput
value={formData.openHeight}
onChange={(value) => handleFieldChange("openHeight", value ?? 0)}
placeholder="3000"
/>
</div>
</div>
<p className="text-xs text-gray-500">
280mm를 .
</p>
</div>
{/* 필수 설정 */}
<div className="space-y-3">
<h4 className="text-sm font-semibold text-gray-700"> </h4>
<div className="grid grid-cols-3 gap-3">
<div>
<label className="text-xs text-gray-500 flex items-center gap-1 mb-1">
🔧
</label>
<Select
value={formData.guideRailType}
onValueChange={(value) => handleFieldChange("guideRailType", value)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{GUIDE_RAIL_TYPES.map((type) => (
<SelectItem key={type.value} value={type.value}>
{type.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<label className="text-xs text-gray-500 flex items-center gap-1 mb-1">
</label>
<Select
value={formData.motorPower}
onValueChange={(value) => handleFieldChange("motorPower", value)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{MOTOR_POWERS.map((power) => (
<SelectItem key={power.value} value={power.value}>
{power.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<label className="text-xs text-gray-500 flex items-center gap-1 mb-1">
📦
</label>
<Select
value={formData.controller}
onValueChange={(value) => handleFieldChange("controller", value)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{CONTROLLERS.map((ctrl) => (
<SelectItem key={ctrl.value} value={ctrl.value}>
{ctrl.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>
</div>
{/* 버튼 */}
<div className="flex gap-3 pt-4 border-t">
<Button
variant="outline"
onClick={handleCancel}
className="flex-1"
>
</Button>
<Button
onClick={handleSave}
className="flex-1 bg-orange-500 hover:bg-orange-600"
>
</Button>
</div>
</DialogContent>
</Dialog>
);
}