From 805063c68600c90ae028fff005d43f97f06b62f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=B3=91=EC=B2=A0?= Date: Wed, 28 Jan 2026 09:57:12 +0900 Subject: [PATCH] =?UTF-8?q?feat(WEB):=20UniversalListPage=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=EB=B2=94=EC=9C=84=20=ED=95=84=ED=84=B0=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=A0=81=EC=9A=A9=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UniversalListPage: - dateRangeSelector.dateField 설정 시 클라이언트 사이드 날짜 필터 자동 적용 - 종료일 23:59:59까지 포함하도록 처리 AttendanceManagement: - 사유 등록 버튼을 extraFilters에서 headerActions로 이동 IntegratedListTemplateV2: - 날짜 범위 관련 타입 및 처리 개선 Co-Authored-By: Claude Opus 4.5 --- .../hr/AttendanceManagement/index.tsx | 17 ++++++++--------- src/components/hr/EmployeeManagement/index.tsx | 3 +++ src/components/molecules/DateRangeSelector.tsx | 5 +++-- .../templates/IntegratedListTemplateV2.tsx | 6 +++--- .../templates/UniversalListPage/index.tsx | 18 +++++++++++++++++- .../templates/UniversalListPage/types.ts | 6 ++++++ 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/components/hr/AttendanceManagement/index.tsx b/src/components/hr/AttendanceManagement/index.tsx index ff7a6ad2..549149ab 100644 --- a/src/components/hr/AttendanceManagement/index.tsx +++ b/src/components/hr/AttendanceManagement/index.tsx @@ -469,6 +469,14 @@ export function AttendanceManagement() { onClick: handleAddAttendance, }, + // 헤더 액션 (근태 등록 버튼 옆에 표시) + headerActions: () => ( + + ), + searchPlaceholder: '이름, 부서 검색...', // 엑셀 다운로드 설정 (클라이언트 사이드 필터링이므로 filteredData 사용) @@ -478,15 +486,6 @@ export function AttendanceManagement() { sheetName: '근태', }, - extraFilters: ( -
- -
- ), - itemsPerPage: itemsPerPage, clientSideFiltering: true, diff --git a/src/components/hr/EmployeeManagement/index.tsx b/src/components/hr/EmployeeManagement/index.tsx index 11ffb51e..41f4b80e 100644 --- a/src/components/hr/EmployeeManagement/index.tsx +++ b/src/components/hr/EmployeeManagement/index.tsx @@ -153,6 +153,8 @@ export function EmployeeManagement() { ); } + // 날짜 필터는 UniversalListPage에서 dateField 설정을 통해 자동 처리됨 + // 정렬 filtered = [...filtered].sort((a, b) => { switch (sortOption) { @@ -450,6 +452,7 @@ export function EmployeeManagement() { endDate, onStartDateChange: setStartDate, onEndDateChange: setEndDate, + dateField: 'hireDate', // 입사일 기준 자동 필터링 }, createButton: { diff --git a/src/components/molecules/DateRangeSelector.tsx b/src/components/molecules/DateRangeSelector.tsx index 2a669e59..e5a925aa 100644 --- a/src/components/molecules/DateRangeSelector.tsx +++ b/src/components/molecules/DateRangeSelector.tsx @@ -182,10 +182,11 @@ export function DateRangeSelector({ } // presetsPosition이 'inline' (기본값) - // PC(1280px+): 달력 | 프리셋버튼 | 검색창 (한 줄) + // PC(1280px+): 달력 | 프리셋버튼 | 검색창 (한 줄, 넘치면 줄바꿈) // 태블릿: 달력 / 프리셋버튼 / 검색창 (세 줄) + // Note: w-full 제거 - 부모 컨테이너에서 다른 요소들과 자연스럽게 한 줄에 배치되도록 함 return ( -
+
{/* 날짜 범위 선택 */} {!hideDateInputs && (
diff --git a/src/components/templates/IntegratedListTemplateV2.tsx b/src/components/templates/IntegratedListTemplateV2.tsx index 56eb3d5b..89694d3a 100644 --- a/src/components/templates/IntegratedListTemplateV2.tsx +++ b/src/components/templates/IntegratedListTemplateV2.tsx @@ -544,7 +544,7 @@ export function IntegratedListTemplateV2({ {/* 레이아웃: [달력] [프리셋버튼] [검색창] -------------- [추가버튼들] [등록버튼] (오른쪽 끝) */} {(dateRangeSelector?.enabled || createButton || headerActions || (hideSearch && onSearchChange)) && ( isLoading ? renderHeaderActionSkeleton() : ( -
+
{/* 날짜 범위 선택기 + 검색창 (왼쪽) */} {dateRangeSelector?.enabled ? ( ({
) )} - {/* 버튼 영역 (오른쪽 끝으로 통합) */} + {/* 버튼 영역 (오른쪽 배치, 공간 부족시 자연스럽게 줄바꿈) */} {(headerActions || createButton) && ( -
+
{/* 헤더 액션 (엑셀 다운로드 등 추가 버튼들) */} {headerActions} {/* 등록 버튼 */} diff --git a/src/components/templates/UniversalListPage/index.tsx b/src/components/templates/UniversalListPage/index.tsx index ce652d80..8da15a77 100644 --- a/src/components/templates/UniversalListPage/index.tsx +++ b/src/components/templates/UniversalListPage/index.tsx @@ -122,6 +122,22 @@ export function UniversalListPage({ ); } + // 날짜 범위 필터 (dateRangeSelector.dateField 설정 시 자동 적용) + const { dateRangeSelector } = config; + if (dateRangeSelector?.enabled && dateRangeSelector.dateField && dateRangeSelector.startDate && dateRangeSelector.endDate) { + const dateField = dateRangeSelector.dateField; + const start = new Date(dateRangeSelector.startDate); + const end = new Date(dateRangeSelector.endDate); + end.setHours(23, 59, 59, 999); // 종료일 끝까지 포함 + + filtered = filtered.filter((item) => { + const itemDate = (item as Record)[dateField]; + if (!itemDate) return false; + const date = new Date(String(itemDate)); + return date >= start && date <= end; + }); + } + // 커스텀 정렬 함수 if (config.customSortFn) { filtered = config.customSortFn(filtered, filters); @@ -152,7 +168,7 @@ export function UniversalListPage({ } return filtered; - }, [rawData, activeTab, searchValue, filters, sortBy, sortOrder, config.clientSideFiltering, config.tabFilter, config.searchFilter, config.customFilterFn, config.customSortFn]); + }, [rawData, activeTab, searchValue, filters, sortBy, sortOrder, config.clientSideFiltering, config.tabFilter, config.searchFilter, config.customFilterFn, config.customSortFn, config.dateRangeSelector]); // 클라이언트 사이드 페이지네이션 const paginatedData = useMemo(() => { diff --git a/src/components/templates/UniversalListPage/types.ts b/src/components/templates/UniversalListPage/types.ts index 3281b9e1..363c26b0 100644 --- a/src/components/templates/UniversalListPage/types.ts +++ b/src/components/templates/UniversalListPage/types.ts @@ -277,6 +277,12 @@ export interface UniversalListConfig { onEndDateChange?: (date: string) => void; /** 추가 액션 (검색창 등) - presetsPosition이 'below'일 때 달력 옆에 배치됨 */ extraActions?: ReactNode; + /** + * 날짜 필터링에 사용할 필드명 (clientSideFiltering: true 시 자동 필터링) + * - 예: 'hireDate', 'createdAt', 'orderDate' 등 + * - 설정 시 startDate ~ endDate 범위로 해당 필드 자동 필터링 + */ + dateField?: string; }; /** * 등록 버튼 (오른쪽 끝 배치)