날짜 입력 시 하루 밀리는 타임존 버그 수정
This commit is contained in:
parent
8cc189da17
commit
a2582a28e4
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Reference in New Issue