Skip to content

Commit

Permalink
카카오로그인 수정 및 토큰 저장 (#18)
Browse files Browse the repository at this point in the history
* chore: 커밋용 next/core-web-vitals삭제

* feat: 회원가입 및 카카오 로그인 후 토큰 저장

* chore: 프로필 이미지 s3

* fix: 인터셉트 엑세스 토큰

* fix: 기존 계정 홈, 새로운 계정 프로필 수정으로 변경 및 토큰 저장

* fix: 404 에러시 data.data에 null 설정

* feat: 받아온 재료 404 에러 시 데이터 전달 조건 추가

* feat: 401 에러시 리프레시 토큰 api 요청 로직 추가

* feat: 홈페이지 로컬스토리지 토큰 없을 시 로그인 페이지 이동

* fix: 커밋 'next/core-web-vitals' 되돌리기
  • Loading branch information
a-honey authored Feb 18, 2024
1 parent 10f9f48 commit 644240d
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 82 deletions.
8 changes: 4 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ module.exports = {
es2021: true,
},
globals: {
'JSX': true
JSX: true,
},
extends: [
'standard-with-typescript',
'eslint:recommended',
'plugin:prettier/recommended',
'next/core-web-vitals'
'next/core-web-vitals',
],
parserOptions: {
ecmaVersion: 'latest',
Expand All @@ -19,7 +19,7 @@ module.exports = {
ignorePatterns: ['/src/assets/**', '/src/styles/**'],
rules: {
'@typescript-eslint/strict-boolean-expressions': 'off',
'prettier/prettier': ["error", { "endOfLine": "auto" }],
'@typescript-eslint/explicit-function-return-type': 'off'
'prettier/prettier': ['error', { endOfLine: 'auto' }],
'@typescript-eslint/explicit-function-return-type': 'off',
},
};
7 changes: 5 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
domains: ['mara-s3bucket.s3.ap-northeast-2.amazonaws.com'],
},
webpack: (config) => {
return {
...config,
Expand All @@ -22,8 +25,8 @@ const nextConfig = {
source: '/',
destination: '/home',
permanent: true,
}
]
},
];
},
};

Expand Down
47 changes: 44 additions & 3 deletions src/api/axiosInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,50 @@ export interface ApiResponseDTO<T> {
const axiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_BASE_URI,
timeout: 5000,
headers: {
'Content-Type': 'application/json',
},
});

axiosInstance.interceptors.request.use((config) => {
config.headers['Content-Type'] = 'application/json';

if (typeof window !== 'undefined') {
config.headers.Authorization = `Bearer ${localStorage.getItem('accessToken')}`;
}

return config;
});

axiosInstance.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;

if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;

const refreshToken =
typeof window !== 'undefined'
? localStorage.getItem('refreshToken')
: null;

try {
const refreshResponse = await axios.post('/users/kakao-login', {
refreshToken,
});

if (typeof window !== 'undefined') {
localStorage.setItem('accessToken', refreshResponse.data.accessToken);
}

originalRequest.headers.Authorization = `Bearer ${refreshResponse.data.accessToken}`;
return await axiosInstance(originalRequest);
} catch (refreshError) {
console.error('Error refreshing token:', refreshError);
throw refreshError;
}
}

return await Promise.reject(error);
},
);

export default axiosInstance;
6 changes: 2 additions & 4 deletions src/components/organisms/FridgeBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,20 @@ import {
IngredientItemBox,
} from '@/components/molecules';

