diff --git a/next.config.ts b/next.config.ts
index a20f13a9..9ae4dc70 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -11,11 +11,12 @@ const nextConfig: NextConfig = {
{ protocol: "https", hostname: "static.toss.im" },
{ protocol: "https", hostname: "windfall-bucket.s3.ap-northeast-2.amazonaws.com" },
{ protocol: "https", hostname: "wind-fall.store" },
+ { protocol: "http", hostname: "img1.kakaocdn.net" },
{ protocol: "http", hostname: "phinf.pstatic.net" },
- { protocol: "https", hostname: "phinf.pstatic.net" },
{ protocol: "http", hostname: "ssl.pstatic.net" },
- { protocol: "https", hostname: "ssl.pstatic.net" },
{ protocol: "http", hostname: "lh3.googleusercontent.com" },
+ { protocol: "https", hostname: "phinf.pstatic.net" },
+ { protocol: "https", hostname: "ssl.pstatic.net" },
{ protocol: "https", hostname: "lh3.googleusercontent.com" },
],
},
diff --git a/src/app/(protected)/users/[userId]/[tab]/page.tsx b/src/app/(protected)/users/[userId]/[tab]/page.tsx
index a81ea0f6..dad43623 100644
--- a/src/app/(protected)/users/[userId]/[tab]/page.tsx
+++ b/src/app/(protected)/users/[userId]/[tab]/page.tsx
@@ -1,3 +1,4 @@
+import { getUserProfileServer } from "@/entities/user/api/user-api.server";
import { UserTabContent } from "@/screens/user";
interface PageProps {
@@ -9,8 +10,8 @@ interface PageProps {
export default async function Page({ params }: PageProps) {
const { userId, tab } = await params;
-
const targetUserId = Number(userId);
+ const profile = await getUserProfileServer(targetUserId);
- return ;
+ return ;
}
diff --git a/src/app/(protected)/users/[userId]/layout.tsx b/src/app/(protected)/users/[userId]/layout.tsx
index 136011ac..32292eee 100644
--- a/src/app/(protected)/users/[userId]/layout.tsx
+++ b/src/app/(protected)/users/[userId]/layout.tsx
@@ -31,7 +31,7 @@ export default async function UserLayout({ children, params }: LayoutProps) {
return (
-
+
{children}
diff --git a/src/entities/user/api/user-api.server.ts b/src/entities/user/api/user-api.server.ts
index 0b82ab9a..978bddad 100644
--- a/src/entities/user/api/user-api.server.ts
+++ b/src/entities/user/api/user-api.server.ts
@@ -4,6 +4,7 @@ import { fetch as apiFetch } from "@/shared/api/server";
import { API_ENDPOINTS } from "@/shared/config/endpoints";
interface UserApiResponse {
+ userId: number;
username: string;
email: string;
profileImage: string | null;
@@ -30,9 +31,10 @@ export const getUserProfileServer = async (targetUserId: number) => {
const { data } = response;
- if (!data) return null;
+ if (!data) return undefined;
return {
+ userId: data.userId,
name: data.username,
email: data.email,
avatarUrl: data.profileImage || undefined,
@@ -41,6 +43,6 @@ export const getUserProfileServer = async (targetUserId: number) => {
isOwner: data.isOwner,
};
} catch {
- return null;
+ return undefined;
}
};
diff --git a/src/screens/user/ui/user-tab-content.tsx b/src/screens/user/ui/user-tab-content.tsx
index c5231d52..3b1f5833 100644
--- a/src/screens/user/ui/user-tab-content.tsx
+++ b/src/screens/user/ui/user-tab-content.tsx
@@ -6,6 +6,7 @@ import dynamic from "next/dynamic";
import { notFound } from "next/navigation";
import { DASHBOARD_TABS, type TabIdType } from "@/entities/user";
+import { UserProfileType } from "@/entities/user";
import { TabLabelHeader } from "@/features/user";
import { useUserProfile } from "@/features/user/api/use-my-profile";
import { CommonItemTabSkeleton, ReviewTabSkeleton, CalendarTabSkeleton } from "@/widgets/user";
@@ -68,9 +69,10 @@ function isValidTabId(id: string): id is TabIdType {
interface UserTabContentProps {
tabId: string;
targetUserId: number;
+ initialData: UserProfileType | undefined;
}
-export function UserTabContent({ tabId, targetUserId }: UserTabContentProps) {
+export function UserTabContent({ tabId, targetUserId, initialData }: UserTabContentProps) {
if (!isValidTabId(tabId)) notFound();
const currentTabId = tabId;
@@ -79,7 +81,12 @@ export function UserTabContent({ tabId, targetUserId }: UserTabContentProps) {
const currentTabConfig = DASHBOARD_TABS.find((t) => t.id === currentTabId);
if (!currentTabConfig) notFound();
- const { data: profile, isLoading, isFetching, isPending } = useUserProfile(targetUserId);
+ const {
+ data: profile,
+ isLoading,
+ isFetching,
+ isPending,
+ } = useUserProfile(targetUserId, initialData);
// 핵심: 프로필/권한이 "확정"되기 전에는 비공개 판정을 하지 말고
// 서버/클라 동일하게 스켈레톤을 렌더해서 트리를 고정한다.
diff --git a/src/widgets/user/ui/user-dashboard-header.tsx b/src/widgets/user/ui/user-dashboard-header.tsx
index d2b04a75..89d11151 100644
--- a/src/widgets/user/ui/user-dashboard-header.tsx
+++ b/src/widgets/user/ui/user-dashboard-header.tsx
@@ -2,15 +2,21 @@
import { useParams } from "next/navigation";
-import { DASHBOARD_TABS } from "@/entities/user";
+import { DASHBOARD_TABS, UserProfileType } from "@/entities/user";
import { ActivityTabs, UserProfileCard } from "@/features/user";
import { useUserProfile } from "@/features/user/api/use-my-profile";
-export function UserDashboardHeader({ targetUserId }: { targetUserId: number }) {
+interface UserDashboardHeaderProps {
+ targetUserId: number;
+ initialData?: UserProfileType; // initial user profile data used before fetching
+}
+
+export function UserDashboardHeader({ targetUserId, initialData }: UserDashboardHeaderProps) {
const params = useParams();
const activeTab = (params.tab as string) || "calendar";
- const { data: profile, isLoading } = useUserProfile(targetUserId);
+ const { data: profile, isLoading } = useUserProfile(targetUserId, initialData);
+
if (isLoading) {
return (