Skip to content

Commit ff7230a

Browse files
ToKyun02junAlexxjunAlexxLMS10
authored
Feat/케밥 답변거절 구현 (#58)
* ✨ feat : 피드 헤더 레이아웃 구현 * 💄 chore : 공유하기 버튼 svg 스타일링 * ✅ chore : 프로필 사진 및 이름 불러오는 handleLoad 함수 구현(테스트용) * 🍱 chore : 헤더이미지파일 추가 및 코드 수정 * 💄 chore : PR 리뷰 내용 반영하여 스타일 수정 * ✨ feat : URL 복사 알림용 토스트 구현 시작 * 💄 chore : 토스트 기본 레이아웃 구현 * ✨ chore : URL버튼 클릭시 클립보드에 현재 URL 복사하는 handleCopyUrl추가 및 onClick 구현 * ✨ chore : npm prop types 다운로드, 링크 복사 버튼 클릭 시 토스트 메시지 보여주는 동작 구현 * 💄 chore : 토스트 애니메이션 효과 구현, tailwind.config.js 수정 * 💄 chore : 토스트 애니메이션 개선 및 tailwind.config.js 수정 * ✨ feat : 삭제하기 버튼 기본 레이아웃 및 스타일 작업 * ✨ feat : 삭제하기 버튼 클릭 시 로컬id 삭제 및 루트로 이동 기능 * 🚚 chore : toast 컴포넌트 및 파일 이름을 toastUrlCopy로 변경 * ✨ feat : 삭제하기 버튼 클릭 시 삭제 완료 안내 토스트 구현 * 🎨 chore : 토스트 애니메이션 동작 시간 수정 and 🐛 fixed : 프로필 사진 렌더링 시 src 오류 해결 * 🐛 fixed: prettier 문제로 발생한 빌드 오류 수정에 관한 커밋 * 🚚 chore : 첫글자 소문자로 적은 폴더 이름 대문자로 변경, 기존 toast 컴포넌트와 폴더 이름을 toastUrlCopy로 변경 * 🚚 chore : 로컬에서 폴더명을 수정했으나 원격에서 인식하지 못해 다시 원상복구 시키는 커밋입니다. * ✨ feat : 답변 등록 구현 * ✨ feat : 케밥 답변삭제 구현 * ✨ feat : 질문삭제 컴포넌트로 분리 * ✨ feat : 질문삭제 컴포넌트 구현 * ✨ feat : 답변 삭제 버튼 클릭 시 원래 상태로 렌더링 되는 기능 구현 * ♻️ chore : textarea 초기화 * ✨ feat : 케밥 답변거절 구현 --------- Co-authored-by: junAlexx <lep240927@gmail.com> Co-authored-by: junAlexx <junrisexci@naver.com> Co-authored-by: LMS10 <ggb7410@naver.com>
1 parent 490d611 commit ff7230a

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

src/components/AnswerContent/index.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const AnswerContent = ({ answer, name, imageSource, id, onAnswerSubmit }) => {
2222
imageSource: 'https://fastly.picsum.photos/id/772/200/200.jpg?hmac=9euSj4JHTPr7uT5QWVmeNJ8JaqAXY8XmJnYfr_DfBJc',
2323
};
2424

25+
// if (answer) {
26+
// console.log(answer);
27+
// }
28+
2529
const location = useLocation();
2630
const [textareaValue, setTextareaValue] = useState('');
2731
const [updatedAnswer, setUpdatedAnswer] = useState(answer);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import PropTypes from 'prop-types';
2+
import { useState } from 'react';
3+
import { postAnswer } from 'api/answers';
4+
import { ReactComponent as Rejection } from 'assets/images/icons/ic_Rejection.svg';
5+
6+
const AnswerRejection = ({ id, setQuestionList }) => {
7+
AnswerRejection.propTypes = {
8+
id: PropTypes.number.isRequired,
9+
setQuestionList: PropTypes.func.isRequired,
10+
};
11+
12+
const [isLoading, setIsLoading] = useState(false);
13+
const [error, setError] = useState(null);
14+
15+
const handleRejection = async () => {
16+
const defaultContent = 'reject';
17+
try {
18+
setIsLoading(true);
19+
setError(null);
20+
21+
const result = await postAnswer(id, {
22+
content: defaultContent,
23+
isRejected: true,
24+
});
25+
26+
setQuestionList((prevQuestions) =>
27+
prevQuestions.map((question) => {
28+
if (question.id === id) {
29+
return { ...question, answer: result };
30+
}
31+
return question;
32+
}),
33+
);
34+
} catch (err) {
35+
setError('답변 거절 중 오류가 발생했습니다.');
36+
} finally {
37+
setIsLoading(false);
38+
}
39+
};
40+
41+
if (error) {
42+
return <div>에러: {error}</div>;
43+
}
44+
45+
return (
46+
<button
47+
type='button'
48+
className='flex justify-center items-center gap-2 rounded-lg w-[103px] h-[30px] text-gray-50 hover:text-gray-60 hover:bg-gray-20'
49+
onClick={handleRejection}
50+
disabled={isLoading}
51+
>
52+
<Rejection className='w-3.5 h-3.5 fill-current' />
53+
답변거절
54+
</button>
55+
);
56+
};
57+
58+
export default AnswerRejection;

src/components/Kebab/index.jsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import PropTypes from 'prop-types';
22
import { useEffect, useRef } from 'react';
33
import QuestionDelete from 'components/QuestionDelete';
4+
import AnswerRejection from 'components/AnswerRejection';
45
import kebab from 'assets/images/icons/ic_Kebab.svg';
5-
import { ReactComponent as Rejection } from 'assets/images/icons/ic_Rejection.svg';
66
import { ReactComponent as Edit } from 'assets/images/icons/ic_Edit.svg';
77
import AnswerDelete from 'components/AnswerDelete';
88

9-
const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAnswerDeleted }) => {
9+
const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAnswerDeleted, setQuestionList }) => {
1010
Kebab.propTypes = {
1111
id: PropTypes.number.isRequired,
1212
isAnswer: PropTypes.shape({
@@ -20,6 +20,7 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn
2020
onKebabClick: PropTypes.func.isRequired,
2121
onDeleteQuestion: PropTypes.func.isRequired,
2222
onAnswerDeleted: PropTypes.func.isRequired,
23+
setQuestionList: PropTypes.func.isRequired,
2324
};
2425

2526
const menuRef = useRef(null);
@@ -59,10 +60,7 @@ const Kebab = ({ id, isAnswer, isKebabOpen, onKebabClick, onDeleteQuestion, onAn
5960
{!isAnswer ? (
6061
<>
6162
<div className='flex justify-center items-center rounded-lg'>
62-
<button type='button' className='flex justify-center items-center gap-2 rounded-lg w-[103px] h-[30px] text-gray-50 hover:text-gray-60 hover:bg-gray-20'>
63-
<Rejection className='w-3.5 h-3.5 fill-current' />
64-
<p>답변거절</p>
65-
</button>
63+
<AnswerRejection id={id} setQuestionList={setQuestionList} />
6664
</div>
6765
<div className='flex justify-center items-center'>
6866
<QuestionDelete id={id} onDeleteQuestion={onDeleteQuestion} />

src/components/QnAList/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const QnAList = ({ name, imageSource, questionList, setQuestionList, onDeleteQue
7878
onClick={handleDeleteQuestion}
7979
onDeleteQuestion={handleDeleteQuestion}
8080
onAnswerDeleted={handleAnswerDeleted}
81+
setQuestionList={setQuestionList}
8182
/>
8283
)}
8384
</div>

0 commit comments

Comments
 (0)