Merge branch 'FE/PasswordChangeForm' into 'frontend'
[Front-End] feat: passwordChangeForm 에러 처리 추가 외 See merge request s11-webmobile1-sub2/S11P12A701!68
This commit is contained in:
commit
03ec142ec3
@ -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>
|
||||
);
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
)}
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
10
frontend/src/hooks/api/useUserInfo.js
Normal file
10
frontend/src/hooks/api/useUserInfo.js
Normal 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`),
|
||||
});
|
||||
}
|
@ -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>
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ export default function StudentHomePage() {
|
||||
const { data: allLectures } = useLectures();
|
||||
const allClasses = allLectures?.data ?? [];
|
||||
|
||||
// TODO: 전체 강의 안에 수강중인 강의가 나옴
|
||||
return (
|
||||
<MaxWidthLayout>
|
||||
<ClassGrid title="수강중인 강의">
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user