'use client'; import { ReactNode, useCallback } from 'react'; import { format, startOfYear, endOfYear, subMonths, startOfMonth, endOfMonth, subDays } from 'date-fns'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; /** * 날짜 범위 프리셋 타입 */ export type DatePreset = 'thisYear' | 'twoMonthsAgo' | 'lastMonth' | 'thisMonth' | 'yesterday' | 'today'; /** * 프리셋 레이블 (한국어) */ const PRESET_LABELS: Record = { thisYear: '당해년도', twoMonthsAgo: '전전월', lastMonth: '전월', thisMonth: '당월', yesterday: '어제', today: '오늘', }; /** * 기본 프리셋 순서 */ const DEFAULT_PRESETS: DatePreset[] = ['thisYear', 'twoMonthsAgo', 'lastMonth', 'thisMonth', 'yesterday', 'today']; interface DateRangeSelectorProps { /** 시작 날짜 (yyyy-MM-dd 형식) */ startDate: string; /** 종료 날짜 (yyyy-MM-dd 형식) */ endDate: string; /** 시작 날짜 변경 핸들러 */ onStartDateChange: (date: string) => void; /** 종료 날짜 변경 핸들러 */ onEndDateChange: (date: string) => void; /** 표시할 프리셋 목록 (기본: 전체) */ presets?: DatePreset[]; /** 추가 액션 (엑셀 다운로드, 등록 버튼 등) */ extraActions?: ReactNode; /** 프리셋 버튼 숨김 */ hidePresets?: boolean; /** 날짜 입력 숨김 */ hideDateInputs?: boolean; /** 날짜 입력 너비 */ dateInputWidth?: string; /** 프리셋 버튼 위치: 'inline' (날짜 옆), 'below' (별도 줄) */ presetsPosition?: 'inline' | 'below'; } /** * 날짜 범위 선택 컴포넌트 * * 달력(날짜 입력) + 기간 프리셋 버튼 (당해년도, 전전월, 전월, 당월, 어제, 오늘) * * @example * ```tsx * * * * * } * /> * ``` */ export function DateRangeSelector({ startDate, endDate, onStartDateChange, onEndDateChange, presets = DEFAULT_PRESETS, extraActions, hidePresets = false, hideDateInputs = false, dateInputWidth = 'w-[140px]', presetsPosition = 'inline', }: DateRangeSelectorProps) { // 프리셋 클릭 핸들러 const handlePresetClick = useCallback((preset: DatePreset) => { const today = new Date(); switch (preset) { case 'thisYear': onStartDateChange(format(startOfYear(today), 'yyyy-MM-dd')); onEndDateChange(format(endOfYear(today), 'yyyy-MM-dd')); break; case 'twoMonthsAgo': { const twoMonthsAgo = subMonths(today, 2); onStartDateChange(format(startOfMonth(twoMonthsAgo), 'yyyy-MM-dd')); onEndDateChange(format(endOfMonth(twoMonthsAgo), 'yyyy-MM-dd')); break; } case 'lastMonth': { const lastMonth = subMonths(today, 1); onStartDateChange(format(startOfMonth(lastMonth), 'yyyy-MM-dd')); onEndDateChange(format(endOfMonth(lastMonth), 'yyyy-MM-dd')); break; } case 'thisMonth': onStartDateChange(format(startOfMonth(today), 'yyyy-MM-dd')); onEndDateChange(format(endOfMonth(today), 'yyyy-MM-dd')); break; case 'yesterday': { const yesterday = subDays(today, 1); onStartDateChange(format(yesterday, 'yyyy-MM-dd')); onEndDateChange(format(yesterday, 'yyyy-MM-dd')); break; } case 'today': onStartDateChange(format(today, 'yyyy-MM-dd')); onEndDateChange(format(today, 'yyyy-MM-dd')); break; } }, [onStartDateChange, onEndDateChange]); // 프리셋 버튼 렌더링 const renderPresets = () => { if (hidePresets || presets.length === 0) return null; return (
{presets.map((preset) => ( ))}
); }; // presetsPosition이 'below'일 때: 달력+extraActions 같은 줄, 프리셋은 아래 줄 if (presetsPosition === 'below') { return (
{/* 1줄: 날짜 + extraActions */}
{/* 날짜 범위 선택 */} {!hideDateInputs && (
onStartDateChange(e.target.value)} className="w-[165px]" /> ~ onEndDateChange(e.target.value)} className="w-[165px]" />
)} {/* extraActions (검색창 등) */} {extraActions}
{/* 2줄: 프리셋 버튼들 */} {renderPresets()}
); } // presetsPosition이 'inline' (기본값) // PC(1280px+): 달력 | 프리셋버튼 | 검색창 (한 줄) // 태블릿: 달력 / 프리셋버튼 / 검색창 (세 줄) return (
{/* 날짜 범위 선택 */} {!hideDateInputs && (
onStartDateChange(e.target.value)} className="w-[165px]" /> ~ onEndDateChange(e.target.value)} className="w-[165px]" />
)} {/* 기간 버튼들 - 달력 바로 옆 */} {renderPresets()} {/* extraActions (검색창 등) - 마지막에 배치 */} {extraActions}
); }