ERP-node/frontend/components/screen/CreateScreenModal.tsx

159 lines
5.4 KiB
TypeScript

"use client";
import { useEffect, useMemo, useState } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { screenApi, tableTypeApi } from "@/lib/api/screen";
import { ScreenDefinition } from "@/types/screen";
import { useAuth } from "@/hooks/useAuth";
interface CreateScreenModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onCreated?: (screen: ScreenDefinition) => void;
}
export default function CreateScreenModal({ open, onOpenChange, onCreated }: CreateScreenModalProps) {
const { user } = useAuth();
const [screenName, setScreenName] = useState("");
const [screenCode, setScreenCode] = useState("");
const [tableName, setTableName] = useState("");
const [description, setDescription] = useState("");
const [tables, setTables] = useState<Array<{ tableName: string; displayName: string }>>([]);
const [submitting, setSubmitting] = useState(false);
// 화면 코드 자동 생성
const generateCode = async () => {
try {
const companyCode = (user as any)?.company_code || (user as any)?.companyCode || "*";
const generatedCode = await screenApi.generateScreenCode(companyCode);
setScreenCode(generatedCode);
} catch (e) {
// console.error("화면 코드 생성 실패", e);
}
};
useEffect(() => {
if (!open) return;
let abort = false;
const loadTables = async () => {
try {
const list = await tableTypeApi.getTables();
if (abort) return;
setTables(list.map((t) => ({ tableName: t.tableName, displayName: t.displayName || t.tableName })));
} catch (e) {
// console.error("테이블 목록 조회 실패", e);
setTables([]);
}
};
loadTables();
return () => {
abort = true;
};
}, [open]);
// 모달이 열릴 때 자동으로 화면 코드 생성
useEffect(() => {
if (open && !screenCode) {
generateCode();
}
}, [open, screenCode]);
const isValid = useMemo(() => {
return screenName.trim().length > 0 && screenCode.trim().length > 0 && tableName.trim().length > 0;
}, [screenName, screenCode, tableName]);
const handleSubmit = async () => {
if (!isValid || submitting) return;
try {
setSubmitting(true);
const companyCode = (user as any)?.company_code || (user as any)?.companyCode || "*";
const created = await screenApi.createScreen({
screenName: screenName.trim(),
screenCode: screenCode.trim(),
tableName: tableName.trim(),
companyCode,
description: description.trim() || undefined,
createdBy: (user as any)?.userId,
} as any);
// 날짜 필드 보정
const mapped: ScreenDefinition = {
...created,
createdDate: created.createdDate ? new Date(created.createdDate as any) : new Date(),
updatedDate: created.updatedDate ? new Date(created.updatedDate as any) : new Date(),
} as ScreenDefinition;
onCreated?.(mapped);
onOpenChange(false);
setScreenName("");
setScreenCode("");
setTableName("");
setDescription("");
} catch (e) {
// console.error("화면 생성 실패", e);
// 필요 시 토스트 추가 가능
} finally {
setSubmitting(false);
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle> </DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="screenName"></Label>
<Input id="screenName" value={screenName} onChange={(e) => setScreenName(e.target.value)} />
</div>
<div className="space-y-2">
<Label htmlFor="screenCode"> </Label>
<Input
id="screenCode"
value={screenCode}
readOnly
placeholder="자동 생성됩니다..."
className="cursor-not-allowed bg-gray-50"
/>
</div>
<div className="space-y-2">
<Label htmlFor="tableName"></Label>
<select
id="tableName"
className="w-full rounded-md border px-3 py-2 text-sm"
value={tableName}
onChange={(e) => setTableName(e.target.value)}
>
<option value=""> ...</option>
{tables.map((t) => (
<option key={t.tableName} value={t.tableName}>
{t.displayName} ({t.tableName})
</option>
))}
</select>
</div>
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Input id="description" value={description} onChange={(e) => setDescription(e.target.value)} />
</div>
</div>
<DialogFooter className="mt-4">
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={submitting}>
</Button>
<Button onClick={handleSubmit} disabled={!isValid || submitting} variant="default">
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}