Merge pull request 'common/feat/dashboard-map' (#292) from common/feat/dashboard-map into main

Reviewed-on: http://39.117.244.52:3000/kjs/ERP-node/pulls/292
This commit is contained in:
hyeonsu 2025-12-16 10:03:04 +09:00
commit 9420b14836
2 changed files with 58 additions and 35 deletions

View File

@ -182,7 +182,8 @@ export const RepeaterInput: React.FC<RepeaterInputProps> = ({
// 항목 제거
const handleRemoveItem = (index: number) => {
if (items.length <= minItems) {
// 🆕 minItems가 0이면 모든 항목 삭제 가능, 그 외에는 minItems 이하로 줄일 수 없음
if (minItems > 0 && items.length <= minItems) {
return;
}
@ -518,17 +519,26 @@ export const RepeaterInput: React.FC<RepeaterInputProps> = ({
);
case "date": {
// 날짜 값 정규화: ISO 형식이면 YYYY-MM-DD로 변환
// 날짜 값 정규화: ISO 형식이면 YYYY-MM-DD로 변환 (타임존 이슈 해결)
let dateValue = value || "";
if (dateValue && typeof dateValue === "string") {
// ISO 형식(YYYY-MM-DDTHH:mm:ss)이면 날짜 부분만 추출
// ISO 형식(YYYY-MM-DDTHH:mm:ss)이면 로컬 시간으로 변환하여 날짜 추출
if (dateValue.includes("T")) {
dateValue = dateValue.split("T")[0];
}
// 유효한 날짜인지 확인
const parsedDate = new Date(dateValue);
if (isNaN(parsedDate.getTime())) {
dateValue = ""; // 유효하지 않은 날짜면 빈 값
const date = new Date(dateValue);
if (!isNaN(date.getTime())) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
dateValue = `${year}-${month}-${day}`;
} else {
dateValue = "";
}
} else {
// 유효한 날짜인지 확인
const parsedDate = new Date(dateValue);
if (isNaN(parsedDate.getTime())) {
dateValue = ""; // 유효하지 않은 날짜면 빈 값
}
}
}
return (
@ -801,7 +811,7 @@ export const RepeaterInput: React.FC<RepeaterInputProps> = ({
{/* 삭제 버튼 */}
<TableCell className="h-12 px-2.5 py-2 text-center">
{!readonly && !disabled && items.length > minItems && (
{!readonly && !disabled && (minItems === 0 || items.length > minItems) && (
<Button
type="button"
variant="ghost"
@ -871,7 +881,7 @@ export const RepeaterInput: React.FC<RepeaterInputProps> = ({
)}
{/* 삭제 버튼 */}
{!readonly && !disabled && items.length > minItems && (
{!readonly && !disabled && (minItems === 0 || items.length > minItems) && (
<Button
type="button"
variant="ghost"

View File

@ -166,8 +166,13 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
}
// ISO 8601 날짜 (2023-12-31T00:00:00.000Z 등)
// 🆕 UTC 시간을 로컬 시간으로 변환하여 날짜 추출 (타임존 이슈 해결)
if (/^\d{4}-\d{2}-\d{2}T/.test(dateStr)) {
return dateStr.split("T")[0];
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
// 다른 형식의 날짜 문자열이나 Date 객체 처리
@ -276,7 +281,7 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
<div className={`relative h-full w-full ${className || ""}`} {...safeDomProps}>
{/* 라벨 렌더링 */}
{component.label && component.style?.labelDisplay !== false && (
<label className="absolute -top-6 left-0 text-sm font-medium text-muted-foreground">
<label className="text-muted-foreground absolute -top-6 left-0 text-sm font-medium">
{component.label}
{component.required && <span className="text-destructive">*</span>}
</label>
@ -299,16 +304,18 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
}}
className={cn(
"h-full min-h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
"placeholder:text-muted-foreground",
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
"disabled:cursor-not-allowed"
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
componentConfig.disabled
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
: "bg-background text-foreground",
"disabled:cursor-not-allowed",
)}
/>
{/* 구분자 */}
<span className="text-base font-medium text-muted-foreground">~</span>
<span className="text-muted-foreground text-base font-medium">~</span>
{/* 종료일 */}
<input
@ -326,11 +333,13 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
}}
className={cn(
"h-full min-h-full flex-1 rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
"placeholder:text-muted-foreground",
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
"disabled:cursor-not-allowed"
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
componentConfig.disabled
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
: "bg-background text-foreground",
"disabled:cursor-not-allowed",
)}
/>
</div>
@ -344,7 +353,7 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
<div className={`relative h-full w-full ${className || ""}`} {...safeDomProps}>
{/* 라벨 렌더링 */}
{component.label && component.style?.labelDisplay !== false && (
<label className="absolute -top-6 left-0 text-sm font-medium text-muted-foreground">
<label className="text-muted-foreground absolute -top-6 left-0 text-sm font-medium">
{component.label}
{component.required && <span className="text-destructive">*</span>}
</label>
@ -368,11 +377,13 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
}}
className={cn(
"box-border h-full min-h-full w-full rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
"placeholder:text-muted-foreground",
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
"disabled:cursor-not-allowed"
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
componentConfig.disabled
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
: "bg-background text-foreground",
"disabled:cursor-not-allowed",
)}
/>
</div>
@ -400,14 +411,16 @@ export const DateInputComponent: React.FC<DateInputComponentProps> = ({
disabled={componentConfig.disabled || false}
required={componentConfig.required || false}
readOnly={componentConfig.readonly || finalAutoGeneration?.enabled || false}
className={cn(
"box-border h-full min-h-full w-full rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"placeholder:text-muted-foreground",
isSelected ? "border-ring ring-2 ring-ring/50" : "border-input",
componentConfig.disabled ? "bg-muted text-muted-foreground cursor-not-allowed opacity-50" : "bg-background text-foreground",
"disabled:cursor-not-allowed"
)}
className={cn(
"box-border h-full min-h-full w-full rounded-md border px-3 py-2 text-sm transition-all duration-200 outline-none",
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
"placeholder:text-muted-foreground",
isSelected ? "border-ring ring-ring/50 ring-2" : "border-input",
componentConfig.disabled
? "bg-muted text-muted-foreground cursor-not-allowed opacity-50"
: "bg-background text-foreground",
"disabled:cursor-not-allowed",
)}
onClick={handleClick}
onDragStart={onDragStart}
onDragEnd={onDragEnd}