feat(WEB): 견적서 V2 컴포넌트 개선 및 미리보기 모달 패턴 적용

- LocationDetailPanel: 6개 탭 구현 (본체, 가이드레일, 케이스, 하단마감재, 모터&제어기, 부자재)
- 각 탭별 다른 테이블 컬럼 구조 적용
- QuoteSummaryPanel: 개소별/상세별 합계 패널 개선
- QuotePreviewModal: EstimateDocumentModal 패턴 적용 (헤더+버튼 영역 분리)
- Input value → defaultValue 변경으로 React 경고 해결
- 팩스/카카오톡 버튼 제거

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2026-01-12 15:26:17 +09:00
parent e56b7d53a4
commit d036ce4f42
40 changed files with 5292 additions and 141 deletions

View File

@@ -11,6 +11,7 @@ interface DayCellProps {
isToday: boolean;
isSelected: boolean;
isWeekend: boolean;
isPast: boolean;
badge?: DayBadge;
onClick: (date: Date) => void;
}
@@ -28,6 +29,7 @@ export function DayCell({
isToday,
isSelected,
isWeekend,
isPast,
badge,
onClick,
}: DayCellProps) {
@@ -44,11 +46,15 @@ export function DayCell({
'hover:bg-primary/10',
// 현재 월 여부
isCurrentMonth ? 'text-foreground' : 'text-muted-foreground/40',
// 주말 색상
isWeekend && isCurrentMonth && 'text-red-500',
// 오늘
isToday && 'bg-accent text-accent-foreground font-bold',
// 선택됨
// 지난 일자 - 더 명확한 회색 (현재 월에서만)
isPast && isCurrentMonth && !isToday && !isSelected && 'text-gray-400',
// 주말 색상 (지난 일자가 아닌 경우만)
isWeekend && isCurrentMonth && !isPast && 'text-red-500',
// 지난 주말 - 연한 색상
isWeekend && isCurrentMonth && isPast && !isToday && !isSelected && 'text-red-300',
// 오늘 - 굵은 글씨 (외곽선은 부모 셀에 적용)
isToday && !isSelected && 'font-bold text-primary',
// 선택됨 - 배경색 하이라이트
isSelected && 'bg-primary text-primary-foreground hover:bg-primary'
)}
>

View File

@@ -11,6 +11,7 @@ import {
getWeekdayHeaders,
isCurrentMonth,
checkIsToday,
checkIsPast,
isSameDate,
splitIntoWeeks,
getEventSegmentsForWeek,
@@ -173,6 +174,10 @@ function WeekRow({
const dayEvents = getEventsForDate(events, date);
const isSelected = isSameDate(selectedDate, date);
const isToday = checkIsToday(date);
const isPast = checkIsPast(date);
const isCurrMonth = isCurrentMonth(date, currentDate);
return (
<div
key={date.toISOString()}
@@ -180,7 +185,11 @@ function WeekRow({
'relative p-1 border-r last:border-r-0',
'flex flex-col cursor-pointer transition-colors',
// 기본 배경
!isCurrentMonth(date, currentDate) && 'bg-muted/30',
!isCurrMonth && 'bg-muted/30',
// 지난 일자 - 회색 배경 (현재 월, 오늘/선택 제외)
isPast && isCurrMonth && !isToday && !isSelected && 'bg-gray-200 dark:bg-gray-700',
// 오늘 - 셀 전체 외곽선 하이라이트
isToday && !isSelected && 'ring-2 ring-primary ring-inset',
// 선택된 날짜 - 셀 전체 배경색 변경 (테두리 없이)
isSelected && 'bg-primary/15'
)}
@@ -189,10 +198,11 @@ function WeekRow({
{/* 날짜 셀 */}
<DayCell
date={date}
isCurrentMonth={isCurrentMonth(date, currentDate)}
isToday={checkIsToday(date)}
isCurrentMonth={isCurrMonth}
isToday={isToday}
isSelected={isSelected}
isWeekend={isWeekend}
isPast={isPast}
badge={badge}
onClick={onDateClick}
/>

View File

@@ -40,7 +40,7 @@ export function ScheduleCalendar({
onViewChange,
titleSlot,
filterSlot,
maxEventsPerDay = 3,
maxEventsPerDay = 5,
weekStartsOn = 0,
isLoading = false,
className,

View File

@@ -7,10 +7,12 @@ import {
endOfMonth,
startOfWeek,
endOfWeek,
startOfDay,
eachDayOfInterval,
isSameMonth,
isSameDay,
isToday,
isBefore,
format,
addMonths,
subMonths,
@@ -71,6 +73,15 @@ export function checkIsToday(date: Date): boolean {
return isToday(date);
}
/**
* 날짜가 오늘 이전인지 확인 (지난 일자)
*/
export function checkIsPast(date: Date): boolean {
const today = startOfDay(new Date());
const targetDate = startOfDay(date);
return isBefore(targetDate, today);
}
/**
* 두 날짜가 같은지 확인
*/