Merge branch 'FE/QuizCard' into 'frontend'

[Front-End] feat: 퀴즈 생성 시 내용 유효성 검사 추가

See merge request s11-webmobile1-sub2/S11P12A701!175
This commit is contained in:
조민우 2024-08-12 15:35:24 +09:00
commit 5bd8557188
7 changed files with 127 additions and 29 deletions

View File

@ -6,7 +6,7 @@ import PlusIcon from '/src/assets/icons/plus.svg?react';
export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) { export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
// TODO: // TODO:
const [question, setQuestion] = useState(quiz.question || ''); const [question, setQuestion] = useState(quiz.question || '');
const [answer, setAnswer] = useState(quiz.answer || ''); const [answer, setAnswer] = useState(Number(quiz.answer) || '');
const [choices, setChoices] = useState(quiz.choices || []); const [choices, setChoices] = useState(quiz.choices || []);
const [image, setImage] = useState(quiz.image || null); const [image, setImage] = useState(quiz.image || null);
const [imagePreview, setImagePreview] = useState( const [imagePreview, setImagePreview] = useState(
@ -31,6 +31,9 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
if (choices.length > 0) { if (choices.length > 0) {
const updatedChoices = choices.slice(0, -1); const updatedChoices = choices.slice(0, -1);
setChoices(updatedChoices); setChoices(updatedChoices);
if (updatedChoices.length < answer) {
setAnswer('');
}
updateQuiz(quiz.id, { ...quiz, question, answer, choices: updatedChoices, image }); updateQuiz(quiz.id, { ...quiz, question, answer, choices: updatedChoices, image });
} }
}; };
@ -57,6 +60,12 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
} }
}; };
const handleChoiceSelect = (choiceContent) => {
console.log(choiceContent);
setAnswer(choiceContent);
updateQuiz(quiz.id, { ...quiz, question, answer: choiceContent, choices, image });
};
return ( return (
<div className={styles.card}> <div className={styles.card}>
<div className={styles.header}> <div className={styles.header}>
@ -102,17 +111,32 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
placeholder="질문 내용을 입력하세요" placeholder="질문 내용을 입력하세요"
/> />
<label className={styles.label}>정답</label> <label className={styles.label}>정답</label>
<input {choices.length > 0 ? (
type="text" <div className={styles.choicesWrapper}>
value={answer} {choices.map((choice, index) => (
maxLength={200} <button
onChange={(e) => { type="button"
setAnswer(e.target.value); key={index + 1}
updateQuiz(quiz.id, { ...quiz, question, answer: e.target.value, choices, image }); onClick={() => handleChoiceSelect(index + 1)}
}} className={`${styles.choiceButton} ${answer === index + 1 ? styles.selected : ''}`}
className={styles.input} >
placeholder="정답을 입력하세요" {index + 1}
/> </button>
))}
</div>
) : (
<input
type="text"
value={answer}
maxLength={200}
onChange={(e) => {
setAnswer(e.target.value);
updateQuiz(quiz.id, { ...quiz, question, answer: e.target.value, choices, image });
}}
className={styles.input}
placeholder="정답을 입력하세요"
/>
)}
<div> <div>
<span>Tip: 선택지를 넣지 않는다면 단답형 문제가 됩니다</span> <span>Tip: 선택지를 넣지 않는다면 단답형 문제가 됩니다</span>
</div> </div>

View File

@ -116,3 +116,39 @@
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
} }
.choicesWrapper {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.choiceButton {
padding: 10px 16px;
background-color: var(--background-secondary);
border: 1px solid var(--background-tertiary);
border-radius: 4px;
cursor: pointer;
transition:
background-color 0.25s,
border-color 0.25s,
stroke 0.25s,
color 0.25s;
}
.choiceButton:hover {
background-color: var(--background-tertiary);
}
.selected {
border: 1px solid var(--primary-color);
background-color: var(--primary-color);
color: var(--on-primary);
stroke: var(--on-primary);
}
.selected:hover {
border: 1px solid var(--primary-color);
background-color: var(--primary-color);
}

View File

@ -1,4 +1,4 @@
import styles from './QuizCard.module.css'; import styles from './QuizDetailCard.module.css';
import { STATIC_URL } from '../../constants'; import { STATIC_URL } from '../../constants';
export default function QuizDetailCard({ index, question, answer, image, choices, userAnswer = null, correct = true }) { export default function QuizDetailCard({ index, question, answer, image, choices, userAnswer = null, correct = true }) {

View File

@ -77,10 +77,6 @@
padding: 7px; padding: 7px;
} }
.input::placeholder {
color: var(--text-color-tertiary);
}
.buttonsWrapper { .buttonsWrapper {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -46,6 +46,7 @@
line-height: 1.2; line-height: 1.2;
font-weight: 800; font-weight: 800;
margin: 0; margin: 0;
word-break: break-all;
} }
.image { .image {

View File

@ -12,18 +12,39 @@ export default function QuizsetEditPage() {
const handleSubmit = async (e, title, quizzes) => { const handleSubmit = async (e, title, quizzes) => {
e.preventDefault(); e.preventDefault();
if (title === '') {
window.alert('퀴즈 제목이 없는 퀴즈셋은 생성할 수 없습니다');
return;
}
if (quizzes.length === 0) {
window.alert('퀴즈가 없는 퀴즈셋은 생성할 수 없습니다');
return;
}
const images = []; const images = [];
const quizContents = []; const quizContents = [];
quizzes.forEach((quiz) => {
const { image, ...quizData } = quiz; for (let quiz of quizzes) {
images.push(image); const { image, question, answer, choices } = quiz;
if (quizData.id > initialValue.quizzes[initialValue.quizzes.length - 1].id) {
const { question, answer, choices } = quizData; if (question === '' || answer === '') {
quizContents.push({ question, answer, choices }); window.alert('질문과 정답은 모든 문제에 필수값입니다.');
} else { return;
quizContents.push(quizData);
} }
});
if (choices.length > 0) {
for (let choice of choices) {
if (choice.content === '') {
window.alert('모든 선택지에는 내용이 필요합니다.');
return;
}
}
}
images.push(image);
quizContents.push({ question, answer, choices });
}
const quizsetObject = { const quizsetObject = {
id: quizsetId, id: quizsetId,

View File

@ -8,6 +8,12 @@ export default function QuizsetWritePage() {
const handleSubmit = async (e, title, quizzes) => { const handleSubmit = async (e, title, quizzes) => {
e.preventDefault(); e.preventDefault();
if (title === '') {
window.alert('퀴즈 제목이 없는 퀴즈셋은 생성할 수 없습니다');
return;
}
if (quizzes.length === 0) { if (quizzes.length === 0) {
window.alert('퀴즈가 없는 퀴즈셋은 생성할 수 없습니다'); window.alert('퀴즈가 없는 퀴즈셋은 생성할 수 없습니다');
return; return;
@ -16,12 +22,26 @@ export default function QuizsetWritePage() {
const images = []; const images = [];
const quizContents = []; const quizContents = [];
quizzes.forEach((quiz) => { for (let quiz of quizzes) {
// eslint-disable-next-line no-unused-vars
const { image, question, answer, choices } = quiz; const { image, question, answer, choices } = quiz;
if (question === '' || answer === '') {
window.alert('질문과 정답은 모든 문제에 필수값입니다.');
return;
}
if (choices.length > 0) {
for (let choice of choices) {
if (choice.content === '') {
window.alert('모든 선택지에는 내용이 필요합니다.');
return;
}
}
}
images.push(image); images.push(image);
quizContents.push({ question, answer, choices }); quizContents.push({ question, answer, choices });
}); }
const quizsetObject = { const quizsetObject = {
title, title,