fix: 빗물펌프장 자체 입력정보에서 '설계빈도(년)'에 숫자만 입력되게끔 수정 (placeholder 추가, alert, validation)

This commit is contained in:
swcho
2025-08-13 14:51:25 +09:00
parent 12baddecbf
commit 10f44bba3c
2 changed files with 131 additions and 16 deletions
@@ -4,7 +4,7 @@ import React, { useState, useEffect } from 'react'
const exclnInputColumn = [
{ id: "swtrmtZoneNm", title: "배수구역", type: "input" },
{ id: "mltvDtdvNm", title: "배수분구", type: "input" },
{ id: "designFrqYr", title: "설계빈도(년)", type: "input" },
{ id: "designFrqYr", title: "설계빈도(년)", type: "input", placeholder: "예: 10", isNumber: true, length: 4 },
]
// 오수펌프장 자체 입력 정보
const drtwInputColumn = [
+130 -15
View File
@@ -1,6 +1,8 @@
import UiPageNations from "@common/business_components/ui/table/uiPageNations";
import { Table, TableBody, TableCell, TableRow, Button } from "@common/components";
import { useEffect, useState } from "react";
import { confirmToast, showConfirmToast } from '@/components/ui/toast'
import { toast, Toaster } from "react-hot-toast";
type UiTableProps = {
headName: React.ReactNode | undefined;
@@ -39,6 +41,8 @@ type UiHeadProps = {
type?: string;
options?: string[];
placeholder?: string;
isNumber?: boolean;
length?: number;
};
export function VerticalTable({
@@ -63,6 +67,16 @@ export function VerticalTable({
}: UiTableProps) {
const [cur, setCur] = useState<number>(1);
const [formData, setFormData] = useState<{ [key: string]: string | number | boolean }>({});
const [errors, setErrors] = useState<{ [key: string]: string }>({}); // 에러 상태 추가
// 컴포넌트 언마운트 시 confirmToast 정리
useEffect(() => {
return () => {
// 컴포넌트가 언마운트될 때 global-confirm-toast ID를 가진 Toast 제거
toast.dismiss("global-confirm-toast");
};
}, []);
useEffect(() => {
if (resetPageNo) {
setCur(1);
@@ -88,16 +102,33 @@ export function VerticalTable({
console.log("New form data:", newFormData); // 디버깅용
setFormData(newFormData);
// 에러 메시지 초기화 (입력이 성공하면 에러 제거)
if (errors[id]) {
setErrors(prev => {
const newErrors = { ...prev };
delete newErrors[id];
return newErrors;
});
}
// 폼 데이터가 변경될 때마다 부모에게 알림
if (onFormDataChange) {
onFormDataChange(newFormData);
}
};
const handlePageChange = (page: number) => {
setCur(page);
onPageChange(page);
};
const showError = (fieldId: string, message: string) => {
setErrors(prev => ({
...prev,
[fieldId]: message
}));
};
return (
<>
{headName ? (
@@ -142,13 +173,55 @@ export function VerticalTable({
))}
</select>
) : head.type === "input" ? (
<input
id={head.id}
type="text"
value={String(formData[head.id] ?? "")}
onChange={(e) => handleInputChange(head.id, e.target.value)}
className="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1"
/>
<div className="w-full">
<input
id={head.id}
type="text"
value={String(formData[head.id] ?? "")}
onChange={(e) => {
if (head.isNumber) {
const newValue = e.target.value;
if (newValue === "") {
handleInputChange(head.id, newValue);
return;
}
const isValidNumber = /^[0-9]+$/.test(newValue);
if (!isValidNumber) {
showError(head.id, `${head.title}는 숫자만 입력 가능합니다.`);
return;
}
if (head.length && newValue.length > head.length) {
showError(head.id, `${head.title}는 최대 ${head.length}자까지 입력 가능합니다.`);
return;
}
const numericValue = parseInt(newValue);
if (isNaN(numericValue) || numericValue < 0) return;
handleInputChange(head.id, numericValue);
} else {
const newValue = e.target.value;
if (head.length && newValue.length > head.length) {
showError(head.id, `${head.title}는 최대 ${head.length}자까지 입력 가능합니다.`);
return;
}
handleInputChange(head.id, e.target.value);
}
}}
className="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1"
placeholder={head.placeholder}
/>
{errors[head.id] && (
<div className="text-red-500 font-bold text-xl mt-1 text-left">
{errors[head.id]}
</div>
)}
</div>
) : (
<span>{formData[head.id] ?? "-"}</span>
)
@@ -189,14 +262,55 @@ export function VerticalTable({
))}
</select>
) : head.type === "input" ? (
<input
id={head.id}
type="text"
value={formData[head.id] !== undefined ? String(formData[head.id]) : ""}
onChange={(e) => handleInputChange(head.id, e.target.value)}
className="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1"
placeholder={head.placeholder}
/>
<div className="w-full">
<input
id={head.id}
type={head.isNumber ? "number" : "text"}
value={formData[head.id] !== undefined ? String(formData[head.id]) : ""}
onChange={(e) => {
if (head.isNumber) {
const newValue = e.target.value;
if (newValue === "") {
handleInputChange(head.id, newValue);
return;
}
const isValidNumber = /^[0-9]+$/.test(newValue);
if (!isValidNumber) {
showError(head.id, `${head.title}는 숫자만 입력 가능합니다.`);
return;
}
if (head.length && newValue.length > head.length) {
showError(head.id, `${head.title}는 최대 ${head.length}자까지 입력 가능합니다.`);
return;
}
const numericValue = parseInt(newValue);
if (isNaN(numericValue) || numericValue < 0) return;
handleInputChange(head.id, numericValue);
} else {
const newValue = e.target.value;
if (head.length && newValue.length > head.length) {
showError(head.id, `${head.title}는 최대 ${head.length}자까지 입력 가능합니다.`);
return;
}
handleInputChange(head.id, e.target.value);
}
}}
className="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1"
placeholder={head.placeholder}
/>
{errors[head.id] && (
<div className="text-red-500 font-bold text-xl mt-1 text-left">
{errors[head.id]}
</div>
)}
</div>
) : (
<span>{formData[head.id] ?? "-"}</span>
)
@@ -218,6 +332,7 @@ export function VerticalTable({
/>
)}
</div>
<Toaster position="top-center"></Toaster>
</>
);
}