diff --git a/e2e/class/journey-map.spec.ts b/e2e/class/journey-map.spec.ts index 5a7043f09..e3e1dc194 100644 --- a/e2e/class/journey-map.spec.ts +++ b/e2e/class/journey-map.spec.ts @@ -61,6 +61,7 @@ test.beforeEach(async ({ context, baseURL }) => { function makeCourseDetail(overrides: Partial = {}): { content: CourseDetailResponse; } { + const viewerStatus = overrides.viewerStatus ?? 'FREE_ENROLLED'; const base: CourseDetailResponse = { courseId: COURSE_ID, slug: 'vibe-intro', @@ -86,11 +87,11 @@ function makeCourseDetail(overrides: Partial = {}): { ], earlyBirdEndsAt: null, canFreeEnroll: null, - isFreeEnrolled: true, + isFreeEnrolled: viewerStatus === 'FREE_ENROLLED', freeLessonCount: 3, journeyMapAvailable: true, - hasFullAccess: false, - isPaidEnrolled: false, + hasFullAccess: viewerStatus === 'PAID', + isPaidEnrolled: viewerStatus === 'PAID', canPurchase: true, }; return { content: { ...base, ...overrides } }; diff --git a/src/app/(class-lesson)/class/[slug]/lesson/[id]/page.tsx b/src/app/(class-lesson)/class/[slug]/lesson/[id]/page.tsx index 815e439d4..5a4f00726 100644 --- a/src/app/(class-lesson)/class/[slug]/lesson/[id]/page.tsx +++ b/src/app/(class-lesson)/class/[slug]/lesson/[id]/page.tsx @@ -47,16 +47,16 @@ export default function LessonPage({ const reviewRef = useRef(null); const contentRef = useRef(null); const topBarRef = useRef(null); + const leftColRef = useRef(null); function scrollToRef(ref: RefObject) { - if (!ref.current) return; - const headerHeight = topBarRef.current?.offsetHeight ?? 64; + if (!ref.current || !leftColRef.current) return; + const container = leftColRef.current; const top = - ref.current.getBoundingClientRect().top + - window.scrollY - - headerHeight - - 16; - window.scrollTo({ top, behavior: 'smooth' }); + container.scrollTop + + ref.current.getBoundingClientRect().top - + container.getBoundingClientRect().top; + container.scrollTo({ top, behavior: 'smooth' }); } function handleTabChange(next: LessonTabValue) { @@ -200,93 +200,101 @@ export default function LessonPage({
-
+
{/* LEFT */} -
- - - - 학습 여정 맵 돌아가기 - - - -
-
- - Lesson {String(lessonId).padStart(2, '0')} +
+ {/* Fixed header: back link, title, description, tabs — never scrolls */} +
+ + + + 학습 여정 맵 돌아가기 -

- {lesson?.title ?? 'AI 처음 만나는 날'} -

+ + +
+
+ + Lesson {String(lessonId).padStart(2, '0')} + +

+ {lesson?.title ?? 'AI 처음 만나는 날'} +

+
+

+ {lesson?.estimatedMinutes + ? `약 ${lesson.estimatedMinutes}분 소요` + : ''} +

-

- {lesson?.estimatedMinutes - ? `약 ${lesson.estimatedMinutes}분 소요` - : ''} -

-
- {lesson?.description ? ( -

- {lesson.description} -

- ) : null} + {lesson?.description ? ( +

+ {lesson.description} +

+ ) : null} -
- +
+ +
-
- {lesson?.contentMarkdown ? ( - - ) : ( -

- 본문이 준비 중입니다. -

- )} -
+ {/* Scroll area: content + review form only */} +
+
+ {lesson?.contentMarkdown ? ( + + ) : ( +

+ 본문이 준비 중입니다. +

+ )} +
-
-
+
+
- {tab === 'review' || tab === 'follow' ? ( - - ) : null} + {tab === 'review' || tab === 'follow' ? ( + + ) : null} -
+
+
- {/* RIGHT sticky sidebar */} -
- setSubmissionModalOpen(true)} - onSelectQna={setSelectedQnaId} - /> - + {/* RIGHT sidebar — stays put while left column scrolls */} +
+
+ setSubmissionModalOpen(true)} + onSelectQna={setSelectedQnaId} + /> + +