From 579879c92fd5b4f19f4e7bdc87886b69ba1f9b42 Mon Sep 17 00:00:00 2001 From: GSB0203 Date: Wed, 16 Jul 2025 19:15:27 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor=20::=20=EC=95=84=EC=9D=B4=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=9D=B4=EB=8F=99=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/NavigationBar.tsx | 2 +- app/stats/page.tsx | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/components/NavigationBar.tsx b/app/components/NavigationBar.tsx index 7dcf664..8d67f4f 100644 --- a/app/components/NavigationBar.tsx +++ b/app/components/NavigationBar.tsx @@ -33,7 +33,7 @@ export default function NavigationBar({ activeTab = "홈", onTabChange }: Naviga ) }, { - id: "아이목록", + id: "아이 목록", label: "아이 목록", path: "/settings", icon: ( diff --git a/app/stats/page.tsx b/app/stats/page.tsx index 002b258..dcba5cc 100644 --- a/app/stats/page.tsx +++ b/app/stats/page.tsx @@ -163,6 +163,31 @@ export default function StatsPage() { return null; } + // 선택된 아이가 없을 때 + if (!selectedChild) { + return ( + +
+
+ + + +
+

선택된 아이가 없습니다

+

+ 아이 목록에서 아이를 선택해주세요 +

+ +
+
+ ); + } + // 감정 예측 정확도 반원형 게이지 차트 데이터 const accuracyChartData = { labels: ['정확도'], From 1028e65576417ebe87ad5c8e4860ba901dd2310f Mon Sep 17 00:00:00 2001 From: GSB0203 Date: Wed, 16 Jul 2025 19:20:54 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat=20::=20=EB=93=B1=EB=A1=9D=EB=90=9C=20?= =?UTF-8?q?=EC=B2=AB=20=EB=B2=88=EC=A7=B8=20=EC=95=84=EC=9D=B4=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=84=A0=ED=83=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/contexts/ChildContext.tsx | 45 ++++++++++++++++++++++++++++++++++- app/home/page.tsx | 11 +++++++-- app/stats/page.tsx | 11 +++++++-- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/app/contexts/ChildContext.tsx b/app/contexts/ChildContext.tsx index 603290f..5f5c64f 100644 --- a/app/contexts/ChildContext.tsx +++ b/app/contexts/ChildContext.tsx @@ -16,6 +16,7 @@ interface ChildContextType { setSelectedChild: (child: ChildData | null) => void; enterChildMode: (child: ChildData) => void; exitChildMode: () => void; + autoSelectFirstChild: () => Promise; } const ChildContext = createContext(undefined); @@ -83,6 +84,47 @@ export function ChildProvider({ children }: { children: React.ReactNode }) { } }; + const autoSelectFirstChild = async () => { + try { + const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL; + const response = await fetch(`${apiBaseUrl}/api/childRelations`, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + if (data && data.length > 0) { + const firstChild = data[0]; + const birthYear = new Date(firstChild.birthdate).getFullYear(); + const thisYear = new Date().getFullYear(); + const age = thisYear - birthYear; + + const childData: ChildData = { + id: firstChild.id, + name: firstChild.username, + age, + registeredDate: new Date(firstChild.createdAt).toLocaleDateString('ko-KR') + }; + + setSelectedChild(childData); + if (typeof window !== 'undefined') { + localStorage.setItem('selectedChild', JSON.stringify(childData)); + } + } + } catch (error) { + console.error('자동 아이 선택 실패:', error); + } + }; + return ( {children} diff --git a/app/home/page.tsx b/app/home/page.tsx index 363f16d..2ade603 100644 --- a/app/home/page.tsx +++ b/app/home/page.tsx @@ -33,7 +33,7 @@ interface DiaryData { export default function Register() { const router = useRouter() - const { isChildMode, selectedChild, isLoading, exitChildMode, enterChildMode } = useChild(); + const { isChildMode, selectedChild, isLoading, exitChildMode, enterChildMode, autoSelectFirstChild } = useChild(); const [childName, setChildName] = useState('') const [activeTab, setActiveTab] = useState('홈') const [selectedDate, setSelectedDate] = useState(null) @@ -210,6 +210,13 @@ export default function Register() { } }, [selectedChild?.name]); + // 선택된 아이가 없을 때 자동 선택 시도 + useEffect(() => { + if (!isLoading && !selectedChild) { + autoSelectFirstChild(); + } + }, [isLoading, selectedChild, autoSelectFirstChild]); + // 아이 모드 전환 함수 const handleEnterChildMode = () => { if (selectedChild) { @@ -244,7 +251,7 @@ export default function Register() { ); } - // 선택된 아이가 없을 때 + // 선택된 아이가 없을 때 (자동 선택 후에도 없으면) if (!selectedChild) { return ( diff --git a/app/stats/page.tsx b/app/stats/page.tsx index dcba5cc..e81009d 100644 --- a/app/stats/page.tsx +++ b/app/stats/page.tsx @@ -57,7 +57,7 @@ const EMOTION_COLORS = { export default function StatsPage() { const router = useRouter() - const { isChildMode, selectedChild } = useChild(); + const { isChildMode, selectedChild, autoSelectFirstChild } = useChild(); const [childName, setChildName] = useState('신희성') const [activeTab, setActiveTab] = useState('통계') const [statsUnit, setStatsUnit] = useState<'week' | 'month'>('week') @@ -148,6 +148,13 @@ export default function StatsPage() { } }, [selectedChild?.id, statsUnit]) + // 선택된 아이가 없을 때 자동 선택 시도 + useEffect(() => { + if (!selectedChild) { + autoSelectFirstChild(); + } + }, [selectedChild, autoSelectFirstChild]); + // 계산된 데이터 const currentAccuracyData = dailyTemperatureData.map(d => d.avgTemp) const latestAccuracy = currentAccuracyData.length > 0 ? currentAccuracyData[currentAccuracyData.length - 1] : 0 @@ -163,7 +170,7 @@ export default function StatsPage() { return null; } - // 선택된 아이가 없을 때 + // 선택된 아이가 없을 때 (자동 선택 후에도 없으면) if (!selectedChild) { return ( From 406a66809582690b03abdd2abff47041193b593c Mon Sep 17 00:00:00 2001 From: GSB0203 Date: Wed, 16 Jul 2025 19:54:02 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat=20::=20=EC=95=84=EC=9D=B4=EA=B0=80=20?= =?UTF-8?q?=ED=95=9C=20=EB=AA=85=EB=8F=84=20=EC=A1=B4=EC=9E=AC=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=84=20=EA=B2=BD=EC=9A=B0=EC=9D=98=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/NavigationBar.tsx | 5 ++- app/contexts/ChildContext.tsx | 37 +++++++++++++++++- app/home/page.tsx | 65 +++++++++++++++++++------------- app/settings/page.tsx | 50 ++++++++++++++++++------ app/stats/page.tsx | 65 +++++++++++++++++++------------- 5 files changed, 156 insertions(+), 66 deletions(-) diff --git a/app/components/NavigationBar.tsx b/app/components/NavigationBar.tsx index 8d67f4f..08fd830 100644 --- a/app/components/NavigationBar.tsx +++ b/app/components/NavigationBar.tsx @@ -2,14 +2,17 @@ import React from "react"; import { useRouter } from "next/navigation"; +import { useChild } from "../contexts/ChildContext"; interface NavigationBarProps { activeTab?: string; onTabChange?: (tab: string) => void; + showToast?: (message: string, type: 'success' | 'error' | 'warning') => void; } -export default function NavigationBar({ activeTab = "홈", onTabChange }: NavigationBarProps) { +export default function NavigationBar({ activeTab = "홈", onTabChange, showToast }: NavigationBarProps) { const router = useRouter(); + const { hasChildren } = useChild(); const tabs = [ { diff --git a/app/contexts/ChildContext.tsx b/app/contexts/ChildContext.tsx index 5f5c64f..baaf143 100644 --- a/app/contexts/ChildContext.tsx +++ b/app/contexts/ChildContext.tsx @@ -13,6 +13,7 @@ interface ChildContextType { selectedChild: ChildData | null; isChildMode: boolean; isLoading: boolean; + hasChildren: boolean; setSelectedChild: (child: ChildData | null) => void; enterChildMode: (child: ChildData) => void; exitChildMode: () => void; @@ -25,8 +26,9 @@ export function ChildProvider({ children }: { children: React.ReactNode }) { const [selectedChild, setSelectedChild] = useState(null); const [isChildMode, setIsChildMode] = useState(false); const [isLoading, setIsLoading] = useState(true); + const [hasChildren, setHasChildren] = useState(false); - // localStorage에서 상태 복원 + // localStorage에서 상태 복원 및 초기 hasChildren 확인 useEffect(() => { // 서버 사이드 렌더링 중에는 localStorage 접근하지 않음 if (typeof window === 'undefined') { @@ -54,6 +56,30 @@ export function ChildProvider({ children }: { children: React.ReactNode }) { } } + // 초기 hasChildren 상태 확인 + const checkHasChildren = async () => { + try { + const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL; + const response = await fetch(`${apiBaseUrl}/api/childRelations`, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }); + + if (response.ok) { + const data = await response.json(); + setHasChildren(data && data.length > 0); + } + } catch (error) { + console.error('hasChildren 확인 실패:', error); + setHasChildren(false); + } + }; + + checkHasChildren(); setIsLoading(false); // 안전장치: 3초 후에도 로딩이 끝나지 않으면 강제로 로딩 종료 @@ -103,6 +129,7 @@ export function ChildProvider({ children }: { children: React.ReactNode }) { const data = await response.json(); if (data && data.length > 0) { + setHasChildren(true); const firstChild = data[0]; const birthYear = new Date(firstChild.birthdate).getFullYear(); const thisYear = new Date().getFullYear(); @@ -119,9 +146,16 @@ export function ChildProvider({ children }: { children: React.ReactNode }) { if (typeof window !== 'undefined') { localStorage.setItem('selectedChild', JSON.stringify(childData)); } + } else { + setHasChildren(false); + // 아이가 없으면 아이 목록 페이지로 이동 + if (typeof window !== 'undefined') { + window.location.href = '/settings'; + } } } catch (error) { console.error('자동 아이 선택 실패:', error); + setHasChildren(false); } }; @@ -130,6 +164,7 @@ export function ChildProvider({ children }: { children: React.ReactNode }) { selectedChild, isChildMode, isLoading, + hasChildren, setSelectedChild, enterChildMode, exitChildMode, diff --git a/app/home/page.tsx b/app/home/page.tsx index 2ade603..5eb78de 100644 --- a/app/home/page.tsx +++ b/app/home/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 Toast from "../components/Toast" import { useChild } from "../contexts/ChildContext" import { getForecastsByDate, @@ -33,7 +34,7 @@ interface DiaryData { export default function Register() { const router = useRouter() - const { isChildMode, selectedChild, isLoading, exitChildMode, enterChildMode, autoSelectFirstChild } = useChild(); + const { isChildMode, selectedChild, isLoading, hasChildren, exitChildMode, enterChildMode, autoSelectFirstChild } = useChild(); const [childName, setChildName] = useState('') const [activeTab, setActiveTab] = useState('홈') const [selectedDate, setSelectedDate] = useState(null) @@ -42,6 +43,15 @@ export default function Register() { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [diaryData, setDiaryData] = useState>({}) + const [toast, setToast] = useState<{ + message: string; + type: 'success' | 'error' | 'warning'; + isVisible: boolean; + }>({ + message: '', + type: 'warning', + isVisible: false + }) const generateCalendarDays = () => { const year = currentMonth.getFullYear(); @@ -210,6 +220,19 @@ export default function Register() { } }, [selectedChild?.name]); + // 토스트 메시지 표시 함수 + const showToast = (message: string, type: 'success' | 'error' | 'warning') => { + setToast({ + message, + type, + isVisible: true + }); + }; + + const hideToast = () => { + setToast(prev => ({ ...prev, isVisible: false })); + }; + // 선택된 아이가 없을 때 자동 선택 시도 useEffect(() => { if (!isLoading && !selectedChild) { @@ -217,6 +240,13 @@ export default function Register() { } }, [isLoading, selectedChild, autoSelectFirstChild]); + // 아이가 없을 때 토스트 메시지 표시 + useEffect(() => { + if (!isLoading && !hasChildren && !selectedChild) { + showToast('이동할 수 없습니다. 아이를 생성하거나 연결해주세요.', 'warning'); + } + }, [isLoading, hasChildren, selectedChild]); + // 아이 모드 전환 함수 const handleEnterChildMode = () => { if (selectedChild) { @@ -251,33 +281,16 @@ export default function Register() { ); } - // 선택된 아이가 없을 때 (자동 선택 후에도 없으면) - if (!selectedChild) { - return ( - -
-
- - - -
-

