Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/일기장 #5

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
86e9efc
[fix]: global style 적용 오류 해결
MrMirror21 Jul 16, 2023
9299d17
initial commit of diary page
MrMirror21 Jul 16, 2023
eef4097
[feature]: 서버에서 일기장 리스트 획득, 페이지에 게시
MrMirror21 Jul 22, 2023
05066ff
[fix]: 현재 페이지 주소에 따라 리스트 반환받도록 수정
MrMirror21 Jul 22, 2023
d5b523a
[feature]: 총 게시물 개수에 따른 페이지 수 조절
MrMirror21 Jul 23, 2023
9a7fb20
[feature]: 페이지 당 게시물 수 조절 기능 추가
MrMirror21 Jul 23, 2023
bd732ab
[chore]: Diary 페이지 useEffect 내 함수 분리, 주석 추가
MrMirror21 Jul 23, 2023
27432bb
[feature]: 게시물 작성 ui: modal 제작
MrMirror21 Jul 23, 2023
34fbc07
[feat]: 게시물 작성 wysiwyg 편집기 ui 추가
MrMirror21 Jul 28, 2023
91648c6
[feat]: 게시물 검색 기능(서버 미구현) 추가
MrMirror21 Jul 29, 2023
23b9312
[feat]: 서버에 작성한 게시글 업로드(서버 해당 api 미구현)
MrMirror21 Jul 30, 2023
9e98c50
[chore]: api 변경에 따른 호출 함수 변경
MrMirror21 Aug 3, 2023
2ae515b
[feat] : 좋아요, 조회수, 댓글 수 등 게시글 세부 정보 표기 기능 추가
MrMirror21 Aug 6, 2023
971e441
[chore] : api url 관련 변경
MrMirror21 Aug 6, 2023
28e570c
[feat]: 다이어리 게시글 리스트 로딩 구현
MrMirror21 Aug 15, 2023
b7803ec
[chore] : 다이어리 작성 양식 변경
MrMirror21 Aug 15, 2023
00b5182
[feat] : 다이어리 상세 페이지 라우팅, ui 작업
MrMirror21 Aug 15, 2023
786683b
[feat] : 다이어리 상세 페이지 : 댓글 기능 구현
MrMirror21 Aug 16, 2023
d3b6ced
refactor: 댓글 개수 표기 컴포넌트 분리
MrMirror21 Sep 6, 2023
f4eb7aa
[feat]: 댓글 작성, 수정 기능 구현
MrMirror21 Sep 6, 2023
cb9e382
[feat]: 게시글 삭제 기능 구현
MrMirror21 Sep 13, 2023
5b5e95a
feat: 게시글 수정, 삭제 기능
MrMirror21 Sep 23, 2023
466dd2a
feat: 게시글 구독 기능 추가
MrMirror21 Sep 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
"@toast-ui/react-editor": "^3.2.3",
"axios": "^1.4.0",
"dotenv": "^16.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.1",
"react-router-dom": "^6.14.1",
"react-scripts": "5.0.1",
"react-scripts": "^5.0.1",
"redux": "^4.2.1",
"redux-devtools-extension": "^2.13.9",
"redux-logger": "^3.0.6",
Expand Down
15 changes: 11 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@ import { Route, Routes } from 'react-router';
import GlobalStyle from './styles/globalStyle';
import Landing from './pages/Landing';
import SignIn from './pages/SignIn';
import Diary from './pages/Diary';
import DiaryDetail from './pages/DiaryDetail';

