Merge branch 'fe/lectureRoute' into 'frontend'
[Front-End] feat: 접근할 수 없는 강의 페이지 접근 못하도록 로직 추가 See merge request s11-webmobile1-sub2/S11P12A701!108
This commit is contained in:
commit
a868c6e3f7
@ -68,11 +68,11 @@ const router = createBrowserRouter([
|
|||||||
element: <LectureCreatePage />,
|
element: <LectureCreatePage />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lecture/:lectureId/info',
|
path: 'lecture/:lectureId',
|
||||||
element: <LectureInfoPage />,
|
element: <LectureInfoPage />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lecture/:lectureId',
|
path: 'lecture/:lectureId/class',
|
||||||
element: <LectureLayout />,
|
element: <LectureLayout />,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
@ -4,10 +4,21 @@ import styles from './ArticleDetail.module.css';
|
|||||||
import ArticleDetailAnswer from './ArticleDetailAnswer/ArticleDetailAnswer';
|
import ArticleDetailAnswer from './ArticleDetailAnswer/ArticleDetailAnswer';
|
||||||
import ArticleDetailAnswerInput from './ArticleDetailAnswer/ArticleDetailAnswerInput';
|
import ArticleDetailAnswerInput from './ArticleDetailAnswer/ArticleDetailAnswerInput';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import useBoundStore from '../../../store';
|
||||||
|
|
||||||
export default function ArticleDetail({ topic, title, author = null, content, answer = null, onDelete, isQna = true }) {
|
export default function ArticleDetail({
|
||||||
|
topic,
|
||||||
|
title,
|
||||||
|
author = null,
|
||||||
|
content,
|
||||||
|
answer = null,
|
||||||
|
onDelete,
|
||||||
|
isMine = false,
|
||||||
|
isQna = true,
|
||||||
|
}) {
|
||||||
const [submittedAnswer, setSubmittedAnswer] = useState(answer);
|
const [submittedAnswer, setSubmittedAnswer] = useState(answer);
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
const userType = useBoundStore((state) => state.userType);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSubmittedAnswer(answer);
|
setSubmittedAnswer(answer);
|
||||||
@ -44,20 +55,24 @@ export default function ArticleDetail({ topic, title, author = null, content, an
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.actionGroup}>
|
<div className={styles.actionGroup}>
|
||||||
<Link
|
{(isMine || userType === 'teacher') && (
|
||||||
className={styles.edit}
|
<>
|
||||||
to={'edit'}
|
<Link
|
||||||
state={{ title: title, content: content, answer: answer }}
|
className={styles.edit}
|
||||||
>
|
to={'edit'}
|
||||||
수정
|
state={{ title: title, content: content, answer: answer }}
|
||||||
</Link>
|
>
|
||||||
<button
|
수정
|
||||||
type="button"
|
</Link>
|
||||||
className={styles.delete}
|
<button
|
||||||
onClick={onDelete}
|
type="button"
|
||||||
>
|
className={styles.delete}
|
||||||
삭제
|
onClick={onDelete}
|
||||||
</button>
|
>
|
||||||
|
삭제
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div>
|
<div>
|
||||||
|
@ -15,15 +15,17 @@ export default function ClassInfo({ classTerm, classTime, status = 'NOT_ENROLLED
|
|||||||
<div className={styles.content}>{classTime}</div>
|
<div className={styles.content}>{classTime}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
{status !== 'MANAGED_BY_OTHERS' && (
|
||||||
onClick={onSubmit}
|
<button
|
||||||
className={styles.button}
|
onClick={onSubmit}
|
||||||
disabled={status === 'PENDING'}
|
className={styles.button}
|
||||||
>
|
disabled={status === 'PENDING'}
|
||||||
{status === 'PENDING' && '수강신청 중'}
|
>
|
||||||
{status === 'ENROLLED' && '강의 상세페이지로 이동'}
|
{status === 'PENDING' && '수강신청 중'}
|
||||||
{status === 'NOT_ENROLLED' && '수강신청'}
|
{status === 'ENROLLED' && '강의 상세페이지로 이동'}
|
||||||
</button>
|
{status === 'NOT_ENROLLED' && '수강신청'}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { Outlet, useParams } from 'react-router-dom';
|
|||||||
import LectureHeader from '../LectureHeader/LectureHeader';
|
import LectureHeader from '../LectureHeader/LectureHeader';
|
||||||
import { SideBar, SideLink, SideItem } from '../SideBar';
|
import { SideBar, SideLink, SideItem } from '../SideBar';
|
||||||
import MaxWidthLayout from './MaxWidthLayout';
|
import MaxWidthLayout from './MaxWidthLayout';
|
||||||
import { Suspense } from 'react';
|
import { Suspense, useEffect } from 'react';
|
||||||
import useBoundStore from '../../store';
|
import useBoundStore from '../../store';
|
||||||
import { useLectureInfo } from '../../hooks/api/useLectureInfo';
|
import { useLectureInfo } from '../../hooks/api/useLectureInfo';
|
||||||
import LoadingIndicator from '../LoadingIndicator.jsx/LoadingIndicator';
|
import LoadingIndicator from '../LoadingIndicator.jsx/LoadingIndicator';
|
||||||
@ -34,6 +34,12 @@ export default function LectureLayout() {
|
|||||||
time: lecture.time,
|
time: lecture.time,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (['NOT_ENROLLED', 'MANAGED_BY_OTHERS', 'PENDING'].includes(lecture.status)) {
|
||||||
|
navigate('..');
|
||||||
|
}
|
||||||
|
}, [lecture.status, navigate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LectureHeader
|
<LectureHeader
|
||||||
|
@ -4,8 +4,12 @@ import SideBar from '../../components/SideBar/SideBar';
|
|||||||
import SideLink from '../../components/SideBar/SideLink';
|
import SideLink from '../../components/SideBar/SideLink';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import LoadingIndicator from '../LoadingIndicator.jsx/LoadingIndicator';
|
import LoadingIndicator from '../LoadingIndicator.jsx/LoadingIndicator';
|
||||||
|
import useBoundStore from '../../store';
|
||||||
|
|
||||||
export default function MyPageLayout() {
|
export default function MyPageLayout() {
|
||||||
|
const userType = useBoundStore((state) => state.userType);
|
||||||
|
const myLectureTitle = userType === 'student' ? '수강중인 강의' : '내 강의';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MaxWidthLayout hasSideBar>
|
<MaxWidthLayout hasSideBar>
|
||||||
@ -15,7 +19,7 @@ export default function MyPageLayout() {
|
|||||||
to={''}
|
to={''}
|
||||||
end
|
end
|
||||||
>
|
>
|
||||||
수강중인 강의
|
{myLectureTitle}
|
||||||
</SideLink>
|
</SideLink>
|
||||||
<SideLink to={'edit'}>개인정보 변경</SideLink>
|
<SideLink to={'edit'}>개인정보 변경</SideLink>
|
||||||
<SideLink to={'changePw'}>비밀번호 변경</SideLink>
|
<SideLink to={'changePw'}>비밀번호 변경</SideLink>
|
||||||
|
@ -6,7 +6,7 @@ export function useAnswerDelete() {
|
|||||||
const newAnswer = {
|
const newAnswer = {
|
||||||
answer: null,
|
answer: null,
|
||||||
};
|
};
|
||||||
return instance.post(`${API_URL}/qna/answer/create/${questionId}`, newAnswer);
|
return instance.post(`${API_URL}/qna/answer/delete/${questionId}`, newAnswer);
|
||||||
};
|
};
|
||||||
|
|
||||||
return { answerDelete };
|
return { answerDelete };
|
||||||
|
@ -14,7 +14,7 @@ export default function StudentHomePage() {
|
|||||||
{allClasses.map?.((lecture) => (
|
{allClasses.map?.((lecture) => (
|
||||||
<ClassCard
|
<ClassCard
|
||||||
key={lecture.id}
|
key={lecture.id}
|
||||||
path={`/lecture/${lecture.id}/info`}
|
path={`/lecture/${lecture.id}`}
|
||||||
img={lecture.image}
|
img={lecture.image}
|
||||||
>
|
>
|
||||||
{lecture.title}
|
{lecture.title}
|
||||||
|
@ -3,21 +3,24 @@ import { Link } from 'react-router-dom';
|
|||||||
import { useMyLectures } from '../../hooks/api/useMyLectures';
|
import { useMyLectures } from '../../hooks/api/useMyLectures';
|
||||||
import CompassIcon from '/src/assets/icons/compass.svg?react';
|
import CompassIcon from '/src/assets/icons/compass.svg?react';
|
||||||
import { STATIC_URL } from '../../constants';
|
import { STATIC_URL } from '../../constants';
|
||||||
|
import useBoundStore from '../../store';
|
||||||
|
|
||||||
export default function LearningLecturesPage() {
|
export default function LearningLecturesPage() {
|
||||||
const { data } = useMyLectures();
|
const { data } = useMyLectures();
|
||||||
const onGoingClasses = data?.data ?? [];
|
const onGoingClasses = data?.data ?? [];
|
||||||
const hasOnGoingClasses = onGoingClasses.length > 0;
|
const hasOnGoingClasses = onGoingClasses.length > 0;
|
||||||
|
const userType = useBoundStore((state) => state.userType);
|
||||||
|
const myLectureTitle = userType === 'student' ? '수강중인 강의' : '내 강의';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<h2 className={styles.title}>수강중인 강의</h2>
|
<h2 className={styles.title}>{myLectureTitle}</h2>
|
||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
{hasOnGoingClasses ? (
|
{hasOnGoingClasses ? (
|
||||||
onGoingClasses.map?.((lecture) => (
|
onGoingClasses.map?.((lecture) => (
|
||||||
<Link
|
<Link
|
||||||
key={lecture.id}
|
key={lecture.id}
|
||||||
to={`/lecture/${lecture.id}`}
|
to={`/lecture/${lecture.id}/class`}
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
>
|
>
|
||||||
{lecture.image ? (
|
{lecture.image ? (
|
||||||
|
@ -24,7 +24,7 @@ export default function LectureInfoPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'ENROLLED') {
|
if (status === 'ENROLLED') {
|
||||||
navigate(`/lecture/${lectureId}`);
|
navigate(`/lecture/${lectureId}/class`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === 'NOT_ENROLLED') {
|
if (status === 'NOT_ENROLLED') {
|
||||||
|
@ -23,6 +23,7 @@ export default function NoticeDetailPage() {
|
|||||||
content={notice.content}
|
content={notice.content}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
isQna={false}
|
isQna={false}
|
||||||
|
isMine={notice.mine}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export default function StudentHomePage() {
|
|||||||
onGoingClasses.map?.((lecture) => (
|
onGoingClasses.map?.((lecture) => (
|
||||||
<ClassCard
|
<ClassCard
|
||||||
key={lecture.id}
|
key={lecture.id}
|
||||||
path={`/lecture/${lecture.id}`}
|
path={`/lecture/${lecture.id}/class`}
|
||||||
img={lecture.image}
|
img={lecture.image}
|
||||||
>
|
>
|
||||||
{lecture.title}
|
{lecture.title}
|
||||||
@ -34,7 +34,7 @@ export default function StudentHomePage() {
|
|||||||
{allClasses.map?.((lecture) => (
|
{allClasses.map?.((lecture) => (
|
||||||
<ClassCard
|
<ClassCard
|
||||||
key={lecture.id}
|
key={lecture.id}
|
||||||
path={`/lecture/${lecture.id}/info`}
|
path={`/lecture/${lecture.id}`}
|
||||||
img={lecture.image}
|
img={lecture.image}
|
||||||
>
|
>
|
||||||
{lecture.title}
|
{lecture.title}
|
||||||
|
@ -16,7 +16,7 @@ export default function TeacherHomePage() {
|
|||||||
{onGoingClasses.map((lecture) => (
|
{onGoingClasses.map((lecture) => (
|
||||||
<ClassCard
|
<ClassCard
|
||||||
key={lecture.id}
|
key={lecture.id}
|
||||||
path={`/lecture/${lecture.id}`}
|
path={`/lecture/${lecture.id}/class`}
|
||||||
img={lecture.image}
|
img={lecture.image}
|
||||||
>
|
>
|
||||||
{lecture.title}
|
{lecture.title}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
width: 295px;
|
width: 100%;
|
||||||
height: 220px;
|
aspect-ratio: 4/3;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
stroke: var(--text-color);
|
stroke: var(--text-color);
|
||||||
|
Loading…
Reference in New Issue
Block a user