Pagination 컴포넌트 구현

type PaginationProps = {
  currentPage: number;
  totalPages: number;
  onPageChange: (page: number) => void;
};

GoogleOAuth 훅 리팩토링

기존의 useGoogleAuth 훅에서 모든 동작을 포함했던 구조를 개선하여 역할을 분리하였습니다.

useGoogleAuthMutaion

const postOAuth = async ({ code }: OAuthRequest): Promise<OAuthResponse> => {
  const res = await clientInstance.post(APIPath.postOAuth, { code });

  const authorizationHeader = res.headers['authorization'];
  const accessToken = authorizationHeader.replace('Bearer ', '');

  if (!accessToken) {
    throw new Error('Authorization header is missing in the response');
  }

  return {
    accessToken,
    type: res.data.type,
    profileImage: res.data.profileImage,
    name: res.data.name,
  };
};

export function useGoogleOAuthMutation() {
  return useMutation<OAuthResponse, AxiosError, OAuthRequest>({
    mutationFn: postOAuth,
  });
}

useGoogleAuth

const googleClientId = import.meta.env.VITE_GOOGLE_AUTH_CLIENT_ID;
const googleRedirectUri = import.meta.env.VITE_GOOGLE_AUTH_REDIRECT_URI;
const googleAuthUri = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${googleClientId}&redirect_uri=${googleRedirectUri}&response_type=code&scope=email%20profile`;

const getAccessTokenFromUrl = () => {
  const searchParams = new URLSearchParams(window.location.search);
  return searchParams.get('code');
};

export function useGoogleOAuth() {
  const [isLoading, setIsLoading] = useState(false);
  const navigate = useNavigate();
  const { mutate } = useGoogleOAuthMutation();

  const redirectToGoogleLogin = useCallback(() => {
    window.location.href = googleAuthUri;
  }, []);

  const handleLogin = useCallback(() => {
    const token = getAccessTokenFromUrl();

    if (token) {
      setIsLoading(true);
      mutate(
        { code: token },
        {
          onSuccess: (data: OAuthResponse) => {
            const { accessToken, type, profileImage, name } = data;
            localStorage.setItem('token', accessToken);
            localStorage.setItem('user', JSON.stringify({ profileImage, name, type }));

            if (type === 'first') {
              navigate(ROUTE_PATH.AUTH.SIGN_UP);
            } else {
              navigate(ROUTE_PATH.HOME);
            }

            window.location.reload();
          },
          onError: (error) => {
            console.error('Error during login:', error);
            alert('로그인에 실패했습니다. 다시 시도해주세요.');
            setIsLoading(false);
          },
        },
      );
    }
  }, [mutate, navigate]);

  useEffect(() => {
    handleLogin();
  }, [handleLogin]);

  return { isLoading, redirectToGoogleLogin };
}

메인 구인/구직 리스트 API 구현

사용자가 선택한 필터(filter)와 페이지 번호(page)에 따라 구인/구직 리스트를 요청할 수 있도록 구현하였습니다.