Skip to content

Commit

Permalink
Merge branch 'develop' into feature/#19-room_list
Browse files Browse the repository at this point in the history
  • Loading branch information
yongaricode authored Jan 9, 2025
2 parents 2e9e56d + 63a45c5 commit 6bb0ee0
Show file tree
Hide file tree
Showing 21 changed files with 354 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ dist-ssr
*.sw?

.DS_Store
.env
91 changes: 91 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"autoprefixer": "^10.4.20",
"axios": "^1.7.9",
"postcss": "^8.4.49",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
Empty file removed src/api/.gitkeep
Empty file.
12 changes: 12 additions & 0 deletions src/api/authApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import instance from './axios';

export const postAuthCode = async (code: string) => {
const res = await instance.post('/login', code); // 백에서 주는 url

return res.data;
};

export const postRole = async (role: string) => {
const res = await instance.post('/signup', role); // 백에서 주는 url
return res.data;
};
36 changes: 36 additions & 0 deletions src/api/axios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import axios, { AxiosInstance } from 'axios';
const baseURL = import.meta.env.VITE_BASE_URL;

const instance: AxiosInstance = axios.create({
baseURL: baseURL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});

instance.interceptors.request.use(
(config) => {
// 요청이 전달되기 전에 헤더에 토큰 추가
// 추후에 바꿔도 될 듯 => 상의 필요
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);

instance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
return Promise.reject(error);
},
);

export default instance;
Empty file removed src/assets/images/.gitkeep
Empty file.
Binary file added src/assets/images/Boy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/Kakao_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/Mom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/Teacher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/components/KakaoLoginButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Kakao_logo from '../assets/images/Kakao_logo.png';

const KakaoLoginButton = () => {
const REST_API_KEY = import.meta.env.VITE_KAKAO_REST_API;
const REDIRECT_URI = import.meta.env.VITE_KAKAO_REDIRECT_URI;
const kakaoURL = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}`;

const handleKakaoLogin = () => {
window.location.href = kakaoURL;
};

return (
<div className="flex px-4 py-6 justify-center fixed bottom-0 max-w-[500px] w-full">
<button
className="flex px-3.5 py-3 justify-center items-center flex-1 rounded-md bg-kakao"
onClick={handleKakaoLogin}
>
<div className="flex justify-center items-center gap-2 px-6">
<img className="w-4 h-4" alt="카카오 로그인" src={Kakao_logo} />
<h3>카카오로 계속하기</h3>
</div>
</button>
</div>
);
};
export default KakaoLoginButton;
36 changes: 36 additions & 0 deletions src/components/KakaoOauth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { postAuthCode } from '../api/authApi';

const KakaoOauth = () => {
const navigate = useNavigate();
const [isProcessed, setIsProcessed] = useState(false);
const code = new URL(window.location.href).searchParams.get('code');
console.log(code);

const handleAuth = async () => {
if (!code) return;

const { accessToken, status } = await postAuthCode(code);
console.log(accessToken);
console.log(status);

if (status === 'existing') {
// 이미 회원인 경우 로그인 완료 -> 메인페이지로 이동
// navigate('/');
} else if (status === 'new') {
// 신규 회원인 경우 -> 회원가입 페이지로 이동
// navigate('/signup');
}
setIsProcessed(true);
};

useEffect(() => {
if (isProcessed) return; // 이미 처리한 경우 return
handleAuth();
}, [isProcessed]);

return <div>회원인지 확인 중입니다.</div>;
};

export default KakaoOauth;
30 changes: 30 additions & 0 deletions src/components/RoleSelectionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Role } from '../utils/RoleList';
import { FaRegCheckCircle } from 'react-icons/fa';
import { FaCheckCircle } from 'react-icons/fa';

interface RoleProps {
role: Role;
onSelect: () => void;
isSelected: boolean;
}

const RoleSelectionButton = ({ role, onSelect, isSelected }: RoleProps) => {
const { title, description, src } = role;
return (
<div
className={`flex w-full justify-center items-center py-2.5 border rounded-xl gap-4 px-4 cursor-pointer ${isSelected ? 'bg-primary_100 border-primary_500' : 'border-gray-200'}`}
onClick={onSelect}
>
<div className={`flex items-center rounded-full p-1.5 ${isSelected ? 'bg-white' : 'bg-primary_100'}`}>
<img className="w-9 h-9" src={src} alt={title} />
</div>
<div className="flex flex-1 flex-col text-gray-900">
<h1 className={`text-body1 font-bold leading-9 ${isSelected ? 'text-primary_800' : ''}`}>{title}</h1>
<h3 className="text-body4 font-regular leading-6">{description}</h3>
</div>
{isSelected ? <FaCheckCircle color="#60CE3F" size={28} /> : <FaRegCheckCircle color="#AAA9A6" size={28} />}
</div>
);
};

export default RoleSelectionButton;
16 changes: 15 additions & 1 deletion src/pages/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import { useNavigate } from 'react-router-dom';
import KakaoLoginButton from '../components/KakaoLoginButton';

const Login = () => {
return <div>Login</div>;
const navigate = useNavigate();
return (
<div className="flex flex-col min-h-screen">
<div className="flex flex-col items-start px-5 py-4 text-heading6 font-bold leading-10 text-gray-900">
<div>더욱 더 편리한 과외 플랫폼</div>
<div>일정 관리부터 과제 제출까지</div>
<div>편리하게 이용하고 공유해요</div>
</div>
<div className="px-4 ">온보딩 일러스트레이션</div>
<KakaoLoginButton />
</div>
);
};

export default Login;
55 changes: 54 additions & 1 deletion src/pages/Signup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,58 @@
import instance from '../api/axios';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { postRole } from '../api/authApi';

import Header from '../components/Header';
import RoleSelectionButton from '../components/RoleSelectionButton';
import { RoleList } from '../utils/RoleList';

const Signup = () => {
return <div>Signup</div>;
const [role, setRole] = useState('');
const navigate = useNavigate();

const sendRoleToServer = async () => {
const data = await postRole(role);
console.log(data);
navigate('/');
};

const handleStart = () => {
if (!role) return;

console.log(`선택한 역할: ${role}`);
sendRoleToServer();
};

return (
<div className="flex flex-col min-h-screen">
<Header />
<div className="flex flex-col items-start py-4 px-5">
<h1 className="text-heading6 font-bold text-gray-900 leading-10">어디로 링크할까요?</h1>
<h3 className="text-body3 font-regular text-gray-600 leading-7">선택하신 정보에 따라 화면이 달라져요!</h3>
</div>
<div className="flex flex-col items-start py-6 px-4 gap-4">
{RoleList.map((item) => (
<RoleSelectionButton
key={item.id}
role={item}
onSelect={() => setRole(item.role)}
isSelected={role === item.role}
/>
))}
</div>
<div className="flex-grow" />
<div className="px-5 py-6 flex justify-center fixed bottom-0 max-w-[500px] w-full">
<button
disabled={!role}
className="flex-1 px-4 py-3.5 text-gray-400 bg-gray-50 enabled:text-black"
onClick={handleStart}
>
시작하기
</button>
</div>
</div>
);
};

export default Signup;
Loading

0 comments on commit 6bb0ee0

Please sign in to comment.