const App = () => {
return (
<Routes>
<>
<GlobalStyle />
<Route path="/" element={<Landing />} />
<Route path="/signin" element={<SignIn />} />
</Routes>
<Routes>
<Route path="/" element={<Landing />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/diary" element={<Diary />} />
<Route path={"/diary/:postId"} element={<DiaryDetail />} />
</Routes>
</>

);
}

Expand Down
3 changes: 3 additions & 0 deletions src/assets/Triangle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/close_gray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/flag.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/images.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/paper_plane.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/pen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions src/components/SearchBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import styled from "styled-components";

const SearchBar = ({ width, height, fontSize, placeholder, value, onChange }) => {
return (
<StyledSearchBar requirement={{width, height, fontSize}}>
<input
type="text"
placeholder={placeholder}
value={value}
onChange={onChange}
/>
</StyledSearchBar>
);
};

export default SearchBar;

export const StyledSearchBar = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: ${(props) => props.requirement.width && props.requirement.width};
height: ${(props) => props.requirement.height && props.requirement.height};
min-height: 44px;
min-width: 375px;
padding-left: 30px;
padding-right: 30px;
border-radius: 100px;
background: #fafafa;
input {
width: ${(props) => props.requirement.width && props.requirement.width};
border: none;
border-radius: 100px;
outline: none;
background: #fafafa;
font-family: Pretendard;
font-size: ${(props) => props.requirement.fontSize && props.requirement.fontSize};
min-height: 44px;
min-width: 375px;
font-weight: 400;
line-height: 44px;
}
`;
44 changes: 44 additions & 0 deletions src/components/diary/PaginationBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react'
import { Link } from 'react-router-dom';
import styled from 'styled-components'

const PaginationBar = ({currentPage, totalPages, setPage}) => {
const renderLinks = (totalPages) => {
const links = [];
for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
links.push(
<Link to={`/diary/?page=${pageNum}`} key={pageNum} className={currentPage === pageNum ? "current" : "non-current"}>
{pageNum}
</Link>
);
}
return links;
}

return (
<>
<Container>
{renderLinks(totalPages)}
</Container>
</>
)
}

export default PaginationBar

const Container = styled.div`
display: flex;
align-items: center;
justify-content: center;
margin: auto;
a {
padding: 0.5rem;
text-decoration: none;
color: #313338;
}
.current {
font-weight: 600;
font-size: 18px
}
`;

29 changes: 29 additions & 0 deletions src/components/diary/PostEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import '@toast-ui/editor/dist/toastui-editor.css';
import { Editor } from '@toast-ui/react-editor';

const PostEditor = ({editorRef}) => {
const toolbarItems = [
['heading', 'bold', 'italic', 'strike'],
['hr'],
['ul', 'ol', 'task'],
['table', 'link'],
['image'],
['code'],
['scrollSync'],
]
return (
<>
<Editor
ref={editorRef}
initialValue={' '}
hideModeSwitch={true}
toolbarItems={toolbarItems}
height='50vh'
initialEditType='wysiwyg'
useCommandShortcut={true}
/>
</>
)
}

export default PostEditor
172 changes: 172 additions & 0 deletions src/components/diary/WritePostModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import React, { useRef, useState } from "react";
import styled from "styled-components";
import { ReactComponent as CloseIcon } from "../../assets/close_gray.svg";
import PostEditor from './PostEditor';
import { uploadPost } from '../../utils/axios';

const POST_IS_EMPTY = "<p><br></p>"

const WritePostModal = ({ setIsModalOpen, name}) => {
const ref = useRef(null);
const [title, setTitle] = useState("")

const handleModalClose = () => {
document.body.style.overflow = "unset";
setIsModalOpen(false);
};
const handleSubmit = () => {
try{
const editorlns = ref?.current?.getInstance();
const content = editorlns.getHTML();
const postData = {
"title" : title,
"content" : content,
"isAnonymous" : true,
"thumbnailIndex": 0,
}
if (content === POST_IS_EMPTY) {
alert('내용을 입력해주세요');
return
}
uploadPost(postData);
} catch (e) {
console.log(e);
alert('다시 시도해주세요');
return
}
setIsModalOpen(false);
}

return (
<>
<ModalBackground>
<ModalOutlay>
<CloseIcon
className="close-button"
onClick={() => handleModalClose()}
/>
<ModalHeader>
<ProfileImg />
<Name>{name}</Name>
</ModalHeader>
<ModalInner>
글 제목
<PostTitle value={title} placeholder="제목을 입력해주세요" onChange={(e) => {setTitle(e.currentTarget.value)}}></PostTitle>
<PostEditor editorRef={ref}/>
</ModalInner>
<ModalFooter>
<SubmitButton onClick={() => handleSubmit()}>게시물 올리기</SubmitButton>
</ModalFooter>
</ModalOutlay>
</ModalBackground>
</>
);
};

export default WritePostModal;

const ModalBackground = styled.div`
display: flex;
box-sizing: border-box;
position: fixed;
top: 64px;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
background: rgba(139, 139, 139, 0.2);
backdrop-filter: blur(15px);
z-index: 999;
overflow: hidden;
transition: .5s;
`;

const ModalOutlay = styled.div`
position: relative;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
flex-direction: column;
margin: auto;
width: 764px;
height: 80vh;
background: #ffffff;
border: 1px solid #fafafa;
box-sizing: border-box;
border-radius: 10px;
.close-button {
position: absolute;
top: 33px;
left: 712px;
color: #8b8b8b;
width: 14px;
height: 14px;
cursor: pointer;
}
`;

const ModalHeader = styled.div`
display: flex;
margin: 40px 45px 0px 45px;
height: 30px;
`;

const ProfileImg = styled.div`
width: 30px;
height: 30px;
border-radius: 100px;
background: #d2d2d2;
`;

const Name = styled.div`
display: flex;
align-items: center;
height: 30px;
font-family: Pretendard;
font-style: normal;
font-weight: bold;
font-size: 16px;
margin-left: 8px;
`;

const ModalInner = styled.div`
margin: 18px 45px 0px 45px;
`;

const PostTitle = styled.input`
width: 670px;
outline: none;
border: none;
background: #fafafa;
font-size: 20px;
padding: 10px;
border-radius: 10px;
`;

const ModalFooter = styled.div`
display: flex;
justify-content: center;
align-items: center;
margin: 56px 0px 45px 0px;
`;

const SubmitButton = styled.button`
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 400px;
height: 48px;
background: #7054ff;
border-radius: 30px;
color: #ffffff;
font-family: Pretendard;
font-style: normal;
font-weight: bold;
font-size: 20px;
line-height: 16px;
cursor: pointer;
`;
Loading