diff --git a/app/baby/page.tsx b/app/baby/page.tsx index 3c24e6c..f78b72c 100644 --- a/app/baby/page.tsx +++ b/app/baby/page.tsx @@ -12,42 +12,36 @@ import { } from "../auth/index" import { getEmotionColor, - fetchEmotionType, - EmotionTypeData + fetchEmotionType } from "../utils/emotionUtils" import Calendar from "../components/Calendar" -import HeaderBar from "../components/HeaderBar" - -// 감정 타입 인터페이스 (공통 유틸리티 사용) -type EmotionType = EmotionTypeData; - -// 시간대별 일기 데이터 구조 (타입 정의만 유지) -interface DiaryData { - morning?: { - predictedEmotions: Array<{emotion: string, category: string, color: string}>; - predictedText: string; - actualEmotions: Array<{emotion: string, category: string, color: string}>; - actualText: string; - }; - afternoon?: { - predictedEmotions: Array<{emotion: string, category: string, color: string}>; - predictedText: string; - actualEmotions: Array<{emotion: string, category: string, color: string}>; - actualText: string; - }; - evening?: { - predictedEmotions: Array<{emotion: string, category: string, color: string}>; - predictedText: string; - actualEmotions: Array<{emotion: string, category: string, color: string}>; - actualText: string; - }; -} +import PageHeader from "../components/PageHeader" +import { + DiaryData, + DiaryTimeData, + TimeSlot, + TIME_PERIODS +} from "../types/common" +import { + formatDate, + isToday, + isPastDate, + isCurrentMonth, + generateCalendarDays +} from "../utils/dateUtils" +import LoadingSpinner from "../components/LoadingSpinner" +import ErrorMessage from "../components/ErrorMessage" +import EmptyState from "../components/EmptyState" +import TimeSlotSelector from "../components/TimeSlotSelector" +import DiaryCard from "../components/DiaryCard" + +// 공통 타입 사용 export default function Present() { const router = useRouter() const { selectedChild, isLoading } = useChild() const [selectedDate, setSelectedDate] = useState(null) - const [selectedTimeSlot, setSelectedTimeSlot] = useState<'morning' | 'afternoon' | 'evening'>('morning') + const [selectedTimeSlot, setSelectedTimeSlot] = useState('morning') const [currentMonth, setCurrentMonth] = useState(new Date()) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) @@ -55,32 +49,12 @@ export default function Present() { - const formatDate = (date: Date) => { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); - return `${year}-${month}-${day}`; - }; - - const isToday = (date: Date) => { - const today = new Date(); - return date.toDateString() === today.toDateString(); - }; - const isTomorrow = (date: Date) => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); return date.toDateString() === tomorrow.toDateString(); }; - const isPastDate = (date: Date) => { - const today = new Date(); - today.setHours(0, 0, 0, 0); - const compareDate = new Date(date); - compareDate.setHours(0, 0, 0, 0); - return compareDate < today; - }; - const isMoreThanTwoDaysLater = (date: Date) => { const today = new Date(); today.setHours(0, 0, 0, 0); @@ -94,10 +68,6 @@ export default function Present() { return compareDate >= twoDaysLater; }; - const isCurrentMonth = (date: Date) => { - return date.getMonth() === currentMonth.getMonth(); - }; - const hasDiary = (date: Date) => { const dateStr = formatDate(date); const diaryData = forecastData[dateStr]; @@ -259,7 +229,7 @@ export default function Present() { }; }; - // 현재 달의 과거 날짜들에 대한 데이터 미리 로드 + // 현재 달의 과거 날짜들과 오늘 날짜에 대한 데이터 미리 로드 useEffect(() => { if (selectedChild?.id && !isLoading) { const today = new Date(); @@ -269,7 +239,7 @@ export default function Present() { const lastDay = new Date(year, month + 1, 0); for (let date = new Date(firstDay); date <= lastDay; date.setDate(date.getDate() + 1)) { - if (isPastDate(date)) { + if (isPastDate(date) || isToday(date)) { const dateStr = formatDate(date); if (!forecastData[dateStr]) { loadForecastData(dateStr); @@ -293,14 +263,7 @@ export default function Present() {
{/* 상단바 */} -
- -
+ {/* 달력 컴포넌트 */} (null); const dobRef = useRef(null); const healthStatusRef = useRef(null); - const nameAdvanceTimeout = useRef(null); useEffect(() => { const fetchChildData = async () => { @@ -95,24 +92,6 @@ function EditChildPageContent() { fetchChildData(); }, [childId]); - useEffect(() => { - switch (currentDisplayStep) { - case 1: - nameRef.current?.focus(); - break; - case 2: - dobRef.current?.focus(); - break; - case 3: - break; - case 4: - healthStatusRef.current?.focus(); - break; - default: - break; - } - }, [currentDisplayStep]); - const showToast = (message: string, type: 'success' | 'error') => { setToast({ message, @@ -125,14 +104,6 @@ function EditChildPageContent() { setToast(prev => ({ ...prev, isVisible: false })); }; - const advanceStep = () => { - if (currentDisplayStep < 4) { - setCurrentDisplayStep(prevStep => prevStep + 1); - } else { - handleSave(); - } - }; - const handleSave = async () => { if (!childId) return; @@ -162,6 +133,7 @@ function EditChildPageContent() { } showToast('아이 정보가 성공적으로 수정되었습니다!', 'success'); + setIsSaving(false); // 성공 후 잠시 대기 후 페이지 이동 setTimeout(() => { @@ -170,40 +142,16 @@ function EditChildPageContent() { } catch (error) { console.error("수정 실패:", error); showToast('아이 정보 수정에 실패했습니다. 다시 시도해주세요.', 'error'); - } finally { setIsSaving(false); } }; - const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.key === 'Enter') { - event.preventDefault(); - - if (currentDisplayStep === 1 && name.trim() === '') return; - if (currentDisplayStep === 2 && dob.trim() === '') return; - if (currentDisplayStep === 4 && healthStatus.trim() === '') return; - - advanceStep(); - } - }; - const handleGenderSelect = (selectedGender: string) => { setGender(selectedGender); - advanceStep(); }; const handleBack = () => { - if (currentDisplayStep === 1) { - router.push('/childList'); - } else { - setCurrentDisplayStep(prev => Math.max(1, prev - 1)); - } - }; - - const fadeInOutVariants = { - hidden: { opacity: 0, y: 10 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.5 } }, - exit: { opacity: 0, y: -10, transition: { duration: 0.3 } }, + router.push('/childList'); }; if (isLoading) { @@ -281,181 +229,121 @@ function EditChildPageContent() {

아이의 정보를 수정해주세요

- - {currentDisplayStep >= 1 && ( - - -
- { - setName(e.target.value); - const koreanCharCount = e.target.value.match(/[\uAC00-\uD7A3]/g)?.length || 0; - if (nameAdvanceTimeout.current) { - clearTimeout(nameAdvanceTimeout.current); - } - if (currentDisplayStep === 1 && koreanCharCount === 3) { - nameAdvanceTimeout.current = setTimeout(() => { - advanceStep(); - }, 500); - } - }} - onKeyDown={handleKeyDown} - /> -
-
- )} -
- - - {currentDisplayStep >= 2 && ( - - -
- { - let value = e.target.value.replace(/[^0-9]/g, ''); - if (value.length > 8) value = value.slice(0, 8); - let formatted = value; - if (value.length > 4) { - formatted = value.slice(0, 4) + '-' + value.slice(4); - } - if (value.length > 6) { - formatted = value.slice(0, 4) + '-' + value.slice(4, 6) + '-' + value.slice(6); - } - setDob(formatted); - if (currentDisplayStep === 2 && value.length === 8) { - advanceStep(); - } - }} - onKeyDown={handleKeyDown} - /> -
-
- )} -
- - - {currentDisplayStep >= 3 && ( - - -
- - -
-
- )} -
- - - {currentDisplayStep >= 4 && ( - - -
- setHealthStatus(e.target.value)} - onKeyDown={handleKeyDown} - /> -
-
- )} -
- - {currentDisplayStep === 4 && ( - + +
+ { + setName(e.target.value); + }} + /> +
+ + +
+ +
+ { + let value = e.target.value.replace(/[^0-9]/g, ''); + if (value.length > 8) value = value.slice(0, 8); + let formatted = value; + if (value.length > 4) { + formatted = value.slice(0, 4) + '-' + value.slice(4); + } + if (value.length > 6) { + formatted = value.slice(0, 4) + '-' + value.slice(4, 6) + '-' + value.slice(6); + } + setDob(formatted); + }} + /> +
+
+ +
+ +
+ + +
+
+ +
+ +
+ setHealthStatus(e.target.value)} + onKeyDown={(e) => { + // 메모 단계에서는 엔터키 동작하지 않음 + if (e.key === 'Enter') { + e.preventDefault(); + } + }} + /> +
+

알레르기와 같은 참고해야할 사항이 있다면 적어주세요.

+
+ +
+ - - )} + {isSaving ? ( + <> +
+ 수정 중... + + ) : ( + '수정 완료' + )} + +
); @@ -463,11 +351,17 @@ function EditChildPageContent() { export default function EditChildPage() { return ( -
-
-
-

로딩 중...

-
-
+ +
+
+
+

페이지를 불러오는 중...

+
+
+ + }> + +
); } \ No newline at end of file diff --git a/app/childList/page.tsx b/app/childList/page.tsx index 720830d..9ce1fde 100644 --- a/app/childList/page.tsx +++ b/app/childList/page.tsx @@ -4,6 +4,7 @@ import { useState, useEffect } from "react" import { useRouter } from "next/navigation" import Container from "../components/Container" import NavigationBar from "../components/NavigationBar" +import PageHeader from "../components/PageHeader" import Toast from "../components/Toast" import { useChild } from "../contexts/ChildContext" @@ -210,9 +211,7 @@ export default function ChildListPage() { setToast(prev => ({ ...prev, isVisible: false })); }; - const handleBack = () => { - window.history.back() - } + const handleChildClick = (childId: number) => { console.log('Child clicked:', childId) @@ -329,13 +328,6 @@ export default function ChildListPage() { if (isLoading) { return ( -
- -
@@ -351,13 +343,6 @@ export default function ChildListPage() { if (error) { return ( -
- -
@@ -389,17 +374,13 @@ export default function ChildListPage() { onClose={hideToast} /> -
- -
+
+ {/* 상단바 */} + +
- 아이 관리

등록된 아이 목록

총 {childrenData.length}명의 아이가 등록되어 있습니다. diff --git a/app/components/Calendar.tsx b/app/components/Calendar.tsx index 581f95d..99dff2a 100644 --- a/app/components/Calendar.tsx +++ b/app/components/Calendar.tsx @@ -8,7 +8,7 @@ interface CalendarProps { hasDiary: (date: Date) => boolean; isToday: (date: Date) => boolean; isPastDate: (date: Date) => boolean; - isCurrentMonth: (date: Date) => boolean; + isCurrentMonth: (date: Date, currentMonth: Date) => boolean; formatDate: (date: Date) => string; readOnly?: boolean; // 읽기 전용 모드 (home 페이지용) showEmptyIcon?: boolean; // 빈 상태 아이콘 표시 여부 @@ -106,7 +106,7 @@ export default function Calendar({ disabled={!isClickable} className={` relative h-10 text-sm rounded-lg transition-colors - ${isCurrentMonth(date) ? 'text-gray-900' : 'text-gray-300'} + ${isCurrentMonth(date, currentMonth) ? 'text-gray-900' : 'text-gray-300'} ${isToday(date) ? 'bg-blue-100 text-blue-600 font-semibold' : ''} ${selectedDate === formatDate(date) ? 'bg-[#FF6F71] text-white' : ''} ${isClickable ? 'hover:bg-gray-100 cursor-pointer' : 'cursor-not-allowed opacity-50'} diff --git a/app/components/Container.tsx b/app/components/Container.tsx index 7e69c2f..f56d636 100644 --- a/app/components/Container.tsx +++ b/app/components/Container.tsx @@ -8,7 +8,7 @@ interface ContainerProps { export default function Container({ children, className = "" }: ContainerProps) { return (

-
+
{children}
diff --git a/app/components/DiaryCard.tsx b/app/components/DiaryCard.tsx new file mode 100644 index 0000000..24a2808 --- /dev/null +++ b/app/components/DiaryCard.tsx @@ -0,0 +1,40 @@ +'use client' + +import React from 'react'; +import { DiaryTimeData } from '../types/common'; + +interface DiaryCardProps { + title: string; + data: DiaryTimeData; + type: 'forecast' | 'record'; // 예보인지 기록인지 구분 + className?: string; +} + +export default function DiaryCard({ title, data, type, className = "" }: DiaryCardProps) { + const emotions = type === 'forecast' ? data.predictedEmotions : data.actualEmotions; + const text = type === 'forecast' ? data.predictedText : data.actualText; + const defaultEmotionText = type === 'forecast' ? '예상 감정' : '실제 감정'; + const defaultText = type === 'forecast' ? '예보 메모가 없습니다.' : '실제 기록이 없습니다.'; + + return ( +
+
+ {title} + + {emotions?.map((e, index) => ( + + {e.emotion} + + )) || defaultEmotionText} + +
+

+ {text || defaultText} +

+
+ ); +} \ No newline at end of file diff --git a/app/components/EmotionSelector.tsx b/app/components/EmotionSelector.tsx new file mode 100644 index 0000000..52367d8 --- /dev/null +++ b/app/components/EmotionSelector.tsx @@ -0,0 +1,144 @@ +'use client' + +import React, { useState, useEffect } from 'react'; +import { motion } from 'framer-motion'; +import { EmotionType, CATEGORY_COLORS } from '../types/common'; + +interface EmotionSelectorProps { + onEmotionSelect: (emotion: EmotionType, category: string) => void; + selectedEmotion?: EmotionType | null; + className?: string; +} + +export default function EmotionSelector({ + onEmotionSelect, + selectedEmotion, + className = "" +}: EmotionSelectorProps) { + const [emotions, setEmotions] = useState([]); + const [emotionCategories, setEmotionCategories] = useState<{[key: string]: EmotionType[]}>({}); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + // 감정 목록 조회 + const fetchEmotions = async () => { + try { + setIsLoading(true); + const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL; + const response = await fetch(`${apiBaseUrl}/api/emotionTypes/emotionType`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + }); + + if (!response.ok) { + throw new Error('감정 목록 조회에 실패했습니다.'); + } + + const emotionData: EmotionType[] = await response.json(); + setEmotions(emotionData); + + // 감정을 타입별로 그룹화 + const grouped = emotionData.reduce((acc, emotion) => { + if (!acc[emotion.type]) { + acc[emotion.type] = []; + } + acc[emotion.type].push(emotion); + return acc; + }, {} as {[key: string]: EmotionType[]}); + + setEmotionCategories(grouped); + } catch (error) { + console.error('감정 목록 조회 실패:', error); + setError('감정 목록을 불러오는데 실패했습니다.'); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + fetchEmotions(); + }, []); + + const handleEmotionClick = (category: string, emotion: EmotionType) => { + onEmotionSelect(emotion, category); + }; + + const fadeInOutVariants = { + hidden: { opacity: 0, y: 10 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.5 } }, + exit: { opacity: 0, y: -10, transition: { duration: 0.3 } }, + }; + + if (isLoading) { + return ( +
+
+

감정 목록을 불러오는 중...

+
+ ); + } + + if (error) { + return ( +
+

{error}

+ +
+ ); + } + + return ( +
+ {Object.entries(emotionCategories).map(([category, categoryEmotions]) => ( + +
{category}
+
+ {categoryEmotions.map((emotion) => { + const isSelected = selectedEmotion?.id === emotion.id; + const categoryColor = CATEGORY_COLORS[category as keyof typeof CATEGORY_COLORS]; + + return ( + handleEmotionClick(category, emotion)} + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + > + {emotion.name} + + ); + })} +
+
+ ))} +
+ ); +} \ No newline at end of file diff --git a/app/components/EmptyState.tsx b/app/components/EmptyState.tsx new file mode 100644 index 0000000..2b4ce62 --- /dev/null +++ b/app/components/EmptyState.tsx @@ -0,0 +1,32 @@ +'use client' + +import React from 'react'; + +interface EmptyStateProps { + message: string; + icon?: React.ReactNode; + className?: string; +} + +export default function EmptyState({ + message, + icon, + className = "" +}: EmptyStateProps) { + const defaultIcon = ( + + + + ); + + return ( +
+
+ {icon || defaultIcon} +
+

+ {message} +

+
+ ); +} \ No newline at end of file diff --git a/app/components/ErrorMessage.tsx b/app/components/ErrorMessage.tsx new file mode 100644 index 0000000..a033e51 --- /dev/null +++ b/app/components/ErrorMessage.tsx @@ -0,0 +1,36 @@ +'use client' + +import React from 'react'; + +interface ErrorMessageProps { + message: string; + onRetry?: () => void; + retryText?: string; + className?: string; +} + +export default function ErrorMessage({ + message, + onRetry, + retryText = "다시 시도", + className = "" +}: ErrorMessageProps) { + return ( +
+
+ + + +
+

{message}

+ {onRetry && ( + + )} +
+ ); +} \ No newline at end of file diff --git a/app/components/HeaderBar.tsx b/app/components/HeaderBar.tsx index 68163b7..26b891a 100644 --- a/app/components/HeaderBar.tsx +++ b/app/components/HeaderBar.tsx @@ -34,13 +34,14 @@ export default function HeaderBar({ if (onSettingsClick) { onSettingsClick(); } else { - router.push('/settings'); + const currentPath = window.location.pathname; + router.push(`/settings?from=${encodeURIComponent(currentPath)}`); } }; return ( -
-
+
+
{childName} {inviteCode && ( @@ -50,7 +51,7 @@ export default function HeaderBar({ {showChildListButton && ( + ))} +
+
+ ); +} \ No newline at end of file diff --git a/app/components/Toast.tsx b/app/components/Toast.tsx index e80f1dc..03a29ab 100644 --- a/app/components/Toast.tsx +++ b/app/components/Toast.tsx @@ -25,30 +25,30 @@ export default function Toast({ message, type, isVisible, onClose }: ToastProps) const iconColor = type === 'success' ? 'bg-green-400' : type === 'error' ? 'bg-red-400' : 'bg-yellow-400'; return ( -
-
+
{type === 'success' ? ( - + ) : type === 'error' ? ( - + ) : ( - + )}
- {message} + {message} - ))} -
-
+ )} {selectedDate && (isPastDate(new Date(selectedDate)) || isToday(new Date(selectedDate))) && ( @@ -517,32 +439,15 @@ export default function Register() { {/* 로딩 상태 */} {loading && ( -
-
- - - -
-

일기 데이터를 불러오는 중...

-
+ )} {/* 에러 상태 */} {error && ( -
-
- - - -
-

{error}

- -
+ selectedDate && loadDiaryData(selectedDate)} + /> )} {/* 데이터 표시 */} @@ -550,7 +455,7 @@ export default function Register() { <> {/* 선택된 시간대 일기 */}
- {timeSlots.find(t => t.key === selectedTimeSlot)?.label} 기록 + {TIME_PERIODS[selectedTimeSlot].label} 기록
{(() => { @@ -567,46 +472,18 @@ export default function Register() { return (
{/* 예보 섹션 */} -
-
- 예보 - - {timeData.predictedEmotions?.map((e: any) => ( - - {e.emotion} - - )) || '예상 감정'} - -
-

- {timeData.predictedText || '예보 메모가 없습니다.'} -

-
+ {/* 예보 기록 섹션 */} -
-
- 예보 기록 - - {timeData.actualEmotions?.map((e: any) => ( - - {e.emotion} - - )) || '실제 감정'} - -
-

- {timeData.actualText || '실제 기록이 없습니다.'} -

-
+
); })()} @@ -615,16 +492,7 @@ export default function Register() { {/* 데이터가 없는 경우 */} {!loading && !error && (!selectedDiary || !selectedDiary[selectedTimeSlot]) && selectedDate && ( -
-
- - - -
-

- 해당 시간대의 예보가 없습니다. -

-
+ )}
)} diff --git a/app/insert-after/page.tsx b/app/insert-after/page.tsx index 6223a36..fe1128a 100644 --- a/app/insert-after/page.tsx +++ b/app/insert-after/page.tsx @@ -1,110 +1,35 @@ 'use client' import React, { useState, useEffect, Suspense } from "react"; -import { motion } from "framer-motion"; import { useRouter, useSearchParams } from "next/navigation"; import Button from "../components/Button"; import { useChild } from "../contexts/ChildContext"; - -const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL; - -// 감정 타입 정의 -interface EmotionType { - id: number; - name: string; - type: string; - temp: number; - image: string; -} - -const CATEGORY_COLORS = { - 긍정: '#3DC8EF', - 중립: '#FFD340', - 부정: '#FF7B6F' -}; - -const TIME_PERIODS = { - morning: { label: '아침', text: '아침에는 어떤 감정을' }, - afternoon: { label: '점심', text: '점심에는 어떤 감정을' }, - evening: { label: '저녁', text: '저녁에는 어떤 감정을' } -}; +import { EmotionType, TIME_PERIODS, TimeSlot } from "../types/common"; +import { getCurrentDate } from "../utils/dateUtils"; +import EmotionSelector from "../components/EmotionSelector"; function InsertAfterPageContent() { const { selectedChild } = useChild(); - const [emotions, setEmotions] = useState([]); - const [emotionCategories, setEmotionCategories] = useState<{[key: string]: EmotionType[]}>({}); - const [selectedEmotion, setSelectedEmotion] = useState<{ - emotion: EmotionType; - categoryIdx: number; - emotionIdx: number; - } | null>(null); - const [currentStep, setCurrentStep] = useState<'morning' | 'afternoon' | 'evening'>('morning'); + const [selectedEmotion, setSelectedEmotion] = useState(null); + const [selectedCategory, setSelectedCategory] = useState(''); + const [currentStep, setCurrentStep] = useState('morning'); const [isLoading, setIsLoading] = useState(false); - const [isLoadingEmotions, setIsLoadingEmotions] = useState(true); - const [error, setError] = useState(null); const [savedSteps, setSavedSteps] = useState>(new Set()); + const router = useRouter(); const searchParams = useSearchParams(); const forecastId = searchParams.get('forecastId'); - // 감정 목록 조회 - const fetchEmotions = async () => { - try { - setIsLoadingEmotions(true); - const response = await fetch(`${apiBaseUrl}/api/emotionTypes/emotionType`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'include', - }); - - if (!response.ok) { - throw new Error('감정 목록 조회에 실패했습니다.'); - } - - const emotionData: EmotionType[] = await response.json(); - setEmotions(emotionData); - - // 감정을 타입별로 그룹화 - const grouped = emotionData.reduce((acc, emotion) => { - if (!acc[emotion.type]) { - acc[emotion.type] = []; - } - acc[emotion.type].push(emotion); - return acc; - }, {} as {[key: string]: EmotionType[]}); - - setEmotionCategories(grouped); - } catch (error) { - console.error('감정 목록 조회 실패:', error); - setError('감정 목록을 불러오는데 실패했습니다.'); - } finally { - setIsLoadingEmotions(false); - } - }; - - useEffect(() => { - fetchEmotions(); - }, []); - useEffect(() => { - const step = searchParams.get('step') as 'morning' | 'afternoon' | 'evening'; + const step = searchParams.get('step') as TimeSlot; if (step && ['morning', 'afternoon', 'evening'].includes(step)) { setCurrentStep(step); } }, [searchParams]); - const handleEmotionClick = (categoryIdx: number, emotionIdx: number) => { - const categories = Object.entries(emotionCategories); - const [categoryName, categoryEmotions] = categories[categoryIdx]; - const emotion = categoryEmotions[emotionIdx]; - - setSelectedEmotion({ - emotion, - categoryIdx, - emotionIdx - }); + const handleEmotionSelect = (emotion: EmotionType, category: string) => { + setSelectedEmotion(emotion); + setSelectedCategory(category); }; const handleBack = () => { @@ -117,8 +42,8 @@ function InsertAfterPageContent() { // 현재 선택된 감정을 localStorage에 저장 const currentEmotionData = { step: currentStep, - emotion: selectedEmotion.emotion, - category: Object.keys(emotionCategories)[selectedEmotion.categoryIdx] + emotion: selectedEmotion, + category: selectedCategory }; // 기존 데이터 가져오기 @@ -143,38 +68,17 @@ function InsertAfterPageContent() { const isEmotionSelected = selectedEmotion !== null; - // 현재 날짜 포맷팅 - const getCurrentDate = () => { - const today = new Date(); - const year = today.getFullYear(); - const month = String(today.getMonth() + 1).padStart(2, '0'); - const day = String(today.getDate()).padStart(2, '0'); - return `${year}-${month}-${day}`; - }; - - const fadeInOutVariants = { - hidden: { opacity: 0, y: 10 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.5 } }, - exit: { opacity: 0, y: -10, transition: { duration: 0.3 } }, - }; - - if (isLoadingEmotions) { - return ( -
-
-
-
-

감정 목록을 불러오는 중...

-
-
-
- ); - } - return (
+ {/* 로고 */} +
+
+ HeartForecast +
+
+
- {error && ( -
- {error} -
- )} - -
- {Object.entries(emotionCategories).map(([category, categoryEmotions], categoryIdx) => ( -
-
{category}
-
- {categoryEmotions.map((emotion, emotionIdx) => { - const isSelected = selectedEmotion && - selectedEmotion.categoryIdx === categoryIdx && - selectedEmotion.emotionIdx === emotionIdx; - const categoryColor = CATEGORY_COLORS[category as keyof typeof CATEGORY_COLORS]; - - return ( - handleEmotionClick(categoryIdx, emotionIdx)} - disabled={isLoading} - > - {emotion.name} - - ); - })} -
-
- ))} + + +
+
- - -
); } -export default function InsertPage() { +export default function InsertAfterPage() { return ( - -
-
-
-

로딩 중...

-
-
-
- }> + Loading...
}> ); diff --git a/app/insert-after/reason/page.tsx b/app/insert-after/reason/page.tsx index 2bcdf30..4bf9885 100644 --- a/app/insert-after/reason/page.tsx +++ b/app/insert-after/reason/page.tsx @@ -79,7 +79,6 @@ function ReasonPageContent() { }; const handleNext = async () => { - if (reason.trim().length === 0) return; if (!currentEmotion || !selectedChild?.id || !forecastId) { setError('필수 정보가 누락되었습니다.'); return; @@ -167,7 +166,7 @@ function ReasonPageContent() { } }; - const isComplete = reason.trim().length > 0; + const isComplete = true; // 메모는 선택사항이므로 항상 true const fadeInOutVariants = { hidden: { opacity: 0, y: 10 }, @@ -200,70 +199,71 @@ function ReasonPageContent() { return (
-
-
- -
- -
-
- {searchParams.get('date') || new Date().toISOString().split('T')[0]} {TIME_PERIODS[currentStep].label} -
-
- {TIME_PERIODS[currentStep].text}{`\n`}느꼈나요? +
+
+
+
- {error && ( -
- {error} +
+
+ {searchParams.get('date') || new Date().toISOString().split('T')[0]} {TIME_PERIODS[currentStep].label}
- )} - -
-
-