Skip to content

Commit

Permalink
✨ Feature - SignUp, SignIn API Connection (#16)
Browse files Browse the repository at this point in the history
* feat: Sign In API Connection

* feat: Sign Up API Connection
  • Loading branch information
kurtyoon authored Aug 19, 2024
1 parent cea58db commit 89afca8
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 18 deletions.
16 changes: 16 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"axios": "^1.7.4",
"js-cookie": "^3.0.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.3.0",
Expand All @@ -22,6 +23,7 @@
"styled-components": "^6.1.12"
},
"devDependencies": {
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.4.1",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
Expand Down
51 changes: 50 additions & 1 deletion src/api/axios.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,63 @@
import axios from "axios";
import Cookie from "js-cookie";
import Cookies from "js-cookie";

const { VITE_APP_SERVER_PORT } = import.meta.env;

const accessToken = Cookies.get('access_token');


const instance = axios.create({
baseURL: VITE_APP_SERVER_PORT + "/api/v1/",
baseURL: VITE_APP_SERVER_PORT,

withCredentials: true,
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`,
},
});

instance.interceptors.request.use((config) => {
const accessToken = Cookies.get('accessToken');
if (accessToken) {
config.headers['Authorization'] = `Bearer ${accessToken}`;
config.withCredentials = true;
}

return config;
}, (error) => {
return Promise.reject(error);
}
);

instance.interceptors.response.use(
response => response,
async (error) => {
if (error.response && error.response.status === 401) {
const originalRequest = error.config;
if (!originalRequest._retry) {
originalRequest._retry = true;

try {
// 토큰 재발급 요청
const response = await axios.post(`${import.meta.env.VITE_APP_SERVER_URL}/api/v1/auth/reissue/token`, {}, {
withCredentials: true,
});

if (response.status === 200) {
const accessToken = Cookies.get('accessToken');
originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
return instance(originalRequest);
}
} catch (refreshError) {
return Promise.reject(refreshError);
}
}
}

return Promise.reject(error);
}
);

export default instance;

26 changes: 21 additions & 5 deletions src/components/auth/sign-in/sign-in-form/SignInForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import RadiusButton from "@components/common/button/radius-button/RadiusButton.t
import InputField from "@components/common/input-field/InputField.tsx";
import { CONSTANT } from "../../../../constants/Constant.ts";
import Label from "@components/common/input-field/label/Label.tsx";
import instance from "../../../../api/axios.ts";

interface props {
onClick: () => void;
Expand All @@ -26,13 +27,28 @@ export default function SingInForm(props: props) {
setPassword(e.target.value);
};

const handleLogin = () => {
console.log(email, password);

// Todo: 로그인 로직 구현
const handleLogin = async () => {

if (isValid) {
navigate("/");
const formData = new FormData();

formData.append("serial_id", email);
formData.append("password", password);

try {
const response = await instance.post("/api/auth/login", formData, {
headers: {
"Content-Type": "multipart/form-data"
},
});

if (response.status === 201) {
navigate("/home");
}
} catch (error) {
console.error(error);
alert("로그인에 실패했습니다.");
}
}
};

Expand Down
62 changes: 53 additions & 9 deletions src/components/auth/sign-up/sign-up-form/SignUpForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Label from "@components/common/input-field/label/Label.tsx";
import InputField from "@components/common/input-field/InputField.tsx";
import RadiusButton from "@components/common/button/radius-button/RadiusButton.tsx";
import RectangleButton from "@components/common/button/rectangle-button/RectangleButton.tsx";
import instance from "../../../../api/axios.ts";

export default function SignUpForm() {
const navigate = useNavigate();
Expand All @@ -23,6 +24,7 @@ export default function SignUpForm() {
const [isValidEmail, setIsValidEmail] = useState<boolean>(false);
const [isValidAuthCode, setIsValidAuthCode] = useState<boolean>(false);
const [isVerification, setIsVerification] = useState<boolean>(false);
const [tempToken, setTempToken] = useState<string>("");

const handleName = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
Expand Down Expand Up @@ -87,29 +89,71 @@ export default function SignUpForm() {
}
}, [name, password, passwordCheck]);

const handleAuthCodeButtonClick = () => {
const handleAuthCodeButtonClick = async () => {
if (isValidEmail && !isIssued) {
alert("인증번호가 발송되었습니다.");
setIsIssued(true);
try {
const response = await instance.post("/api/auth/validations/email", {
email: email,
is_duplicate_check: false,
})

if (response.status === 200) {
alert("인증번호가 발송되었습니다.");
setIsIssued(true);
}

const tryCount = response.data.data.tryCnt;

if (tryCount > 5) {
alert("인증번호 발송 횟수를 초과했습니다.");
return;
}
} catch (error) {
alert("인증번호 전송에 실패했습니다");
}
}
};

const handleVerificationButtonClick = () => {
const handleVerificationButtonClick = async () => {
if (
authCode !== "" &&
isIssued &&
!isVerification &&
CONSTANT.REGEX.AUTH_CODE.test(authCode)
) {
alert("인증되었습니다.");
setIsVerification(true);
try {
const response = await instance.post("/api/auth/validations/authentication-code", {
email: email,
authentication_code: authCode,
});

if (response.status === 201) {
setIsVerification(true);
setTempToken(response.data.data.temporary_token);
alert("인증되었습니다.");
}
} catch (error) {
alert("인증에 실패했습니다.");
}
}
};

const handleSubmitButtonClick = () => {
const handleSubmitButtonClick = async () => {
if (isValid) {
alert("회원가입이 완료되었습니다.");
navigate("/");
try {
const response = await instance.post("/api/auth/sign-up", {
nickname: name,
password: password,
temporary_token: tempToken,
})

if (response.status === 201) {
alert("회원가입이 완료되었습니다.");
navigate("/home");
}
} catch (error) {
alert("회원가입에 실패했습니다.");
}
}
};

Expand Down
6 changes: 3 additions & 3 deletions src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const Wrapper = styled.div`

const Layout: React.FC = () => {
const location = useLocation();
const showNavbar = location.pathname !== "/entry";
const showNavbar = location.pathname !== "/";

return (
<Wrapper>
Expand All @@ -38,9 +38,9 @@ export default function Router(): JSX.Element {
<BrowserRouter>
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route index element={<Auth />} />
<Route path="/home" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/entry" element={<Auth />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down

0 comments on commit 89afca8

Please sign in to comment.