Skip to content

Commit

Permalink
Merge pull request #79 from UMC-FITple/feat/#65
Browse files Browse the repository at this point in the history
Feat/#65 로그인, 회원가입 API 연결
  • Loading branch information
SeyeonJang authored Aug 21, 2024
2 parents a244386 + e203e80 commit 67c9294
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 41 deletions.
69 changes: 69 additions & 0 deletions FITple-Frontend/data/MyPageApi.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const API_BASE_URL = 'http://localhost:3000';

// 임시 토큰 발급 함수
const fetchToken = async () => {
try {
const response = await fetch(`${API_BASE_URL}/temp-token`, {
method: 'POST', // POST 요청
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// 필요한 경우 바디 데이터를 추가
}),
});

if (!response.ok) {
throw new Error('Failed to fetch token');
}

const data = await response.json();
return data.token; // 가져온 토큰을 반환
} catch (error) {
console.error('Error fetching token:', error);
throw error;
}
};

export const submitUserInfo = async (data, imageFile) => {
const formData = new FormData();

// JSON 데이터를 문자열로 변환해서 추가
formData.append('data', JSON.stringify(data));

// 이미지 파일 추가
if (imageFile) {
formData.append('image', imageFile);
}

try {
// 임시 토큰 발급
const token = await fetchToken();

// 사용자 정보 제출
const response = await fetch(`${API_BASE_URL}/FITple/myprofile`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
},
body: formData,
credentials: 'include',
});

if (!response.ok) {
if (response.status === 407) {
console.error('이미 존재하는 닉네임입니다.');
}
throw new Error(`Network response was not ok: ${response.status}`);
}

const responseData = await response.json();
console.log('submit User Info!');
console.log(responseData);

return response;
} catch (error) {
console.error('Error:', error);
throw error;
}
};
25 changes: 25 additions & 0 deletions FITple-Frontend/data/SignupApi.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const API_BASE_URL = 'http://localhost:3000';

export const signup = async (userData) => {
try {
const response = await fetch(`${API_BASE_URL}/FITple/signup`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});

const data = await response.json();

if (response.status === 200) {
console.log(response.status);
console.log(response.statusText);
return data;
} else {
throw { status: response.status, message: data.message || '오류가 발생했습니다.' };
}
} catch (error) {
throw { status: error.status || 500, message: error.message || '서버 에러가 발생했습니다.' };
}
};
9 changes: 9 additions & 0 deletions FITple-Frontend/data/store/userAuthStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { create } from 'zustand';

const useAuthStore = create((set) => ({
token: null,
setToken: (newToken) => set({ token: newToken }),
clearToken: () => set({ token: null }),
}));

