Skip to content

Commit

Permalink
merge/feat: axios instance 생성 및 로그인/회원가입 api 연동
Browse files Browse the repository at this point in the history
  • Loading branch information
ro-el-c authored Aug 12, 2024
2 parents 6a0738d + a3c98a0 commit 9dccfa2
Show file tree
Hide file tree
Showing 21 changed files with 307 additions and 185 deletions.
2 changes: 1 addition & 1 deletion src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import TimeLine from './pages/TimeLine/TimeLine';
import Map from './pages/Map/Map';
import Explore from './pages/Explore/Explore';
import UserProfile from './pages/UserProfile/UserProfile';
import Login from './pages/login/Login';
import Login from './pages/Login/Login';

const Router = () => {
const router = createBrowserRouter([
Expand Down
26 changes: 26 additions & 0 deletions src/apis/auth/socialLogin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useMutation, useQuery } from 'react-query';
import instance from '../instance';
import { BaseResponse } from '../../types/BaseResponse';
import { LoginSuccess } from '../../types/auth/login';

export const socialLogin = async (social: string, code: string) => {
const response = await instance.post<BaseResponse<LoginSuccess>>(
`/user/signin`,
{
socialType: social,
code: code,
},
);
return response.data;
};

export const useLogInDataQuery = (social: string, code: string) => {
const { data: loginData, isLoading: isLoginDataLoading } = useQuery({
queryKey: ['socialLogin'],

// 쿼리 함수를 설정. 이 함수는 API 호출을 담당하며, 여기서는 fetchFeedsData 함수를 호출
queryFn: () => socialLogin(social, code),
});

return { loginData, isLoginDataLoading };
};
52 changes: 52 additions & 0 deletions src/apis/auth/useSignUpMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useMutation } from 'react-query';
import instance from '../instance';
import { BaseResponse } from '../../types/BaseResponse';
import { LoginSuccess } from '../../types/auth/login';
import { ResponseCode } from '../../types/enum/ResponseCode';
import useRegisterStore from '../../stores/registerStore';
import { useNavigate } from 'react-router-dom';

export const useSignUpMutation = (prevUrl: string) => {
const { setLogIn } = useRegisterStore();
const navigate = useNavigate();

const mutation = useMutation({
mutationFn: async (data: FormData) => {
return await instance.post<BaseResponse<LoginSuccess>>(
`/user/singup`,
data,
{
headers: { 'Content-Type': 'multipart/form-data' },
},
);
},
onSuccess: (response) => {
const respone = response.data;

if (respone.code === ResponseCode.LOGGED_IN) {
console.log('새로운 사용자, 회원가입 성공!');

const profileId = respone.result.profileId;
const imgUrl = respone.result.imgUrl;
const accessToken = respone.result.accessToken;
setLogIn(profileId, imgUrl, accessToken);

instance.defaults.headers.common['Authorization'] =
`Bearer ${accessToken}`; //로그인 된 유저에 대하여 모든 api 호출에 accesstoken 포함시키는 코드
} else {
//TODO: 회원가입 오류
}

if (prevUrl === '/') navigate('/timeline');
else navigate(prevUrl);
},
onError: () => {
console.log('회원가입 실패');
navigate(prevUrl);
},
});

return mutation;
};

export default useSignUpMutation;
34 changes: 34 additions & 0 deletions src/apis/instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import axios from 'axios';
import useRegisterStore from '../stores/registerStore';

// axios 인스턴스 생성
const instance = axios.create({
baseURL: `${process.env.REACT_APP_BASE_URL}`,
withCredentials: true, //쿠키를 포함한 요청을 보낼 때 필요
});

// 요청 인터셉터
instance.interceptors.request.use(
(config) => {
// console.log('axios config : ', config);
return config;
},
(error) => {
// 요청 에러 처리
return Promise.reject(error);
},
);

// 응답 인터셉터
instance.interceptors.response.use(
(response) => {
console.log('response: ', response);
return response;
},
// (error) => {
// // 응답 에러 처리
// throw new Error(' data error');
// },
);

export default instance;
4 changes: 2 additions & 2 deletions src/components/login/LoginModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import GoogleLogo from '../../assets/login/ico_google.svg';
const LoginModal = () => {
const navigate = useNavigate();
const pathname = useLocation().pathname;
const { setLoginNeeded } = useRegisterStore();
const { setLoginNeededStatus } = useRegisterStore();

//oauth 요청 URL
const ENCODED_PRESENT_URI = encodeURIComponent(pathname);
Expand All @@ -25,7 +25,7 @@ const LoginModal = () => {
};

const handleLater = () => {
setLoginNeeded(false);
setLoginNeededStatus(false);
if (pathname === '/') {
navigate('/timeline');
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const MapTitleAndDescriptionInputContainer: React.FC<Props> = ({ mode }) => {
isBookmarked,
switchIsBookmarked,
} = useMapInfoStore();
const { registerStatus, setLoginNeeded } = useRegisterStore();
const { registerStatus, setLoginNeededStatus } = useRegisterStore();
const [editedTitle, setEditedTitle] = useState<string>('');
const [editedDescription, setEditedDescription] = useState<string>('');

Expand Down Expand Up @@ -57,7 +57,7 @@ const MapTitleAndDescriptionInputContainer: React.FC<Props> = ({ mode }) => {

const handleSwitchIsBookmarked = () => {
if (registerStatus !== RegisterStatus.LOG_IN) {
setLoginNeeded(true);
setLoginNeededStatus(true);
} else {
//TODO: 북마크 설정 api 호출
switchIsBookmarked();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ const MapProducerConatiner = () => {
nickname: 'producer',
amIFollowing: false,
});
const { registerStatus, setLoginNeeded } = useRegisterStore();
const { registerStatus, setLoginNeededStatus } = useRegisterStore();

const handleFollowBtn = () => {
if (registerStatus !== RegisterStatus.LOG_IN) setLoginNeeded(true);
if (registerStatus !== RegisterStatus.LOG_IN) setLoginNeededStatus(true);
else {
//TODO: 팔로우 api
setMockData((state) => {
Expand Down
6 changes: 6 additions & 0 deletions src/components/profile_setting/ProfileInfoSetting.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
gap: 40px;
}

.inputContainer {
display: flex;
flex-direction: column;
gap: 20px;
}

.submitBtn {
padding: 12px 0;
border-radius: 8px;
Expand Down
96 changes: 75 additions & 21 deletions src/components/profile_setting/ProfileInfoSetting.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,79 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import styles from './ProfileInfoSetting.module.scss';
import { RegisterStatus } from '../../types/enum/RegisterStatus';
import useRegisterStore from '../../stores/registerStore';
import UserDataInputContainer from './UserDataInputContainer';
import imageCompression from 'browser-image-compression';
import styles from './ProfileInfoSetting.module.scss';

import useSignUpMutation from '../../apis/auth/useSignUpMutation';

import NicknameInput from './input/NicknameInput';
import IdInput from './input/IdInput';
import UserDefaultImage from '../../assets/img_user_default_profile.svg';
import ProfileEditPen from '../../assets/btn_profile_edit_pen.svg';

import useRegisterStore from '../../stores/registerStore';
import { RegisterStatus } from '../../types/enum/RegisterStatus';

const ProfileInfoSetting = () => {
const { registerStatus, setLogIn } = useRegisterStore();
const prevUrl = useLocation().pathname.split('?')[0];

const { registerStatus } = useRegisterStore();

const [isComplete, setIsComplete] = useState<boolean>(false);
const [imgFile, setImgFile] = useState<string>();
const navigate = useNavigate();
const pathname = useLocation().pathname;
const [nickname, setNickname] = useState<string>(); //TODO: api 호출에 필요
const [id, setId] = useState<string>();
const [imgFile, setImgFile] = useState<File>();
const [imagePreview, setImagePreview] = useState<string>();

const handleSignUp = () => {
//TODO: 회원가입 api 연결
setLogIn('profileId', 'profileImgUrl', 'true access', 'true refresh'); //아마 얘가 회원가입 api 연결 코드 내부로 이동
const prevUrl = pathname.split('?')[0];
//실시간 유효성 검사
const [isNicknameEmpty, setIsNicknameEmpty] = useState<boolean>(false);
const [isValidNickname, setIsValidNickname] = useState<boolean>(true);

const [isIdEmpty, setIsIdEmpty] = useState<boolean>(false);
const [isValidId, setIsValidId] = useState<boolean>(true);

//시작/적용하기 눌렀을 때
const [idDuplicatedError, setIdDuplicatedError] = useState<boolean>(false); //사용 중인 아이디인지

const signUpMutation = useSignUpMutation(prevUrl);

useEffect(() => {
if (id === undefined || nickname === undefined) {
setIsComplete(false);
return;
}

if (prevUrl === '/') navigate('/timeline');
else navigate(prevUrl);
if (!isNicknameEmpty && !isIdEmpty && isValidNickname && isValidId)
setIsComplete(true);
else setIsComplete(false);
}, [isNicknameEmpty, isValidNickname, isIdEmpty, isValidId]);

const handleProfileSettingSubmit = async () => {
//TODO: profileId 중복 검사

const formData = new FormData();
imgFile && formData.append('imageFile', imgFile);
const requestDTO = JSON.stringify({
nickname: nickname,
profileId: id,
});
formData.append('requestDTO', requestDTO);

//TODO: 회원가입 api 연결
await signUpMutation.mutate(formData);
};

const onChangIamge = async (e: React.ChangeEvent<HTMLInputElement>) => {
const onChangeIamge = async (e: React.ChangeEvent<HTMLInputElement>) => {
//이미지 압축
if (!e.target.files) return;
const file = e.target.files[0];
setImgFile(file);

const options = {
maxSizeMB: 0.6,
maxWidthOrHeight: 512,
};
const compressedFile = await imageCompression(file, options);
setImgFile(URL.createObjectURL(compressedFile));
setImagePreview(URL.createObjectURL(compressedFile));
};

return (
Expand All @@ -43,15 +82,15 @@ const ProfileInfoSetting = () => {
<div className={styles.userImg}>
<div className={styles.userImg__view}>
<img
src={imgFile ? `${imgFile}` : `${UserDefaultImage}`}
src={imagePreview ? `${imagePreview}` : `${UserDefaultImage}`}
alt="사용자 기본 프로필 이미지"
/>
<input
type="file"
id="user-profile-img"
className={styles.profileEditInput}
accept=".jpg, .jpeg, .png"
onChange={onChangIamge}
onChange={onChangeIamge}
/>
</div>
<label htmlFor="user-profile-img" className={styles.profileEditBtn}>
Expand All @@ -60,12 +99,27 @@ const ProfileInfoSetting = () => {
</div>
</div>
<div className={styles.userDataContainer}>
<UserDataInputContainer setIsComplete={setIsComplete} />
<div className={styles.inputContainer}>
<NicknameInput
isNicknameEmpty={isNicknameEmpty}
isValidNickname={isValidNickname}
setIsNicknameEmpty={setIsNicknameEmpty}
setIsValidNickname={setIsValidNickname}
setNickname={setNickname}
/>
<IdInput
isIdEmpty={isIdEmpty}
isValidId={isValidId}
setIsIdEmpty={setIsIdEmpty}
setIsValidId={setIsValidId}
setId={setId}
/>
</div>
<button
type="submit"
className={styles.submitBtn}
disabled={!isComplete}
onClick={handleSignUp}
onClick={handleProfileSettingSubmit}
>
{registerStatus === RegisterStatus.SIGNING_UP ? (
<span>시작하기</span>
Expand Down

This file was deleted.

54 changes: 0 additions & 54 deletions src/components/profile_setting/UserDataInputContainer.tsx

This file was deleted.

Loading

0 comments on commit 9dccfa2

Please sign in to comment.