Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/signup.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export type SignupPayload = {
nickname: string;
email: string;
password: string;
streakDays: number;
tilCount: number;
};

export async function signupWithEmail(p: SignupPayload) {
Expand All @@ -15,6 +17,8 @@ export async function signupWithEmail(p: SignupPayload) {
nickname: p.nickname,
email: p.email,
createdAt: serverTimestamp(),
streakDays: 0,
tilCount: 0,
});
return cred.user;
}
57 changes: 38 additions & 19 deletions app/(with-sidebar)/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,20 @@ import {
AddTodo,
toggleTodoStatus,
} from '@/lib/home/todoService';
import { getProfile, Profile } from '@/lib/home/profileService';

import { User, onAuthStateChanged } from 'firebase/auth';
import { auth } from '@/lib/firebase';

const Page = () => {
const [profile, setProfile] = useState<Profile | null>(null);
const [todos, setTodos] = useState<Todo[]>([]);

const [error, setError] = useState<string | null>(null);

// 현재 사용자 정보
const [currentUser, setCurrentUser] = useState<User | null>(null);

// 사용자 로그인 상태 감지
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setCurrentUser(user);
});

return () => unsubscribe();
}, []);

// 사용자가 존재하면 데이터 불러옴
useEffect(() => {
if (currentUser) {
loadTodos(currentUser.uid);
} else {
setTodos([]);
}
}, [currentUser]);

// 1. 할 일 목록 불러오기
const loadTodos = async (uid: string) => {
try {
Expand Down Expand Up @@ -86,6 +71,36 @@ const Page = () => {
}
};

// 사용자 로그인 상태 감지
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setCurrentUser(user);
});

return () => unsubscribe();
}, []);

// 사용자가 존재하면 데이터 불러옴
useEffect(() => {
if (currentUser) {
const loadData = async () => {
try {
const userProfile = await getProfile(currentUser.uid);
setProfile(userProfile);
await loadTodos(currentUser.uid);
} catch (err) {
console.error(err);
setError('프로필 정보를 불러오는 데 실패하였습니다');
}
};
loadData();
} else {
setTodos([]);
setProfile(null);
}
}, [currentUser]);
Comment on lines +83 to +101
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

getProfile 호출 시 에러 처리 누락

loadTodos 함수는 내부적으로 try/catch로 에러를 처리하지만, getProfile 호출은 에러 처리가 없습니다. Firestore 요청 실패 시 unhandled promise rejection이 발생할 수 있습니다.

🛠️ 에러 처리 추가 제안
   useEffect(() => {
     if (currentUser) {
       const loadData = async () => {
-        const userProfile = await getProfile(currentUser.uid);
-        setProfile(userProfile);
-
-        await loadTodos(currentUser.uid);
+        try {
+          const userProfile = await getProfile(currentUser.uid);
+          setProfile(userProfile);
+          await loadTodos(currentUser.uid);
+        } catch (err) {
+          console.error(err);
+          setError('프로필 정보를 불러오는 데 실패하였습니다');
+        }
       };
       loadData();
     } else {
       setTodos([]);
       setProfile(null);
     }
   }, [currentUser]);
🤖 Prompt for AI Agents
In `@app/`(with-sidebar)/(home)/page.tsx around lines 83 - 97, The loadData
function inside the useEffect needs to handle errors from getProfile to avoid
unhandled promise rejections: wrap the getProfile call (and subsequent
setProfile / loadTodos sequence) in a try/catch inside loadData, on error log or
surface the error (e.g., via console.error or processLogger) and
setProfile(null) and setTodos([]) as a safe fallback; keep the existing
loadTodos error handling unchanged and ensure loadData still returns/awaits
properly.


// 유저 정보가 없을 시
if (!currentUser) {
return (
<div className="flex min-h-screen items-center justify-center">
Expand All @@ -94,13 +109,17 @@ const Page = () => {
);
}

// 유저 정보가 있을 시
return (
<div className="bg-background flex min-h-screen flex-col gap-4 font-sans md:p-[137px]">
{/* 1. Header */}
<HeaderSection />

{/* 2-1. ProfileSection */}
<ProfileSection className="grid grid-cols-1 gap-4 md:grid-cols-3" />
<ProfileSection
className="grid grid-cols-1 gap-4 md:grid-cols-3"
profile={profile}
/>

{/* 2-2. GraphSection */}
<GraphSection></GraphSection>
Expand Down
14 changes: 9 additions & 5 deletions components/home/ProfileSection.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Profile } from '@/lib/home/profileService';
import Card from './Card';

interface ProfileSectionProps {
className?: string;
profile: Profile | null;
}

const ProfileSection = ({ className }: ProfileSectionProps) => {
const ProfileSection = ({ className, profile }: ProfileSectionProps) => {
return (
<div className={className}>
<div className="md:col-span-2">
Expand All @@ -14,12 +16,14 @@ const ProfileSection = ({ className }: ProfileSectionProps) => {
</div>

<div>
<h3 className="text-xl font-bold text-gray-900">이건무</h3>
<p className="text-sm text-gray-500">@mnmnnmm324</p>
<h3 className="text-xl font-bold text-gray-900">
{profile?.nickname}
</h3>
<p className="text-sm text-gray-500">{profile?.email}</p>
<div className="mt-1 flex gap-2 text-xs font-medium">
<span className="text-primary">38193일 </span>연속
<span className="text-primary">{profile?.streakDays}일 </span>연속
<span className="text-gray-400">|</span>
<span className="text-primary">12개 </span>TIL
<span className="text-primary">{profile?.tilCount}개 </span>TIL
</div>
</div>
</Card>
Expand Down
22 changes: 22 additions & 0 deletions lib/home/profileService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { doc, getDoc } from 'firebase/firestore';
import { db } from '../firebase';

// 프로필 데이터 타입
export interface Profile {
nickname: string;
email: string;
streakDays: number;
tilCount: number;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// 1. 유저 프로필 정보 가져오기
export const getProfile = async (uid: string): Promise<Profile | null> => {
const userDocRef = doc(db, 'users', uid);
const docSnap = await getDoc(userDocRef);

if (docSnap.exists()) {
return docSnap.data() as Profile;
} else return null;
};

// 2. 사용자 프로필 정보 업데이트
2 changes: 1 addition & 1 deletion lib/home/todoService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface Todo {
// 1. 할 일 목록 가져오기
export const fetchTodos = async (uid: string): Promise<Todo[]> => {
const todosCollectionPath = collection(db, 'users', uid, 'todos');
const q = query(todosCollectionPath, orderBy('createAt', 'desc'));
const q = query(todosCollectionPath, orderBy('createAt', 'asc'));
const snapshot = await getDocs(q);

return snapshot.docs.map((doc) => ({
Expand Down