feat: Qna와 Answer 수정 삭제 생성 기능 추가
This commit is contained in:
parent
ebf5b15daa
commit
bdcd01acb7
@ -25,6 +25,7 @@ const MyInfoChangePage = lazy(async () => await import('./pages/MyInfoChangePage
|
||||
const PasswordChangePage = lazy(async () => await import('./pages/PasswordChangePage'));
|
||||
const LearningLecturesPage = lazy(async () => await import('./pages/LearningLecturesPage'));
|
||||
const LectureCreatePage = lazy(async () => await import('./pages/LectureCreatePage'));
|
||||
const EditQuestionPage = lazy(async () => await import('./pages/EditQuestionPage'));
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@ -97,8 +98,21 @@ const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: ':questionId',
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <QuestionDetailPage />,
|
||||
},
|
||||
{
|
||||
path: 'edit',
|
||||
element: <EditQuestionPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ':questionId/edit',
|
||||
element: <EditQuestionPage />,
|
||||
},
|
||||
{
|
||||
path: 'write',
|
||||
element: <CreateQuestionPage />,
|
||||
|
@ -2,13 +2,36 @@ import BackIcon from '/src/assets/icons/back.svg?react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './ArticleDetail.module.css';
|
||||
import ArticleDetailAnswer from './ArticleDetailAnswer/ArticleDetailAnswer';
|
||||
import ArticleDetailAnswerInput from './ArticleDetailAnswer/ArticleDetailAnswerInput';
|
||||
import EditIcon from '/src/assets/icons/edit.svg?react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export default function ArticleDetail({ topic, title, author = null, content, answer = null }) {
|
||||
// TODO: 답변 작성 기능 추가
|
||||
export default function ArticleDetail({ topic, title, author = null, content, answer = null, onDelete }) {
|
||||
const [submittedAnswer, setSubmittedAnswer] = useState(answer);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setSubmittedAnswer(answer);
|
||||
}, [answer]);
|
||||
|
||||
const handleAnswerSubmit = (newAnswer) => {
|
||||
setSubmittedAnswer(newAnswer);
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
const handleEditClick = () => {
|
||||
setIsEditing(true);
|
||||
};
|
||||
|
||||
const handleDeleteSubmit = () => {
|
||||
setSubmittedAnswer(null);
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.articleDetail}>
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerInside}>
|
||||
<Link
|
||||
to={'..'}
|
||||
className={styles.goBack}
|
||||
@ -20,11 +43,40 @@ export default function ArticleDetail({ topic, title, author = null, content, an
|
||||
<h1 className={styles.title}>{title}</h1>
|
||||
{author && <span className={styles.author}>{author}</span>}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
type="button"
|
||||
className={styles.editButton}
|
||||
to={'edit'}
|
||||
state={{ title: title, content: content, answer: answer }}
|
||||
>
|
||||
<EditIcon className={styles.icon} />
|
||||
<span>수정하기</span>
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.deleteButton}
|
||||
onClick={onDelete}
|
||||
>
|
||||
삭제하기
|
||||
</button>
|
||||
</header>
|
||||
<div>
|
||||
<p className={styles.content}>{content}</p>
|
||||
</div>
|
||||
{answer && <ArticleDetailAnswer answer={answer} />}
|
||||
{/* TODO: 이 부분에서 answer 만든다음 뒤로가기로 나갔다가 돌아오면 0.1초 정도 input 칸이 보였다가 answer 로 바뀜. 수정필요 */}
|
||||
{submittedAnswer && !isEditing ? (
|
||||
<ArticleDetailAnswer
|
||||
answer={submittedAnswer}
|
||||
onEditClick={handleEditClick}
|
||||
onDeleteSubmit={handleDeleteSubmit}
|
||||
/>
|
||||
) : (
|
||||
<ArticleDetailAnswerInput
|
||||
onSubmit={handleAnswerSubmit}
|
||||
initialAnswer={submittedAnswer}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -11,6 +11,12 @@
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.headerInside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
@ -49,3 +55,39 @@
|
||||
margin: 0;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.icon {
|
||||
stroke: var(--text-color);
|
||||
}
|
||||
|
||||
.editButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
background: var(--background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
font-weight: 700;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid var(--error-color);
|
||||
background-color: var(--error-color);
|
||||
color: var(--on-primary);
|
||||
stroke: var(--error-color);
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 700;
|
||||
align-self: end;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -1,14 +1,42 @@
|
||||
import styles from './ArticleDetailAnswer.module.css';
|
||||
import ReplyIcon from '/src/assets/icons/reply.svg?react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useAnswerDelete } from '../../../../hooks/api/useAnswerDelete';
|
||||
|
||||
export default function ArticleDetailAnswer({ answer, onEditClick, onDeleteSubmit }) {
|
||||
const { questionId } = useParams();
|
||||
const { answerDelete } = useAnswerDelete();
|
||||
|
||||
const handleDeleteSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
await answerDelete(questionId);
|
||||
onDeleteSubmit();
|
||||
};
|
||||
|
||||
export default function ArticleDetailAnswer({ answer }) {
|
||||
return (
|
||||
<>
|
||||
<section className={styles.answer}>
|
||||
<div className={styles.answerHeader}>
|
||||
<ReplyIcon />
|
||||
<div className={styles.author}>선생님의 답변</div>
|
||||
</div>
|
||||
<p className={styles.content}>{answer}</p>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.deleteButton}
|
||||
onClick={handleDeleteSubmit}
|
||||
>
|
||||
<div>삭제</div>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.editButton}
|
||||
onClick={onEditClick}
|
||||
>
|
||||
수정
|
||||
</button>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -29,3 +29,37 @@
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.editButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid var(--primary-color);
|
||||
background-color: var(--primary-color);
|
||||
color: var(--on-primary);
|
||||
stroke: var(--on-primary);
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 700;
|
||||
align-self: end;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid var(--error-color);
|
||||
background-color: var(--error-color);
|
||||
color: var(--on-primary);
|
||||
stroke: var(--on-primary);
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 700;
|
||||
align-self: end;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
import styles from './ArticleDetailAnswerInput.module.css';
|
||||
import { useAnswerWrite } from '../../../../hooks/api/useAnswerWrite';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function ArticleDetailAnswerInput({ onSubmit, initialAnswer }) {
|
||||
const { answerWrite } = useAnswerWrite();
|
||||
const { questionId } = useParams();
|
||||
const [newAnswer, setNewAnswer] = useState(initialAnswer);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
await answerWrite(questionId, newAnswer);
|
||||
onSubmit(newAnswer);
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className={styles.answer}
|
||||
>
|
||||
{/* TODO: 여기 css 부분은 내가 임의로 넣었음 */}
|
||||
<input
|
||||
type="text"
|
||||
value={newAnswer}
|
||||
onChange={(e) => setNewAnswer(e.target.value)}
|
||||
placeholder="답변 작성"
|
||||
className={styles.input}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className={styles.button}
|
||||
>
|
||||
작성
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
.answer {
|
||||
border: 1px solid #ccc;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.input {
|
||||
flex: 1;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 8px 16px;
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 700;
|
||||
background-color: var(--primary-color);
|
||||
color: var(--on-primary);
|
||||
stroke: var(--on-primary);
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
64
frontend/src/components/Article/EditQna/EditQna.jsx
Normal file
64
frontend/src/components/Article/EditQna/EditQna.jsx
Normal file
@ -0,0 +1,64 @@
|
||||
import { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './EditQna.module.css';
|
||||
import EditIcon from '/src/assets/icons/edit.svg?react';
|
||||
import BackIcon from '/src/assets/icons/back.svg?react';
|
||||
|
||||
export default function EditQna({ topic, title, prevContent, prevTitle, onSubmit }) {
|
||||
const [articleTitle, setArticleTitle] = useState(prevTitle);
|
||||
const [articleContent, setArticleContent] = useState(prevContent);
|
||||
|
||||
const handleInput = (e) => {
|
||||
setArticleContent(e.target.value);
|
||||
e.target.style.height = 'auto';
|
||||
e.target.style.height = e.target.scrollHeight + 'px';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.createArticle}>
|
||||
<header className={styles.header}>
|
||||
<Link
|
||||
to={'..'}
|
||||
className={styles.goBack}
|
||||
>
|
||||
<BackIcon />
|
||||
<span>{title}</span>
|
||||
</Link>
|
||||
<div className={styles.title}>{topic}</div>
|
||||
</header>
|
||||
<form
|
||||
className={styles.formWrapper}
|
||||
onSubmit={(e) => onSubmit(e, articleTitle, articleContent)}
|
||||
>
|
||||
<div className={styles.fieldWrapper}>
|
||||
<label className={styles.label}>제목</label>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.titleInput}
|
||||
placeholder={'제목을 입력하세요'}
|
||||
value={articleTitle}
|
||||
onChange={(e) => setArticleTitle(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.fieldWrapper}>
|
||||
<label className={styles.label}>내용</label>
|
||||
<textarea
|
||||
className={styles.contentInput}
|
||||
placeholder="내용을 입력하세요"
|
||||
value={articleContent}
|
||||
onChange={handleInput}
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.button}
|
||||
onClick={(e) => onSubmit(e, articleTitle, articleContent)}
|
||||
disabled={!articleTitle || !articleContent}
|
||||
>
|
||||
<EditIcon />
|
||||
<div>글 수정하기</div>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
110
frontend/src/components/Article/EditQna/EditQna.module.css
Normal file
110
frontend/src/components/Article/EditQna/EditQna.module.css
Normal file
@ -0,0 +1,110 @@
|
||||
.createArticle {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.goBack {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
font-weight: 400;
|
||||
color: var(--text-color-secondary);
|
||||
stroke: var(--text-color-secondary);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32px;
|
||||
line-height: 1.2;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.formWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.fieldWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--text-color);
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.titleInput {
|
||||
padding: 20px;
|
||||
background: var(--background);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.titleInput::placeholder {
|
||||
color: var(--text-color-tertiary);
|
||||
}
|
||||
|
||||
.contentInput {
|
||||
padding: 20px;
|
||||
height: 80px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: var(--background-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.contentInput::placeholder {
|
||||
color: var(--text-color-tertiary);
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid var(--primary-color);
|
||||
background-color: var(--primary-color);
|
||||
color: var(--on-primary);
|
||||
stroke: var(--on-primary);
|
||||
font-size: 16px;
|
||||
line-height: 1.4;
|
||||
font-weight: 700;
|
||||
align-self: end;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 0.25s,
|
||||
border-color 0.25s,
|
||||
stroke 0.25s,
|
||||
color 0.25s;
|
||||
}
|
||||
|
||||
.button:disabled,
|
||||
.button[disabled] {
|
||||
border-color: var(--border-color);
|
||||
background-color: var(--background-tertiary);
|
||||
color: var(--text-color-tertiary);
|
||||
cursor: not-allowed;
|
||||
stroke: var(--text-color-tertiary);
|
||||
}
|
@ -3,3 +3,5 @@ export { default as ArticleDetailAnswer } from './ArticleDetail/ArticleDetailAns
|
||||
export { default as CreateArticle } from './CreateArticle/CreateArticle.jsx';
|
||||
export { default as ArticlePreview } from './ArticlePreview/ArticlePreview.jsx';
|
||||
export { default as EditArticle } from './EditArticle/EditArticle.jsx';
|
||||
export { default as EditQna } from './EditQna/EditQna.jsx';
|
||||
export { default as ArticleDetailAnswerInput } from './ArticleDetail/ArticleDetailAnswer/ArticleDetailAnswerInput.jsx';
|
||||
|
13
frontend/src/hooks/api/useAnswerDelete.js
Normal file
13
frontend/src/hooks/api/useAnswerDelete.js
Normal file
@ -0,0 +1,13 @@
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export function useAnswerDelete() {
|
||||
const answerDelete = (questionId) => {
|
||||
const newAnswer = {
|
||||
answer: null,
|
||||
};
|
||||
return instance.post(`${API_URL}/qna/answer/create/${questionId}`, newAnswer);
|
||||
};
|
||||
|
||||
return { answerDelete };
|
||||
}
|
15
frontend/src/hooks/api/useAnswerEdit.js
Normal file
15
frontend/src/hooks/api/useAnswerEdit.js
Normal file
@ -0,0 +1,15 @@
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export function useAnswerEdit() {
|
||||
const answerEdit = (questionId, title, content, answer) => {
|
||||
const newAnswer = {
|
||||
title,
|
||||
content,
|
||||
answer,
|
||||
};
|
||||
return instance.put(`${API_URL}/qna/answer/update/${questionId}`, newAnswer);
|
||||
};
|
||||
|
||||
return { answerEdit };
|
||||
}
|
13
frontend/src/hooks/api/useAnswerWrite.js
Normal file
13
frontend/src/hooks/api/useAnswerWrite.js
Normal file
@ -0,0 +1,13 @@
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export function useAnswerWrite() {
|
||||
const answerWrite = (questionId, answer) => {
|
||||
const newAnswer = {
|
||||
answer: answer,
|
||||
};
|
||||
return instance.post(`${API_URL}/qna/answer/create/${questionId}`, newAnswer);
|
||||
};
|
||||
|
||||
return { answerWrite };
|
||||
}
|
10
frontend/src/hooks/api/useNoticeDelete.js
Normal file
10
frontend/src/hooks/api/useNoticeDelete.js
Normal file
@ -0,0 +1,10 @@
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export function useNoticeDelete() {
|
||||
const noticeDelete = (boardId) => {
|
||||
return instance.delete(`${API_URL}/board/${boardId}`);
|
||||
};
|
||||
|
||||
return { noticeDelete };
|
||||
}
|
10
frontend/src/hooks/api/useQnaDelete.js
Normal file
10
frontend/src/hooks/api/useQnaDelete.js
Normal file
@ -0,0 +1,10 @@
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export function useQnaDelete() {
|
||||
const qnaDelete = (questionId) => {
|
||||
return instance.delete(`${API_URL}/qna/${questionId}`);
|
||||
};
|
||||
|
||||
return { qnaDelete };
|
||||
}
|
15
frontend/src/hooks/api/useQnaEdit.js
Normal file
15
frontend/src/hooks/api/useQnaEdit.js
Normal file
@ -0,0 +1,15 @@
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export function useQnaEdit() {
|
||||
const qnaEdit = (questionId, title, content, answer) => {
|
||||
const newQna = {
|
||||
title,
|
||||
content,
|
||||
answer,
|
||||
};
|
||||
return instance.put(`${API_URL}/qna/${questionId}`, newQna);
|
||||
};
|
||||
|
||||
return { qnaEdit };
|
||||
}
|
27
frontend/src/pages/EditQuestionPage/EditQuestionPage.jsx
Normal file
27
frontend/src/pages/EditQuestionPage/EditQuestionPage.jsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { useQnaEdit } from '../../hooks/api/useQnaEdit';
|
||||
import { useParams, useNavigate, useLocation } from 'react-router-dom';
|
||||
import { EditQna } from '../../components/Article';
|
||||
|
||||
export default function EditQuestionPage() {
|
||||
const navigate = useNavigate();
|
||||
const { questionId } = useParams();
|
||||
const { qnaEdit } = useQnaEdit();
|
||||
const location = useLocation();
|
||||
|
||||
const handleSubmit = async (e, title, content, answer) => {
|
||||
e.preventDefault();
|
||||
|
||||
await qnaEdit(questionId, title, content, answer);
|
||||
navigate('..');
|
||||
};
|
||||
return (
|
||||
<EditQna
|
||||
topic="질문하기"
|
||||
title="Q&A"
|
||||
prevTitle={location.state.title}
|
||||
prevContent={location.state.content}
|
||||
prevAnswer={location.state.answer}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
);
|
||||
}
|
1
frontend/src/pages/EditQuestionPage/index.js
Normal file
1
frontend/src/pages/EditQuestionPage/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './EditQuestionPage';
|
@ -1,19 +1,28 @@
|
||||
import { ArticleDetail } from '../../components/Article';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useNoticeDetail } from '../../hooks/api/useNoticeDetail';
|
||||
import { useNoticeDelete } from '../../hooks/api/useNoticeDelete';
|
||||
|
||||
export default function NoticeDetailPage() {
|
||||
const params = useParams();
|
||||
const noticeId = params.noticeId;
|
||||
const { data } = useNoticeDetail(noticeId);
|
||||
const notice = data?.data;
|
||||
const navigate = useNavigate();
|
||||
const { noticeDelete } = useNoticeDelete();
|
||||
// TODO: 수정 버튼 추가(여기에 또는 ArticleDetail에)
|
||||
|
||||
const handleDelete = async () => {
|
||||
await noticeDelete(noticeId);
|
||||
navigate('..');
|
||||
};
|
||||
|
||||
return (
|
||||
<ArticleDetail
|
||||
topic="공지사항"
|
||||
title={notice.title}
|
||||
content={notice.content}
|
||||
onDelete={handleDelete}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
import { ArticleDetail } from '../../components/Article';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useQnaDetail } from '../../hooks/api/useQnaDetail';
|
||||
import { useQnaDelete } from '../../hooks/api/useQnaDelete';
|
||||
|
||||
export default function QuestionDetailPage() {
|
||||
const params = useParams();
|
||||
const qnaId = params.questionId;
|
||||
const { data } = useQnaDetail(qnaId);
|
||||
const qna = data?.data;
|
||||
const { qnaDelete } = useQnaDelete();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleDelete = async () => {
|
||||
await qnaDelete(qnaId);
|
||||
navigate('..');
|
||||
};
|
||||
|
||||
return (
|
||||
<ArticleDetail
|
||||
@ -15,6 +23,7 @@ export default function QuestionDetailPage() {
|
||||
author={qna.username}
|
||||
content={qna.content}
|
||||
answer={qna?.answer}
|
||||
onDelete={handleDelete}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user