Skip to content

Commit fdaaf57

Browse files
authored
refactor: 몰입 화면 prefetch 적용 (#175)
* refactor: sharp 라이브러리 세팅 * chore: 마이페이지 stale 시간 제거 * refactor: 작업 완료 모달 애니메이션 추가 * refactor: 몰입화면 prefetch 적용
1 parent 6c08eac commit fdaaf57

File tree

9 files changed

+1068
-324
lines changed

9 files changed

+1068
-324
lines changed

package-lock.json

Lines changed: 1033 additions & 284 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
"react": "^19.0.0",
3535
"react-day-picker": "^8.10.1",
3636
"react-dom": "^19.0.0",
37+
"sharp": "^0.34.1",
3738
"tailwind-merge": "^2.6.0",
38-
"tailwindcss-animate": "^1.0.7",
3939
"vaul": "^1.1.2",
4040
"zustand": "^5.0.3"
4141
},
@@ -56,6 +56,7 @@
5656
"prettier": "^3.4.2",
5757
"prettier-plugin-tailwindcss": "^0.6.10",
5858
"tailwindcss": "^3.4.17",
59+
"tailwindcss-animate": "^1.0.7",
5960
"typescript": "^5"
6061
}
6162
}

src/app/(protected)/(create)/_components/characterDialog/CharacterDialog.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import Loader from "@/components/loader/Loader";
34
import { Button } from "@/components/ui/button";
45
import {
56
Dialog,
@@ -18,6 +19,7 @@ interface CharacterDialogProps {
1819
taskType: string;
1920
personaName: string;
2021
personaId?: number;
22+
isLoading: boolean;
2123
onClick: () => void;
2224
}
2325

@@ -27,13 +29,14 @@ const CharacterDialog = ({
2729
taskType,
2830
personaName,
2931
personaId,
32+
isLoading,
3033
onClick,
3134
}: CharacterDialogProps) => {
3235
const { userData } = useUserStore();
3336
const personaImageSrc = getPersonaImage(personaId);
3437

3538
return (
36-
<Dialog open={isOpen} onOpenChange={onClick}>
39+
<Dialog open={isOpen} onOpenChange={onClick} modal>
3740
<DialogContent className="w-[328px] rounded-[24px] border-none bg-component-gray-secondary px-4 py-6">
3841
<DialogHeader>
3942
<DialogTitle className="text-normal t3 mb-1">
@@ -65,7 +68,13 @@ const CharacterDialog = ({
6568
<span className="l6 text-inverse">{`${personaName} ${userData.nickname}`}</span>
6669
</div>
6770
</div>
68-
<Button variant="primary" className="w-full" onClick={onClick}>
71+
<Button
72+
variant="primary"
73+
className="w-full"
74+
disabled={isLoading}
75+
onClick={onClick}
76+
>
77+
{isLoading && <Loader width={24} height={24} />}
6978
{taskType === "instant" ? "시작" : "확인"}
7079
</Button>
7180
</DialogContent>

src/app/(protected)/(create)/instant-create/page.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,17 @@
11
"use client";
22

33
import BackHeader from "@/components/backHeader/BackHeader";
4-
import Loader from "@/components/loader/Loader";
4+
55
import useMount from "@/hooks/useMount";
66
import type { InstantTaskType, TimePickerType } from "@/types/create";
77
import { useMutation, useQueryClient } from "@tanstack/react-query";
88
import { createFunnelSteps, useFunnel } from "@use-funnel/browser";
9-
import dynamic from "next/dynamic";
9+
1010
import { useRouter } from "next/navigation";
11+
import InstantTaskTypeInput from "../_components/instantTaskTypeInput/InstantTaskTypeInput";
1112
import TaskInput from "../_components/taskInput/TaskInput";
1213
import type { InstantTaskInputType, TaskInputType } from "../context";
1314

14-
const InstantTaskTypeInput = dynamic(
15-
() =>
16-
import(
17-
"@/app/(protected)/(create)/_components/instantTaskTypeInput/InstantTaskTypeInput"
18-
),
19-
{
20-
loading: () => <Loader />,
21-
},
22-
);
23-
2415
type FormState = {
2516
task?: string;
2617
deadlineDate?: Date;

src/app/(protected)/(root)/_components/header/headerBar/HeaderBar.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ const HeaderBar = () => {
1010
alt="SPURT"
1111
width={54}
1212
height={20}
13-
priority
1413
className="w-[54px]"
14+
priority
1515
/>
1616
<Link href="/my-page" className="flex items-center">
1717
<button type="button">
@@ -20,6 +20,7 @@ const HeaderBar = () => {
2020
alt="마이페이지"
2121
width={20}
2222
height={20}
23+
priority
2324
/>
2425
</button>
2526
</Link>

src/app/(protected)/(root)/_components/todayTaskTabWrapper/TodayTaskTabWrapper.tsx

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
"use client";
22

33
import type { Task } from "@/types/task";
4-
import { useRouter } from "next/navigation";
5-
import { useState } from "react";
64

7-
import ExpiredTaskDrawer from "../expiredTaskDrawer/ExpiredTaskDrawer";
85
import HasAllTasksOnlyScreen from "../hasAllTasksOnlyScreen/HasAllTasksOnlyScreen";
96
import HasInProgressTasksOnlyScreen from "../hasInProgressTasksOnlyScreen/HasInProgressTasksOnlyScreen";
107
import HasTodayAndInProgressTasksScreen from "../hasTodayAndInProgressTasksScreen/HasTodayAndInProgressTasksScreen";
@@ -37,20 +34,6 @@ const TodayTaskTabWrapper = ({
3734
handleDetailTask,
3835
handleDeleteTask,
3936
}: TodayTaskTabWrapperProps) => {
40-
const router = useRouter();
41-
42-
const [showExpiredTaskSheet, setShowExpiredTaskSheet] = useState(false);
43-
const [expiredTask, setExpiredTask] = useState<Task | null>(null);
44-
45-
const handleGoToReflection = (taskId: number) => {
46-
router.push(`/retrospection/${taskId}`);
47-
setShowExpiredTaskSheet(false);
48-
};
49-
50-
const handleCloseExpiredSheet = () => {
51-
setShowExpiredTaskSheet(false);
52-
};
53-
5437
return (
5538
<>
5639
{isTotallyEmpty && <IsEmptyScreen />}
@@ -94,14 +77,14 @@ const TodayTaskTabWrapper = ({
9477
/>
9578
)}
9679

97-
{/* 뭔가 잘못된거 같음. expiredTask를 할당하는 로직이 없음. */}
80+
{/* 뭔가 잘못된거 같음. expiredTask를 할당하는 로직이 없음.
9881
{showExpiredTaskSheet && expiredTask && (
9982
<ExpiredTaskDrawer
10083
expiredTask={expiredTask}
10184
handleGoToReflection={handleGoToReflection}
10285
handleCloseExpiredSheet={handleCloseExpiredSheet}
10386
/>
104-
)}
87+
)} */}
10588
</>
10689
);
10790
};

src/app/(protected)/(root)/page.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ const HomePageContent = () => {
4444
inProgressTasks,
4545
});
4646

47-
// 화면 분기 처리를 위한 상태
4847
const [isDetailSheetOpen, setIsDetailSheetOpen] = useState(false);
4948
const [activeTab, setActiveTab] = useState<"today" | "all">("today");
5049
const [detailTask, setDetailTask] = useState<Task | null>(null);
@@ -60,6 +59,7 @@ const HomePageContent = () => {
6059
const [urgentTaskId, setUrgentTaskId] = useState<number | undefined>(
6160
undefined,
6261
);
62+
const [isLoading, setIsLoading] = useState(false);
6363

6464
const handleDetailTask = (task: Task) => {
6565
setDetailTask(task);
@@ -99,12 +99,15 @@ const HomePageContent = () => {
9999
setIsCreateSheetOpen(false);
100100
};
101101

102-
const handleCharacterDialogButtonClick = () => {
102+
const handleCharacterDialogButtonClick = async () => {
103103
if (taskType === "instant") {
104-
router.push(`/immersion/${urgentTaskId}`);
104+
setIsLoading(true);
105+
await router.push(`/immersion/${urgentTaskId}`);
105106
} else {
106107
setIsDialogOpen(false);
107108
}
109+
110+
setIsLoading(false);
108111
};
109112

110113
const handleFailedDialogButtonClick = () => {
@@ -115,6 +118,12 @@ const HomePageContent = () => {
115118
setActiveTab(tab);
116119
}, []);
117120

121+
useEffect(() => {
122+
if (isDialogOpen && taskType === "instant") {
123+
router.prefetch(`immersion/${urgentTaskId}`);
124+
}
125+
}, [isDialogOpen, router, taskType, urgentTaskId]);
126+
118127
useEffect(() => {
119128
if (searchParams.get("dialog") === "success") {
120129
setIsDialogOpen(true);
@@ -231,6 +240,7 @@ const HomePageContent = () => {
231240
taskType={taskType}
232241
personaName={personaName}
233242
personaId={personaId}
243+
isLoading={isLoading}
234244
onClick={handleCharacterDialogButtonClick}
235245
/>
236246

src/app/(protected)/my-page/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export default function MyPage() {
2525
queryKey: ["myPage"],
2626
queryFn: async () => await fetch("/api/my-page").then((res) => res.json()),
2727
enabled: !!userData.memberId,
28-
staleTime: 1000 * 60 * 5,
2928
});
3029

3130
const handlePersonaClick = (id: number) => {

tailwind.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Config } from "tailwindcss";
2+
import animatePlugin from "tailwindcss-animate";
23

34
export default {
45
darkMode: ["class"],
@@ -209,5 +210,5 @@ export default {
209210
},
210211
},
211212
},
212-
plugins: [],
213+
plugins: [animatePlugin],
213214
} satisfies Config;

0 commit comments

Comments
 (0)