143 lines
4.3 KiB
TypeScript
143 lines
4.3 KiB
TypeScript
|
|
import { useState } from "react";
|
||
|
|
import { CompanyModalState, CompanyFormData } from "@/types/company";
|
||
|
|
import { Button } from "@/components/ui/button";
|
||
|
|
import { Input } from "@/components/ui/input";
|
||
|
|
import { Label } from "@/components/ui/label";
|
||
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
||
|
|
import { LoadingSpinner } from "@/components/common/LoadingSpinner";
|
||
|
|
|
||
|
|
interface CompanyFormModalProps {
|
||
|
|
modalState: CompanyModalState;
|
||
|
|
isLoading: boolean;
|
||
|
|
error: string | null;
|
||
|
|
onClose: () => void;
|
||
|
|
onSave: () => Promise<boolean>;
|
||
|
|
onFormChange: (field: keyof CompanyFormData, value: string) => void;
|
||
|
|
onClearError: () => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 회사 등록/수정 모달 컴포넌트
|
||
|
|
*/
|
||
|
|
export function CompanyFormModal({
|
||
|
|
modalState,
|
||
|
|
isLoading,
|
||
|
|
error,
|
||
|
|
onClose,
|
||
|
|
onSave,
|
||
|
|
onFormChange,
|
||
|
|
onClearError,
|
||
|
|
}: CompanyFormModalProps) {
|
||
|
|
const [isSaving, setIsSaving] = useState(false);
|
||
|
|
|
||
|
|
// 모달이 열려있지 않으면 렌더링하지 않음
|
||
|
|
if (!modalState.isOpen) return null;
|
||
|
|
|
||
|
|
const { mode, formData, selectedCompany } = modalState;
|
||
|
|
const isEditMode = mode === "edit";
|
||
|
|
|
||
|
|
// 저장 처리
|
||
|
|
const handleSave = async () => {
|
||
|
|
// 입력값 검증
|
||
|
|
if (!formData.company_name.trim()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
setIsSaving(true);
|
||
|
|
onClearError();
|
||
|
|
|
||
|
|
try {
|
||
|
|
const success = await onSave();
|
||
|
|
if (success) {
|
||
|
|
// 성공 시 모달 닫기
|
||
|
|
onClose();
|
||
|
|
}
|
||
|
|
} catch (err) {
|
||
|
|
// 에러는 부모 컴포넌트에서 처리
|
||
|
|
} finally {
|
||
|
|
setIsSaving(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// 취소 처리
|
||
|
|
const handleCancel = () => {
|
||
|
|
onClearError();
|
||
|
|
onClose();
|
||
|
|
};
|
||
|
|
|
||
|
|
// Enter 키 처리
|
||
|
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||
|
|
if (e.key === "Enter" && !isLoading && !isSaving) {
|
||
|
|
e.preventDefault();
|
||
|
|
handleSave();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Dialog open={modalState.isOpen} onOpenChange={handleCancel}>
|
||
|
|
<DialogContent className="sm:max-w-[425px]" onKeyDown={handleKeyDown}>
|
||
|
|
<DialogHeader>
|
||
|
|
<DialogTitle>{isEditMode ? "회사 정보 수정" : "새 회사 등록"}</DialogTitle>
|
||
|
|
</DialogHeader>
|
||
|
|
|
||
|
|
<div className="space-y-4 py-4">
|
||
|
|
{/* 회사명 입력 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="company_name">
|
||
|
|
회사명 <span className="text-destructive">*</span>
|
||
|
|
</Label>
|
||
|
|
<Input
|
||
|
|
id="company_name"
|
||
|
|
value={formData.company_name}
|
||
|
|
onChange={(e) => onFormChange("company_name", e.target.value)}
|
||
|
|
placeholder="회사명을 입력하세요"
|
||
|
|
disabled={isLoading || isSaving}
|
||
|
|
className={error ? "border-destructive" : ""}
|
||
|
|
autoFocus
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 에러 메시지 */}
|
||
|
|
{error && (
|
||
|
|
<div className="bg-destructive/10 rounded-md p-3">
|
||
|
|
<p className="text-destructive text-sm">{error}</p>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 수정 모드일 때 추가 정보 표시 */}
|
||
|
|
{isEditMode && modalState.selectedCompany && (
|
||
|
|
<div className="bg-muted/50 rounded-md p-3">
|
||
|
|
<div className="space-y-1 text-sm">
|
||
|
|
<p>
|
||
|
|
<span className="font-medium">회사 코드:</span> {modalState.selectedCompany.company_code}
|
||
|
|
</p>
|
||
|
|
<p>
|
||
|
|
<span className="font-medium">등록자:</span> {modalState.selectedCompany.writer}
|
||
|
|
</p>
|
||
|
|
<p>
|
||
|
|
<span className="font-medium">등록일:</span>{" "}
|
||
|
|
{new Date(modalState.selectedCompany.regdate).toLocaleDateString("ko-KR")}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<DialogFooter>
|
||
|
|
<Button variant="outline" onClick={handleCancel} disabled={isLoading || isSaving}>
|
||
|
|
취소
|
||
|
|
</Button>
|
||
|
|
<Button
|
||
|
|
onClick={handleSave}
|
||
|
|
disabled={isLoading || isSaving || !formData.company_name.trim()}
|
||
|
|
className="min-w-[80px]"
|
||
|
|
>
|
||
|
|
{(isLoading || isSaving) && <LoadingSpinner className="mr-2 h-4 w-4" />}
|
||
|
|
{isEditMode ? "수정" : "등록"}
|
||
|
|
</Button>
|
||
|
|
</DialogFooter>
|
||
|
|
</DialogContent>
|
||
|
|
</Dialog>
|
||
|
|
);
|
||
|
|
}
|