feat(assignments): 주차별 과제 → 학습 문서(과제집) 연결 고리
과제 페이지에 '이 주차 학습 문서' 링크를 붙였다. 학생이 과제만 보고 '뭘 보고 하나' 헷갈리던 문제 해결. 주차별 과제집(week1~4-assignments)이 있는 주차에만 뜨고, 없는 주차(5~8)엔 안 뜬다.
This commit is contained in:
parent
d931281946
commit
4a7e75f92d
@ -1,6 +1,7 @@
|
|||||||
// 이 파일이 하는 일: 주차별 과제 목록을 요일(일차)별로 묶어 보여주고, 각 과제에 대해
|
// 이 파일이 하는 일: 주차별 과제 목록을 요일(일차)별로 묶어 보여주고, 각 과제에 대해
|
||||||
// 제출 폼(내용 + 링크)과 내 제출 상태·멘토 피드백을 표시한다.
|
// 제출 폼(내용 + 링크)과 내 제출 상태·멘토 피드백을 표시한다.
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import client from '../api/client';
|
import client from '../api/client';
|
||||||
import Badge from '../components/Badge';
|
import Badge from '../components/Badge';
|
||||||
|
|
||||||
@ -119,6 +120,7 @@ export default function AssignmentsPage() {
|
|||||||
const [week, setWeek] = useState(1);
|
const [week, setWeek] = useState(1);
|
||||||
const [assignments, setAssignments] = useState([]);
|
const [assignments, setAssignments] = useState([]);
|
||||||
const [mySubmissions, setMySubmissions] = useState([]);
|
const [mySubmissions, setMySubmissions] = useState([]);
|
||||||
|
const [docs, setDocs] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
// 내 제출 목록만 다시 불러오는 함수 — 제출 직후에도 호출한다.
|
// 내 제출 목록만 다시 불러오는 함수 — 제출 직후에도 호출한다.
|
||||||
@ -146,6 +148,12 @@ export default function AssignmentsPage() {
|
|||||||
};
|
};
|
||||||
}, [week]);
|
}, [week]);
|
||||||
|
|
||||||
|
// 학습 문서 목록(주차별 과제집 등)을 한 번 불러온다 — 과제 화면에서 관련 문서로 바로 잇기 위해.
|
||||||
|
// API는 학생에게 볼 수 있는 문서만 준다(멘토 전용 강의안은 안 옴).
|
||||||
|
useEffect(() => {
|
||||||
|
client.get('/documents').then((res) => setDocs(res.data)).catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 학습 포인트: 과제 목록과 내 제출 목록은 별도 API다.
|
// 학습 포인트: 과제 목록과 내 제출 목록은 별도 API다.
|
||||||
// assignmentId로 짝을 맞춰(매칭) 과제 카드에 제출 상태를 얹는다.
|
// assignmentId로 짝을 맞춰(매칭) 과제 카드에 제출 상태를 얹는다.
|
||||||
function findSubmission(assignmentId) {
|
function findSubmission(assignmentId) {
|
||||||
@ -157,6 +165,9 @@ export default function AssignmentsPage() {
|
|||||||
const percent =
|
const percent =
|
||||||
assignments.length === 0 ? 0 : Math.round((submittedCount / assignments.length) * 100);
|
assignments.length === 0 ? 0 : Math.round((submittedCount / assignments.length) * 100);
|
||||||
|
|
||||||
|
// 이 주차에 해당하는 학습 문서(주차별 과제집). 학생이 과제 전에 배경을 읽도록 연결한다.
|
||||||
|
const weekDocs = docs.filter((d) => d.week === week);
|
||||||
|
|
||||||
// 요일(일차)별로 묶는다 — 대시보드와 같은 방식이라 화면 리듬이 익숙해진다.
|
// 요일(일차)별로 묶는다 — 대시보드와 같은 방식이라 화면 리듬이 익숙해진다.
|
||||||
const groups = new Map();
|
const groups = new Map();
|
||||||
for (const assignment of assignments) {
|
for (const assignment of assignments) {
|
||||||
@ -199,6 +210,20 @@ export default function AssignmentsPage() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 이 주차 학습 문서로 가는 고리 — "과제만 있고 뭘 보고 하는지 모르겠다"를 없앤다.
|
||||||
|
주차별 과제집이 있는 1~4주차엔 링크가, 없는 주차(5~8)엔 안 뜬다. */}
|
||||||
|
{weekDocs.length > 0 && (
|
||||||
|
<div className="assignment-doc-links">
|
||||||
|
{weekDocs.map((d) => (
|
||||||
|
<Link key={d.slug} to={`/docs/${d.slug}`} className="card assignment-doc-link">
|
||||||
|
<span className="assignment-doc-badge">📚 학습 문서</span>
|
||||||
|
<span className="assignment-doc-title">{d.title}</span>
|
||||||
|
<span className="assignment-doc-cta">과제 전에 먼저 읽어 보세요 →</span>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<p className="empty">불러오는 중...</p>
|
<p className="empty">불러오는 중...</p>
|
||||||
) : assignments.length === 0 ? (
|
) : assignments.length === 0 ? (
|
||||||
|
|||||||
@ -1588,3 +1588,36 @@ inline-code, .icode {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.helper-send:disabled { opacity: 0.5; cursor: default; }
|
.helper-send:disabled { opacity: 0.5; cursor: default; }
|
||||||
|
|
||||||
|
/* ── 과제 → 학습 문서 연결 고리 ──────────────────────────────────── */
|
||||||
|
.assignment-doc-links { margin: 14px 0; }
|
||||||
|
.assignment-doc-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--ink);
|
||||||
|
word-break: keep-all; /* 한글 단어 중간 줄바꿈 금지 */
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
}
|
||||||
|
.assignment-doc-link + .assignment-doc-link { margin-top: 10px; }
|
||||||
|
.assignment-doc-link:hover {
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
.assignment-doc-badge {
|
||||||
|
flex: none;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.assignment-doc-title { font-weight: 600; }
|
||||||
|
.assignment-doc-cta {
|
||||||
|
margin-left: auto;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
@media (max-width: 520px) {
|
||||||
|
.assignment-doc-cta { margin-left: 0; } /* 좁은 화면에선 CTA를 다음 줄로 */
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user