export default useAuthStore;
7 changes: 7 additions & 0 deletions FITple-Frontend/src/pages/LoginPage/LoginPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { useNavigate } from "react-router-dom";
import logo from "../../../assets/Logo.svg";
import { login } from "../../../data/LoginApi";
import useAuthStore from '../../../data/store/userAuthStore';
import {
LoginPageWrapper,
MainText,
Expand All @@ -17,6 +18,8 @@ function LoginPage() {
const [loginPw, setLoginPw] = useState("");
const [isButtonActive, setIsButtonActive] = useState(false);
const navigate = useNavigate();

const setToken = useAuthStore((state) => state.setToken); // Zustand 스토어에서 토큰 설정

useEffect(() => {
setIsButtonActive(!!(loginId && loginPw));
Expand All @@ -27,9 +30,13 @@ function LoginPage() {

try {
const response = await login(loginId, loginPw);
const data = await response.json(); // 응답 데이터를 JSON으로 파싱

switch (response.status) {
case 200:
setToken(data.result); // 로그인 성공 시 토큰을 Zustand 스토어에 저장
console.log('토큰 발급 완료');
console.log(data.result);
alert("로그인 성공!");
navigate('/cloth');
break;
Expand Down
106 changes: 65 additions & 41 deletions FITple-Frontend/src/pages/SignupPage/SignupPage.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logo from "../../../assets/Logo.svg";
import { useState } from "react";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { signup } from "../../../data/SignupApi";
import logo from "../../../assets/Logo.svg";
import {
SignupPageWrapper,
FormWrapper,
Expand All @@ -25,18 +26,12 @@ function SignupPage() {
const [pwError, setPwError] = useState("영어, 소문자, 숫자를 조합하여 입력해주세요.");
const [pwConfirmError, setPwConfirmError] = useState("");
const [emailError, setEmailError] = useState("");
const [signupError, setSignupError] = useState("");

const handleIdChange = (e) => {
const id = e.target.value;
setLoginId(id);

if (id === "umc") {
setIdError("중복된 아이디입니다.");
} else if (id) {
setIdError("사용할 수 있는 아이디입니다.");
} else {
setIdError(" ");
}
setIdError("");
};

const handlePwChange = (e) => {
Expand All @@ -47,7 +42,7 @@ function SignupPage() {
if (!pwRegex.test(pw)) {
setPwError("영어 소문자, 숫자를 조합하여 8글자 이상 입력해주세요.");
} else {
setPwError(" ");
setPwError("");
}
};

Expand All @@ -58,74 +53,102 @@ function SignupPage() {
if (pwConfirm !== loginPw) {
setPwConfirmError("입력한 비밀번호와 일치하지 않습니다.");
} else {
setPwConfirmError(" ");
setPwConfirmError("");
}
};

const handleEmailChange = (e) => {
const email = e.target.value;
setLoginEmail(email);

if (email === "[email protected]") {
setEmailError("이미 가입된 이메일입니다.");
} else if (email) {
setEmailError("사용할 수 있는 이메일입니다.");
} else {
setEmailError(" ");
}
setEmailError("");
};

const handleCheckboxChange = (event) => {
setIsChecked(event.target.checked);
};

const handleButtonClick = () => {
navigate('/userinfo');
const handleSubmit = async () => {
if (!loginId || !loginPw || !loginPwConfirm || !loginEmail) {
setSignupError("모든 필드를 입력해주세요.");
return;
}
if (loginPw !== loginPwConfirm) {
setSignupError("비밀번호가 일치하지 않습니다.");
return;
}

try {
const userData = {
user_id: loginId,
password: loginPw,
email: loginEmail,
};

const result = await signup(userData);
console.log("--------------");
console.log(result);

if (result.code === 200) {
setIdError("사용 가능한 아이디입니다.");
alert("회원 가입 성공!");
navigate("/userinfo");
} else if (result.code === 'SIGNUP001') {
setIdError("이미 존재하는 아이디입니다.");
}
} catch (error) {
if (error.status === 401) {
setIdError("중복된 아이디입니다.");
} else {
setSignupError(
error.message || "알 수 없는 오류가 발생했습니다."
);
}
}
};

return (
<SignupPageWrapper>
<img width="50px" src={logo} alt="FITple Logo" />
<FormWrapper>
<InputText>아이디</InputText>
<InputBox
type="text"
id="login-id"
<InputBox
type="text"
id="login-id"
value={loginId}
onChange={handleIdChange}
placeholder=""
placeholder=""
/>
<ErrorText isError={idError.includes("중복된")}>{idError}</ErrorText>
<ErrorText isError={!!idError}>{idError}</ErrorText>

<InputText>비밀번호</InputText>
<InputBox
type="password"
id="login-pw"
<InputBox
type="password"
id="login-pw"
value={loginPw}
onChange={handlePwChange}
placeholder=""
placeholder=""
/>
<ErrorText isError={!!pwError}>{pwError}</ErrorText>

<InputText>비밀번호 확인</InputText>
<InputBox
type="password"
id="login-pw2"
<InputBox
type="password"
id="login-pw2"
value={loginPwConfirm}
onChange={handlePwConfirmChange}
placeholder=""
placeholder=""
/>
<ErrorText isError={!!pwConfirmError}>{pwConfirmError}</ErrorText>

<InputText>이메일</InputText>
<InputBox
type="email"
id="login-email"
<InputBox
type="email"
id="login-email"
value={loginEmail}
onChange={handleEmailChange}
placeholder=""
placeholder=""
/>
<ErrorText isError={emailError.includes("가입된")}>{emailError}</ErrorText>
<ErrorText isError={!!emailError}>{emailError}</ErrorText>

<InputText>이메일 마케팅 정보 수신 동의</InputText>
<CheckboxContainer>
Expand All @@ -143,7 +166,8 @@ function SignupPage() {
<CheckboxLabel>동의하지 않음</CheckboxLabel>
</CheckboxContainer>

<SubmitButton onClick={handleButtonClick}>회원정보 작성하기</SubmitButton>
<SubmitButton onClick={handleSubmit}>회원정보 작성하기</SubmitButton>
{signupError && <ErrorText isError={true}>{signupError}</ErrorText>}
</FormWrapper>
</SignupPageWrapper>
);
Expand Down
19 changes: 19 additions & 0 deletions FITple-Frontend/src/pages/UserInfoPage/UserInfoPage.style.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ export const MainBox = styled.div`
padding: 0 30px;
`;

export const ProfileImageWrapper = styled.div`
width: 150px;
height: 150px;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
// border: 2px solid #0276FE;
margin-bottom: 20px;
`;

export const ProfileImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`;

export const MainText = styled.p`
font-size: 28px;
font-weight: bold;
Expand Down

0 comments on commit 67c9294

Please sign in to comment.