const FridgeBoard: React.FC = () => {
const FridgeBoard: React.FC<{ data?: any | null }> = ({ data }) => {
const [currentTabName, setCurrentTabName] = useState<'냉장' | '냉동'>('냉장');

const handleTabNameChange: (tabName: '냉장' | '냉동') => void = (tabName) => {
setCurrentTabName(tabName);
};

const datas = ['d'];

return (
<Container className="p-[20px] bg-white">
<FridgeTab
currentTabName={currentTabName}
handleTabNameChange={handleTabNameChange}
/>
{datas.length !== 0 ? (
{data !== null || (Array.isArray(data) && data?.length !== 0) ? (
<div className="flex flex-col w-full gap-[24px]">
<IngredientItemBox />
<IngredientItemBox />
Expand Down
1 change: 1 addition & 0 deletions src/components/organisms/FridgeListModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const FridgeListModal: React.FC<{
<div className="flex flex-col gap-[10px] mt-[25px] mb-[32px]">
{FRIDGE_NAME_LIST.map((fridgeName) => (
<FridgeListItem
key={fridgeName}
isCurrentFridge={currentFridgeName === fridgeName}
fridgeName={fridgeName}
onClick={() => {
Expand Down
5 changes: 1 addition & 4 deletions src/components/templates/withLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React, { useEffect } from 'react';
import { useRouter } from 'next/router';
import useToast from '@/hooks/useToast';

const withLogin = (InnerComponent: React.FC) => {
return () => {
const router = useRouter();
const token = localStorage.getItem('token');
const { showToast } = useToast();
const token = localStorage.getItem('accessToken');

const redirectToLogin: () => Promise<void> = async () => {
if (!token) {
showToast('로그인이 필요합니다.', 'info');
try {
await router.push('/login');
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/queries/fridge/useGetIngredientList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useBaseQuery } from '../useBaseQuery';
const useGetIngredientList = () => {
// const testApiEndpoint = 'https://jsonplaceholder.typicode.com/todos';

return useBaseQuery<IngredientType>(queryKeys.INGREDIENT(), '/ingrs');
return useBaseQuery<IngredientType>(queryKeys.INGREDIENT(), '/regrigs/my');
};

export default useGetIngredientList;
1 change: 1 addition & 0 deletions src/hooks/queries/login/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as useGetKakaoToken } from './useGetKakaoToken';
export { default as usePostUser } from './usePostUser';
24 changes: 18 additions & 6 deletions src/hooks/queries/login/useGetKakaoToken.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { useRouter } from 'next/router';
import { queryKeys } from '../queryKeys';
import { useBaseQuery } from '../useBaseQuery';

const useGetKakaoToken = (code: string | null = '') => {
const { data } = useBaseQuery<{ data: { accessToken: string } }>(
queryKeys.KAKAO(),
`/users/kakao-login?code=${code}`,
);
if (data) {
localStorage.setItem('token', data.data.accessToken);
const router = useRouter();
const { data } = useBaseQuery<{
accessToken: string;
refreshToken: string;
kakaoId: number;
kakaoEmail: string;
}>(queryKeys.KAKAO(), `/users/kakao-login?code=${code}`, true);

if (data?.data?.accessToken === undefined) {
void router.push(
`/mypage/profile?kakaoId=${data?.data?.kakaoId}&kakaoEmail=${data?.data?.kakaoEmail}`,
);
}
if (data?.data) {
localStorage.setItem('accessToken', data.data.accessToken);
localStorage.setItem('refreshToken', data.data.refreshToken);
void router.push('/home');
}
};

Expand Down
35 changes: 35 additions & 0 deletions src/hooks/queries/login/usePostUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useRouter } from 'next/router';
import { queryKeys } from '../queryKeys';
import { useBaseMutation } from '../useBaseMutation';

interface PostUserBodyType {
nickName: string;
kakaoId: number;
kakaoEmail: string;
googleEmail: string;
profileImage: string;
}

const usePostUser = () => {
const router = useRouter();
const onSuccess = ({
data,
}: {
data: {
accessToken: string;
refreshToken: string;
email: string;
nickName: string;
};
}) => {
localStorage.setItem('accessToken', data.accessToken);
localStorage.setItem('refreshToken', data.refreshToken);
void router.push('/home');
};
return useBaseMutation<PostUserBodyType>(
queryKeys.KAKAO(),
`/users`,
onSuccess,
);
};
export default usePostUser;
22 changes: 22 additions & 0 deletions src/hooks/queries/useBaseMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import axiosInstance from '@/api/axiosInstance';
import { useMutation } from '@tanstack/react-query';

export const fetchData = async <T>(url: string, body: T) => {
const response = await axiosInstance.post<{ data: T }>(url, body);
return response.data;
};

export const useBaseMutation = <T>(
mutationKey: any,
url: string,
onSuccess: (any: any) => void,
) => {
return useMutation({
mutationKey,
mutationFn: async (body: T) => {
const response = await fetchData<T>(url, body);

onSuccess(response.data);
},
});
};
27 changes: 21 additions & 6 deletions src/hooks/queries/useBaseQuery.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import axiosInstance from '@/api/axiosInstance';
import { useSuspenseQuery } from '@tanstack/react-query';

export const fetchData = async <T>(url: string) => {
const response = await axiosInstance.get<{ data: T }>(url);
return response.data;
export const fetchData = async <T>(url: string, isNotCatch: boolean) => {
try {
const response = await axiosInstance.get<{ data: T; status?: number }>(url);
return response.data;
} catch (error: any) {
if (!isNotCatch) {
if (error.response && error.response.status === 404) {
return await Promise.resolve({ data: null });
} else {
throw error;
}
}
}
};

export const useBaseQuery = <T>(queryKey: any, url: string) => {
export const useBaseQuery = <T>(
queryKey: any,
url: string,
isNotCatch: boolean = false,
) => {
return useSuspenseQuery({
queryKey,
queryFn: async () => await fetchData<T>(url).then((res) => res.data),
queryFn: async () => {
return await fetchData<T>(url, isNotCatch);
},
});
};
8 changes: 4 additions & 4 deletions src/pages/fridge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
ModalContent,
useDisclosure,
} from '@chakra-ui/react';
// import { useGetIngredientList } from '@/hooks/queries/fridge';
import { useGetIngredientList } from '@/hooks/queries/fridge';

const FridgePage: NextPage = () => {
const {
Expand All @@ -27,8 +27,8 @@ const FridgePage: NextPage = () => {
onOpen: onOpenFridgeListModal,
onClose: onCloseFridgeListModal,
} = useDisclosure();
// const data = useGetIngredientList();
// console.log('받아올 데이터', data);

const { data } = useGetIngredientList();

return (
<>
Expand Down Expand Up @@ -81,7 +81,7 @@ const FridgePage: NextPage = () => {
toggleIsOpenFridgeListModal={onOpenFridgeListModal}
toggleIsOpenIngredientAddModal={onOpenIngredientAddModal}
/>
<FridgeBoard />
<FridgeBoard data={data?.data} />
</section>
</div>
</>
Expand Down
10 changes: 7 additions & 3 deletions src/pages/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { IngredientBoard } from '@/components/organisms';
import Header from '@/components/organisms/Header';
import Link from 'next/link';
import { AlarmIcon } from '@/assets/icons';
import withLogin from '@/components/templates/withLogin';

const NEAR_EXPIRATION_COUNT_MOCK_DATA=2;
const NEAR_EXPIRATION_COUNT_MOCK_DATA = 2;

const Home: NextPage = () => {
const isNearExpirationWarn = true;
Expand All @@ -26,7 +27,10 @@ const Home: NextPage = () => {
/>
<section className={`flex flex-col min-h-screen p-20 bg-gray1`}>
{isNearExpirationWarn && (
<NearExpirationWarnBox className="mt-12" count={NEAR_EXPIRATION_COUNT_MOCK_DATA} />
<NearExpirationWarnBox
className="mt-12"
count={NEAR_EXPIRATION_COUNT_MOCK_DATA}
/>
)}
<div className="flex gap-8.5 mt-12">
<SvgAndTextBox
Expand All @@ -53,4 +57,4 @@ const Home: NextPage = () => {
</div>
);
};
export default Home;
export default withLogin(Home);
Loading

0 comments on commit 644240d

Please sign in to comment.