선택된 아이가 없습니다

-

- 아이 목록에서 아이를 선택해주세요 -

- -
-
- ); - } + return ( +
{displayChildName} @@ -487,7 +500,7 @@ export default function Register() { )}
{/* 네비게이션바는 보호자 모드에서만 노출 */} - {!isChildMode && } + {!isChildMode && } ) } \ No newline at end of file diff --git a/app/settings/page.tsx b/app/settings/page.tsx index a43814d..77e206d 100644 --- a/app/settings/page.tsx +++ b/app/settings/page.tsx @@ -167,7 +167,7 @@ function DeleteModal({ isOpen, childId, childName, onClose, onDeleteRelation, on export default function SettingsPage() { const router = useRouter() - const { setSelectedChild, isChildMode } = useChild(); + const { selectedChild, setSelectedChild, isChildMode, autoSelectFirstChild } = useChild(); const [activeTab, setActiveTab] = useState('아이 목록') const [openMenuId, setOpenMenuId] = useState(null) const [childrenData, setChildrenData] = useState([]) @@ -241,10 +241,10 @@ export default function SettingsPage() { fetchChildRelations() }, []) - const showToast = (message: string, type: 'success' | 'error') => { + const showToast = (message: string, type: 'success' | 'error' | 'warning') => { setToast({ message, - type, + type: type === 'warning' ? 'error' : type, isVisible: true }); }; @@ -291,8 +291,21 @@ export default function SettingsPage() { throw new Error(`관계 삭제 실패: ${response.status}`) } + // 삭제된 아이가 현재 선택된 아이인지 확인 + if (selectedChild?.id === childId) { + setSelectedChild(null); + if (typeof window !== 'undefined') { + localStorage.removeItem('selectedChild'); + } + } + setChildrenData(prev => prev.filter(child => child.id !== childId)) showToast('돌봄관계가 삭제되었습니다.', 'success') + + // 삭제 후 자동으로 첫 번째 아이 선택 + setTimeout(() => { + autoSelectFirstChild(); + }, 100); } catch (error) { console.error('관계 삭제 실패:', error) showToast('돌봄관계 삭제에 실패했습니다.', 'error') @@ -313,8 +326,21 @@ export default function SettingsPage() { throw new Error(`아이 삭제 실패: ${response.status}`) } + // 삭제된 아이가 현재 선택된 아이인지 확인 + if (selectedChild?.id === childId) { + setSelectedChild(null); + if (typeof window !== 'undefined') { + localStorage.removeItem('selectedChild'); + } + } + setChildrenData(prev => prev.filter(child => child.id !== childId)) showToast('아이가 완전히 삭제되었습니다.', 'success') + + // 삭제 후 자동으로 첫 번째 아이 선택 + setTimeout(() => { + autoSelectFirstChild(); + }, 100); } catch (error) { console.error('아이 삭제 실패:', error) showToast('아이 삭제에 실패했습니다.', 'error') @@ -367,7 +393,7 @@ export default function SettingsPage() {

아이 목록을 불러오는 중...

- +
) } @@ -400,7 +426,7 @@ export default function SettingsPage() { - +
) } @@ -427,7 +453,7 @@ export default function SettingsPage() { 설정

등록된 아이 목록

- 총 {childrenData.length}명의 아이가 등록되어 있습니다 + 총 {childrenData.length}명의 아이가 등록되어 있습니다.

@@ -493,13 +519,13 @@ export default function SettingsPage() { {childrenData.length === 0 && (
-
- - +
+ +
-

등록된 아이가 없습니다

-

아이를 등록하여 관리를 시작해보세요

+

등록된 아이가 없습니다.

+

아이를 생성하거나 연결해야 합니다.

)} @@ -520,7 +546,7 @@ export default function SettingsPage() {
- + ('week') const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + const [toast, setToast] = useState<{ + message: string; + type: 'success' | 'error' | 'warning'; + isVisible: boolean; + }>({ + message: '', + type: 'warning', + isVisible: false + }) // API 데이터 상태 const [dailyTemperatureData, setDailyTemperatureData] = useState([]) @@ -148,6 +158,19 @@ export default function StatsPage() { } }, [selectedChild?.id, statsUnit]) + // 토스트 메시지 표시 함수 + const showToast = (message: string, type: 'success' | 'error' | 'warning') => { + setToast({ + message, + type, + isVisible: true + }); + }; + + const hideToast = () => { + setToast(prev => ({ ...prev, isVisible: false })); + }; + // 선택된 아이가 없을 때 자동 선택 시도 useEffect(() => { if (!selectedChild) { @@ -155,6 +178,13 @@ export default function StatsPage() { } }, [selectedChild, autoSelectFirstChild]); + // 아이가 없을 때 토스트 메시지 표시 + useEffect(() => { + if (!hasChildren && !selectedChild) { + showToast('이동할 수 없습니다. 아이를 생성하거나 연결해주세요.', 'warning'); + } + }, [hasChildren, selectedChild]); + // 계산된 데이터 const currentAccuracyData = dailyTemperatureData.map(d => d.avgTemp) const latestAccuracy = currentAccuracyData.length > 0 ? currentAccuracyData[currentAccuracyData.length - 1] : 0 @@ -170,30 +200,7 @@ export default function StatsPage() { return null; } - // 선택된 아이가 없을 때 (자동 선택 후에도 없으면) - if (!selectedChild) { - return ( - -
-
- - - -
-

선택된 아이가 없습니다

-

- 아이 목록에서 아이를 선택해주세요 -

- -
-
- ); - } + // 감정 예측 정확도 반원형 게이지 차트 데이터 const accuracyChartData = { @@ -399,6 +406,12 @@ export default function StatsPage() { return ( +
{childName}의 통계 @@ -583,7 +596,7 @@ export default function StatsPage() { )}
- + ) } \ No newline at end of file From 147e6abdf07d6cb2566c0459de712b57272e0ae5 Mon Sep 17 00:00:00 2001 From: GSB0203 Date: Wed, 16 Jul 2025 20:03:14 +0900 Subject: [PATCH 4/8] =?UTF-8?q?fix=20::=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EB=B9=84=EC=9C=A8=20=EB=A7=8C=ED=81=BC=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=95=88=EB=90=A8=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/auth/callback/page.tsx | 10 +- app/components/Container.tsx | 6 +- app/components/ProtectedRoute.tsx | 18 +- app/insert-children/page.tsx | 365 +++++++++++++++--------------- app/insert/page.tsx | 202 +++++++++-------- app/insert/reason/page.tsx | 88 +++---- app/page.tsx | 108 ++++----- 7 files changed, 410 insertions(+), 387 deletions(-) diff --git a/app/auth/callback/page.tsx b/app/auth/callback/page.tsx index 7c67719..4db7bd2 100644 --- a/app/auth/callback/page.tsx +++ b/app/auth/callback/page.tsx @@ -98,10 +98,12 @@ function AuthCallbackContent() { export default function AuthCallback() { return ( -
-
-

로딩 중...

+
+
+
+
+

로딩 중...

+
}> diff --git a/app/components/Container.tsx b/app/components/Container.tsx index e285f46..7e69c2f 100644 --- a/app/components/Container.tsx +++ b/app/components/Container.tsx @@ -7,8 +7,10 @@ interface ContainerProps { export default function Container({ children, className = "" }: ContainerProps) { return ( -
- {children} +
+
+ {children} +
); } \ No newline at end of file diff --git a/app/components/ProtectedRoute.tsx b/app/components/ProtectedRoute.tsx index 4e739eb..8285166 100644 --- a/app/components/ProtectedRoute.tsx +++ b/app/components/ProtectedRoute.tsx @@ -23,10 +23,12 @@ export default function ProtectedRoute({ children, fallback }: ProtectedRoutePro if (loading) { return ( -
-
-
-

로딩 중...

+
+
+
+
+

로딩 중...

+
); @@ -34,9 +36,11 @@ export default function ProtectedRoute({ children, fallback }: ProtectedRoutePro if (!isLoggedIn) { return fallback || ( -
-
-

로그인이 필요합니다.

+
+
+
+

로그인이 필요합니다.

+
); diff --git a/app/insert-children/page.tsx b/app/insert-children/page.tsx index 85b8647..cd4f7a8 100644 --- a/app/insert-children/page.tsx +++ b/app/insert-children/page.tsx @@ -155,198 +155,201 @@ export default function Register() { }; return ( -
-
- -
- -
-
- 새로운 아이 프로필 추가 -

새로운 아이 프로필을 생성할게요.

+
+
+
+
- - {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 && ( + + {error && ( + +

{error}

+
+ )} + +
+ )}
- {currentDisplayStep >= 4 && ( - - {error && ( - -

{error}

-
- )} - -
- )}
); } \ No newline at end of file diff --git a/app/insert/page.tsx b/app/insert/page.tsx index 062211a..f066d20 100644 --- a/app/insert/page.tsx +++ b/app/insert/page.tsx @@ -191,113 +191,117 @@ function InsertPageContent() { if (isLoadingEmotions) { return ( -
-
-
-

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

+
+
+
+
+

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

+
); } return ( -
-
-
- -
-
-
{getCurrentDate()} {TIME_PERIODS[currentStep].label}
-
- {TIME_PERIODS[currentStep].text}{`\n`}느낄까요? +
+
+
+
+
- - {error && ( -
- {error} +
+
{getCurrentDate()} {TIME_PERIODS[currentStep].label}
+
+ {TIME_PERIODS[currentStep].text}{`\n`}느낄까요?
- )} + + {error && ( +
+ {error} +
+ )} - {isStepCompleted && ( -
- ✓ {TIME_PERIODS[currentStep].label} 감정이 저장되었습니다 -
- )} - -
- {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 || isStepCompleted} - > - {emotion.name} - - ); - })} -
+ {isStepCompleted && ( +
+ ✓ {TIME_PERIODS[currentStep].label} 감정이 저장되었습니다
- ))} + )} + +
+ {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 || isStepCompleted} + > + {emotion.name} + + ); + })} +
+
+ ))} +
-
- - - + + +
); } @@ -305,10 +309,12 @@ function InsertPageContent() { export default function InsertPage() { return ( -
-
-

로딩 중...

+
+
+
+
+

로딩 중...

+
}> diff --git a/app/insert/reason/page.tsx b/app/insert/reason/page.tsx index 68c8fc6..020be84 100644 --- a/app/insert/reason/page.tsx +++ b/app/insert/reason/page.tsx @@ -101,55 +101,57 @@ function ReasonPageContent() { }; return ( -
-
- -
- -
-
7월 12일 토요일 {TIME_PERIODS[currentStep].label}
-
- {TIME_PERIODS[currentStep].text}{`\n`}느낄 것 같나요? +
+
+
+
-
-
-