Skip to content

Commit

Permalink
Merge pull request #113 from kakao-tech-campus-2nd-step3/feat/#94-log…
Browse files Browse the repository at this point in the history
…in-kakao

로그인, 유저 모드 api 연결 #94
  • Loading branch information
joojjang authored Nov 14, 2024
2 parents c8fe67a + 4baa060 commit 60a49d7
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/apis/instance/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios';

const BASE_URL = import.meta.env.VITE_APP_BASE_URL;
const BASE_URL = `${import.meta.env.VITE_APP_BASE_URL}/v1`;

const initInstance = (config: AxiosRequestConfig): AxiosInstance => {
const instance = axios.create({
Expand Down
1 change: 1 addition & 0 deletions src/apis/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const QUERY_KEYS = {
LOGIN: 'login',
FEED: 'feed',
FOLLOW_LIST: 'followList',
USER_INFO: 'userInfo',
Expand Down
38 changes: 38 additions & 0 deletions src/apis/users/getUserMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// import { useQuery } from '@tanstack/react-query';
import { isAxiosError } from 'axios';

import fetchInstance from '../fetchInstance';
// import QUERY_KEYS from '../queryKeys';

type UserModeResponse = { role: string; userType: string };

async function getUserMode(): Promise<UserModeResponse> {
try {
const response = await fetchInstance().get('/users/type');

return response.data.data; // todo: dto 확인하기, 타입이 뭔지 확인
} catch (error) {
if (isAxiosError(error)) {
if (error.response) {
throw new Error(error.response.data.message || 'user mode 가져오기 실패');
} else {
throw new Error('네트워크 오류 또는 서버에 연결할 수 없습니다.');
}
} else {
throw new Error('알 수 없는 오류입니다.');
}
}
}

// const useGetFollow = () => {
// const { data, status, refetch } = useQuery<APIResponse<FollowResponse>, Error>({
// queryKey: [QUERY_KEYS.FOLLOW_LIST],
// queryFn: getFollow,
// });

// return { data, status, refetch };
// };

// export default useGetFollow;

export default getUserMode;
18 changes: 16 additions & 2 deletions src/pages/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import { useEffect, useState } from 'react';

import getUserMode from '@/apis/users/getUserMode';
import SearchModal from '@/components/common/SearchModal';
import Footer from '@/components/layouts/Footer';
import Header from '@/components/layouts/Header';
import { AD_LIST, ARTICLE_LIST } from '@/constants/home';
import { HEIGHTS } from '@/styles/constants';
import { setTokens } from '@/utils/queryParams';
import AdBanner from './components/AdBanner';
import ArticleBanner from './components/ArticleBanner';

const Home = () => {
const [isModalOpen, setIsModalOpen] = useState(false);

useEffect(() => {
const initializeTokensAndUserMode = async () => {
await setTokens();

const accessToken = localStorage.getItem('accessToken');
if (accessToken) {
getUserMode();
}
};

initializeTokensAndUserMode();
}, []);

const handleModalOpen = () => {
setIsModalOpen(true);
};

return (
<Wrapper>
{isModalOpen && <SearchModal modalClose={() => setIsModalOpen(false)} />}

<Header modalOpen={handleModalOpen} />
<AdBanner adList={AD_LIST} />
{ARTICLE_LIST.map((item) => (
Expand Down
31 changes: 31 additions & 0 deletions src/pages/Login/components/KakaoLoginButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import styled from '@emotion/styled';

import KakaoSymbol from '@/assets/kakao-symbol.svg?react';

type KakaoLoginButtonProps = {
onClick: () => void;
};

const KakaoLoginButton = ({ onClick }: KakaoLoginButtonProps) => {
return (
<StyledKakaoLoginButton onClick={onClick}>
<KakaoSymbol />
카카오로 시작하기
</StyledKakaoLoginButton>
);
};

export default KakaoLoginButton;

const StyledKakaoLoginButton = styled.button`
display: inline-flex;
justify-content: center;
align-items: center;
margin: 0 16px;
padding: 10px 50px;
background-color: var(--color-yellow-kakao);
border-radius: var(--border-radius);
gap: 16px;
font-size: var(--font-size-md);
font-weight: 500;
`;
42 changes: 7 additions & 35 deletions src/pages/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@ import { Text } from '@chakra-ui/react';
import styled from '@emotion/styled';
import { useNavigate } from 'react-router-dom';

import KakaoSymbol from '@/assets/kakao-symbol.svg?react';
// import { getKakaoLgoin } from '@/apis/login/useGetKakaoLogin';
import Logo from '@/assets/logo.svg?react';
import IconButton from '@/components/common/IconButton';
import Header from '@/components/layouts/Header';
import { BACKGROUND_IMAGE_LIST } from '@/constants/login';
import { RouterPath } from '@/routes/path';
import { HEIGHTS } from '@/styles/constants';
import KakaoLoginButton from './components/KakaoLoginButton';

const Login = () => {
const isMember = false; // 추후 API 연동
const navigate = useNavigate();

// 랜덤 배경이미지
const randomIndex = Math.floor(Math.random() * BACKGROUND_IMAGE_LIST.length);
const backgroundImage = BACKGROUND_IMAGE_LIST[randomIndex].src;
const backgroundImageCreator = BACKGROUND_IMAGE_LIST[randomIndex].creator;

const handleLogin = () => {
window.location.href = `http://golden-ratio.duckdns.org/oauth2/login/kakao`; // 외부 경로로 리다이렉트
};

return (
<Wrapper backgroundImage={backgroundImage}>
<Header
Expand All @@ -40,7 +44,7 @@ const Login = () => {
그 무한은 숨겨진 가치를 밝혀줍니다. <br />
예술 속에 숨겨진 가치를 찾아드립니다.
</Text>
<KakaoLoginButton isMember={isMember} />
<KakaoLoginButton onClick={handleLogin} />
</ContentWrapper>
<Text
fontSize="var(--font-size-xs)"
Expand All @@ -57,25 +61,6 @@ const Login = () => {

export default Login;

type KakaoLoginButtonProps = { isMember: boolean };

const KakaoLoginButton = ({ isMember }: KakaoLoginButtonProps) => {
const navigate = useNavigate();

const handleLogin = () => {
if (!isMember) {
navigate(`/${RouterPath.signup}`);
}
};

return (
<StyledKakaoLoginButton onClick={handleLogin}>
<KakaoSymbol />
카카오로 시작하기
</StyledKakaoLoginButton>
);
};

const Wrapper = styled.div<{ backgroundImage: string }>`
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -110,16 +95,3 @@ const ContentWrapper = styled.div`
}
}
`;

const StyledKakaoLoginButton = styled.button`
display: inline-flex;
justify-content: center;
align-items: center;
margin: 0 16px;
padding: 10px 50px;
background-color: var(--color-yellow-kakao);
border-radius: var(--border-radius);
gap: 16px;
font-size: var(--font-size-md);
font-weight: 500;
`;
7 changes: 6 additions & 1 deletion src/pages/Signup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import IconButton from '@/components/common/IconButton';
Expand All @@ -9,6 +9,7 @@ import useStudentArtistStore from '@/store/useStudentArtistStore';
import useUserStore from '@/store/useUserStore';
import { HEIGHTS } from '@/styles/constants';
import type { Mode } from '@/types';
import { setTokens } from '@/utils/queryParams';
import SellerProgress from './progresses/ArtistProgress';
import DefaultProgress from './progresses/DefaultProgress';
import UserProgress from './progresses/UserProgress';
Expand All @@ -20,6 +21,10 @@ const Signup = () => {
const [memberType, setMemberType] = useState<Mode | undefined>();
const [progressStep, setProgressStep] = useState<'default' | Mode>('default');

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

const handleMemberTypeSelection = (type: Mode) => {
setMemberType(type);
setProgressStep(type === 'user' ? 'user' : 'artist');
Expand Down
15 changes: 14 additions & 1 deletion src/utils/queryParams.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export function getQueryParams(params: Record<any, any>) {
// query param으로 만들어 반환
export function getQueryParams(params: Record<any, any>): URLSearchParams {
const queryParams = new URLSearchParams();

Object.entries(params).forEach(([key, value]) => {
Expand All @@ -9,3 +10,15 @@ export function getQueryParams(params: Record<any, any>) {
// 'param1=param1&param2=param2' 형식으로 반환
return queryParams;
}

// 로그인 후 호출되어 query param의 토큰을 로컬 스토리지에 저장
export function setTokens(): void {
const queryParams = new URLSearchParams(window.location.search);
const accessToken = queryParams.get('accessToken');
const refreshToken = queryParams.get('refreshToken');

if (accessToken && refreshToken) {
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
}
}

0 comments on commit 60a49d7

Please sign in to comment.