Skip to content

Commit

Permalink
Merge pull request #14 from codestates-seb/dev
Browse files Browse the repository at this point in the history
Upstream Pull
  • Loading branch information
KYUNGMINMON authored Jun 23, 2023
2 parents ea96146 + 4033430 commit d561f8b
Show file tree
Hide file tree
Showing 26 changed files with 1,209 additions and 127 deletions.
74 changes: 74 additions & 0 deletions client/package-lock.json

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

5 changes: 5 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-regular-svg-icons": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@reduxjs/toolkit": "^1.9.5",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
Expand Down
106 changes: 106 additions & 0 deletions client/src/components/pagenation/Pagenation.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import styled, { css } from 'styled-components';

const Nav = styled.nav`
display: flex;
justify-content: space-between;
align-items: center;
gap: 0.25rem;
`;

const Button = styled.button`
display: flex;
border: none;
padding: 0.5rem;
border-radius: 0.188rem;
background: hsl(210, 8%, 85%);
color: black;
width: 1.563rem;
height: 1.563rem;
justify-content: center;
align-items: center;
font-size: 0.8rem;
${(props) =>
props.active &&
css`
background: #f48225;
`}
`;
const PageBtn = styled.button`
display: flex;
border: none;
padding: 0.5rem;
border-radius: 0.188rem;
background: ${(props) => (props.active ? '#f48225' : 'hsl(210, 8%, 85%)')};
color: black;
width: 1.563rem;
height: 1.563rem;
justify-content: center;
align-items: center;
font-size: 0.8rem;
`;
const LeftButtons = styled.div`
display: flex;
align-items: center;
justify-content: center;
gap: 0.25rem;
`;

const RightButtons = styled.div`
display: flex;
align-items: center;
gap: 0.25rem;
`;
// total : 전체 질문의 갯수
// limit : 페이지 당 게시물 수
// setPage : 현재 페이지의 번호 상태

function Pagination({ total, limit, setPage, page, setLimit }) {
// Pagenation 알고리즘 -> 전체 질문의 갯수/ 페이지 당 게시물 수
const numPages = Math.ceil(total / limit);
const handleLimitChange = (value) => {
setLimit(value);
};
return (
<>
<Nav>
<LeftButtons>
<Button onClick={() => setPage(page - 1)} disabled={page === 1}>
Pre
</Button>
{Array(numPages)
.fill()
.map((_, i) => (
<Button
key={i + 1}
active={i + 1 === page}
onClick={() => setPage(i + 1)}
>
{i + 1}
</Button>
))}
<Button
onClick={() => setPage(page + 1)}
disabled={page === numPages}
>
Next
</Button>
</LeftButtons>

<RightButtons>
<PageBtn onClick={() => handleLimitChange(5)} active={limit === 5}>
5
</PageBtn>
<PageBtn onClick={() => handleLimitChange(30)} active={limit === 30}>
30
</PageBtn>
<PageBtn onClick={() => handleLimitChange(30)} active={limit === 50}>
50
</PageBtn>
</RightButtons>
</Nav>
</>
);
}

export default Pagination;
56 changes: 56 additions & 0 deletions client/src/pages/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useState } from 'react';
import { useDispatch } from 'react-redux';
import styled, { createGlobalStyle } from 'styled-components';
import { ReactComponent as Logo } from '../assets/icons/logo.svg';
import Header from '../components/layouts/Header';
import { ReactComponent as GoogleLogo } from '../assets/icons/logo_google.svg';
import { ReactComponent as GithubLogo } from '../assets/icons/logo_github.svg';
import { ReactComponent as FacebookLogo } from '../assets/icons/logo_facebook.svg';
import { useNavigate } from 'react-router-dom';
import { loginSuccess } from '../redux/reducers/loginSlice';

const GlobalStyle = createGlobalStyle`
*, *::before, *::after {
Expand Down Expand Up @@ -167,6 +170,53 @@ const Login = () => {

if (!password) {
setErrors((prevErrors) => [...prevErrors, 'Password_empty']);
} else {
// 유효성 검사를 통과한 경우에만 로그인 시도
fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username: email, password: password }),
})
.then((response) => {
if (
// 헤더에 토큰이 포함된다면 로그인 성공
response.headers.get('Authorization') &&
response.headers.get('Refresh')
) {
return response.json();
} else if (response.status === 401) {
// 로그인 실패 했을 경우
return response.json().then((data) => {
if (data.message === 'Member not found : Unauthorized') {
setErrors((prevErrors) => [...prevErrors, 'NotMember']);
throw new Error('등록된 이메일이 아닙니다.');
} else if (data.message === 'Unauthorized') {
setErrors((prevErrors) => [...prevErrors, 'WrongPassword']);
throw new Error('비밀번호가 잘못되었습니다.');
} else {
throw new Error('로그인에 실패했습니다.');
}
});
}
})
.then((data) => {
// 토큰 저장 로직
const accessToken = data.headers.get('Authorization').split(' ')[1]; // Bearer를 건너뛰고 실제 토큰 부분을 추출
const refreshToken = data.headers.get('Refresh');
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);

// 상태 변경
useDispatch(loginSuccess({ accessToken, refreshToken }));

// 로그인 성공한 경우 메인 페이지로 이동
useNavigate('/');
})
.catch((error) => {
console.error('로그인 요청 중 오류가 발생했습니다.', error);
});
}
};

Expand Down Expand Up @@ -205,6 +255,9 @@ const Login = () => {
This email is not a valid email address.
</ErrorMessage>
)}
{errors.includes('NotMember') && (
<ErrorMessage>등록된 이메일이 아닙니다.</ErrorMessage>
)}

<Label>
Password
Expand All @@ -219,6 +272,9 @@ const Login = () => {
{errors.includes('Password_empty') && (
<ErrorMessage>Password cannot be empty.</ErrorMessage>
)}
{errors.includes('WrongPassword') && (
<ErrorMessage>비밀번호가 일치하지 않습니다.</ErrorMessage>
)}
<Button type="submit" onClick={handleLogin}>
Log In
</Button>
Expand Down
Loading

0 comments on commit d561f8b

Please sign in to comment.