fix: 게시판 부분 maxLength 추가
This commit is contained in:
parent
591cfa1e30
commit
1a0b020ec5
@ -2,23 +2,42 @@ import styles from './ArticleDetailAnswerInput.module.css';
|
|||||||
import { useAnswerWrite } from '../../../../hooks/api/useAnswerWrite';
|
import { useAnswerWrite } from '../../../../hooks/api/useAnswerWrite';
|
||||||
import { useAnswerEdit } from '../../../../hooks/api/useAnswerEdit';
|
import { useAnswerEdit } from '../../../../hooks/api/useAnswerEdit';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useState } from 'react';
|
import { useRef, useEffect, useState } from 'react';
|
||||||
import SendIcon from '/src/assets/icons/send.svg?react';
|
import SendIcon from '/src/assets/icons/send.svg?react';
|
||||||
export default function ArticleDetailAnswerInput({ onSubmit, initialAnswer, isEditing = false }) {
|
export default function ArticleDetailAnswerInput({ onSubmit, initialAnswer, isEditing = false }) {
|
||||||
|
// TODO: 우선 Textarea로 댓글 수정. 필요시 Input으로 다시 변경
|
||||||
const { answerWrite } = useAnswerWrite();
|
const { answerWrite } = useAnswerWrite();
|
||||||
const { answerEdit } = useAnswerEdit();
|
const { answerEdit } = useAnswerEdit();
|
||||||
const { questionId } = useParams();
|
const { questionId } = useParams();
|
||||||
const [newAnswer, setNewAnswer] = useState(initialAnswer);
|
const [answer, setAnswer] = useState(initialAnswer);
|
||||||
|
|
||||||
|
const textareaRef = useRef(null);
|
||||||
|
|
||||||
|
const adjustTextareaHeight = () => {
|
||||||
|
if (textareaRef.current) {
|
||||||
|
textareaRef.current.style.height = 'auto';
|
||||||
|
textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
adjustTextareaHeight();
|
||||||
|
}, [answer]);
|
||||||
|
|
||||||
|
const handleInput = (e) => {
|
||||||
|
const { value } = e.target;
|
||||||
|
setAnswer(value);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log(isEditing);
|
console.log(isEditing);
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
await answerEdit(questionId, newAnswer);
|
await answerEdit(questionId, answer);
|
||||||
} else {
|
} else {
|
||||||
await answerWrite(questionId, newAnswer);
|
await answerWrite(questionId, answer);
|
||||||
}
|
}
|
||||||
onSubmit(newAnswer);
|
onSubmit(answer);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -26,14 +45,16 @@ export default function ArticleDetailAnswerInput({ onSubmit, initialAnswer, isEd
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className={styles.answer}
|
className={styles.answer}
|
||||||
>
|
>
|
||||||
<input
|
<textarea
|
||||||
type="text"
|
maxLength={1000}
|
||||||
maxLength={255}
|
value={answer}
|
||||||
value={newAnswer}
|
onChange={handleInput}
|
||||||
onChange={(e) => setNewAnswer(e.target.value)}
|
ref={textareaRef}
|
||||||
placeholder="답변 작성하기"
|
placeholder="답변 작성하기"
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
/>
|
/>
|
||||||
|
{answer.length > 950 && <div className={styles.textLength}>{answer.length} / 1000</div>}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import styles from './CreateArticle.module.css';
|
import styles from './CreateArticle.module.css';
|
||||||
import EditIcon from '/src/assets/icons/edit.svg?react';
|
import EditIcon from '/src/assets/icons/edit.svg?react';
|
||||||
@ -7,12 +7,22 @@ import BackIcon from '/src/assets/icons/back.svg?react';
|
|||||||
export default function CreateArticle({ topic, title, onSubmit }) {
|
export default function CreateArticle({ topic, title, onSubmit }) {
|
||||||
const [articleTitle, setArticleTitle] = useState('');
|
const [articleTitle, setArticleTitle] = useState('');
|
||||||
const [articleContent, setArticleContent] = useState('');
|
const [articleContent, setArticleContent] = useState('');
|
||||||
const [textAreaHeight, setTextAreaHeight] = useState('auto');
|
const textareaRef = useRef(null);
|
||||||
|
|
||||||
|
const adjustTextareaHeight = () => {
|
||||||
|
if (textareaRef.current) {
|
||||||
|
textareaRef.current.style.height = 'auto';
|
||||||
|
textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
adjustTextareaHeight();
|
||||||
|
}, [articleContent]);
|
||||||
|
|
||||||
const handleInput = (e) => {
|
const handleInput = (e) => {
|
||||||
const { value, scrollHeight } = e.target;
|
const { value } = e.target;
|
||||||
setArticleContent(value);
|
setArticleContent(value);
|
||||||
setTextAreaHeight(scrollHeight + 'px');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,22 +45,26 @@ export default function CreateArticle({ topic, title, onSubmit }) {
|
|||||||
<label className={styles.label}>제목</label>
|
<label className={styles.label}>제목</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
maxLength={255}
|
maxLength={200}
|
||||||
className={styles.titleInput}
|
className={styles.titleInput}
|
||||||
placeholder="제목을 입력하세요"
|
placeholder="제목을 입력하세요"
|
||||||
value={articleTitle}
|
value={articleTitle}
|
||||||
onChange={(e) => setArticleTitle(e.target.value)}
|
onChange={(e) => setArticleTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
{articleTitle.length > 190 && <div className={styles.textLength}>{articleTitle.length} / 200</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.fieldWrapper}>
|
<div className={styles.fieldWrapper}>
|
||||||
<label className={styles.label}>내용</label>
|
<label className={styles.label}>내용</label>
|
||||||
<textarea
|
<textarea
|
||||||
|
ref={textareaRef}
|
||||||
className={styles.contentInput}
|
className={styles.contentInput}
|
||||||
placeholder="내용을 입력하세요"
|
placeholder="내용을 입력하세요"
|
||||||
value={articleContent}
|
value={articleContent}
|
||||||
|
maxLength={1000}
|
||||||
onChange={handleInput}
|
onChange={handleInput}
|
||||||
style={{ height: textAreaHeight, overflow: 'hidden' }}
|
style={{ overflow: 'hidden' }}
|
||||||
></textarea>
|
></textarea>
|
||||||
|
{articleContent.length > 950 && <div className={styles.textLength}>{articleContent.length} / 1000</div>}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -108,3 +108,9 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
stroke: var(--text-color-tertiary);
|
stroke: var(--text-color-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLength {
|
||||||
|
margin-top: 4px;
|
||||||
|
align-self: end;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -9,10 +9,6 @@ export default function EditArticle({ topic, title, prevTitle, prevContent, onSu
|
|||||||
const [articleContent, setArticleContent] = useState(prevContent);
|
const [articleContent, setArticleContent] = useState(prevContent);
|
||||||
const textAreaRef = useRef(null);
|
const textAreaRef = useRef(null);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// adjustTextAreaHeight();
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
adjustTextAreaHeight();
|
adjustTextAreaHeight();
|
||||||
}, [articleContent]);
|
}, [articleContent]);
|
||||||
@ -48,23 +44,26 @@ export default function EditArticle({ topic, title, prevTitle, prevContent, onSu
|
|||||||
<label className={styles.label}>제목</label>
|
<label className={styles.label}>제목</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
maxLength={255}
|
maxLength={200}
|
||||||
className={styles.titleInput}
|
className={styles.titleInput}
|
||||||
placeholder="제목을 입력하세요"
|
placeholder="제목을 입력하세요"
|
||||||
value={articleTitle}
|
value={articleTitle}
|
||||||
onChange={(e) => setArticleTitle(e.target.value)}
|
onChange={(e) => setArticleTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
{articleTitle.length > 190 && <div className={styles.textLength}>{articleTitle.length} / 200</div>}
|
||||||
|
</div>
|
||||||
<div className={styles.fieldWrapper}>
|
<div className={styles.fieldWrapper}>
|
||||||
<label className={styles.label}>내용</label>
|
<label className={styles.label}>내용</label>
|
||||||
<textarea
|
<textarea
|
||||||
ref={textAreaRef}
|
ref={textAreaRef}
|
||||||
className={styles.contentInput}
|
className={styles.contentInput}
|
||||||
|
maxLength={1000}
|
||||||
placeholder="내용을 입력하세요"
|
placeholder="내용을 입력하세요"
|
||||||
value={articleContent}
|
value={articleContent}
|
||||||
onChange={handleInput}
|
onChange={handleInput}
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
{articleContent.length > 950 && <div className={styles.textLength}>{articleContent.length} / 1000</div>}
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
|
@ -108,3 +108,9 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
stroke: var(--text-color-tertiary);
|
stroke: var(--text-color-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLength {
|
||||||
|
margin-top: 4px;
|
||||||
|
align-self: end;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useRef, useState, useEffect } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import styles from './EditFreeboard.module.css';
|
import styles from './EditFreeboard.module.css';
|
||||||
import EditIcon from '/src/assets/icons/edit.svg?react';
|
import EditIcon from '/src/assets/icons/edit.svg?react';
|
||||||
@ -7,11 +7,21 @@ import BackIcon from '/src/assets/icons/back.svg?react';
|
|||||||
export default function EditFreeboard({ topic, title, prevContent, prevTitle, onSubmit }) {
|
export default function EditFreeboard({ topic, title, prevContent, prevTitle, onSubmit }) {
|
||||||
const [articleTitle, setArticleTitle] = useState(prevTitle);
|
const [articleTitle, setArticleTitle] = useState(prevTitle);
|
||||||
const [articleContent, setArticleContent] = useState(prevContent);
|
const [articleContent, setArticleContent] = useState(prevContent);
|
||||||
|
const textAreaRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
adjustTextAreaHeight();
|
||||||
|
}, [articleContent]);
|
||||||
|
|
||||||
|
const adjustTextAreaHeight = () => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
textAreaRef.current.style.height = 'auto';
|
||||||
|
textAreaRef.current.style.height = `${textAreaRef.current.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleInput = (e) => {
|
const handleInput = (e) => {
|
||||||
setArticleContent(e.target.value);
|
setArticleContent(e.target.value);
|
||||||
e.target.style.height = 'auto';
|
|
||||||
e.target.style.height = e.target.scrollHeight + 'px';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -34,21 +44,25 @@ export default function EditFreeboard({ topic, title, prevContent, prevTitle, on
|
|||||||
<label className={styles.label}>제목</label>
|
<label className={styles.label}>제목</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
maxLength={255}
|
maxLength={200}
|
||||||
className={styles.titleInput}
|
className={styles.titleInput}
|
||||||
placeholder={'제목을 입력하세요'}
|
placeholder={'제목을 입력하세요'}
|
||||||
value={articleTitle}
|
value={articleTitle}
|
||||||
onChange={(e) => setArticleTitle(e.target.value)}
|
onChange={(e) => setArticleTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
{articleTitle.length > 190 && <div className={styles.textLength}>{articleTitle.length} / 200</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.fieldWrapper}>
|
<div className={styles.fieldWrapper}>
|
||||||
<label className={styles.label}>내용</label>
|
<label className={styles.label}>내용</label>
|
||||||
<textarea
|
<textarea
|
||||||
className={styles.contentInput}
|
className={styles.contentInput}
|
||||||
placeholder="내용을 입력하세요"
|
placeholder="내용을 입력하세요"
|
||||||
|
ref={textAreaRef}
|
||||||
|
maxLength={1000}
|
||||||
value={articleContent}
|
value={articleContent}
|
||||||
onChange={handleInput}
|
onChange={handleInput}
|
||||||
></textarea>
|
></textarea>
|
||||||
|
{articleContent.length > 950 && <div className={styles.textLength}>{articleContent.length} / 1000</div>}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -108,3 +108,9 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
stroke: var(--text-color-tertiary);
|
stroke: var(--text-color-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLength {
|
||||||
|
margin-top: 4px;
|
||||||
|
align-self: end;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useRef, useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import styles from './EditQna.module.css';
|
import styles from './EditQna.module.css';
|
||||||
import EditIcon from '/src/assets/icons/edit.svg?react';
|
import EditIcon from '/src/assets/icons/edit.svg?react';
|
||||||
@ -7,11 +7,21 @@ import BackIcon from '/src/assets/icons/back.svg?react';
|
|||||||
export default function EditQna({ topic, title, prevContent, prevTitle, onSubmit }) {
|
export default function EditQna({ topic, title, prevContent, prevTitle, onSubmit }) {
|
||||||
const [articleTitle, setArticleTitle] = useState(prevTitle);
|
const [articleTitle, setArticleTitle] = useState(prevTitle);
|
||||||
const [articleContent, setArticleContent] = useState(prevContent);
|
const [articleContent, setArticleContent] = useState(prevContent);
|
||||||
|
const textAreaRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
adjustTextAreaHeight();
|
||||||
|
}, [articleContent]);
|
||||||
|
|
||||||
|
const adjustTextAreaHeight = () => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
textAreaRef.current.style.height = 'auto';
|
||||||
|
textAreaRef.current.style.height = `${textAreaRef.current.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleInput = (e) => {
|
const handleInput = (e) => {
|
||||||
setArticleContent(e.target.value);
|
setArticleContent(e.target.value);
|
||||||
e.target.style.height = 'auto';
|
|
||||||
e.target.style.height = e.target.scrollHeight + 'px';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -34,21 +44,25 @@ export default function EditQna({ topic, title, prevContent, prevTitle, onSubmit
|
|||||||
<label className={styles.label}>제목</label>
|
<label className={styles.label}>제목</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
maxLength={255}
|
maxLength={200}
|
||||||
className={styles.titleInput}
|
className={styles.titleInput}
|
||||||
placeholder={'제목을 입력하세요'}
|
placeholder={'제목을 입력하세요'}
|
||||||
value={articleTitle}
|
value={articleTitle}
|
||||||
onChange={(e) => setArticleTitle(e.target.value)}
|
onChange={(e) => setArticleTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
{articleTitle.length > 190 && <div className={styles.textLength}>{articleTitle.length} / 200</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.fieldWrapper}>
|
<div className={styles.fieldWrapper}>
|
||||||
<label className={styles.label}>내용</label>
|
<label className={styles.label}>내용</label>
|
||||||
<textarea
|
<textarea
|
||||||
|
ref={textAreaRef}
|
||||||
|
maxLength={1000}
|
||||||
className={styles.contentInput}
|
className={styles.contentInput}
|
||||||
placeholder="내용을 입력하세요"
|
placeholder="내용을 입력하세요"
|
||||||
value={articleContent}
|
value={articleContent}
|
||||||
onChange={handleInput}
|
onChange={handleInput}
|
||||||
></textarea>
|
></textarea>
|
||||||
|
{articleContent.length > 950 && <div className={styles.textLength}>{articleContent.length} / 1000</div>}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -108,3 +108,9 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
stroke: var(--text-color-tertiary);
|
stroke: var(--text-color-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLength {
|
||||||
|
margin-top: 4px;
|
||||||
|
align-self: end;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -41,11 +41,13 @@ export default function FreeboardComment({ content, author, onDeleteSubmit, onEd
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={newComment}
|
value={newComment}
|
||||||
|
maxLength={200}
|
||||||
onChange={(e) => setNewComment(e.target.value)}
|
onChange={(e) => setNewComment(e.target.value)}
|
||||||
placeholder="댓글 수정하기"
|
placeholder="댓글 수정하기"
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
{newComment.length > 190 && <div className={styles.textLength}>{newComment.length} / 200</div>}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
|
@ -91,3 +91,9 @@
|
|||||||
.delete {
|
.delete {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLength {
|
||||||
|
margin-top: 4px;
|
||||||
|
align-self: end;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -19,11 +19,13 @@ export default function FreeboardCommentInput({ onCommentSubmit }) {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={newComment}
|
value={newComment}
|
||||||
|
maxLength={200}
|
||||||
onChange={(e) => setNewComment(e.target.value)}
|
onChange={(e) => setNewComment(e.target.value)}
|
||||||
placeholder="댓글 작성하기"
|
placeholder="댓글 작성하기"
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
{newComment.length > 190 && <div className={styles.textLength}>{newComment.length} / 200</div>}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
|
@ -26,3 +26,9 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLength {
|
||||||
|
margin-top: 4px;
|
||||||
|
align-self: end;
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import styles from './InfoEditForm.module.css';
|
import styles from './InfoEditForm.module.css';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
export default function InfoEditForm({ name, email, onSubmit }) {
|
export default function InfoEditForm({ name, email, onSubmit, usingEmail }) {
|
||||||
const [username, setUsername] = useState(name);
|
const [username, setUsername] = useState(name);
|
||||||
const [useremail, setUseremail] = useState(email);
|
const [useremail, setUseremail] = useState(email);
|
||||||
|
|
||||||
@ -39,17 +39,18 @@ export default function InfoEditForm({ name, email, onSubmit }) {
|
|||||||
htmlFor="useremail"
|
htmlFor="useremail"
|
||||||
className={styles.textBody}
|
className={styles.textBody}
|
||||||
>
|
>
|
||||||
이메일을 입력하세요.
|
이메일을 입력하세요
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
placeholder="이메일"
|
placeholder="이메일"
|
||||||
type="text"
|
type="text"
|
||||||
id="useremail"
|
id="useremail"
|
||||||
className={`${styles.input} ${styles.textBody}`}
|
className={`${styles.input} ${styles.textBody} ${usingEmail && styles.errorBox}`}
|
||||||
value={useremail}
|
value={useremail}
|
||||||
onChange={(e) => setUseremail(e.target.value)}
|
onChange={(e) => setUseremail(e.target.value)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
{usingEmail && <div className={styles.errorText}>이미 사용중인 이메일입니다</div>}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
disabled={(!username && !useremail) || (username == name && useremail == email)}
|
disabled={(!username && !useremail) || (username == name && useremail == email)}
|
||||||
|
@ -64,3 +64,12 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
stroke: var(--text-color-tertiary);
|
stroke: var(--text-color-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorBox {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid var(--error-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.errorText {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import styles from './QuizCard.module.css';
|
import styles from './QuizCard.module.css';
|
||||||
import { STATIC_URL } from '../../constants';
|
import { STATIC_URL } from '../../constants';
|
||||||
|
|
||||||
export default function QuizCard({ index, question, answer, image, choices, userAnswer, correct = true }) {
|
export default function QuizDetailCard({ index, question, answer, image, choices, userAnswer = null, correct = true }) {
|
||||||
// TODO: 정답 / 오답 관련 표현 필요 시 추가
|
console.log(correct);
|
||||||
console.log(choices);
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.card}>
|
<div className={`${styles.card} ${!correct && styles.incorrect}`}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<span className={styles.heading}>{index}번 퀴즈</span>
|
<span className={styles.heading}>{index}번 퀴즈</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.incorrect {
|
||||||
|
background-color: #db3232;
|
||||||
|
border: 1px solid var(--red300);
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
|
@ -21,19 +21,16 @@ export default function QuizsetForm({ headerTitle, topic, to, onSubmit, initialV
|
|||||||
}, [initialValue]);
|
}, [initialValue]);
|
||||||
|
|
||||||
const handleAddQuiz = () => {
|
const handleAddQuiz = () => {
|
||||||
console.log(quizzes);
|
|
||||||
setQuizzes([...quizzes, { id: quizId, question: '', answer: '', choices: [], image: null }]);
|
setQuizzes([...quizzes, { id: quizId, question: '', answer: '', choices: [], image: null }]);
|
||||||
setQuizId(quizId + 1);
|
setQuizId(quizId + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateQuiz = (id, updatedQuiz) => {
|
const updateQuiz = (id, updatedQuiz) => {
|
||||||
console.log(quizzes);
|
|
||||||
const updatedQuizzes = quizzes.map((quiz) => (quiz.id === id ? updatedQuiz : quiz));
|
const updatedQuizzes = quizzes.map((quiz) => (quiz.id === id ? updatedQuiz : quiz));
|
||||||
setQuizzes(updatedQuizzes);
|
setQuizzes(updatedQuizzes);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteQuiz = (id) => {
|
const deleteQuiz = (id) => {
|
||||||
console.log(quizzes);
|
|
||||||
setQuizzes(quizzes.filter((quiz) => quiz.id !== id));
|
setQuizzes(quizzes.filter((quiz) => quiz.id !== id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
frontend/src/hooks/api/useReportSetDelete.js
Normal file
10
frontend/src/hooks/api/useReportSetDelete.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import instance from '../../utils/axios/instance';
|
||||||
|
import { API_URL } from '../../constants';
|
||||||
|
|
||||||
|
export function useReportSetDelete() {
|
||||||
|
const reportsetDelete = (reportsetId) => {
|
||||||
|
return instance.delete(`${API_URL}/report/teacher/report/${reportsetId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { reportsetDelete };
|
||||||
|
}
|
@ -2,18 +2,26 @@ import { InfoEditForm } from '../../components/InfoEditForm';
|
|||||||
import { useAuth } from '../../hooks/api/useAuth';
|
import { useAuth } from '../../hooks/api/useAuth';
|
||||||
import { useUserInfo } from '../../hooks/api/useUserInfo';
|
import { useUserInfo } from '../../hooks/api/useUserInfo';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
export default function MyInfoChangePage() {
|
export default function MyInfoChangePage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { data } = useUserInfo();
|
const { data } = useUserInfo();
|
||||||
const myInfo = data.data?.userInfo;
|
const myInfo = data.data?.userInfo;
|
||||||
const { updateInfo } = useAuth();
|
const { updateInfo } = useAuth();
|
||||||
|
const [usingEmail, setUsingEmail] = useState(false);
|
||||||
|
|
||||||
const handleSubmit = async (e, username, useremail) => {
|
const handleSubmit = async (e, username, useremail) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await updateInfo(username, useremail)
|
await updateInfo(username, useremail)
|
||||||
.then(() => navigate('/'))
|
.then(() => navigate('/'))
|
||||||
.catch((err) => console.log(err));
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
console.log(err.response.data);
|
||||||
|
if (err.response.data === '이미 사용 중인 이메일입니다.') {
|
||||||
|
setUsingEmail(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -21,6 +29,7 @@ export default function MyInfoChangePage() {
|
|||||||
name={myInfo.name}
|
name={myInfo.name}
|
||||||
email={myInfo.email}
|
email={myInfo.email}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
usingEmail={usingEmail}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ export default function StudentReportDetailPage() {
|
|||||||
answer={quiz.answer}
|
answer={quiz.answer}
|
||||||
choices={quiz.choices}
|
choices={quiz.choices}
|
||||||
userAnswer={quiz.userAnswer}
|
userAnswer={quiz.userAnswer}
|
||||||
|
correct={quiz.correct}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,8 +9,9 @@ export default function StudentReportPage() {
|
|||||||
const { lectureId } = useParams();
|
const { lectureId } = useParams();
|
||||||
const { data } = useStudentReports(lectureId);
|
const { data } = useStudentReports(lectureId);
|
||||||
const reports = data?.data;
|
const reports = data?.data;
|
||||||
|
console.log(reports);
|
||||||
|
|
||||||
const totalCounts = reports.reduce(
|
const totalCounts = reports.reduce?.(
|
||||||
(acc, report) => {
|
(acc, report) => {
|
||||||
if (acc.allCount > 0) {
|
if (acc.allCount > 0) {
|
||||||
acc.correctCount += report.correctCount;
|
acc.correctCount += report.correctCount;
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import { ArticleLink } from '../../components/ArticleLink';
|
import { ArticleLink } from '../../components/ArticleLink';
|
||||||
import ArticleBoard from '../../components/ArticleBoard/ArticleBoard';
|
import ArticleBoard from '../../components/ArticleBoard/ArticleBoard';
|
||||||
import { useReportSetDetail } from '../../hooks/api/useReportSetDetail';
|
import { useReportSetDetail } from '../../hooks/api/useReportSetDetail';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useReportSetDelete } from '../../hooks/api/useReportSetDelete';
|
||||||
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
export default function TeacherReportsetDetailPage() {
|
export default function TeacherReportsetDetailPage() {
|
||||||
const { reportsetId } = useParams();
|
const { reportsetId } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { reportsetDelete } = useReportSetDelete();
|
||||||
const { data } = useReportSetDetail(reportsetId);
|
const { data } = useReportSetDetail(reportsetId);
|
||||||
const reports = data?.data;
|
const reports = data?.data;
|
||||||
|
|
||||||
@ -16,27 +19,41 @@ export default function TeacherReportsetDetailPage() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await reportsetDelete(reportsetId);
|
||||||
|
navigate('..');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ArticleBoard
|
<div>
|
||||||
title="퀴즈 조회"
|
<ArticleBoard
|
||||||
canCreate={false}
|
title="퀴즈 조회"
|
||||||
>
|
canCreate={false}
|
||||||
{reports.length &&
|
>
|
||||||
reports.map?.((report) => {
|
{reports.length &&
|
||||||
const formattedDate = formatDate(report.date);
|
reports.map?.((report) => {
|
||||||
return (
|
const formattedDate = formatDate(report.date);
|
||||||
<ArticleLink
|
return (
|
||||||
key={`${report.reportId}`}
|
<ArticleLink
|
||||||
title={
|
key={`${report.reportId}`}
|
||||||
report.correctCount == -1
|
title={
|
||||||
? `${report.name} - 미응시`
|
report.correctCount == -1
|
||||||
: `${report.name} - ${report.title} 점수: ${report.correctCount}/${report.allCount}`
|
? `${report.name} - 미응시`
|
||||||
}
|
: `${report.name} - ${report.title} 점수: ${report.correctCount}/${report.allCount}`
|
||||||
sub={`${formattedDate}`}
|
}
|
||||||
to={`../report/${report.reportId}`}
|
sub={`${formattedDate}`}
|
||||||
/>
|
to={`../report/${report.reportId}`}
|
||||||
);
|
/>
|
||||||
})}
|
);
|
||||||
</ArticleBoard>
|
})}
|
||||||
|
</ArticleBoard>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleDelete}
|
||||||
|
>
|
||||||
|
리포트 삭제
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user