- {visible.map(({ userId, src, username }) => (
-
handleProfileClick(userId)}>
-

-
{username}
+ {visible.map(({ userId, profileImageUrl, nickname }) => (
+
handleProfileClick(userId)}>
+

+
{nickname}
))}
diff --git a/src/components/feed/UserProfileItem.tsx b/src/components/feed/UserProfileItem.tsx
index a7ea0c83..d4c16639 100644
--- a/src/components/feed/UserProfileItem.tsx
+++ b/src/components/feed/UserProfileItem.tsx
@@ -56,7 +56,7 @@ const UserProfileItem = ({
)}
{type === 'followerlist' && (
-
{followerCount}명이 띱하는 중
+
{followerCount ?? 0}명이 띱하는 중
)}
diff --git a/src/hooks/useOAuthToken.ts b/src/hooks/useOAuthToken.ts
new file mode 100644
index 00000000..3cd202d0
--- /dev/null
+++ b/src/hooks/useOAuthToken.ts
@@ -0,0 +1,37 @@
+import { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { apiClient } from '@/api/index';
+
+export const useOAuthToken = () => {
+ const [isTokenRequested, setIsTokenRequested] = useState(false);
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ const params = new URLSearchParams(window.location.search);
+ const loginTokenKey = params.get('loginTokenKey');
+
+ if (loginTokenKey && !isTokenRequested) {
+ console.log('=== 🔑 소셜 로그인 토큰 발급 요청 ===');
+ console.log('📋 인가코드:', loginTokenKey);
+
+ setIsTokenRequested(true);
+
+ // 서버에 토큰 발급 요청
+ apiClient
+ .post('/oauth-success', { loginTokenKey }, { withCredentials: true })
+ .then(response => {
+ console.log('✅ 토큰 발급 성공:', response.data);
+ // URL에서 code 파라미터 제거
+ const newUrl = window.location.pathname;
+ window.history.replaceState({}, document.title, newUrl);
+ })
+ .catch(error => {
+ console.error('❌ 토큰 발급 실패:', error);
+ // 에러 발생 시 로그인 페이지로 이동
+ navigate('/');
+ });
+ }
+ }, [isTokenRequested, navigate]);
+
+ return { isTokenRequested };
+};
diff --git a/src/hooks/useUserSearch.ts b/src/hooks/useUserSearch.ts
index be7e6c5d..49fad7be 100644
--- a/src/hooks/useUserSearch.ts
+++ b/src/hooks/useUserSearch.ts
@@ -6,9 +6,15 @@ interface UseUserSearchProps {
keyword: string;
size?: number;
delay?: number;
+ isFinalized?: boolean;
}
-export const useUserSearch = ({ keyword, size = 10, delay = 300 }: UseUserSearchProps) => {
+export const useUserSearch = ({
+ keyword,
+ size = 10,
+ delay = 300,
+ isFinalized = false,
+}: UseUserSearchProps) => {
const [userList, setUserList] = useState
([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
@@ -27,10 +33,10 @@ export const useUserSearch = ({ keyword, size = 10, delay = 300 }: UseUserSearch
try {
setLoading(true);
setError(null);
-
const response = await getUsers({
keyword: searchKeyword,
size,
+ isFinalized,
});
const newUserList = response.data.userList;
@@ -49,7 +55,7 @@ export const useUserSearch = ({ keyword, size = 10, delay = 300 }: UseUserSearch
setLoading(false);
}
},
- [size],
+ [size, isFinalized],
);
// 디바운스된 키워드가 변경될 때 검색 실행
diff --git a/src/pages/feed/Feed.tsx b/src/pages/feed/Feed.tsx
index 08da8f6e..7c8e3be7 100644
--- a/src/pages/feed/Feed.tsx
+++ b/src/pages/feed/Feed.tsx
@@ -9,6 +9,7 @@ import writefab from '../../assets/common/writefab.svg';
import { useNavigate, useLocation } from 'react-router-dom';
import { getTotalFeeds } from '@/api/feeds/getTotalFeed';
import { getMyFeeds } from '@/api/feeds/getMyFeed';
+import { useOAuthToken } from '@/hooks/useOAuthToken';
import type { PostData } from '@/types/post';
const tabs = ['피드', '내 피드'];
@@ -19,6 +20,9 @@ const Feed = () => {
const initialTabFromState = (location.state as { initialTab?: string } | null)?.initialTab;
const [activeTab, setActiveTab] = useState(initialTabFromState ?? tabs[0]);
+ // 소셜 로그인 토큰 발급 처리
+ useOAuthToken();
+
// 최초 마운트 시에만 history state 제거하여 이후 재방문 시 영향 없도록 처리
useEffect(() => {
if (initialTabFromState) {
diff --git a/src/pages/feed/UserSearch.tsx b/src/pages/feed/UserSearch.tsx
index 5cbb4a68..ded4c001 100644
--- a/src/pages/feed/UserSearch.tsx
+++ b/src/pages/feed/UserSearch.tsx
@@ -20,6 +20,7 @@ const UserSearch = () => {
keyword: searchTerm,
size: 20,
delay: 300,
+ isFinalized: isSearched,
});
const [recentSearches, setRecentSearches] = useState([
diff --git a/src/pages/signup/SignupGenre.tsx b/src/pages/signup/SignupGenre.tsx
index 5d4984c3..2ac65561 100644
--- a/src/pages/signup/SignupGenre.tsx
+++ b/src/pages/signup/SignupGenre.tsx
@@ -1,11 +1,9 @@
import { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
-import { useCookies } from 'react-cookie';
import { Container } from './Signup.styled';
import leftarrow from '../../assets/common/leftArrow.svg';
import TitleHeader from '../../components/common/TitleHeader';
import { postSignup } from '@/api/users/postSignup';
-import { apiClient } from '@/api/index';
const SignupGenre = () => {
const [genres, setGenres] = useState<
@@ -23,73 +21,27 @@ const SignupGenre = () => {
} | null>(null);
const navigate = useNavigate();
const location = useLocation();
- const [cookies] = useCookies(['Authorization']);
// SignupNickname에서 넘어온 nickname 받기
const nickname = location.state?.nickname;
- // react-cookie를 사용하여 Authorization 토큰 추출
- const getAuthTokenFromCookie = () => {
- console.log('=== react-cookie 디버깅 ===');
- console.log('현재 페이지 URL:', window.location.href);
- console.log('현재 도메인:', window.location.hostname);
- console.log('react-cookie로 읽은 Authorization:', cookies.Authorization);
-
- if (cookies.Authorization) {
- console.log('react-cookie로 Authorization 토큰 발견:', cookies.Authorization);
- return cookies.Authorization;
- }
-
- // 방법 2: 직접 쿠키 이름으로 검색
- const authCookie = document.cookie
- .split(';')
- .find(cookie => cookie.trim().startsWith('Authorization='));
-
- if (authCookie) {
- const token = authCookie.split('=')[1];
- console.log('직접 검색으로 Authorization 토큰 발견:', token);
- return token;
- }
-
- // 방법 3: 정규식으로 검색
- const cookieMatch = document.cookie.match(/Authorization=([^;]+)/);
- if (cookieMatch && cookieMatch[1]) {
- console.log('정규식으로 Authorization 토큰 발견:', cookieMatch[1]);
- return cookieMatch[1];
- }
-
- // 방법 4: 모든 쿠키를 순회하며 검색
- const allCookies = document.cookie.split(';');
- for (let i = 0; i < allCookies.length; i++) {
- const cookie = allCookies[i].trim();
- if (cookie.startsWith('Authorization=')) {
- const token = cookie.substring('Authorization='.length);
- console.log('순회 검색으로 Authorization 토큰 발견:', token);
- return token;
- }
- }
-
- // 방법 5: 쿠키가 비어있는지 확인
- if (!document.cookie || document.cookie.trim() === '') {
- console.log('document.cookie가 비어있습니다.');
+ // 페이지 로드 시 간단한 확인
+ useEffect(() => {
+ console.log('=== 🔍 SignupGenre 페이지 로드 ===');
+ console.log('📍 현재 페이지:', window.location.pathname);
+ console.log('👤 받은 nickname:', nickname);
+
+ // nickname이 없으면 이전 페이지로 돌아가기
+ if (!nickname) {
+ console.log('❌ nickname이 전달되지 않았습니다.');
+ console.log('❌ 이전 페이지로 돌아갑니다.');
+ navigate(-1);
+ return;
}
- // 방법 6: 쿠키 길이 확인
- console.log('쿠키 총 길이:', document.cookie.length);
- console.log('쿠키 원본 문자열:', JSON.stringify(document.cookie));
-
- console.log('react-cookie로 Authorization 토큰을 찾을 수 없습니다.');
- return null;
- };
-
- // 토큰을 헤더에 설정
- const setAuthTokenToHeader = (token: string) => {
- // localStorage에 저장 (페이지 새로고침 시에도 유지)
- localStorage.setItem('authToken', token);
-
- // apiClient 기본 헤더에 설정
- apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`;
- };
+ console.log('✅ nickname이 정상적으로 전달되었습니다.');
+ console.log('✅ 쿠키는 브라우저가 자동으로 처리합니다.');
+ }, [nickname, navigate]);
useEffect(() => {
fetch('/genres.json')
@@ -105,27 +57,20 @@ const SignupGenre = () => {
const handleNextClick = async () => {
if (!selectedAlias || !nickname) return;
- // 쿠키에서 토큰 추출
- const authToken = getAuthTokenFromCookie();
- if (!authToken) {
- console.log('쿠키에서 Authorization 토큰을 찾을 수 없습니다.');
- console.log('토큰이 없어 회원가입을 진행할 수 없습니다.');
- return; // 토큰이 없으면 함수 종료하여 페이지에 머무름
- }
-
- // 토큰을 헤더에 설정
- setAuthTokenToHeader(authToken);
- console.log('Authorization 토큰을 헤더에 설정했습니다.');
+ console.log('=== 🚀 다음 버튼 클릭 ===');
+ console.log('🎭 선택된 alias:', selectedAlias);
+ console.log('👤 nickname:', nickname);
try {
+ console.log('🚀 postSignup API 호출 시작...');
+ // ✅ 쿠키는 브라우저가 자동으로 전송
const result = await postSignup({
aliasName: selectedAlias.subTitle,
nickName: nickname,
});
if (result.success) {
- console.log('회원가입 성공! 사용자 ID:', result.data.userId);
- // 회원가입 완료 페이지로 이동
+ console.log('🎉 회원가입 성공! 사용자 ID:', result.data.userId);
navigate('/signupdone', {
state: {
aliasName: selectedAlias.subTitle,
@@ -133,10 +78,10 @@ const SignupGenre = () => {
},
});
} else {
- console.error('회원가입 실패:', result.message);
+ console.error('❌ 회원가입 실패:', result.message);
}
} catch (error) {
- console.error('회원가입 중 오류 발생:', error);
+ console.error('💥 회원가입 중 오류 발생:', error);
}
};
diff --git a/src/pages/signup/SignupNickname.tsx b/src/pages/signup/SignupNickname.tsx
index 63cd7dc4..49d59feb 100644
--- a/src/pages/signup/SignupNickname.tsx
+++ b/src/pages/signup/SignupNickname.tsx
@@ -1,8 +1,9 @@
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Container, InputBox, StyledInput, CharCount } from './Signup.styled';
import Header from '../../components/common/TitleHeader';
import { postNickname } from '@/api/users/postNickname';
+import { useOAuthToken } from '@/hooks/useOAuthToken';
const SignupNickname = () => {
const [nickname, setNickname] = useState('');
@@ -10,8 +11,18 @@ const SignupNickname = () => {
const maxLength = 10;
const navigate = useNavigate();
+ // 소셜 로그인 토큰 발급 처리
+ useOAuthToken();
+
const isNextActive = nickname.length >= 2 && nickname.length <= maxLength;
+ // 페이지 로드 시 간단한 확인
+ useEffect(() => {
+ console.log('=== 🔍 SignupNickname 페이지 로드 ===');
+ console.log('📍 현재 페이지:', window.location.pathname);
+ console.log('✅ 토큰 발급 후 쿠키는 브라우저가 자동으로 처리합니다.');
+ }, []);
+
const handleBackClick = () => {
navigate(-1);
};
@@ -20,18 +31,24 @@ const SignupNickname = () => {
if (!isNextActive) return;
setError('');
+ console.log('=== 🚀 닉네임 검증 시작 ===');
+ console.log('👤 입력된 닉네임:', nickname);
+
try {
+ // ✅ 쿠키는 브라우저가 자동으로 전송
const result = await postNickname(nickname);
if (result.data.isVerified) {
+ console.log('✅ 닉네임 검증 성공!');
// 닉네임 검증 성공 - 다음 단계로 진행
navigate('/signup/genre', { state: { nickname } });
} else {
+ console.log('❌ 닉네임 검증 실패 - 이미 사용중');
// 닉네임 검증 실패 - 우리가 정한 에러 메시지
setError('이미 사용중인 닉네임이에요.');
}
} catch (error) {
- console.error('닉네임 검증 실패:', error);
+ console.error('💥 닉네임 검증 중 오류 발생:', error);
setError('닉네임 검증 중 오류가 발생했습니다.');
}
};