화면 목록 저장기능
This commit is contained in:
158
frontend/components/screen/CreateScreenModal.tsx
Normal file
158
frontend/components/screen/CreateScreenModal.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
"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} className="bg-blue-600 hover:bg-blue-700">
|
||||
생성
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user