-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #121 from soohwanpak/next-박수환-sprint8
[박수환] Sprint8
- Loading branch information
Showing
52 changed files
with
6,516 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "next/core-web-vitals" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.* | ||
.yarn/* | ||
!.yarn/patches | ||
!.yarn/plugins | ||
!.yarn/releases | ||
!.yarn/versions | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# env files (can opt-in for committing if needed) | ||
.env* | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { useState, useRef, useEffect } from 'react'; | ||
import styles from '@/css/Dropdown.module.css'; | ||
import Image from 'next/image'; | ||
import instance from '@/lib/axios'; | ||
|
||
export default function ArticleCommentDropDown({ id, onCommentAdded }) { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const [isEditing, setIsEditing] = useState(false); | ||
const [editContent, setEditContent] = useState('댓글 수정'); | ||
const dropdownRef = useRef(null); | ||
|
||
|
||
const toggleDropdown = () => { | ||
setIsOpen(!isOpen); | ||
}; | ||
|
||
const handlePatch = () => { | ||
try { | ||
instance.patch(`/articleComment/${id}`, { | ||
content: editContent, | ||
}); | ||
alert('댓글이 수정되었습니다!'); | ||
setIsEditing(!isEditing); | ||
setIsOpen(!isOpen); | ||
onCommentAdded(); | ||
} catch (error) { | ||
console.error('댓글 수정 중 오류 발생:', error); | ||
} | ||
} | ||
|
||
const handleDelete = () => { | ||
instance.delete(`/articleComment/${id}`) | ||
.then((response) => { | ||
alert("댓글이 삭제되었습니다!"); | ||
onCommentAdded(); | ||
setIsOpen(!isOpen); | ||
}).catch((error) => { | ||
console.error(error); | ||
}); | ||
}; | ||
|
||
useEffect(() => { | ||
const handleClickOutside = (e) => { | ||
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) { | ||
setIsOpen(false); | ||
} | ||
}; | ||
|
||
window.addEventListener('click', handleClickOutside); | ||
return () => { | ||
window.removeEventListener('click', handleClickOutside); | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<div className={styles.dropdownContainer} ref={dropdownRef}> | ||
<button | ||
className={styles.dropdownButton1} | ||
onClick={toggleDropdown} | ||
> | ||
<Image | ||
width={24} | ||
height={24} | ||
src="/images/dropdownbutton.png" alt="User" /> | ||
</button> | ||
{isOpen && ( | ||
<ul className={styles.dropdownMenu}> | ||
<div | ||
className={styles.menuItem1} | ||
onClick={() => handlePatch()} | ||
> | ||
수정하기 | ||
</div> | ||
<div | ||
className={styles.menuItem1} | ||
onClick={() => handleDelete('삭제하기')} | ||
> | ||
삭제하기 | ||
</div> | ||
</ul> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import styles from '@/css/articleDetail.module.css'; | ||
import Image from 'next/image'; | ||
import dayjs from "dayjs"; | ||
import { useRouter } from 'next/router'; | ||
import { useState } from 'react'; | ||
import instance from '@/lib/axios'; | ||
import ArticleDropDown from './ArticleDropDown'; | ||
import ArticleCommentDropDown from './ArticleCommentDropDown'; | ||
|
||
export default function ArticleDetail({ article, onCommentAdded }) { | ||
const [content, setContent] = useState(''); | ||
const router = useRouter(); | ||
|
||
const handleClick = () => { | ||
router.push(`/`); | ||
}; | ||
|
||
const handlePostSubmit = () => { | ||
if (!content) { | ||
alert('내용을 입력해주세요!'); | ||
} | ||
if (content) { | ||
instance.post(`/articleComment`, { | ||
articleId: article.id, | ||
content, | ||
}).then((response) => { | ||
alert("댓글이 등록되었습니다!"); | ||
onCommentAdded(); | ||
setContent(''); | ||
}).catch((error) => { | ||
console.error(error); | ||
}); | ||
} | ||
}; | ||
|
||
const handleKeyDown = (e) => { | ||
if (e.key === 'Enter') { | ||
handlePostSubmit(); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className={styles.articleDetailContain}> | ||
<div className={styles.ArticleDetailHead}> | ||
<div className={styles.ArticleDetailText}> | ||
{article.title} | ||
</div> | ||
<ArticleDropDown id={article.id} /> | ||
</div> | ||
<div className={styles.ArticleDetailMain}> | ||
<div className={styles.ArticleDetailUser}> | ||
<div> | ||
<Image | ||
width={40} | ||
height={40} | ||
src="/images/userIcon.png" alt="User" /> | ||
</div> | ||
<div className={styles.ArticleDetailUserName}>{article.user}</div> | ||
<div className={styles.ArticleDetailDate}>{dayjs(article.createdAt).format('YYYY. MM. DD')}</div> | ||
</div> | ||
<div className={styles.ArticleDetailLikeContain}> | ||
<div className={styles.heartIconImage}> | ||
<Image | ||
width={36} | ||
height={36} | ||
src="/images/heart.png" alt="heart" /> | ||
</div> | ||
<div className={styles.ArticleDetailLikeCount}>{article.like}</div> | ||
</div> | ||
</div> | ||
|
||
<div className={styles.ArticleDetailLikeContain2}> | ||
{article.content} | ||
</div> | ||
|
||
<div className={styles.ArticleDetailCommentTitle}>댓글 달기</div> | ||
<textarea | ||
value={content} | ||
onKeyDown={handleKeyDown} | ||
onChange={(e) => setContent(e.target.value)} | ||
className={styles.ArticleDetailInput} | ||
placeholder='내용을 입력해주세요' /> | ||
<div className={styles.ArticleDetailCommentRegContain}> | ||
<div | ||
onClick={handlePostSubmit} | ||
className={styles.ArticleDetailCommentReg}>등록</div> | ||
</div> | ||
|
||
|
||
{article.ArticleComment && article.ArticleComment.length > 0 ? ( | ||
article.ArticleComment.map((comment, index) => ( | ||
<div key={index} className={styles.ArticleDetailCommentBoxContain}> | ||
<div className={styles.ArticleDetailCommentBox}> | ||
<div> | ||
{comment.content} | ||
</div> | ||
<ArticleCommentDropDown id={comment.id} onCommentAdded={onCommentAdded} /> | ||
</div> | ||
|
||
<div className={styles.ArticleDetailCommentUserAll}> | ||
<div> | ||
<Image | ||
width={40} | ||
height={40} | ||
src="/images/userIcon.png" | ||
alt="User" | ||
/> | ||
</div> | ||
<div className={styles.ArticleDetailCommentUser}> | ||
<div className={styles.ArticleDetailCommentUserName}> | ||
{comment.user} | ||
</div> | ||
<div className={styles.ArticleDetailCommentUserTime}> | ||
{dayjs(comment.createdAt).format('YYYY. MM. DD')} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
)) | ||
) : ( | ||
<div className={styles.noCommentImage}> | ||
<Image | ||
width={1200} | ||
height={208} | ||
src="/images/noComment.png" | ||
alt="User" | ||
/> | ||
</div> | ||
)} | ||
<div | ||
onClick={handleClick} | ||
className={styles.returnImage}> | ||
<Image | ||
width={240} | ||
height={48} | ||
src="/images/return.png" | ||
alt="User" | ||
/> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { useState, useRef, useEffect } from 'react'; | ||
import styles from '@/css/Dropdown.module.css'; | ||
import Image from 'next/image'; | ||
import instance from '@/lib/axios'; | ||
import { useRouter } from 'next/router'; | ||
|
||
export default function ArticleDropDown({ id }) { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const dropdownRef = useRef(null); | ||
const router = useRouter(); | ||
|
||
const toggleDropdown1 = () => { | ||
setIsOpen(!isOpen); | ||
}; | ||
|
||
const handleDelete1 = () => { | ||
instance.delete(`/article/${id}`) | ||
.then((response) => { | ||
alert("게시글이 삭제되었습니다!"); | ||
router.push(`/`); | ||
}).catch((error) => { | ||
console.error(error); | ||
}); | ||
}; | ||
|
||
const handlePatch = () => { | ||
router.push(`/${id}/articleUpdate`); | ||
}; | ||
|
||
useEffect(() => { | ||
const handleClickOutside = (e) => { | ||
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) { | ||
setIsOpen(false); | ||
} | ||
}; | ||
|
||
window.addEventListener('click', handleClickOutside); | ||
return () => { | ||
window.removeEventListener('click', handleClickOutside); | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<div className={styles.dropdownContainer} ref={dropdownRef}> | ||
<button | ||
className={styles.dropdownButton2} | ||
onClick={toggleDropdown1} | ||
> | ||
<Image | ||
width={24} | ||
height={24} | ||
src="/images/dropdownbutton.png" alt="dropdownbutton" /> | ||
</button> | ||
{isOpen && ( | ||
<ul className={styles.dropdownMenu}> | ||
<div | ||
className={styles.menuItem2} | ||
onClick={() => handlePatch()} | ||
> | ||
수정하기 | ||
</div> | ||
<div | ||
className={styles.menuItem2} | ||
onClick={() => handleDelete1()} | ||
> | ||
삭제하기 | ||
</div> | ||
</ul> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import BestItemList from './BestItemList'; | ||
import { useState, useEffect } from "react"; | ||
import styles from '@/css/BestItem.module.css' | ||
import instance from "@/lib/axios"; | ||
|
||
export default function BestItem({ }) { | ||
|
||
const [posts, setPosts] = useState([]); | ||
|
||
useEffect(() => { | ||
instance.get(`/article/articleList?pageSize=3&orderBy='like'`) | ||
.then((response) => { | ||
setPosts(response.data.Articles); | ||
}) | ||
.catch((error) => console.error(error)); | ||
}, []); | ||
|
||
return ( | ||
<div className={styles.BestItemContain}> | ||
<div className={styles.BestItemHeader}>베스트 게시글 </div> | ||
<div className={styles.test123}> | ||
{posts.map((post) => ( | ||
<BestItemList key={post.id} post={post} /> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.