diff --git a/package-lock.json b/package-lock.json index a9e8b5a..c65dcdf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@types/react-datepicker": "^4.4.2", "@types/react-dom": "^18.0.5", "axios": "^0.27.2", + "http-proxy-middleware": "^2.0.6", "lodash": "^4.17.21", "react": "^18.2.0", "react-datepicker": "^4.8.0", diff --git a/package.json b/package.json index f0df93f..ae121e7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "frontend", "version": "0.1.0", "private": true, - "proxy": "http://localhost:8080", "dependencies": { "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", @@ -14,6 +13,7 @@ "@types/react-datepicker": "^4.4.2", "@types/react-dom": "^18.0.5", "axios": "^0.27.2", + "http-proxy-middleware": "^2.0.6", "lodash": "^4.17.21", "react": "^18.2.0", "react-datepicker": "^4.8.0", diff --git a/src/api/Apis.tsx b/src/api/Apis.tsx index 3471626..998efa9 100644 --- a/src/api/Apis.tsx +++ b/src/api/Apis.tsx @@ -3,9 +3,10 @@ import { ICreateMessage } from '../types'; import { getApi, postApi, putApi, deleteApi } from './baseApi'; // 로그인 api -export const kakaoLoginApi = (code: string) => { +export const kakaoLoginApi = async (code: string) => { const url = `kakaoLogin?code=${code}`; - const data = getApi(url); + const data = await getApi(url); + console.log(data); return data; }; diff --git a/src/components/Layout/Sidebar.tsx b/src/components/Layout/Sidebar.tsx index 971237f..893b3b9 100644 --- a/src/components/Layout/Sidebar.tsx +++ b/src/components/Layout/Sidebar.tsx @@ -2,8 +2,7 @@ import axios from 'axios'; import React, { useRef, useEffect } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import styled from 'styled-components'; -import { deleteUser } from '../../api/Apis'; -import { User } from '../common/interface'; +import { useUserDispatch } from '../../contexts/UserContext'; const SideBarWrap = styled.div` background-color: #ffe2e2; @@ -41,8 +40,9 @@ const QuitMenu = styled.span` function Sidebar({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: any }) { const outside = useRef(); - const userInfo = localStorage.getItem('user'); + const userInfo = localStorage.getItem('token'); const navigate = useNavigate(); + const dispatch = useUserDispatch(); useEffect(() => { document.addEventListener('mousedown', handlerOutside); @@ -65,9 +65,8 @@ function Sidebar({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: any }) { // 회원 탈퇴 api try { const { data } = await axios.delete( - `/user/${user.id}?socialLoginType=${social}` + `${process.env.REACT_APP_API_URL}/user/${user.id}?socialLoginType=${social}` ); - console.log(data); if (data.deleteUser) { alert('탈퇴 되었습니다.'); // 구글로그인 탈퇴인 경우 redirect @@ -89,6 +88,9 @@ function Sidebar({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: any }) { // 로그아웃 const handelLogout = () => { localStorage.clear(); + dispatch({ + type: 'REMOVE' + }); }; const toggleSide = () => { diff --git a/src/components/common/interface.ts b/src/components/common/interface.ts index 75bd5e7..ffff475 100644 --- a/src/components/common/interface.ts +++ b/src/components/common/interface.ts @@ -12,6 +12,7 @@ export interface User { } export interface NicknameProps { - email: string; + socialId: string; socialLoginType: number; + refreshToken: string; } diff --git a/src/contexts/UserContext.tsx b/src/contexts/UserContext.tsx new file mode 100644 index 0000000..521c35c --- /dev/null +++ b/src/contexts/UserContext.tsx @@ -0,0 +1,62 @@ +import { createContext, Dispatch, useContext, useReducer } from 'react'; +import { User } from '../components/common/interface'; + +type UserState = User; + +const initailState: User = { + id: 0, + email: '', + nickname: '' +}; + +const UserStateContext = createContext(undefined); + +type Action = { type: 'CREATE'; user: User } | { type: 'REMOVE' }; + +type UserDispatch = Dispatch; +const UserDispatchContext = createContext(undefined); + +function userReducer(state: UserState, action: Action): UserState { + switch (action.type) { + case 'CREATE': + return { + ...state, + id: action.user.id, + email: action.user.email, + nickname: action.user.nickname + }; + case 'REMOVE': + return { + ...state, + ...initailState + }; + default: + throw new Error('Unhandled action'); + } +} +export function UserContextProvider({ + children +}: { + children: React.ReactNode; +}) { + const [user, dispatch] = useReducer(userReducer, initailState); + return ( + + + {children} + + + ); +} + +export function useUserState() { + const state = useContext(UserStateContext); + if (!state) throw new Error('UserProvider not found'); + return state; +} + +export function useUserDispatch() { + const dispatch = useContext(UserDispatchContext); + if (!dispatch) throw new Error('UserProvider not found'); + return dispatch; +} diff --git a/src/pages/AnniversaryManagement.tsx b/src/pages/AnniversaryManagement.tsx index ab67b43..f9f56c7 100644 --- a/src/pages/AnniversaryManagement.tsx +++ b/src/pages/AnniversaryManagement.tsx @@ -216,7 +216,7 @@ const CategoryWarningSpan = styled.span` `; interface ICategoryButtonProps { - index: number | null; + index: number | undefined; currentCategory: number | null; } diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 931c1ab..1220b21 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -3,6 +3,7 @@ import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { ThemeProvider } from 'styled-components'; import GlobalStyles from '../common/style/GlobalStyle'; import theme from '../common/style/theme'; +import { UserContextProvider } from '../contexts/UserContext'; import LandingPage from '.'; import Main from './Main'; @@ -17,25 +18,27 @@ import GuestResult from './GuestResult'; function App() { return ( - - - - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - + + + + + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + + + ); } diff --git a/src/pages/Main.tsx b/src/pages/Main.tsx index 52757ea..c33e5b9 100644 --- a/src/pages/Main.tsx +++ b/src/pages/Main.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components'; import { debounce } from 'lodash'; import { Link } from 'react-router-dom'; import { Helmet } from 'react-helmet'; +import { useUserState } from '../contexts/UserContext'; import EventCard from '../components/main/EventCard'; import { getApi } from '../api/baseApi'; import { categoryList } from '../constants'; @@ -126,6 +127,7 @@ export default function Main() { categoryName: '' }); const [currentTargetEvent, setCurrentTargetEvent] = useState(-1); + const users = useUserState(); const [query, setQuery] = useState(''); const getUserId = useCallback(() => { diff --git a/src/pages/NicknameRegist.tsx b/src/pages/NicknameRegist.tsx index 3fac2f3..eeb2805 100644 --- a/src/pages/NicknameRegist.tsx +++ b/src/pages/NicknameRegist.tsx @@ -4,6 +4,7 @@ import { useLocation, useNavigate } from 'react-router-dom'; import styled from 'styled-components'; import { NicknameProps } from '../components/common/interface'; import { Button, Title } from '../components/common/style'; +import { useUserDispatch } from '../contexts/UserContext'; const NickWrap = styled.div` height: 100%; @@ -49,26 +50,24 @@ function NicknameRegist() { const location = useLocation(); const navigate = useNavigate(); + const dispatch = useUserDispatch(); const changeNickname = (e: any) => { setNickname(e.target.value); }; const registUser = () => { - console.log(location.state); const state = location.state as NicknameProps; - const { email } = state; - const { socialLoginType } = state; + const { socialId, socialLoginType, refreshToken } = state; - console.log(email); - console.log(nickname); // 구글 0 , 카카오 1 - console.log(socialLoginType); - if (email) { + if (socialId) { axios - .post(`/login/user/nickname`, { + .post(`http://3.37.37.6:8080/login/user/nickname`, { nickname, - email + socialId, + socialLoginType, + refreshToken }) .then((res) => { const { data } = res; @@ -76,7 +75,10 @@ function NicknameRegist() { if (data.message === 'success') { localStorage.setItem('token', data.accessToken); localStorage.setItem('social', JSON.stringify(socialLoginType)); - localStorage.setItem('user', JSON.stringify(data.user)); + dispatch({ + type: 'CREATE', + user: data.user + }); navigate('/main'); // 메인 화면으로 } }) diff --git a/src/pages/SocialLogin/KakaoLogin.tsx b/src/pages/SocialLogin/KakaoLogin.tsx index b6763cb..fcbd9d6 100644 --- a/src/pages/SocialLogin/KakaoLogin.tsx +++ b/src/pages/SocialLogin/KakaoLogin.tsx @@ -8,8 +8,8 @@ import { function Kakao() { // backend와 통일 - const REST_API_KEY = 'cdbaf8838f9e64259177edf602022031'; - const REDIRECT_URI = 'http://localhost:3000/login/redirect'; + const REST_API_KEY = process.env.REACT_APP_KAKAO_CLIENT_API; + const REDIRECT_URI = process.env.REACT_APP_KAKAO_REDIRECT_URI; const getKakao = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`; const kakaoLogin = () => { diff --git a/src/pages/SocialLogin/SocialRedirect.tsx b/src/pages/SocialLogin/SocialRedirect.tsx index f337e95..c5acbe0 100644 --- a/src/pages/SocialLogin/SocialRedirect.tsx +++ b/src/pages/SocialLogin/SocialRedirect.tsx @@ -1,12 +1,12 @@ import axios from 'axios'; import React, { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { googleLoginApi, kakaoLoginApi } from '../../api/Apis'; -import { NicknameProps } from '../../components/common/interface'; import LoadingPage from '../../components/LoadingPage'; +import { useUserDispatch, useUserState } from '../../contexts/UserContext'; function SocialRedirect() { const navigate = useNavigate(); + const dispatch = useUserDispatch(); useEffect(() => { handlerLogin(); @@ -15,35 +15,44 @@ function SocialRedirect() { const handlerLogin = async () => { const code = new URL(window.location.href).searchParams.get('code'); const email = new URL(window.location.href).searchParams.get('email'); + let data: any; try { - let data; if (code) { // 카카오 로그인 - data = await axios.get(`/kakaoLogin?code=${code}`); + await axios + .get(`${process.env.REACT_APP_API_URL}kakaoLogin?code=${code}`) + .then((res) => { + data = res.data; + }) + .catch((err) => { + console.log(err); + }); } else if (email) { // 구글 로그인 data = await axios.get(`/login/sucess?email=${email}`); } - data = data?.data; + console.log(data); if (data.existingUser === 'true') { // 가입된 회원 localStorage.setItem('token', data.accessToken); localStorage.setItem('social', data.socialLoginType); - localStorage.setItem('user', JSON.stringify(data.user)); + dispatch({ + type: 'CREATE', + user: data.user + }); navigate('/main'); // 메인 화면으로 } else { navigate('/login/nickname', { state: { - email: data.email, - socialLoginType: data.socialLoginType + socialId: data.socialId, + socialLoginType: data.socialLoginType, + refreshToken: data.refreshToken } }); } return data; - } catch (error) { - console.log(error); - alert('문제가 발생했습니다 '); - return error; + } catch (err) { + return err; } }; diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 024c86a..40466a2 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -13,6 +13,7 @@ interface IMenu { } interface ICategory { + // eslint-disable-next-line @typescript-eslint/no-explicit-any categoryId: any; categoryName: string; }