From a10476e8d14d028a6c10801d8a051cd8022e801f Mon Sep 17 00:00:00 2001 From: junAlexx Date: Tue, 24 Dec 2024 15:12:17 +0900 Subject: [PATCH 1/7] =?UTF-8?q?:art:=20chore=20:=20=EC=BC=80=EB=B0=A5=20?= =?UTF-8?q?=EB=A9=94=EB=89=B4=20=ED=86=A0=EA=B8=80=20=EB=B0=8F=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=A4=91=20=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EA=B0=80=EB=A6=AC=EA=B8=B0=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AnswerDelete/index.jsx | 28 ++++++++++++-------- src/components/AnswerEdit/index.jsx | 15 +++++++---- src/components/AnswerRejection/index.jsx | 4 ++- src/components/Kebab/index.jsx | 11 ++++---- src/components/QnAList/index.jsx | 1 + src/components/QuestionDelete/index.jsx | 30 +++++++++++---------- src/pages/Answer/index.jsx | 33 +++++++++++++----------- 7 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/components/AnswerDelete/index.jsx b/src/components/AnswerDelete/index.jsx index 4603c3a..67d5e6b 100644 --- a/src/components/AnswerDelete/index.jsx +++ b/src/components/AnswerDelete/index.jsx @@ -4,10 +4,12 @@ import PropTypes from 'prop-types'; import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -const AnswerDelete = ({ answerId, onAnswerDeleted }) => { +const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick }) => { AnswerDelete.propTypes = { + id: PropTypes.number.isRequired, answerId: PropTypes.number.isRequired, onAnswerDeleted: PropTypes.func.isRequired, + onKebabClick: PropTypes.func.isRequired, }; const [isDeleting, setIsDeleting] = useState(false); @@ -15,18 +17,22 @@ const AnswerDelete = ({ answerId, onAnswerDeleted }) => { const navigate = useNavigate(); const handleAnswerDelete = async () => { - setIsDeleting(true); + const userConfirmed = window.confirm('정말로 삭제하시겠습니까?', ''); // user 확인작업은 confirm으로 임시로 만들었습니다. + if (userConfirmed) { + onKebabClick(id); + setIsDeleting(true); - try { - const response = await deleteAnswer(answerId); - if (!response.ok) { - throw new Error('답변 삭제 중 오류가 발생했습니다.'); + try { + const response = await deleteAnswer(answerId); + if (!response.ok) { + throw new Error('답변 삭제 중 오류가 발생했습니다.'); + } + onAnswerDeleted(answerId); + } catch (err) { + navigate('/'); + } finally { + setIsDeleting(false); } - onAnswerDeleted(answerId); - } catch (err) { - navigate('/'); - } finally { - setIsDeleting(false); } }; diff --git a/src/components/AnswerEdit/index.jsx b/src/components/AnswerEdit/index.jsx index b6f1a6f..d3f0f5e 100644 --- a/src/components/AnswerEdit/index.jsx +++ b/src/components/AnswerEdit/index.jsx @@ -2,21 +2,26 @@ import PropTypes from 'prop-types'; import { ReactComponent as Edit } from 'assets/images/icons/ic_Edit.svg'; // eslint-disable-next-line -const AnswerEdit = ({ id, setEditId, answerId }) => { +const AnswerEdit = ({ id, editId, setEditId, answerId, onKebabClick }) => { AnswerEdit.propTypes = { id: PropTypes.number.isRequired, + editId: PropTypes.number.isRequired, setEditId: PropTypes.func.isRequired, + onKebabClick: PropTypes.func.isRequired, }; const handleEdit = () => { setEditId(answerId); + onKebabClick(id); }; return ( - + editId === null && ( + + ) ); }; diff --git a/src/components/AnswerRejection/index.jsx b/src/components/AnswerRejection/index.jsx index 2b568fe..f127390 100644 --- a/src/components/AnswerRejection/index.jsx +++ b/src/components/AnswerRejection/index.jsx @@ -3,10 +3,11 @@ import { useState } from 'react'; import { postAnswer } from 'api/answers'; import { ReactComponent as Rejection } from 'assets/images/icons/ic_Rejection.svg'; -const AnswerRejection = ({ id, setQuestionList }) => { +const AnswerRejection = ({ id, setQuestionList, onKebabClick }) => { AnswerRejection.propTypes = { id: PropTypes.number.isRequired, setQuestionList: PropTypes.func.isRequired, + onKebabClick: PropTypes.func.isRequired, }; const [isLoading, setIsLoading] = useState(false); @@ -17,6 +18,7 @@ const AnswerRejection = ({ id, setQuestionList }) => { try { setIsLoading(true); setError(null); + onKebabClick(id); const result = await postAnswer(id, { content: defaultContent, diff --git a/src/components/Kebab/index.jsx b/src/components/Kebab/index.jsx index 65bb775..715f2aa 100644 --- a/src/components/Kebab/index.jsx +++ b/src/components/Kebab/index.jsx @@ -6,7 +6,7 @@ import kebab from 'assets/images/icons/ic_Kebab.svg'; import AnswerDelete from 'components/AnswerDelete'; import AnswerEdit from 'components/AnswerEdit'; -const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAnswerDeleted, setQuestionList, setEditId, answerId }) => { +const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAnswerDeleted, setQuestionList, editId, setEditId, answerId }) => { Kebab.propTypes = { id: PropTypes.number.isRequired, isAnswer: PropTypes.shape({ @@ -21,6 +21,7 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn onDeleteQuestion: PropTypes.func.isRequired, onAnswerDeleted: PropTypes.func.isRequired, setQuestionList: PropTypes.func.isRequired, + editId: PropTypes.number.isRequired, setEditId: PropTypes.func.isRequired, answerId: PropTypes.number.isRequired, }; @@ -62,7 +63,7 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn {!isAnswer ? ( <>
- +
@@ -71,13 +72,13 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn ) : ( <>
- +
- +
- +
)} diff --git a/src/components/QnAList/index.jsx b/src/components/QnAList/index.jsx index 47452c8..f13e44a 100644 --- a/src/components/QnAList/index.jsx +++ b/src/components/QnAList/index.jsx @@ -80,6 +80,7 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue onDeleteQuestion={handleDeleteQuestion} onAnswerDeleted={handleAnswerDeleted} setQuestionList={setQuestionList} + editId={editId} setEditId={setEditId} answerId={question.answer ? question.answer.id : null} /> diff --git a/src/components/QuestionDelete/index.jsx b/src/components/QuestionDelete/index.jsx index 54ea43c..34f216a 100644 --- a/src/components/QuestionDelete/index.jsx +++ b/src/components/QuestionDelete/index.jsx @@ -13,23 +13,25 @@ const QuestionDelete = ({ id, onDeleteQuestion }) => { const [error, setError] = useState(null); const handleDelete = async () => { - try { - setIsLoading(true); - setError(null); - - const response = await deleteQuestion(id); - if (!response.ok) { - throw new Error('질문 삭제 중 오류가 발생했습니다.'); + const userConfirmed = window.confirm('정말로 삭제하시겠습니까?', ''); // user 확인작업은 confirm으로 임시로 만들었습니다. + if (userConfirmed) { + try { + setIsLoading(true); + setError(null); + + const response = await deleteQuestion(id); + if (!response.ok) { + throw new Error('질문 삭제 중 오류가 발생했습니다.'); + } + + onDeleteQuestion(id); + } catch (err) { + setError('질문 삭제 중 오류가 발생했습니다.'); + } finally { + setIsLoading(false); } - - onDeleteQuestion(id); - } catch (err) { - setError('질문 삭제 중 오류가 발생했습니다.'); - } finally { - setIsLoading(false); } }; - if (error) { return
에러: {error}
; } diff --git a/src/pages/Answer/index.jsx b/src/pages/Answer/index.jsx index b0cb7fa..1e4884d 100644 --- a/src/pages/Answer/index.jsx +++ b/src/pages/Answer/index.jsx @@ -42,21 +42,24 @@ const Answer = () => { const observerRef = useRef(null); const handleDelete = async () => { - try { - const response = await deleteSubject(subjectId); - if (!response.ok) { - throw new Error('삭제 중 오류가 발생했습니다. 3초 후 페이지를 새로고침 합니다.'); + const userConfirmed = window.confirm('정말로 삭제하시겠습니까?', ''); // user 확인작업은 confirm으로 임시로 만들었습니다. + if (userConfirmed) { + try { + const response = await deleteSubject(subjectId); + if (!response.ok) { + throw new Error('삭제 중 오류가 발생했습니다. 3초 후 페이지를 새로고침 합니다.'); + } + localStorage.removeItem('id'); + setIsDelete(true); + setTimeout(() => { + navigate('/'); + }, 2000); + } catch (err) { + setError(err.message); + setTimeout(() => { + setError(null); + }, 3000); } - localStorage.removeItem('id'); - setIsDelete(true); - setTimeout(() => { - navigate('/'); - }, 2000); - } catch (err) { - setError(err.message); - setTimeout(() => { - setError(null); - }, 3000); } }; @@ -161,7 +164,7 @@ const Answer = () => { return (
-
+
{isDelete ? (
From 9c133942fb52e8a09086482dd1b1b7f9d00bfc55 Mon Sep 17 00:00:00 2001 From: junAlexx Date: Tue, 24 Dec 2024 20:11:41 +0900 Subject: [PATCH 2/7] =?UTF-8?q?:art:=20chore=20:=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=ED=81=B4=EB=A6=AD=20?= =?UTF-8?q?=EC=8B=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=EC=9A=A9=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AnswerDelete/index.jsx | 64 ++++++++++++++---------- src/components/AnswerEdit/index.jsx | 2 +- src/components/AnswerRejection/index.jsx | 2 +- src/components/ConfirmModal/index.jsx | 52 +++++++++++++++++++ src/components/QuestionDelete/index.jsx | 58 +++++++++++++-------- src/pages/Answer/index.jsx | 44 +++++++++------- 6 files changed, 157 insertions(+), 65 deletions(-) create mode 100644 src/components/ConfirmModal/index.jsx diff --git a/src/components/AnswerDelete/index.jsx b/src/components/AnswerDelete/index.jsx index 67d5e6b..b788391 100644 --- a/src/components/AnswerDelete/index.jsx +++ b/src/components/AnswerDelete/index.jsx @@ -3,6 +3,7 @@ import { ReactComponent as Close } from 'assets/images/icons/ic_Close.svg'; import PropTypes from 'prop-types'; import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import ConfirmModal from 'components/ConfirmModal'; // Import the modal component const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick }) => { AnswerDelete.propTypes = { @@ -13,39 +14,50 @@ const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick }) => { }; const [isDeleting, setIsDeleting] = useState(false); - // const [error, setError] = useState(null); const navigate = useNavigate(); - const handleAnswerDelete = async () => { - const userConfirmed = window.confirm('정말로 삭제하시겠습니까?', ''); // user 확인작업은 confirm으로 임시로 만들었습니다. - if (userConfirmed) { - onKebabClick(id); - setIsDeleting(true); - - try { - const response = await deleteAnswer(answerId); - if (!response.ok) { - throw new Error('답변 삭제 중 오류가 발생했습니다.'); - } - onAnswerDeleted(answerId); - } catch (err) { - navigate('/'); - } finally { - setIsDeleting(false); + const [showModal, setShowModal] = useState(false); + + const handleDelete = async () => { + setShowModal(true); // Show the modal when delete is clicked + }; + + const handleModalCancel = () => { + onKebabClick(id); + setShowModal(false); // Close the modal if canceled + }; + + const handleModalConfirm = async () => { + onKebabClick(id); + setShowModal(false); // Close the modal + setIsDeleting(true); + + try { + const response = await deleteAnswer(answerId); + if (!response.ok) { + throw new Error('답변 삭제 중 오류가 발생했습니다.'); } + onAnswerDeleted(answerId); + } catch (err) { + navigate('/'); + } finally { + setIsDeleting(false); } }; return ( - + <> + + + ); }; diff --git a/src/components/AnswerEdit/index.jsx b/src/components/AnswerEdit/index.jsx index d3f0f5e..c20af6d 100644 --- a/src/components/AnswerEdit/index.jsx +++ b/src/components/AnswerEdit/index.jsx @@ -17,7 +17,7 @@ const AnswerEdit = ({ id, editId, setEditId, answerId, onKebabClick }) => { return ( editId === null && ( - diff --git a/src/components/AnswerRejection/index.jsx b/src/components/AnswerRejection/index.jsx index f127390..e50c28f 100644 --- a/src/components/AnswerRejection/index.jsx +++ b/src/components/AnswerRejection/index.jsx @@ -47,7 +47,7 @@ const AnswerRejection = ({ id, setQuestionList, onKebabClick }) => { return ( + +
+
+
+ ); +}; + +export default ConfirmModal; diff --git a/src/components/QuestionDelete/index.jsx b/src/components/QuestionDelete/index.jsx index 34f216a..de1cb5f 100644 --- a/src/components/QuestionDelete/index.jsx +++ b/src/components/QuestionDelete/index.jsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import { useState } from 'react'; import { deleteQuestion } from 'api/questions'; import { ReactComponent as Close } from 'assets/images/icons/ic_Close.svg'; +import ConfirmModal from 'components/ConfirmModal'; // Import the modal component const QuestionDelete = ({ id, onDeleteQuestion }) => { QuestionDelete.propTypes = { @@ -12,24 +13,33 @@ const QuestionDelete = ({ id, onDeleteQuestion }) => { const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); + const [showModal, setShowModal] = useState(false); + const handleDelete = async () => { - const userConfirmed = window.confirm('정말로 삭제하시겠습니까?', ''); // user 확인작업은 confirm으로 임시로 만들었습니다. - if (userConfirmed) { - try { - setIsLoading(true); - setError(null); - - const response = await deleteQuestion(id); - if (!response.ok) { - throw new Error('질문 삭제 중 오류가 발생했습니다.'); - } - - onDeleteQuestion(id); - } catch (err) { - setError('질문 삭제 중 오류가 발생했습니다.'); - } finally { - setIsLoading(false); + setShowModal(true); // Show the modal when delete is clicked + }; + + const handleModalCancel = () => { + setShowModal(false); // Close the modal if canceled + }; + + const handleModalConfirm = async () => { + setShowModal(false); // Close the moda + + try { + setIsLoading(true); + setError(null); + + const response = await deleteQuestion(id); + if (!response.ok) { + throw new Error('질문 삭제 중 오류가 발생했습니다.'); } + + onDeleteQuestion(id); + } catch (err) { + setError('질문 삭제 중 오류가 발생했습니다.'); + } finally { + setIsLoading(false); } }; if (error) { @@ -37,10 +47,18 @@ const QuestionDelete = ({ id, onDeleteQuestion }) => { } return ( - + <> + + + ); }; diff --git a/src/pages/Answer/index.jsx b/src/pages/Answer/index.jsx index 1e4884d..594acd4 100644 --- a/src/pages/Answer/index.jsx +++ b/src/pages/Answer/index.jsx @@ -8,6 +8,7 @@ import CountQuestion from 'components/CountQuestion'; import QnAList from 'components/QnAList'; import ToastDeleteId from 'components/ToastDeleteId'; import questionBoxImg from 'assets/images/img_QuestionBox.svg'; +import ConfirmModal from 'components/ConfirmModal'; // Import the modal component const getDynamicLimit = () => { const screenHeight = window.innerHeight; @@ -41,25 +42,33 @@ const Answer = () => { const observerRef = useRef(null); + const [showModal, setShowModal] = useState(false); // State for showing the modal + const handleDelete = async () => { - const userConfirmed = window.confirm('정말로 삭제하시겠습니까?', ''); // user 확인작업은 confirm으로 임시로 만들었습니다. - if (userConfirmed) { - try { - const response = await deleteSubject(subjectId); - if (!response.ok) { - throw new Error('삭제 중 오류가 발생했습니다. 3초 후 페이지를 새로고침 합니다.'); - } - localStorage.removeItem('id'); - setIsDelete(true); - setTimeout(() => { - navigate('/'); - }, 2000); - } catch (err) { - setError(err.message); - setTimeout(() => { - setError(null); - }, 3000); + setShowModal(true); // Show the modal when delete is clicked + }; + + const handleModalCancel = () => { + setShowModal(false); // Close the modal if canceled + }; + + const handleModalConfirm = async () => { + setShowModal(false); // Close the modal + try { + const response = await deleteSubject(subjectId); + if (!response.ok) { + throw new Error('삭제 중 오류가 발생했습니다. 3초 후 페이지를 새로고침 합니다.'); } + localStorage.removeItem('id'); + setIsDelete(true); + setTimeout(() => { + navigate('/'); + }, 2000); + } catch (err) { + setError(err.message); + setTimeout(() => { + setError(null); + }, 3000); } }; @@ -185,6 +194,7 @@ const Answer = () => { )}
{isDelete && } +
); }; From 8bd4a20ad575611125ccd9b898128dd57e9a7a2c Mon Sep 17 00:00:00 2001 From: junAlexx Date: Tue, 24 Dec 2024 21:06:06 +0900 Subject: [PATCH 3/7] =?UTF-8?q?:lipstick:=20chore=20:=20=EC=BC=80=EB=B0=A5?= =?UTF-8?q?=20=EB=A1=9C=EB=94=A9=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=ED=99=95=EC=9D=B8=20=EB=AA=A8=EB=8B=AC=20=EC=97=90?= =?UTF-8?q?=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AnswerContent/index.jsx | 5 ++++- src/components/AnswerDelete/index.jsx | 5 ++++- src/components/AnswerEditForm/index.jsx | 5 ++++- src/components/AnswerRejection/index.jsx | 7 +++++-- src/components/ConfirmModal/index.jsx | 4 ++-- src/components/Kebab/index.jsx | 16 +++++++++------- src/components/QnAList/index.jsx | 6 +++++- src/components/QuestionDelete/index.jsx | 5 ++++- 8 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/components/AnswerContent/index.jsx b/src/components/AnswerContent/index.jsx index fb1544b..9161000 100644 --- a/src/components/AnswerContent/index.jsx +++ b/src/components/AnswerContent/index.jsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import formatCreatedAt from 'utils/dateUtils'; import { postAnswer } from 'api/answers'; -const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit }) => { +const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit, setIsKebabLoading }) => { AnswerContent.propTypes = { answer: PropTypes.shape({ id: PropTypes.number.isRequired, @@ -16,6 +16,7 @@ const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit }) => { imageSource: PropTypes.string, id: PropTypes.number.isRequired, onAnswerSubmit: PropTypes.func.isRequired, + setIsKebabLoading: PropTypes.func.isRequired, }; AnswerContent.defaultProps = { @@ -45,6 +46,7 @@ const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit }) => { let response; try { + setIsKebabLoading(true); setIsLoading(true); response = await postAnswer(id, postBody); setUpdatedAnswer(response); @@ -53,6 +55,7 @@ const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit }) => { // eslint-disable-next-line console.error(err); } finally { + setIsKebabLoading(false); setIsLoading(false); } }; diff --git a/src/components/AnswerDelete/index.jsx b/src/components/AnswerDelete/index.jsx index b788391..03c335b 100644 --- a/src/components/AnswerDelete/index.jsx +++ b/src/components/AnswerDelete/index.jsx @@ -5,12 +5,13 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import ConfirmModal from 'components/ConfirmModal'; // Import the modal component -const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick }) => { +const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabLoading }) => { AnswerDelete.propTypes = { id: PropTypes.number.isRequired, answerId: PropTypes.number.isRequired, onAnswerDeleted: PropTypes.func.isRequired, onKebabClick: PropTypes.func.isRequired, + setIsKebabLoading: PropTypes.func.isRequired, }; const [isDeleting, setIsDeleting] = useState(false); @@ -29,6 +30,7 @@ const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick }) => { const handleModalConfirm = async () => { onKebabClick(id); + setIsKebabLoading(true); setShowModal(false); // Close the modal setIsDeleting(true); @@ -42,6 +44,7 @@ const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick }) => { navigate('/'); } finally { setIsDeleting(false); + setIsKebabLoading(false); } }; diff --git a/src/components/AnswerEditForm/index.jsx b/src/components/AnswerEditForm/index.jsx index 74d0b6e..eeeb141 100644 --- a/src/components/AnswerEditForm/index.jsx +++ b/src/components/AnswerEditForm/index.jsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import { putAnswer } from 'api/answers'; // eslint-disable-next-line -const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionList }) => { +const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionList, setIsKebabLoading }) => { AnswerEditForm.propTypes = { answer: PropTypes.shape({ id: PropTypes.number.isRequired, @@ -14,6 +14,7 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL name: PropTypes.string.isRequired, imageSource: PropTypes.string, id: PropTypes.number.isRequired, + setIsKebabLoading: PropTypes.func.isRequired, }; AnswerEditForm.defaultProps = { @@ -35,6 +36,7 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL const handleAnswerPatch = async (e) => { e.preventDefault(); try { + setIsKebabLoading(true); setIsLoading(true); const result = await putAnswer(answer.id, { content: textareaValue, // textareaValue에서 내용을 가져옵니다. @@ -51,6 +53,7 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL } catch (err) { // handle error here (e.g., show error message) } finally { + setIsKebabLoading(false); setIsLoading(false); setEditId(null); } diff --git a/src/components/AnswerRejection/index.jsx b/src/components/AnswerRejection/index.jsx index e50c28f..d9d9a48 100644 --- a/src/components/AnswerRejection/index.jsx +++ b/src/components/AnswerRejection/index.jsx @@ -3,11 +3,12 @@ import { useState } from 'react'; import { postAnswer } from 'api/answers'; import { ReactComponent as Rejection } from 'assets/images/icons/ic_Rejection.svg'; -const AnswerRejection = ({ id, setQuestionList, onKebabClick }) => { +const AnswerRejection = ({ id, setQuestionList, onKebabClick, setIsKebabLoading }) => { AnswerRejection.propTypes = { id: PropTypes.number.isRequired, setQuestionList: PropTypes.func.isRequired, onKebabClick: PropTypes.func.isRequired, + setIsKebabLoading: PropTypes.func.isRequired, }; const [isLoading, setIsLoading] = useState(false); @@ -16,9 +17,10 @@ const AnswerRejection = ({ id, setQuestionList, onKebabClick }) => { const handleRejection = async () => { const defaultContent = 'reject'; try { + onKebabClick(id); + setIsKebabLoading(true); setIsLoading(true); setError(null); - onKebabClick(id); const result = await postAnswer(id, { content: defaultContent, @@ -37,6 +39,7 @@ const AnswerRejection = ({ id, setQuestionList, onKebabClick }) => { setError('답변 거절 중 오류가 발생했습니다.'); } finally { setIsLoading(false); + setIsKebabLoading(false); } }; diff --git a/src/components/ConfirmModal/index.jsx b/src/components/ConfirmModal/index.jsx index fd85dfc..28d5a1e 100644 --- a/src/components/ConfirmModal/index.jsx +++ b/src/components/ConfirmModal/index.jsx @@ -37,10 +37,10 @@ const ConfirmModal = ({ isOpen, onConfirm, onCancel, message }) => { {message}
- -
diff --git a/src/components/Kebab/index.jsx b/src/components/Kebab/index.jsx index 715f2aa..b3f917d 100644 --- a/src/components/Kebab/index.jsx +++ b/src/components/Kebab/index.jsx @@ -6,7 +6,7 @@ import kebab from 'assets/images/icons/ic_Kebab.svg'; import AnswerDelete from 'components/AnswerDelete'; import AnswerEdit from 'components/AnswerEdit'; -const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAnswerDeleted, setQuestionList, editId, setEditId, answerId }) => { +const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAnswerDeleted, setQuestionList, editId, setEditId, answerId, isKebabLoading, setIsKebabLoading }) => { Kebab.propTypes = { id: PropTypes.number.isRequired, isAnswer: PropTypes.shape({ @@ -24,6 +24,8 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn editId: PropTypes.number.isRequired, setEditId: PropTypes.func.isRequired, answerId: PropTypes.number.isRequired, + isKebabLoading: PropTypes.bool.isRequired, + setIsKebabLoading: PropTypes.func.isRequired, }; const menuRef = useRef(null); @@ -55,7 +57,7 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn return (
- {isKebabOpen && ( @@ -63,22 +65,22 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn {!isAnswer ? ( <>
- +
- +
) : ( <>
- +
- +
- +
)} diff --git a/src/components/QnAList/index.jsx b/src/components/QnAList/index.jsx index f13e44a..29c4f6e 100644 --- a/src/components/QnAList/index.jsx +++ b/src/components/QnAList/index.jsx @@ -37,6 +37,7 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue const location = useLocation(); const isAnswerPage = location.pathname.startsWith('/post/') && location.pathname.includes('/answer'); const [editId, setEditId] = useState(null); + const [isKebabLoading, setIsKebabLoading] = useState(false); const handleKebabClick = (id) => { setVisibleMenuId((prevVisibleMenuId) => (prevVisibleMenuId === id ? null : id)); @@ -83,6 +84,8 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue editId={editId} setEditId={setEditId} answerId={question.answer ? question.answer.id : null} + isKebabLoading={isKebabLoading} + setIsKebabLoading={setIsKebabLoading} /> )}
@@ -98,9 +101,10 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue id={question.id} setEditId={setEditId} setQuestionList={setQuestionList} + setIsKebabLoading={setIsKebabLoading} /> ) : ( - + )} diff --git a/src/components/QuestionDelete/index.jsx b/src/components/QuestionDelete/index.jsx index de1cb5f..d96723a 100644 --- a/src/components/QuestionDelete/index.jsx +++ b/src/components/QuestionDelete/index.jsx @@ -4,10 +4,11 @@ import { deleteQuestion } from 'api/questions'; import { ReactComponent as Close } from 'assets/images/icons/ic_Close.svg'; import ConfirmModal from 'components/ConfirmModal'; // Import the modal component -const QuestionDelete = ({ id, onDeleteQuestion }) => { +const QuestionDelete = ({ id, onDeleteQuestion, setIsKebabLoading }) => { QuestionDelete.propTypes = { id: PropTypes.number.isRequired, onDeleteQuestion: PropTypes.func.isRequired, + setIsKebabLoading: PropTypes.func.isRequired, }; const [isLoading, setIsLoading] = useState(false); @@ -27,6 +28,7 @@ const QuestionDelete = ({ id, onDeleteQuestion }) => { setShowModal(false); // Close the moda try { + setIsKebabLoading(true); setIsLoading(true); setError(null); @@ -39,6 +41,7 @@ const QuestionDelete = ({ id, onDeleteQuestion }) => { } catch (err) { setError('질문 삭제 중 오류가 발생했습니다.'); } finally { + setIsKebabLoading(false); setIsLoading(false); } }; From 80390afe603b96a22b3fcdd03391107c5efdbd90 Mon Sep 17 00:00:00 2001 From: junAlexx Date: Wed, 25 Dec 2024 10:02:49 +0900 Subject: [PATCH 4/7] =?UTF-8?q?:lipstick:=20chore=20:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EB=8F=99=EC=9E=91=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=A9=94=EC=84=B8=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AnswerContent/index.jsx | 7 ++++- src/components/AnswerDelete/index.jsx | 7 ++++- src/components/AnswerEditForm/index.jsx | 7 ++++- src/components/AnswerRejection/index.jsx | 7 ++++- src/components/DeleteIdBtn/index.jsx | 2 +- src/components/Kebab/index.jsx | 11 +++---- src/components/QnAList/index.jsx | 15 ++++++++-- src/components/QuestionDelete/index.jsx | 10 ++++++- src/components/ToastSuccess/index.jsx | 37 ++++++++++++++++++++++++ src/pages/Answer/index.jsx | 25 +++++++++++----- 10 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 src/components/ToastSuccess/index.jsx diff --git a/src/components/AnswerContent/index.jsx b/src/components/AnswerContent/index.jsx index 9161000..151c72b 100644 --- a/src/components/AnswerContent/index.jsx +++ b/src/components/AnswerContent/index.jsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import formatCreatedAt from 'utils/dateUtils'; import { postAnswer } from 'api/answers'; -const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit, setIsKebabLoading }) => { +const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit, setIsKebabLoading, setIsToast }) => { AnswerContent.propTypes = { answer: PropTypes.shape({ id: PropTypes.number.isRequired, @@ -17,6 +17,7 @@ const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit, setIsKeb id: PropTypes.number.isRequired, onAnswerSubmit: PropTypes.func.isRequired, setIsKebabLoading: PropTypes.func.isRequired, + setIsToast: PropTypes.func.isRequired, }; AnswerContent.defaultProps = { @@ -51,12 +52,16 @@ const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit, setIsKeb response = await postAnswer(id, postBody); setUpdatedAnswer(response); onAnswerSubmit(id, response); + setIsToast('등록'); } catch (err) { // eslint-disable-next-line console.error(err); } finally { setIsKebabLoading(false); setIsLoading(false); + setTimeout(() => { + setIsToast(null); + }, 3000); } }; diff --git a/src/components/AnswerDelete/index.jsx b/src/components/AnswerDelete/index.jsx index 03c335b..e1d7709 100644 --- a/src/components/AnswerDelete/index.jsx +++ b/src/components/AnswerDelete/index.jsx @@ -5,13 +5,14 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import ConfirmModal from 'components/ConfirmModal'; // Import the modal component -const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabLoading }) => { +const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabLoading, setIsToast }) => { AnswerDelete.propTypes = { id: PropTypes.number.isRequired, answerId: PropTypes.number.isRequired, onAnswerDeleted: PropTypes.func.isRequired, onKebabClick: PropTypes.func.isRequired, setIsKebabLoading: PropTypes.func.isRequired, + setIsToast: PropTypes.func.isRequired, }; const [isDeleting, setIsDeleting] = useState(false); @@ -40,11 +41,15 @@ const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabL throw new Error('답변 삭제 중 오류가 발생했습니다.'); } onAnswerDeleted(answerId); + setIsToast('답변'); } catch (err) { navigate('/'); } finally { setIsDeleting(false); setIsKebabLoading(false); + setTimeout(() => { + setIsToast(null); + }, 3000); } }; diff --git a/src/components/AnswerEditForm/index.jsx b/src/components/AnswerEditForm/index.jsx index eeeb141..1a9e715 100644 --- a/src/components/AnswerEditForm/index.jsx +++ b/src/components/AnswerEditForm/index.jsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import { putAnswer } from 'api/answers'; // eslint-disable-next-line -const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionList, setIsKebabLoading }) => { +const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionList, setIsKebabLoading, setIsToast }) => { AnswerEditForm.propTypes = { answer: PropTypes.shape({ id: PropTypes.number.isRequired, @@ -15,6 +15,7 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL imageSource: PropTypes.string, id: PropTypes.number.isRequired, setIsKebabLoading: PropTypes.func.isRequired, + setIsToast: PropTypes.func.isRequired, }; AnswerEditForm.defaultProps = { @@ -42,6 +43,7 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL content: textareaValue, // textareaValue에서 내용을 가져옵니다. isRejected: false, // 필요하다면 다른 데이터도 추가 가능합니다. }); + setIsToast('수정'); setQuestionList((prevQuestions) => prevQuestions.map((question) => { if (question.id === id) { @@ -56,6 +58,9 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL setIsKebabLoading(false); setIsLoading(false); setEditId(null); + setTimeout(() => { + setIsToast(null); + }, 3000); } }; diff --git a/src/components/AnswerRejection/index.jsx b/src/components/AnswerRejection/index.jsx index d9d9a48..11b9f0d 100644 --- a/src/components/AnswerRejection/index.jsx +++ b/src/components/AnswerRejection/index.jsx @@ -3,12 +3,13 @@ import { useState } from 'react'; import { postAnswer } from 'api/answers'; import { ReactComponent as Rejection } from 'assets/images/icons/ic_Rejection.svg'; -const AnswerRejection = ({ id, setQuestionList, onKebabClick, setIsKebabLoading }) => { +const AnswerRejection = ({ id, setQuestionList, onKebabClick, setIsKebabLoading, setIsToast }) => { AnswerRejection.propTypes = { id: PropTypes.number.isRequired, setQuestionList: PropTypes.func.isRequired, onKebabClick: PropTypes.func.isRequired, setIsKebabLoading: PropTypes.func.isRequired, + setIsToast: PropTypes.func.isRequired, }; const [isLoading, setIsLoading] = useState(false); @@ -35,11 +36,15 @@ const AnswerRejection = ({ id, setQuestionList, onKebabClick, setIsKebabLoading return question; }), ); + setIsToast('거절'); } catch (err) { setError('답변 거절 중 오류가 발생했습니다.'); } finally { setIsLoading(false); setIsKebabLoading(false); + setTimeout(() => { + setIsToast(null); + }, 3000); } }; diff --git a/src/components/DeleteIdBtn/index.jsx b/src/components/DeleteIdBtn/index.jsx index 1cec6de..aa2bbc0 100644 --- a/src/components/DeleteIdBtn/index.jsx +++ b/src/components/DeleteIdBtn/index.jsx @@ -14,7 +14,7 @@ const DeleteIdBtn = ({ onClick, id }) => {
- +
- +
)} diff --git a/src/components/QnAList/index.jsx b/src/components/QnAList/index.jsx index 29c4f6e..6db2c11 100644 --- a/src/components/QnAList/index.jsx +++ b/src/components/QnAList/index.jsx @@ -9,7 +9,7 @@ import Kebab from 'components/Kebab'; import questionBoxImg from 'assets/images/img_QuestionBox.svg'; import AnswerEditForm from 'components/AnswerEditForm'; -const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQuestion }) => { +const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQuestion, setIsToast }) => { QnAList.propTypes = { name: PropTypes.string.isRequired, imageSource: PropTypes.string.isRequired, @@ -31,6 +31,7 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue ).isRequired, setQuestionList: PropTypes.func.isRequired, onDeleteQuestion: PropTypes.func.isRequired, + setIsToast: PropTypes.func.isRequired, }; const [visibleMenuId, setVisibleMenuId] = useState(null); @@ -86,6 +87,7 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue answerId={question.answer ? question.answer.id : null} isKebabLoading={isKebabLoading} setIsKebabLoading={setIsKebabLoading} + setIsToast={setIsToast} /> )} @@ -102,9 +104,18 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue setEditId={setEditId} setQuestionList={setQuestionList} setIsKebabLoading={setIsKebabLoading} + setIsToast={setIsToast} /> ) : ( - + )} diff --git a/src/components/QuestionDelete/index.jsx b/src/components/QuestionDelete/index.jsx index d96723a..dc3f13c 100644 --- a/src/components/QuestionDelete/index.jsx +++ b/src/components/QuestionDelete/index.jsx @@ -4,11 +4,13 @@ import { deleteQuestion } from 'api/questions'; import { ReactComponent as Close } from 'assets/images/icons/ic_Close.svg'; import ConfirmModal from 'components/ConfirmModal'; // Import the modal component -const QuestionDelete = ({ id, onDeleteQuestion, setIsKebabLoading }) => { +const QuestionDelete = ({ id, onDeleteQuestion, onKebabClick, setIsKebabLoading, setIsToast }) => { QuestionDelete.propTypes = { id: PropTypes.number.isRequired, onDeleteQuestion: PropTypes.func.isRequired, + onKebabClick: PropTypes.func.isRequired, setIsKebabLoading: PropTypes.func.isRequired, + setIsToast: PropTypes.func.isRequired, }; const [isLoading, setIsLoading] = useState(false); @@ -21,6 +23,7 @@ const QuestionDelete = ({ id, onDeleteQuestion, setIsKebabLoading }) => { }; const handleModalCancel = () => { + onKebabClick(id); setShowModal(false); // Close the modal if canceled }; @@ -37,12 +40,17 @@ const QuestionDelete = ({ id, onDeleteQuestion, setIsKebabLoading }) => { throw new Error('질문 삭제 중 오류가 발생했습니다.'); } + setIsToast('질문'); + onDeleteQuestion(id); } catch (err) { setError('질문 삭제 중 오류가 발생했습니다.'); } finally { setIsKebabLoading(false); setIsLoading(false); + setTimeout(() => { + setIsToast(null); + }, 3000); } }; if (error) { diff --git a/src/components/ToastSuccess/index.jsx b/src/components/ToastSuccess/index.jsx new file mode 100644 index 0000000..6fd27ef --- /dev/null +++ b/src/components/ToastSuccess/index.jsx @@ -0,0 +1,37 @@ +import PropTypes from 'prop-types'; + +const ToastSuccess = ({ toastMsg }) => { + ToastSuccess.propTypes = { + toastMsg: PropTypes.string.isRequired, + }; + if (toastMsg === '질문' || toastMsg === '답변') { + return ( +
+ {toastMsg}이 삭제되었습니다. +
+ ); + } + if (toastMsg === '수정') { + return ( +
+ {toastMsg}이 완료되었습니다. +
+ ); + } + if (toastMsg === '거절') { + return ( +
+ 답변이 {toastMsg}되었습니다. +
+ ); + } + if (toastMsg === '등록') { + return ( +
+ 답변이 {toastMsg}되었습니다. +
+ ); + } + return null; +}; +export default ToastSuccess; diff --git a/src/pages/Answer/index.jsx b/src/pages/Answer/index.jsx index 594acd4..8f2ab13 100644 --- a/src/pages/Answer/index.jsx +++ b/src/pages/Answer/index.jsx @@ -9,6 +9,7 @@ import QnAList from 'components/QnAList'; import ToastDeleteId from 'components/ToastDeleteId'; import questionBoxImg from 'assets/images/img_QuestionBox.svg'; import ConfirmModal from 'components/ConfirmModal'; // Import the modal component +import ToastDelete from 'components/ToastSuccess'; const getDynamicLimit = () => { const screenHeight = window.innerHeight; @@ -28,7 +29,8 @@ const Answer = () => { const [profile, setProfile] = useState(null); const [questionCount, setQuestionCount] = useState(0); const [error, setError] = useState(null); - const [isDelete, setIsDelete] = useState(false); + const [isDeleteId, setIsDeleteId] = useState(false); + const [isToast, setIsToast] = useState(null); const LocalId = localStorage.getItem('id'); const navigate = useNavigate(); @@ -60,8 +62,9 @@ const Answer = () => { throw new Error('삭제 중 오류가 발생했습니다. 3초 후 페이지를 새로고침 합니다.'); } localStorage.removeItem('id'); - setIsDelete(true); + setIsDeleteId(true); setTimeout(() => { + setIsDeleteId(true); navigate('/'); }, 2000); } catch (err) { @@ -85,7 +88,7 @@ const Answer = () => { try { setProfileLoading(true); - if (!isDelete) { + if (!isDeleteId) { if (LocalId === subjectId) { const response = await getSubjectById(subjectId); if (typeof response === 'string' && response.includes('에러')) { @@ -109,7 +112,7 @@ const Answer = () => { }; getProfile(); - }, [subjectId, isDelete, LocalId, navigate]); + }, [subjectId, isDeleteId, LocalId, navigate]); useEffect(() => { const fetchQuestions = async () => { @@ -175,7 +178,7 @@ const Answer = () => {
- {isDelete ? ( + {isDeleteId ? (
질문 박스 이미지 @@ -183,7 +186,14 @@ const Answer = () => { ) : (
    - + {listLoading && (
    @@ -193,7 +203,8 @@ const Answer = () => {
)}
- {isDelete && } + {isDeleteId && } + {isToast && }
); From 2d2e78a8ef173f404e0943cb21a9ca98e8141d12 Mon Sep 17 00:00:00 2001 From: junAlexx Date: Wed, 25 Dec 2024 11:55:10 +0900 Subject: [PATCH 5/7] =?UTF-8?q?:sparkles:=20feat=20:=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EC=B7=A8=EC=86=8C=20=EB=B2=84=ED=8A=BC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AnswerDelete/index.jsx | 8 +- src/components/AnswerEditForm/index.jsx | 36 ++++++-- src/components/Kebab/index.jsx | 112 +++++++++++++++++------- src/components/QuestionDelete/index.jsx | 9 +- 4 files changed, 122 insertions(+), 43 deletions(-) diff --git a/src/components/AnswerDelete/index.jsx b/src/components/AnswerDelete/index.jsx index e1d7709..385f79e 100644 --- a/src/components/AnswerDelete/index.jsx +++ b/src/components/AnswerDelete/index.jsx @@ -5,7 +5,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import ConfirmModal from 'components/ConfirmModal'; // Import the modal component -const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabLoading, setIsToast }) => { +const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabLoading, setIsToast, editId, setEditId }) => { AnswerDelete.propTypes = { id: PropTypes.number.isRequired, answerId: PropTypes.number.isRequired, @@ -13,6 +13,8 @@ const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabL onKebabClick: PropTypes.func.isRequired, setIsKebabLoading: PropTypes.func.isRequired, setIsToast: PropTypes.func.isRequired, + editId: PropTypes.number.isRequired, + setEditId: PropTypes.func.isRequired, }; const [isDeleting, setIsDeleting] = useState(false); @@ -35,6 +37,10 @@ const AnswerDelete = ({ id, answerId, onAnswerDeleted, onKebabClick, setIsKebabL setShowModal(false); // Close the modal setIsDeleting(true); + if (editId !== null) { + setEditId(null); + } + try { const response = await deleteAnswer(answerId); if (!response.ok) { diff --git a/src/components/AnswerEditForm/index.jsx b/src/components/AnswerEditForm/index.jsx index 1a9e715..9cbf8c9 100644 --- a/src/components/AnswerEditForm/index.jsx +++ b/src/components/AnswerEditForm/index.jsx @@ -1,6 +1,8 @@ import PropTypes from 'prop-types'; import { useState } from 'react'; import { putAnswer } from 'api/answers'; +import { ReactComponent as Close } from 'assets/images/icons/ic_Close.svg'; +import ConfirmModal from 'components/ConfirmModal'; // eslint-disable-next-line const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionList, setIsKebabLoading, setIsToast }) => { @@ -26,6 +28,7 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL const [textareaValue, setTextareaValue] = useState(answer.content === null || answer.content === 'reject' ? '' : answer.content); const [isLoading, setIsLoading] = useState(false); const [isValid, setIsValid] = useState(false); + const [showModal, setShowModal] = useState(false); const handleTextareaChange = (event) => { const text = event.target.value; @@ -64,10 +67,26 @@ const AnswerEditForm = ({ answer, name, imageSource, id, setEditId, setQuestionL } }; + const onCancelClick = () => { + setShowModal(true); + }; + + const handleModalCancel = () => { + setShowModal(false); + }; + + const handleModalConfirm = () => { + setShowModal(false); + setEditId(null); + }; + const renderProfileImg = () => {`${name}의; const renderAnswerForm = () => ( -
+ +