From 977f83d69b88c45ed981dbe0b5b62c5a41909c1a Mon Sep 17 00:00:00 2001 From: TTOCHIwas <95687307+TTOCHIwas@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:46:43 +0900 Subject: [PATCH 1/5] =?UTF-8?q?refector:=20useUploadLoadingProgress=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=EB=A5=A0=20=EC=83=81=ED=83=9C=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EC=BA=A1?= =?UTF-8?q?=EC=8A=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/upload/hooks/index.ts | 1 + .../upload/hooks/useUploadLoadingProgress.ts | 75 +++++++++++++++++++ .../upload/_loading/UploadLoadingPage.tsx | 58 +------------- 3 files changed, 79 insertions(+), 55 deletions(-) create mode 100644 src/features/upload/hooks/useUploadLoadingProgress.ts diff --git a/src/features/upload/hooks/index.ts b/src/features/upload/hooks/index.ts index c8ab502..99b1e5d 100644 --- a/src/features/upload/hooks/index.ts +++ b/src/features/upload/hooks/index.ts @@ -1,3 +1,4 @@ +export * from "./useUploadLoadingProgress"; export * from "./useUploadStepData"; export * from "./useUploadStepNavigation"; export * from "./useUploadStepProject"; diff --git a/src/features/upload/hooks/useUploadLoadingProgress.ts b/src/features/upload/hooks/useUploadLoadingProgress.ts new file mode 100644 index 0000000..0dd5fd2 --- /dev/null +++ b/src/features/upload/hooks/useUploadLoadingProgress.ts @@ -0,0 +1,75 @@ +import { useEffect, useMemo, useState } from "react"; +import { useNavigate } from "react-router"; + +import { useUploadFlowStore } from "@/entities"; +import { DYNAMIC_ROUTE_PATHS, ROUTE_PATHS } from "@/shared"; + +const LOADING_STEPS = [ + { threshold: 0, message: "파일 업로드 중.." }, + { threshold: 20, message: "PDF 텍스트 추출 중.." }, + { threshold: 50, message: "과제 내용 분석 중.." }, + { threshold: 75, message: "로드맵 생성 중.." }, + { threshold: 95, message: "마무리 중.." }, +]; + +type Result = { + progress: number; + currentStepMessage: string; +}; + +export const useUploadLoadingProgress = (): Result => { + const navigate = useNavigate(); + const [timerProgress, setTimerProgress] = useState(0); + + const projectId = useUploadFlowStore((state) => state.projectId); + const error = useUploadFlowStore((state) => state.error); + + const progress = projectId ? 100 : timerProgress; + + useEffect(() => { + const interval = setInterval(() => { + setTimerProgress((prev) => { + if (prev >= 90) { + clearInterval(interval); + return 90; + } + + const increment = prev < 70 ? 1.2 : 0.6; + return Math.min(prev + increment, 90); + }); + }, 80); + + return () => clearInterval(interval); + }, []); + + useEffect(() => { + if (error) { + navigate(ROUTE_PATHS.FILE_UPLOAD); + } + }, [error, navigate]); + + useEffect(() => { + if (!projectId) { + return; + } + + const timer = setTimeout(() => { + navigate(DYNAMIC_ROUTE_PATHS.UPLOAD_STEP(projectId, 1)); + }, 600); + + return () => clearTimeout(timer); + }, [projectId, navigate]); + + const currentStepMessage = useMemo(() => { + const currentStep = + [...LOADING_STEPS].reverse().find((step) => progress >= step.threshold) ?? + LOADING_STEPS[0]; + + return currentStep.message; + }, [progress]); + + return { + progress, + currentStepMessage, + }; +}; diff --git a/src/pages/upload/_loading/UploadLoadingPage.tsx b/src/pages/upload/_loading/UploadLoadingPage.tsx index c023f50..20947f4 100644 --- a/src/pages/upload/_loading/UploadLoadingPage.tsx +++ b/src/pages/upload/_loading/UploadLoadingPage.tsx @@ -1,62 +1,10 @@ -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router"; - import { Box, Flex, Image, Text, VStack } from "@chakra-ui/react"; -import { useUploadFlowStore } from "@/entities"; -import { SproutAnimation } from "@/features"; -import { DYNAMIC_ROUTE_PATHS, ROUTE_PATHS } from "@/shared"; +import { SproutAnimation, useUploadLoadingProgress } from "@/features"; import AbstractBackgroundCircle from "@/shared/_assets/images/abstract-background-circle.svg"; -const LOADING_STEPS = [ - { threshold: 0, message: "파일 업로드 중..." }, - { threshold: 20, message: "PDF 텍스트 추출 중..." }, - { threshold: 50, message: "과제 내용 분석 중..." }, - { threshold: 75, message: "로드맵 생성 중..." }, - { threshold: 95, message: "마무리 중..." }, -]; - export default function UploadLoadingPage() { - const navigate = useNavigate(); - const [timerProgress, setTimerProgress] = useState(0); - - const projectId = useUploadFlowStore((state) => state.projectId); - const error = useUploadFlowStore((state) => state.error); - - const progress = projectId ? 100 : timerProgress; - - useEffect(() => { - const interval = setInterval(() => { - setTimerProgress((prev) => { - if (prev >= 90) { - clearInterval(interval); - return 90; - } - const increment = prev < 70 ? 1.2 : 0.6; - return Math.min(prev + increment, 90); - }); - }, 80); - return () => clearInterval(interval); - }, []); - - useEffect(() => { - if (error) { - navigate(ROUTE_PATHS.FILE_UPLOAD); - } - }, [error, navigate]); - - useEffect(() => { - if (projectId) { - const timer = setTimeout(() => { - navigate(DYNAMIC_ROUTE_PATHS.UPLOAD_STEP(projectId, 1)); - }, 600); - return () => clearTimeout(timer); - } - }, [projectId, navigate]); - - const currentStep = - [...LOADING_STEPS].reverse().find((s) => progress >= s.threshold) ?? - LOADING_STEPS[0]; + const { progress, currentStepMessage } = useUploadLoadingProgress(); return ( - {currentStep.message} + {currentStepMessage} {Math.round(progress)}% From ea3a81c3953dd2edaf0b9f3d33d8b1605c3d5e41 Mon Sep 17 00:00:00 2001 From: TTOCHIwas <95687307+TTOCHIwas@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:58:36 +0900 Subject: [PATCH 2/5] =?UTF-8?q?refector:=20UploadLoadingSection=20?= =?UTF-8?q?=EC=84=B9=EC=85=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/section/UploadLoadingSection.tsx | 108 ++++++++++++++++++ src/features/upload/ui/section/index.ts | 1 + .../upload/_loading/UploadLoadingPage.tsx | 100 +--------------- 3 files changed, 114 insertions(+), 95 deletions(-) create mode 100644 src/features/upload/ui/section/UploadLoadingSection.tsx diff --git a/src/features/upload/ui/section/UploadLoadingSection.tsx b/src/features/upload/ui/section/UploadLoadingSection.tsx new file mode 100644 index 0000000..0e4023c --- /dev/null +++ b/src/features/upload/ui/section/UploadLoadingSection.tsx @@ -0,0 +1,108 @@ +import { Box, Flex, Image, Text, VStack } from "@chakra-ui/react"; + +import { SproutAnimation } from "@/features"; +import AbstractBackgroundCircle from "@/shared/_assets/images/abstract-background-circle.svg"; + +type Props = { + progress: number; + currentStepMessage: string; +}; + +export const UploadLoadingSection = ({ + progress, + currentStepMessage, +}: Props) => { + return ( + + + + + background circle + + + + + + AI가 과제의 핵심을 +
+ 분석하고 있어요 +
+ + 분석이 완료되면 나만의 로드맵이 펼쳐집니다. + +
+ + + + + {currentStepMessage} + + + {Math.round(progress)}% + + + + + + + + + 잠시만 기다려주세요, 거의 다 되었습니다. + + +
+
+ ); +}; diff --git a/src/features/upload/ui/section/index.ts b/src/features/upload/ui/section/index.ts index d17f2c8..07e0795 100644 --- a/src/features/upload/ui/section/index.ts +++ b/src/features/upload/ui/section/index.ts @@ -1,2 +1,3 @@ +export * from "./UploadLoadingSection"; export * from "./UploadStepContentSection"; export * from "./UploadStepHeaderSection"; diff --git a/src/pages/upload/_loading/UploadLoadingPage.tsx b/src/pages/upload/_loading/UploadLoadingPage.tsx index 20947f4..6cd7c1a 100644 --- a/src/pages/upload/_loading/UploadLoadingPage.tsx +++ b/src/pages/upload/_loading/UploadLoadingPage.tsx @@ -1,102 +1,12 @@ -import { Box, Flex, Image, Text, VStack } from "@chakra-ui/react"; - -import { SproutAnimation, useUploadLoadingProgress } from "@/features"; -import AbstractBackgroundCircle from "@/shared/_assets/images/abstract-background-circle.svg"; +import { UploadLoadingSection, useUploadLoadingProgress } from "@/features"; export default function UploadLoadingPage() { const { progress, currentStepMessage } = useUploadLoadingProgress(); return ( - - - - - background circle - - - - - - AI가 과제의 핵심을 -
- 분석하고 있어요 -
- - 분석이 완료되면 나만의 로드맵이 펼쳐집니다. - -
- - - - - {currentStepMessage} - - - {Math.round(progress)}% - - - - - - - - - 잠시만 기다려주세요, 거의 다 되었습니다. - - -
-
+ ); } From 06008d2ccb768bf1bef0c50cf5f49cd9d4812720 Mon Sep 17 00:00:00 2001 From: TTOCHIwas <95687307+TTOCHIwas@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:18:04 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EC=88=98=EC=9A=A9-=20projectId=20=EC=A1=B4=EC=9E=AC=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=83=80?= =?UTF-8?q?=EC=9D=B4=EB=A8=B8=20=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/upload/hooks/useUploadLoadingProgress.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/features/upload/hooks/useUploadLoadingProgress.ts b/src/features/upload/hooks/useUploadLoadingProgress.ts index 0dd5fd2..e6d5068 100644 --- a/src/features/upload/hooks/useUploadLoadingProgress.ts +++ b/src/features/upload/hooks/useUploadLoadingProgress.ts @@ -27,6 +27,10 @@ export const useUploadLoadingProgress = (): Result => { const progress = projectId ? 100 : timerProgress; useEffect(() => { + if (projectId) { + return; + } + const interval = setInterval(() => { setTimerProgress((prev) => { if (prev >= 90) { @@ -40,7 +44,7 @@ export const useUploadLoadingProgress = (): Result => { }, 80); return () => clearInterval(interval); - }, []); + }, [projectId]); useEffect(() => { if (error) { From e191412e6e6587fdb5778ecae100c2aa03ed3609 Mon Sep 17 00:00:00 2001 From: TTOCHIwas <95687307+TTOCHIwas@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:25:14 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EC=88=98=EC=9A=A9-=20=EB=A7=A4=EC=A7=81=20=EB=84=98=EB=B2=84?= =?UTF-8?q?=20=EC=83=81=EC=88=98=EB=A1=9C=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../upload/hooks/useUploadLoadingProgress.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/features/upload/hooks/useUploadLoadingProgress.ts b/src/features/upload/hooks/useUploadLoadingProgress.ts index e6d5068..2bb016c 100644 --- a/src/features/upload/hooks/useUploadLoadingProgress.ts +++ b/src/features/upload/hooks/useUploadLoadingProgress.ts @@ -4,6 +4,13 @@ import { useNavigate } from "react-router"; import { useUploadFlowStore } from "@/entities"; import { DYNAMIC_ROUTE_PATHS, ROUTE_PATHS } from "@/shared"; +const MAX_TIMER_PROGRESS = 90; +const PROGRESS_SLOWDOWN_THRESHOLD = 70; +const FAST_PROGRESS_INCREMENT = 1.2; +const SLOW_PROGRESS_INCREMENT = 0.6; +const PROGRESS_INTERVAL_MS = 80; +const STEP_REDIRECT_DELAY_MS = 600; + const LOADING_STEPS = [ { threshold: 0, message: "파일 업로드 중.." }, { threshold: 20, message: "PDF 텍스트 추출 중.." }, @@ -33,15 +40,19 @@ export const useUploadLoadingProgress = (): Result => { const interval = setInterval(() => { setTimerProgress((prev) => { - if (prev >= 90) { + if (prev >= MAX_TIMER_PROGRESS) { clearInterval(interval); - return 90; + return MAX_TIMER_PROGRESS; } - const increment = prev < 70 ? 1.2 : 0.6; - return Math.min(prev + increment, 90); + const increment = + prev < PROGRESS_SLOWDOWN_THRESHOLD + ? FAST_PROGRESS_INCREMENT + : SLOW_PROGRESS_INCREMENT; + + return Math.min(prev + increment, MAX_TIMER_PROGRESS); }); - }, 80); + }, PROGRESS_INTERVAL_MS); return () => clearInterval(interval); }, [projectId]); @@ -59,7 +70,7 @@ export const useUploadLoadingProgress = (): Result => { const timer = setTimeout(() => { navigate(DYNAMIC_ROUTE_PATHS.UPLOAD_STEP(projectId, 1)); - }, 600); + }, STEP_REDIRECT_DELAY_MS); return () => clearTimeout(timer); }, [projectId, navigate]); From 9494661576d8eb557a7649245ad419d303f2ecf3 Mon Sep 17 00:00:00 2001 From: TTOCHIwas <95687307+TTOCHIwas@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:41:03 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C?= =?UTF-8?q?=20useMemo=20=EC=82=AC=EC=9A=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../upload/hooks/useUploadLoadingProgress.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/features/upload/hooks/useUploadLoadingProgress.ts b/src/features/upload/hooks/useUploadLoadingProgress.ts index 2bb016c..e0b87bf 100644 --- a/src/features/upload/hooks/useUploadLoadingProgress.ts +++ b/src/features/upload/hooks/useUploadLoadingProgress.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import { useNavigate } from "react-router"; import { useUploadFlowStore } from "@/entities"; @@ -12,11 +12,11 @@ const PROGRESS_INTERVAL_MS = 80; const STEP_REDIRECT_DELAY_MS = 600; const LOADING_STEPS = [ - { threshold: 0, message: "파일 업로드 중.." }, - { threshold: 20, message: "PDF 텍스트 추출 중.." }, - { threshold: 50, message: "과제 내용 분석 중.." }, - { threshold: 75, message: "로드맵 생성 중.." }, { threshold: 95, message: "마무리 중.." }, + { threshold: 75, message: "로드맵 생성 중.." }, + { threshold: 50, message: "과제 내용 분석 중.." }, + { threshold: 20, message: "파일 텍스트 추출 중.." }, + { threshold: 0, message: "파일 업로드 중.." }, ]; type Result = { @@ -75,13 +75,9 @@ export const useUploadLoadingProgress = (): Result => { return () => clearTimeout(timer); }, [projectId, navigate]); - const currentStepMessage = useMemo(() => { - const currentStep = - [...LOADING_STEPS].reverse().find((step) => progress >= step.threshold) ?? - LOADING_STEPS[0]; - - return currentStep.message; - }, [progress]); + const currentStepMessage = + LOADING_STEPS.find((step) => progress >= step.threshold)?.message ?? + LOADING_STEPS[LOADING_STEPS.length - 1].message; return { progress,