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 }) {
// TODO:
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 [image, setImage] = useState(quiz.image || null);
const [imagePreview, setImagePreview] = useState(
@ -31,6 +31,9 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
if (choices.length > 0) {
const updatedChoices = choices.slice(0, -1);
setChoices(updatedChoices);
if (updatedChoices.length < answer) {
setAnswer('');
}
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 (
<div className={styles.card}>
<div className={styles.header}>
@ -102,17 +111,32 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
placeholder="질문 내용을 입력하세요"
/>
<label className={styles.label}>정답</label>
<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="정답을 입력하세요"
/>
{choices.length > 0 ? (
<div className={styles.choicesWrapper}>
{choices.map((choice, index) => (
<button
type="button"
key={index + 1}
onClick={() => handleChoiceSelect(index + 1)}
className={`${styles.choiceButton} ${answer === index + 1 ? styles.selected : ''}`}
>
{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>
<span>Tip: 선택지를 넣지 않는다면 단답형 문제가 됩니다</span>
</div>

View File

@ -116,3 +116,39 @@
cursor: pointer;
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';
export default function QuizDetailCard({ index, question, answer, image, choices, userAnswer = null, correct = true }) {

View File

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

View File

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

View File

@ -12,18 +12,39 @@ export default function QuizsetEditPage() {
const handleSubmit = async (e, title, quizzes) => {
e.preventDefault();
if (title === '') {
window.alert('퀴즈 제목이 없는 퀴즈셋은 생성할 수 없습니다');
return;
}
if (quizzes.length === 0) {
window.alert('퀴즈가 없는 퀴즈셋은 생성할 수 없습니다');
return;
}
const images = [];
const quizContents = [];
quizzes.forEach((quiz) => {
const { image, ...quizData } = quiz;
images.push(image);
if (quizData.id > initialValue.quizzes[initialValue.quizzes.length - 1].id) {
const { question, answer, choices } = quizData;
quizContents.push({ question, answer, choices });
} else {
quizContents.push(quizData);
for (let quiz of quizzes) {
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);
quizContents.push({ question, answer, choices });
}
const quizsetObject = {
id: quizsetId,

View File

@ -8,6 +8,12 @@ export default function QuizsetWritePage() {
const handleSubmit = async (e, title, quizzes) => {
e.preventDefault();
if (title === '') {
window.alert('퀴즈 제목이 없는 퀴즈셋은 생성할 수 없습니다');
return;
}
if (quizzes.length === 0) {
window.alert('퀴즈가 없는 퀴즈셋은 생성할 수 없습니다');
return;
@ -16,12 +22,26 @@ export default function QuizsetWritePage() {
const images = [];
const quizContents = [];
quizzes.forEach((quiz) => {
// eslint-disable-next-line no-unused-vars
for (let quiz of quizzes) {
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);
quizContents.push({ question, answer, choices });
});
}
const quizsetObject = {
title,