Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/common/ToastMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface ToastItemProps {

export const ToastItem = ({ message, icon }: ToastItemProps) => {
return (
<div className="animate-toast-in relative min-h-[3.75rem] w-[20.3125rem]">
<div className="animate-toast-in relative w-[20.3125rem]">
{/* blur 배경 레이어 - opacity 항상 1 */}
<div className="bg-neutral-875/70 absolute inset-0 rounded-[1.125rem] border border-neutral-800 shadow-lg backdrop-blur-3xl" />

Expand Down
6 changes: 1 addition & 5 deletions src/components/photoLab/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ChevronLeftIcon } from "@/assets/icon";
import DateChip from "@/components/common/chips/DateChip";
import { WEEKDAYS } from "@/constants/date";
import { buildCalendarGrid, getVisibleDays } from "@/utils/calendar";
import { isSameDay } from "@/utils/dateFormat";

interface CalendarProps {
selectedDate?: Date;
Expand Down Expand Up @@ -45,11 +46,6 @@ export default function Calendar({
return getVisibleDays(grid, effectiveMinDate, isDateDisabled);
}, [year, month, effectiveMinDate, isDateDisabled]);

const isSameDay = (d1: Date, d2: Date) =>
d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();

return (
<div className="flex flex-col gap-3">
{/* 년/월 네비게이션 */}
Expand Down
35 changes: 31 additions & 4 deletions src/components/photoLab/FilterBottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useMemo, useEffect } from "react";
import { useState, useMemo, useEffect, useCallback } from "react";
import BottomSheet from "@/components/common/BottomSheet";
import UnderlineTabs from "@/components/common/UnderlineTabs";
import Calendar from "@/components/photoLab/Calendar";
Expand All @@ -8,13 +8,22 @@ import RegionSelector from "@/components/photoLab/RegionSelector";
import { TIME_SLOTS } from "@/constants/photoLab/timeSlots";
import { REGIONS, MAX_REGION_SELECTIONS } from "@/constants/photoLab/regions";
import { useRegionFilters } from "@/hooks/photoLab";
import { isSameDay } from "@/utils/dateFormat";
import type { FilterState, Region, RegionSelection } from "@/types/photoLab";

// 전체 시트 높이 (Handle + Tabs + ContentPad + Calendar + TimeSlot + Buttons + Gaps)
const CONTENT_BASE_HEIGHT_REM = 46; // 캘린더 6줄 기준
const MAX_CALENDAR_ROWS = 6;
const ROW_HEIGHT_REM = 3.125; // 3rem (DateChip) + 0.125rem (gap)

// "오전 9:00" → 9, "오후 2:00" → 14 변환
function parseHour(slot: string): number {
const [period, hm] = slot.split(" ");
const h = parseInt(hm, 10);
if (period === "오전") return h;
return h === 12 ? 12 : h + 12;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION : 이 부분은 유틸 함수로 안 빼신 이유가 있으실까요??

interface FilterBottomSheetProps {
open: boolean;
onClose: () => void;
Expand Down Expand Up @@ -85,6 +94,21 @@ export default function FilterBottomSheet({
initialFilter?.regionSelections?.[0]?.parentName ?? defaultDisplayRegion,
);

// 오늘인데 모든 시간 슬롯이 지났으면 선택 불가
const isDateDisabled = useCallback((date: Date) => {
const now = new Date();
return isSameDay(date, now) && now.getHours() >= 20;
}, []);

// 오늘이면 지난 시간 숨김 (선택 상태는 유지, 적용 시 정리)
const filteredSlots = useMemo(() => {
if (!selectedDate) return TIME_SLOTS;
const now = new Date();
if (!isSameDay(selectedDate, now)) return TIME_SLOTS;
const currentHour = now.getHours();
return TIME_SLOTS.filter((slot) => parseHour(slot) > currentHour);
}, [selectedDate]);
Comment on lines +104 to +110
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

filteredSlotsselectedDate에만 의존하고 있어, 시간이 지나도 필터링된 시간 목록이 실시간으로 업데이트되지 않는 잠재적인 문제가 있습니다. 예를 들어, 사용자가 오늘 날짜를 선택한 상태로 필터 창을 9:59에 열어두면, 10:01이 되어도 '오전 10:00' 슬롯이 사라지지 않습니다.

이 문제를 해결하기 위해 useEffectuseState를 사용하여 1분마다 현재 시간을 업데이트하고, 이 시간 값을 useMemo의 의존성 배열에 추가하는 것을 고려해볼 수 있습니다.

// 컴포넌트 상단에 추가
const [currentTime, setCurrentTime] = useState(new Date());

useEffect(() => {
  const timerId = setInterval(() => setCurrentTime(new Date()), 60000); // 1분마다 업데이트
  return () => clearInterval(timerId);
}, []);

// useMemo 수정
const filteredSlots = useMemo(() => {
  if (!selectedDate) return TIME_SLOTS;
  const now = currentTime; // new Date() 대신 상태 사용
  // ...
}, [selectedDate, currentTime]); // 의존성 배열에 currentTime 추가

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

큰 문제는 아니고, 시간 빼는 것도 UX를 위해 추가한거라 굳이


// 시간 토글 (복수 선택)
const handleTimeToggle = (time: string) => {
setSelectedTimes((prev) =>
Expand Down Expand Up @@ -155,8 +179,10 @@ export default function FilterBottomSheet({
const d = String(selectedDate.getDate()).padStart(2, "0");
filter.date = `${y}-${m}-${d}`;
}
if (selectedTimes.length > 0) {
filter.time = selectedTimes;
// 현재 보이는 슬롯에 포함된 시간만 적용
const validTimes = selectedTimes.filter((t) => filteredSlots.includes(t));
if (validTimes.length > 0) {
filter.time = validTimes;
}
if (selectedRegions.length > 0) {
filter.regionSelections = selectedRegions;
Expand Down Expand Up @@ -238,9 +264,10 @@ export default function FilterBottomSheet({
onDateSelect={setSelectedDate}
viewDate={viewDate}
onViewDateChange={setViewDate}
isDateDisabled={isDateDisabled}
/>
<TimeSlotList
slots={TIME_SLOTS}
slots={filteredSlots}
selectedTimes={selectedTimes}
onTimeToggle={handleTimeToggle}
/>
Expand Down
5 changes: 5 additions & 0 deletions src/utils/dateFormat.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { WEEKDAYS } from "@/constants/date";

export const isSameDay = (d1: Date, d2: Date) =>
d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();

// 시간을 12시간제로
export function to12Hour(hour: number): {
period: string;
Expand Down