Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#86 메인페이지 필터 API 구현, Pagination 컴포넌트 추가 및 GoogleOAuth API 연동 작업 #118

Merged
merged 8 commits into from
Nov 8, 2024

Conversation

kang-kibong
Copy link
Member

Issue

close #86

Description

Pagination 컴포넌트 구현

type PaginationProps = {
  currentPage: number;
  totalPages: number;
  onPageChange: (page: number) => void;
};
  • 페이지 네비게이션을 위한 공용 Pagination 컴포넌트를 구현하였습니다.
    • currentPage: 현재 페이지 번호
    • totalPages: 전체 페이지 수
    • onPageChange: 페이지 변경 시 호출되는 핸들러
  • 현재 페이지 강조 표시 및 이전/다음 버튼 활성화/비활성화 로직을 포함하여 동작하도록 구현하였습니다.

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,
  });
}
  • Google OAuth 관련 API 호출 및 Mutation 동작만 처리하도록 설계하였습니다.
  • 응답 헤더에서 Authorization 토큰을 추출하여 반환하도록 구현하였습니다.

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 };
}
  • 인증 관련 로직 및 Google 로그인 리다이렉션 동작을 처리하도록 구현하였습니다.
  • 사용자가 Google 로그인 이후 리다이렉트된 URL에서 code를 추출하여 Mutation을 실행합니다.
  • 인증에 성공하면 다음과 같이 수행됩니다.
    • 토큰을 localStorage에 저장합니다.
    • 유저 정보(프로필 이미지, 이름, 구인/구직 여부)를 localStorage에 저장합니다.
    • 첫 사용자와 기존 사용자에 따라 다른 경로로 리다이렉트 처리합니다.

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

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

const getRecruitments = async (filter: string, page: number): Promise<RecruitmentResponse[]> => {
  const url = `${getDynamicAPIPath.getRecruitments(filter)}?page=${page}`;
  const res = await clientInstance.get<RecruitmentResponse[]>(url);
  return res.data;
};

export const useFetchRecruitments = (
  filter: string,
  page: number,
): UseSuspenseQueryResult<RecruitmentResponse[], AxiosError> => {
  return useSuspenseQuery<RecruitmentResponse[], AxiosError>({
    queryKey: [QUERY_KEYS.RECRUITMENTS, filter, page],
    queryFn: () => getRecruitments(filter, page),
  });
};

필터와 페이지 번호를 기반으로 데이터를 요청하여, 동적으로 리스트를 가져올 수 있도록 설계하였습니다.


메인페이지, 로그인, 회원가입 페이지 i18Next 번역

i18Next를 활용하여 메인 페이지, 로그인, 회원가입 관련 UI 텍스트를 번역하였습니다.

export const KO = {
  home: { ...homeData[Languages.KO] },
  signIn: { ...signInData[Languages.KO] },
  signUp: { ...signUpData[Languages.KO] },
  signUpModal: { ...signUpModalData[Languages.KO] },
	...
};

export const VE = {
  home: { ...homeData[Languages.VE] },
  signIn: { ...signInData[Languages.VE] },
  signUp: { ...signUpData[Languages.VE] },
  signUpModal: { ...signUpModalData[Languages.VE] },
  ...
};

SignUpModal은 회원가입 진행 시 사업주/근로자 역할 선택 모달에 대한 텍스트 번역에 해당합니다.


ScreenShots(optional)

Nov-08-2024 13-58-57

@YIMSEBIN YIMSEBIN merged commit f705635 into Weekly Nov 8, 2024
2 of 3 checks passed
@kang-kibong kang-kibong deleted the feat/#86 branch November 8, 2024 05:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants