Skip to content

Commit 06ffd88

Browse files
committed
FIX: 바텀시트 컴포넌트 취소 완료 버튼 추가 및 trigger 추가
1 parent bbe3988 commit 06ffd88

File tree

3 files changed

+55
-31
lines changed

3 files changed

+55
-31
lines changed

src/feature/todo/weeklyTodoList/components/AddTodoButton.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
3737
showToast('투두가 추가되었습니다.', 'success');
3838
},
3939
onError: error => {
40+
setOpen(false);
4041
showToast(error?.response?.data.message || '투두 추가에 실패했습니다.', 'error');
4142
},
4243
});
@@ -46,7 +47,9 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
4647
handleSubmit,
4748
setValue,
4849
watch,
49-
formState: { errors, isValid },
50+
trigger,
51+
clearErrors,
52+
formState: { errors },
5053
reset,
5154
} = useForm<AddTodoFormData>({
5255
mode: 'onChange',
@@ -56,7 +59,6 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
5659
},
5760
});
5861

59-
const watchedContent = watch('content');
6062
const watchedSelectedDate = watch('selectedDate');
6163
const startDate = new Date(goal.duration.startDate);
6264
const endDate = new Date(goal.duration.endDate);
@@ -83,7 +85,17 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
8385
setValue('selectedDate', date, { shouldValidate: true });
8486
};
8587

88+
const handleCompleteClick = async () => {
89+
const isFormValid = await trigger(['content', 'selectedDate']);
90+
91+
if (!isFormValid) {
92+
return;
93+
}
94+
handleSubmit(onSubmit)();
95+
};
96+
8697
const handlePlusClick = () => {
98+
clearErrors(); // Sheet를 열 때 에러 상태 초기화
8799
trackButtonClick({
88100
eventName: GTM_EVENTS.HOME_TODO_CLICK,
89101
buttonName: GTM_BUTTON_NAME.ADD_TODO,
@@ -103,6 +115,7 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
103115
buttonName: GTM_BUTTON_NAME.ADD_TODO_SHEET,
104116
});
105117
reset({ content: '', selectedDate: selectedDate || undefined });
118+
clearErrors(); // 에러 상태 초기화
106119
}
107120
};
108121

