From 0de235160bfa9375f7d308aa219ce37a6552d314 Mon Sep 17 00:00:00 2001 From: jpark0506 <45231740+jpark0506@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:28:19 +0900 Subject: [PATCH 1/6] =?UTF-8?q?fix=20:=20=EB=8F=84=EC=9B=80=EB=A7=90?= =?UTF-8?q?=EC=9D=B4=20=EC=A0=95=ED=99=95=ED=95=98=EA=B2=8C=20=EB=8F=8C?= =?UTF-8?q?=EC=95=84=EA=B0=80=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(help)/help.tsx | 11 ++++++++++- app/(tabs-user)/chat-list/[id].tsx | 10 +++++----- shared/ui/buttons/help-button.tsx | 8 ++++++-- shared/ui/header/navbar.tsx | 10 ++++++++-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/app/(help)/help.tsx b/app/(help)/help.tsx index 4d8ed97..a55adc5 100644 --- a/app/(help)/help.tsx +++ b/app/(help)/help.tsx @@ -1,4 +1,5 @@ import { BackHeader, Footer, MainLayout } from "@/shared/ui"; +import { useLocalSearchParams } from "expo-router"; import { Image } from "expo-image"; import { Image as RNImage, ScrollView } from "react-native"; @@ -6,11 +7,19 @@ const helpImg = require("@/assets/images/img_help.png"); const { width: imgW, height: imgH } = RNImage.resolveAssetSource(helpImg); const aspectRatio = imgW / imgH; +function resolveReturnTo(param: string | string[] | undefined): string | undefined { + if (param == null) return undefined; + return Array.isArray(param) ? param[0] : param; +} + export default function HelpScreen() { + const { returnTo } = useLocalSearchParams<{ returnTo?: string }>(); + const replaceTo = resolveReturnTo(returnTo); + return ( - + diff --git a/app/(tabs-user)/chat-list/[id].tsx b/app/(tabs-user)/chat-list/[id].tsx index 6153cd2..3f115d2 100644 --- a/app/(tabs-user)/chat-list/[id].tsx +++ b/app/(tabs-user)/chat-list/[id].tsx @@ -13,15 +13,15 @@ import { import { queries } from "@/entities"; import { - getChatHistory, - type ChatHistoryResponse, - type ChatMessage, cleanupExpiredPendingChatMessages, + getChatHistory, getPendingChatMessages, removePendingChatMessage, + type ChatHistoryResponse, + type ChatMessage, } from "@/entities/chatbot"; import { normalizeEmotion } from "@/shared/lib/emotions"; -import { BackHeader, MainLayout } from "@/shared/ui"; +import { BackHeader, HelpButton, MainLayout } from "@/shared/ui"; import { ChatBubble, ChatInput, DiaryBottomSheet, VoiceMessageModal, VoicePlaybackModal } from "@/widgets/chat"; import { useSendMessage } from "@/widgets/chat/model/useSendMessage"; @@ -356,7 +356,7 @@ export default function ChatDetailScreen() { return ( - + } /> { const router = useRouter(); + const pathname = usePathname(); const handlePress = () => { - router.push('/(help)/help'); + router.push({ + pathname: "/(help)/help", + params: pathname ? { returnTo: pathname } : undefined, + }); }; return ( diff --git a/shared/ui/header/navbar.tsx b/shared/ui/header/navbar.tsx index 3c693d1..0b5f249 100644 --- a/shared/ui/header/navbar.tsx +++ b/shared/ui/header/navbar.tsx @@ -5,13 +5,19 @@ import { Icon } from '../svg'; type HeaderProps = { title: string; navigateTo?: Href; + /** 돌아갈 경로. 지정 시 router.replace()로 이동해 스택이 쌓이지 않음 (예: 도움말 → 이전 화면) */ + replaceTo?: Href; rightComponent?: React.ReactNode; -} +}; -export const BackHeader = ({ title, navigateTo, rightComponent }: HeaderProps) => { +export const BackHeader = ({ title, navigateTo, replaceTo, rightComponent }: HeaderProps) => { const router = useRouter(); const handlePress = () => { + if (replaceTo) { + router.replace(replaceTo); + return; + } if (navigateTo) { router.push(navigateTo); return; From 9d99caa786d1d53ebb359e24bfe8687abac42dff Mon Sep 17 00:00:00 2001 From: jpark0506 <45231740+jpark0506@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:33:55 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix=20:=20CARE=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=8F=8C=EC=95=84=EA=B0=80=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shared/ui/buttons/help-button.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/shared/ui/buttons/help-button.tsx b/shared/ui/buttons/help-button.tsx index bc61c28..7050615 100644 --- a/shared/ui/buttons/help-button.tsx +++ b/shared/ui/buttons/help-button.tsx @@ -1,15 +1,20 @@ -import { usePathname, useRouter } from "expo-router"; +import { useRouter, useSegments } from "expo-router"; import { TouchableOpacity } from "react-native"; import { Icon } from "../svg"; +function useFullPath(): string { + const segments = useSegments(); + return "/" + (segments as string[]).join("/"); +} + export const HelpButton = () => { const router = useRouter(); - const pathname = usePathname(); + const returnTo = useFullPath(); const handlePress = () => { router.push({ pathname: "/(help)/help", - params: pathname ? { returnTo: pathname } : undefined, + params: { returnTo }, }); }; return ( From 86582a1458b636ff94fd01c61cf0a44663b62551 Mon Sep 17 00:00:00 2001 From: jpark0506 <45231740+jpark0506@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:35:35 +0900 Subject: [PATCH 3/6] =?UTF-8?q?fix=20:=20=EB=A7=88=EC=9D=8C=20=EC=9D=BC?= =?UTF-8?q?=EA=B8=B0=20->=20=EC=9D=BC=EA=B8=B0=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A9=94=EB=89=B4=20=EC=A0=9C=EB=AA=A9=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(tabs-user)/_layout.tsx | 2 +- app/(tabs-user)/diary.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/(tabs-user)/_layout.tsx b/app/(tabs-user)/_layout.tsx index bbbb726..3d16245 100644 --- a/app/(tabs-user)/_layout.tsx +++ b/app/(tabs-user)/_layout.tsx @@ -31,7 +31,7 @@ export default function UserTabsLayout() { ( { - queryClient.invalidateQueries({ queryKey: queries.voices._def }); queryClient.invalidateQueries({ queryKey: queries.questions._def }); queryClient.invalidateQueries({ queryKey: queries.chatbot._def }); @@ -279,7 +278,7 @@ export default function DiaryScreen() { return ( - } /> + } /> Date: Sun, 22 Feb 2026 19:53:37 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix=20:=20=EC=9D=BC=EA=B8=B0=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=EA=B2=B0=EA=B3=BC=EC=97=90=EC=84=9C=20404=EC=8B=9C?= =?UTF-8?q?=20=EB=AC=B4=ED=95=9C=20=EC=97=90=EB=9F=AC=20alert=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- widgets/chat/report/ui/weekly-story.tsx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/widgets/chat/report/ui/weekly-story.tsx b/widgets/chat/report/ui/weekly-story.tsx index 33f3330..ea39641 100644 --- a/widgets/chat/report/ui/weekly-story.tsx +++ b/widgets/chat/report/ui/weekly-story.tsx @@ -1,11 +1,12 @@ import { useIsMutating, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useEffect, useMemo } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { ActivityIndicator, Text, View } from "react-native"; import { FluentSparkleIcon } from "@/assets/icons"; import { queries } from "@/entities"; import { createWeeklyReport, type WeeklyReportItem } from "@/entities/chatbot"; import { normalizeEmotion } from "@/shared/lib/emotions"; +import { Icon } from "@/shared/ui"; export const WeeklyStory = ({ username }: { username: string }) => { const queryClient = useQueryClient(); @@ -46,6 +47,12 @@ export const WeeklyStory = ({ username }: { username: string }) => { // mutation key 생성 const createWeeklyReportMutationKey = ["createWeeklyReport", username, currentWeekStart]; + // 같은 주에 대해 생성 요청을 한 번만 시도하기 위한 ref (404/무데이터 시 무한 재시도 방지) + const triedCreateForWeekRef = useRef(null); + if (triedCreateForWeekRef.current !== null && triedCreateForWeekRef.current !== currentWeekStart) { + triedCreateForWeekRef.current = null; + } + // mutation이 진행 중인지 확인 const isMutating = useIsMutating({ mutationKey: createWeeklyReportMutationKey, @@ -120,7 +127,13 @@ export const WeeklyStory = ({ username }: { username: string }) => { const is404Error = isError && (error as any)?.response?.status === 404; + // 같은 주에 대해 이미 생성 시도를 했으면 다시 호출하지 않음 (404/무데이터 시 무한 재시도 방지) + if (triedCreateForWeekRef.current === currentWeekStart) { + return; + } + if (is404Error) { + triedCreateForWeekRef.current = currentWeekStart; console.log("[WeeklyStory] 주간 리포트 생성 이유: monthlyReports API에서 404 에러 발생", { username, year, @@ -133,6 +146,7 @@ export const WeeklyStory = ({ username }: { username: string }) => { } if (!isError && !currentWeekReport) { + triedCreateForWeekRef.current = currentWeekStart; const hasReports = monthlyReports?.reports && monthlyReports.reports.length > 0; const reason = !monthlyReports?.reports ? "monthlyReports 데이터가 없음" @@ -209,7 +223,12 @@ export const WeeklyStory = ({ username }: { username: string }) => { - ) : null} + ) : ( + + + 주간 마음 소설을 불러올 수 없습니다 + + )} ); }; \ No newline at end of file From 63483b9263db0fc6dcfcbad00e39c8b58a498b08 Mon Sep 17 00:00:00 2001 From: jpark0506 <45231740+jpark0506@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:58:48 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix=20:=20=EB=A3=A8=ED=8A=B8=20Slot?= =?UTF-8?q?=EC=9D=84=20Stack=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EB=8F=84=EC=9B=80=EB=A7=90=20=EB=92=A4?= =?UTF-8?q?=EB=A1=9C=EA=B0=80=EA=B8=B0=20=EA=B7=BC=EB=B3=B8=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 루트 레이아웃이 Slot이라 네비게이션 스택이 없어 형제 그룹 간 뒤로가기가 꼬이던 문제를 Stack으로 변경하여 해결. returnTo 파라미터와 replaceTo prop 제거. Co-Authored-By: Claude Opus 4.6 --- app/(help)/help.tsx | 12 +----------- app/_layout.tsx | 4 ++-- shared/ui/buttons/help-button.tsx | 15 +++------------ shared/ui/header/navbar.tsx | 10 ++-------- 4 files changed, 8 insertions(+), 33 deletions(-) diff --git a/app/(help)/help.tsx b/app/(help)/help.tsx index a55adc5..531aa21 100644 --- a/app/(help)/help.tsx +++ b/app/(help)/help.tsx @@ -1,5 +1,4 @@ import { BackHeader, Footer, MainLayout } from "@/shared/ui"; -import { useLocalSearchParams } from "expo-router"; import { Image } from "expo-image"; import { Image as RNImage, ScrollView } from "react-native"; @@ -7,19 +6,11 @@ const helpImg = require("@/assets/images/img_help.png"); const { width: imgW, height: imgH } = RNImage.resolveAssetSource(helpImg); const aspectRatio = imgW / imgH; -function resolveReturnTo(param: string | string[] | undefined): string | undefined { - if (param == null) return undefined; - return Array.isArray(param) ? param[0] : param; -} - export default function HelpScreen() { - const { returnTo } = useLocalSearchParams<{ returnTo?: string }>(); - const replaceTo = resolveReturnTo(returnTo); - return ( - + @@ -39,4 +30,3 @@ export default function HelpScreen() { ); } - diff --git a/app/_layout.tsx b/app/_layout.tsx index c8e4193..7adb03d 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -3,7 +3,7 @@ import { isAxiosError } from "axios"; import { useFonts } from "expo-font"; import { Redirect, - Slot, + Stack, useRootNavigationState, useSegments, } from "expo-router"; @@ -146,7 +146,7 @@ export default function RootLayout() { - + diff --git a/shared/ui/buttons/help-button.tsx b/shared/ui/buttons/help-button.tsx index 7050615..c5bab1a 100644 --- a/shared/ui/buttons/help-button.tsx +++ b/shared/ui/buttons/help-button.tsx @@ -1,25 +1,16 @@ -import { useRouter, useSegments } from "expo-router"; +import { useRouter } from "expo-router"; import { TouchableOpacity } from "react-native"; import { Icon } from "../svg"; -function useFullPath(): string { - const segments = useSegments(); - return "/" + (segments as string[]).join("/"); -} - export const HelpButton = () => { const router = useRouter(); - const returnTo = useFullPath(); const handlePress = () => { - router.push({ - pathname: "/(help)/help", - params: { returnTo }, - }); + router.push("/(help)/help"); }; return ( ); -}; \ No newline at end of file +}; diff --git a/shared/ui/header/navbar.tsx b/shared/ui/header/navbar.tsx index 0b5f249..b6f11e0 100644 --- a/shared/ui/header/navbar.tsx +++ b/shared/ui/header/navbar.tsx @@ -5,19 +5,13 @@ import { Icon } from '../svg'; type HeaderProps = { title: string; navigateTo?: Href; - /** 돌아갈 경로. 지정 시 router.replace()로 이동해 스택이 쌓이지 않음 (예: 도움말 → 이전 화면) */ - replaceTo?: Href; rightComponent?: React.ReactNode; }; -export const BackHeader = ({ title, navigateTo, replaceTo, rightComponent }: HeaderProps) => { +export const BackHeader = ({ title, navigateTo, rightComponent }: HeaderProps) => { const router = useRouter(); const handlePress = () => { - if (replaceTo) { - router.replace(replaceTo); - return; - } if (navigateTo) { router.push(navigateTo); return; @@ -40,4 +34,4 @@ export const BackHeader = ({ title, navigateTo, replaceTo, rightComponent }: Hea )} ); -}; \ No newline at end of file +}; From 8c1bd8d6815fd9b71e778d4fefbc9714fd4281a0 Mon Sep 17 00:00:00 2001 From: jpark0506 <45231740+jpark0506@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:59:33 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore=20:=20console.log=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- widgets/chat/report/ui/weekly-story.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/widgets/chat/report/ui/weekly-story.tsx b/widgets/chat/report/ui/weekly-story.tsx index ea39641..6a274bf 100644 --- a/widgets/chat/report/ui/weekly-story.tsx +++ b/widgets/chat/report/ui/weekly-story.tsx @@ -1,4 +1,4 @@ -import { useIsMutating, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { noop, useIsMutating, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useEffect, useMemo, useRef } from "react"; import { ActivityIndicator, Text, View } from "react-native"; @@ -103,6 +103,7 @@ export const WeeklyStory = ({ username }: { username: string }) => { target_date: currentWeekStart, }); }, + onError: noop, onSuccess: () => { queryClient.invalidateQueries({ queryKey: queries.chatbot.monthlyReports(username, year, month).queryKey, @@ -134,13 +135,6 @@ export const WeeklyStory = ({ username }: { username: string }) => { if (is404Error) { triedCreateForWeekRef.current = currentWeekStart; - console.log("[WeeklyStory] 주간 리포트 생성 이유: monthlyReports API에서 404 에러 발생", { - username, - year, - month, - currentWeekStart, - currentWeekEnd, - }); createWeeklyStory(); return; } @@ -226,7 +220,8 @@ export const WeeklyStory = ({ username }: { username: string }) => { ) : ( - 주간 마음 소설을 불러올 수 없습니다 + { + error?.response?.data?.message ?? "금주 대화가 없어 생성할 수 없습니다."} )}