Merge branch 'FE/PasswordChangeForm' into 'frontend'

[Front-End] feat: passwordChangeForm 에러 처리 추가 외

See merge request s11-webmobile1-sub2/S11P12A701!68
This commit is contained in:
조현수 2024-08-06 16:02:34 +09:00
commit 03ec142ec3
15 changed files with 119 additions and 48 deletions

View File

@ -1,6 +1,7 @@
import styles from './ClassInfo.module.css';
export default function ClassInfo({ classTerm, classTime, onPending = false, onSubmit }) {
export default function ClassInfo({ classTerm, classTime, status = 'NOT_ENROLLED', onSubmit }) {
// TODO: ()
return (
<div className={styles.classInfo}>
<div className={styles.title}>수업정보</div>
@ -17,9 +18,11 @@ export default function ClassInfo({ classTerm, classTime, onPending = false, onS
<button
onClick={onSubmit}
className={styles.button}
disabled={onPending}
disabled={status === 'PENDING'}
>
{onPending ? '수강신청 중' : '수강신청'}
{status === 'PENDING' && '수강신청 중'}
{status === 'ENROLLED' && '강의 상세페이지로 이동'}
{status === 'NOT_ENROLLED' && '수강신청'}
</button>
</div>
);

View File

@ -1,9 +1,14 @@
import styles from './InfoEditForm.module.css';
import { useState } from 'react';
import { useState, useEffect } from 'react';
export default function InfoEditForm({ onSubmit }) {
const [username, setUsername] = useState('');
const [useremail, setUseremail] = useState('');
export default function InfoEditForm({ name, email, onSubmit }) {
const [username, setUsername] = useState(name);
const [useremail, setUseremail] = useState(email);
useEffect(() => {
setUsername(name);
setUseremail(email);
}, [name, email]);
return (
<form
@ -46,7 +51,12 @@ export default function InfoEditForm({ onSubmit }) {
required
/>
</div>
<button className={styles.buttonBox}> 정보 수정</button>
<button
disabled={(!username && !useremail) || (username == name && useremail == email)}
className={styles.buttonBox}
>
정보 수정
</button>
</form>
);
}

View File

@ -55,3 +55,12 @@
display: flex;
justify-content: end;
}
.buttonBox:disabled,
.buttonBox[disabled] {
border-color: var(--border-color);
background-color: var(--background-tertiary);
color: var(--text-color-tertiary);
cursor: not-allowed;
stroke: var(--text-color-tertiary);
}

View File

@ -1,14 +1,17 @@
import { useState, useRef } from 'react';
import { useState, useRef, useEffect } from 'react';
import styles from './PasswordChangeForm.module.css';
export default function PasswordChangeForm({ onSubmit, onPwError = false }) {
// TODO: onPwError( )
export default function PasswordChangeForm({ onSubmit, pwError = false }) {
const [errorConfirmMessage, setErrorConfirmMessage] = useState(false);
const [errorSameMessage, setErrorSameMessage] = useState(false);
const currentPasswordRef = useRef('');
const newPasswordRef = useRef('');
const confirmPasswordRef = useRef('');
useEffect(() => {
setErrorSameMessage(pwError);
}, [pwError]);
const handleSubmit = (e) => {
e.preventDefault();
const currentPassword = currentPasswordRef.current.value;
@ -18,12 +21,6 @@ export default function PasswordChangeForm({ onSubmit, onPwError = false }) {
if (newPassword === confirmPassword) {
setErrorConfirmMessage(false);
onSubmit(currentPassword, newPassword, confirmPassword);
if (onPwError) {
setErrorSameMessage(true);
} else {
setErrorSameMessage(false);
}
} else {
setErrorConfirmMessage(true);
}

View File

@ -7,8 +7,9 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
const [answer, setAnswer] = useState(quiz.answer || '');
const [choices, setChoices] = useState(quiz.choices || []);
const [image, setImage] = useState(quiz.image || null);
const [imagePreview, setImagePreview] = useState(quiz.image || null);
const [imagePreview, setImagePreview] = useState(
quiz.image ? `${import.meta.env.VITE_STATIC_URL}${quiz.image}` : null
);
const handleChoiceChange = (num, content) => {
const updatedChoices = choices.map((choice) => (choice.num === num ? { ...choice, content } : choice));
setChoices(updatedChoices);
@ -36,7 +37,6 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
const file = e.target.files[0] ?? null;
setImage(file);
updateQuiz(quiz.id, { ...quiz, question, answer, choices, image: file });
if (file) {
const fileReader = new FileReader();
fileReader.onloadend = () => {
@ -59,10 +59,7 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
X
</button>
</div>
<label
htmlFor={`file-input-${quiz.id}`}
className={styles.imageLabel}
>
<label htmlFor={`file-input-${quiz.id}`}>
{imagePreview ? (
<img
src={imagePreview}
@ -71,7 +68,6 @@ export default function QuizCard({ quiz, updateQuiz, deleteQuiz }) {
/>
) : (
<div className={styles.imagePreview}>
{/* <CompassIcon /> */}
<div>이미지 업로드</div>
</div>
)}

View File

@ -21,11 +21,22 @@ export default function QuizsetDetail({ topic, title, quizzes = [], onDelete, on
{quizzes.map((quiz, index) => (
<div key={index}>
<div>질문 : {quiz.question}</div>
<img
src={`${import.meta.env.VITE_STATIC_URL}${quiz.image}`}
alt="강의 이미지"
/>
{quiz.image && (
<img
src={`${import.meta.env.VITE_STATIC_URL}${quiz.image}`}
alt="강의 이미지"
className={styles.image}
/>
)}
<div>정답 : {quiz.answer}</div>
{quiz.choices != [] &&
quiz.choices.map?.((choice, choiceIndex) => (
<div key={choice.id}>
<div>
선택지 {choiceIndex + 1} : {choice.content}
</div>
</div>
))}
</div>
))}
</div>

View File

@ -34,3 +34,11 @@
font-weight: 800;
margin: 0;
}
.image {
width: 295px;
height: 220px;
margin: 10px auto;
border-radius: 8px;
background-color: var(--background-secondary);
}

View File

@ -2,7 +2,6 @@ import instance from '../../utils/axios/instance';
import { API_URL } from '../../constants';
export function usePasswordChange() {
// TODO: API 수정 후 실제 기능하는지 확인
const passwordChange = (currentPw, newPw, newPwCheck) => {
const newPasswordBody = {
currentPassword: currentPw,

View File

@ -0,0 +1,10 @@
import { useSuspenseQuery } from '@tanstack/react-query';
import instance from '../../utils/axios/instance';
import { API_URL } from '../../constants';
export function useUserInfo() {
return useSuspenseQuery({
queryKey: ['myInfo'],
queryFn: () => instance.get(`${API_URL}/user/userinfo`),
});
}

View File

@ -15,8 +15,7 @@ export default function LectureInfoPage() {
const startDate = new Date(lectureData.startDate).toLocaleDateString();
const endDate = new Date(lectureData.endDate).toLocaleDateString();
const userType = useBoundStore((state) => state.userType);
console.log(lectureData);
const onPending = lectureData.status === 'PENDING' ? true : false;
const status = lectureData.status;
const { lectureRegister } = useLectureRegister();
const handleSubmit = () => {
if (userType === null) {
@ -24,15 +23,20 @@ export default function LectureInfoPage() {
navigate('/auth/login');
}
lectureRegister(lectureId)
.then(() => {
// navigate(`/lecture/${lectureId}`);
window.alert('강사가 수강신청 수락시 수업이 시작됩니다.');
navigate('/');
})
.catch((err) => {
console.log(err);
});
if (status === 'ENROLLED') {
navigate(`/lecture/${lectureId}`);
}
if (status === 'NOT_ENROLLED') {
lectureRegister(lectureId)
.then(() => {
window.alert('강사가 수강신청 수락시 수업이 시작됩니다.');
navigate('/');
})
.catch((err) => {
console.log(err);
});
}
};
return (
@ -59,7 +63,7 @@ export default function LectureInfoPage() {
classTerm={`${startDate} ~ ${endDate}`}
classTime={lectureData.time}
onSubmit={handleSubmit}
onPending={onPending}
status={status}
/>
</aside>
</MaxWidthLayout>

View File

@ -1,9 +1,12 @@
import { InfoEditForm } from '../../components/InfoEditForm';
import { useAuth } from '../../hooks/api/useAuth';
import { useUserInfo } from '../../hooks/api/useUserInfo';
import { useNavigate } from 'react-router-dom';
export default function MyInfoChangePage() {
const navigate = useNavigate();
const { data } = useUserInfo();
const myInfo = data.data?.userInfo;
const { updateInfo } = useAuth();
const handleSubmit = async (e, username, useremail) => {
@ -13,5 +16,11 @@ export default function MyInfoChangePage() {
.catch((err) => console.log(err));
};
return <InfoEditForm onSubmit={handleSubmit} />;
return (
<InfoEditForm
name={myInfo.name}
email={myInfo.email}
onSubmit={handleSubmit}
/>
);
}

View File

@ -10,7 +10,6 @@ export default function NoticeDetailPage() {
const notice = data?.data;
const navigate = useNavigate();
const { noticeDelete } = useNoticeDelete();
// TODO: ( ArticleDetail)
const handleDelete = async () => {
await noticeDelete(noticeId);

View File

@ -1,12 +1,30 @@
import { PasswordChangeForm } from '../../components/PasswordChangeForm';
import { useAuth } from '../../hooks/api/useAuth';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
export default function PasswordChangePage() {
const navigate = useNavigate();
const [pwError, setPwError] = useState(false);
const { updatePassword } = useAuth();
const handleSubmit = async (currentPw, newPw, newPwCheck) => {
await updatePassword(currentPw, newPw, newPwCheck).then(() => navigate('/'));
await updatePassword(currentPw, newPw, newPwCheck)
.then((res) => {
console.log(res);
navigate('/');
})
.catch((err) => {
console.log(err.response.data);
if (err.response.data === 'Current password is incorrect') {
console.log('현재 비밀번호 에러');
setPwError(true);
}
});
};
return <PasswordChangeForm onSubmit={handleSubmit} />;
return (
<PasswordChangeForm
onSubmit={handleSubmit}
pwError={pwError}
/>
);
}

View File

@ -11,7 +11,6 @@ export default function StudentHomePage() {
const { data: allLectures } = useLectures();
const allClasses = allLectures?.data ?? [];
// TODO:
return (
<MaxWidthLayout>
<ClassGrid title="수강중인 강의">

View File

@ -20,7 +20,6 @@ export default function UserRegisterPage() {
const handleSubmit = async (e) => {
e.preventDefault();
// TODO: POST
const isPWMatch = passwordRef.current.value === passwordConfirmRef.current.value;
setPasswordMatch(isPWMatch);