@@ -138,7 +151,7 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
138151
onClick={() => setOpen(false)}
139152
className="label-1-normal font-bold text-status-negative"
140153
>
141-
닫기
154+
취소
142155
</button>
143156
<DateSelector
144157
selectedDate={watchedSelectedDate}
@@ -149,8 +162,8 @@ export const AddTodoButton = ({ goal, selectedPlanId, selectedDate }: AddTodoBut
149162
/>
150163
<button
151164
type="button"
152-
onClick={handleSubmit(onSubmit)}
153-
disabled={loading || !isValid}
165+
onClick={handleCompleteClick}
166+
disabled={loading}
154167
className="label-1-normal font-bold text-label-normal"
155168
>
156169
완료

src/feature/todo/weeklyTodoList/components/DateSelector.tsx

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { useState } from 'react';
1+
import { useState, useEffect } from 'react';
22
import { Sheet, SheetContent, SheetTrigger } from '@/shared/components/ui/sheet';
33
import DateSelectorPanel from './DateSelectorPanel';
44
import { useGTMActions } from '@/shared/hooks/useGTM';
55
import { GTM_BUTTON_NAME, GTM_EVENTS } from '@/shared/constants/gtm-events';
66
import { Z_INDEX } from '@/shared/lib/z-index';
7-
import { XIcon } from 'lucide-react';
87

98
interface DateSelectorProps {
109
selectedDate: Date | undefined;
@@ -23,23 +22,28 @@ export const DateSelector = ({
2322
}: DateSelectorProps) => {
2423
const [open, setOpen] = useState(false);
2524
const [focusedDate, setFocusedDate] = useState<Date | undefined>(selectedDate);
25+
const [selectedDateLocal, setSelectedDateLocal] = useState<Date | undefined>(selectedDate);
2626
const { trackButtonClick } = useGTMActions();
2727

28+
// selectedDate prop이 변경될 때 내부 상태 동기화
29+
useEffect(() => {
30+
setSelectedDateLocal(selectedDate);
31+
setFocusedDate(selectedDate);
32+
}, [selectedDate]);
33+
2834
const formatDate = (date: Date) => {
2935
const year = date.getFullYear().toString().slice(-2);
3036
const month = String(date.getMonth() + 1).padStart(2, '0');
3137
const day = String(date.getDate()).padStart(2, '0');
3238
return `${year}-${month}-${day}`;
3339
};
3440

35-
const handleDateSelect = (date: Date) => {
36-
onDateSelect(date);
37-
setOpen(false);
38-
};
39-
4041
const handleOpenChange = (newOpen: boolean) => {
4142
setOpen(newOpen);
4243
if (newOpen) {
44+
// Sheet가 열릴 때 selectedDate를 초기값으로 설정
45+
setSelectedDateLocal(selectedDate);
46+
setFocusedDate(selectedDate || new Date());
4347
trackButtonClick({
4448
eventName: GTM_EVENTS.SHEET_OPEN,
4549
buttonName: GTM_BUTTON_NAME.DATE_SELECTOR_SHEET,
@@ -52,6 +56,13 @@ export const DateSelector = ({
5256
}
5357
};
5458

59+
const handleComplete = () => {
60+
if (selectedDateLocal) {
61+
onDateSelect(selectedDateLocal);
62+
}
63+
setOpen(false);
64+
};
65+
5566
return (
5667
<Sheet open={open} onOpenChange={handleOpenChange}>
5768
<SheetTrigger asChild>
@@ -71,20 +82,31 @@ export const DateSelector = ({
7182
</button>
7283
</div> */}
7384
<div className="flex-1 p-4 space-y-4">
74-
<div className="flex justify-end text-label-normal">
75-
<button type="button" onClick={() => handleOpenChange(false)}>
76-
<XIcon className="w-5 h-5" />
85+
<div className="flex justify-between text-label-normal">
86+
<button
87+
type="button"
88+
onClick={() => handleOpenChange(false)}
89+
className="label-1-normal font-bold text-status-negative"
90+
>
91+
취소
92+
</button>
93+
<button
94+
type="button"
95+
onClick={handleComplete}
96+
disabled={!selectedDateLocal}
97+
className="label-1-normal font-bold"
98+
>
99+
완료
77100
</button>
78101
</div>
79102
<DateSelectorPanel
80-
selectedDate={selectedDate}
103+
selectedDate={selectedDateLocal}
81104
focusedDate={focusedDate || new Date()}
82105
isStartDate={false}
83106
minDate={minDate}
84107
maxDate={maxDate}
85-
onDateSelect={handleDateSelect}
108+
onDateSelect={setSelectedDateLocal}
86109
onFocusedDateChange={setFocusedDate}
87-
onClose={() => handleOpenChange(false)}
88110
/>
89111
</div>
90112
</SheetContent>

src/feature/todo/weeklyTodoList/components/DateSelectorPanel.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,11 @@ interface DateSelectorPanelProps {
1212
maxDate?: Date; // 최대 선택 가능 날짜
1313
onDateSelect: (date: Date) => void;
1414
onFocusedDateChange: (date: Date) => void;
15-
onClose: () => void;
1615
}
1716

1817
const DateSelectorPanel = React.forwardRef<HTMLDivElement, DateSelectorPanelProps>(
1918
(
20-
{
21-
selectedDate,
22-
focusedDate,
23-
isStartDate,
24-
allowedDaysOfWeek,
25-
minDate,
26-
maxDate,
27-
onDateSelect,
28-
onFocusedDateChange,
29-
onClose,
30-
},
19+
{ selectedDate, focusedDate, isStartDate, allowedDaysOfWeek, minDate, maxDate, onDateSelect, onFocusedDateChange },
3120
ref
3221
) => {
3322
const [currentMonth, setCurrentMonth] = useState(focusedDate);
@@ -290,7 +279,7 @@ const DateSelectorPanel = React.forwardRef<HTMLDivElement, DateSelectorPanelProp
290279
relative w-10 h-10 flex items-center justify-center label-1-regular rounded-full transition-colors
291280
${!isSelectable ? 'pointer-events-none text-label-assistive opacity-50' : ''}
292281
${isStartDate && day.getDay() !== 0 && 'pointer-events-none text-label-assistive'}
293-
${isSelected ? 'bg-[var(--color-brand-neon)] text-black' : ''}
282+
${isSelected ? 'bg-[var(--color-brand-neon)]' : ''}
294283
${isFocused && !isSelected ? 'bg-gray-700 text-primary-normal' : ''}
295284
${!isInCurrentMonth ? 'text-gray-500' : ''}
296285
${isToday && !isSelected ? 'bg-gray-600' : ''}

0 commit comments

Comments
 (0)