Discussion only open while a study is active; v2.11.1
Publish Container / build (push) Has been cancelled

- Community posts, replies, likes and lesson comments are refused (403) for finished and planned studies
- Reading a closed study's community/comments returns an empty list with closed:true
- Discussion hub lists only active studies; community page shows a closed notice
- Lesson page hides Lesson Discussion, 'Discuss this lesson' and 'Go to Community' for inactive studies; Community buttons hidden on study/dashboard pages
- Tests for isStudyDiscussionOpen

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-09 11:49:03 -04:00
1 parent bb83f3e8c5
commit f1d4909acb
7 files changed
+98 -14

No files matched your search

+35 -10
View File
@@ -212,6 +212,11 @@ function getEffectiveStudyStatus(study: StudyProgram): 'active' | 'planned' | 'c
return 'active'
}
// Discussion (community board and lesson comments) is only open while a study is active.
function isDiscussionOpen(study: StudyProgram | undefined): boolean {
return Boolean(study) && getEffectiveStudyStatus(study as StudyProgram) === 'active'
}
function getNextReleaseLabel(study: StudyProgram): string {
const upcoming = study.sections
.map(getSectionReleaseDate)
@@ -931,7 +936,7 @@ export function StudyLandingPage({ content }: Props) {
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', marginTop: '1rem' }}>
<Link to={`/study/${study.slug}`} className="btn-primary">{study.completed ? 'Review Lessons' : 'Continue'}</Link>
<Link to={`/study/${study.slug}/notes`} className="btn-secondary">My Notes</Link>
<Link to={`/study/${study.slug}/community`} className="btn-secondary">Community</Link>
{isDiscussionOpen(studyMeta) && <Link to={`/study/${study.slug}/community`} className="btn-secondary">Community</Link>}
{study.completed && <Link to="/study/account" className="btn-secondary">🏅 Certificate</Link>}
</div>
</div>
@@ -1693,7 +1698,7 @@ export function ColossiansStudyIndexPage({ content }: Props) {
)}
{allLessonsDone && <Link to="/study/account" className="btn-secondary">🏅 My Certificate</Link>}
{enrolled && <Link to={`/study/${study.slug}/notes`} className="btn-secondary">My Notes</Link>}
{enrolled && <Link to={`/study/${study.slug}/community`} className="btn-secondary">Community</Link>}
{enrolled && studyStatus === 'active' && <Link to={`/study/${study.slug}/community`} className="btn-secondary">Community</Link>}
{auth.authenticated && <Link to="/study/account" className="btn-secondary">My Account</Link>}
</div>
{enrollMessage && <p className="study-note-status" style={{ marginTop: '0.75rem' }}>{enrollMessage}</p>}
@@ -1856,6 +1861,7 @@ export function ColossiansStudySectionPage({ content }: Props) {
const currentStudySlug = study?.slug ?? 'colossians'
const noteId = section?.id ? getNoteId(currentStudySlug, section.id) : ''
const isEnrolled = isEnrolledInStudy(auth, currentStudySlug)
const discussionOpen = isDiscussionOpen(study)
const lessonCompleted = section?.id ? completedSectionIds.includes(section.id) : false
usePageMeta(
@@ -2371,7 +2377,7 @@ export function ColossiansStudySectionPage({ content }: Props) {
))}
</ol>
<div style={{ marginTop: '1rem', display: 'flex', gap: '0.75rem', flexWrap: 'wrap' }}>
<Link to={`/study/${study.slug}/community`} className="btn-primary">Go to Community</Link>
{discussionOpen && <Link to={`/study/${study.slug}/community`} className="btn-primary">Go to Community</Link>}
<Link to={`/contact?source=community&study=${encodeURIComponent(study.title)}`} className="btn-secondary">Ask Nate</Link>
</div>
</article>
@@ -2480,14 +2486,14 @@ export function ColossiansStudySectionPage({ content }: Props) {
)
})()}
<article className="study-class-block">
{discussionOpen && <article className="study-class-block">
<h2>Lesson Discussion</h2>
<p className="study-detail-copy" style={{ fontSize: '0.88rem', color: '#7a7060', margin: '0 0 1rem' }}>
Share a thought or reaction with other students in this lesson.{' '}
<Link to={`/study/${study.slug}/community`} style={{ color: '#e0b840' }}>See all community posts →</Link>
</p>
<StudySectionComments studySlug={currentStudySlug} sectionId={section.id} isEnrolled={isEnrolled} />
</article>
</article>}
</div>
<aside className="study-classroom-sidebar" aria-label="Lesson tools">
@@ -2566,7 +2572,7 @@ export function ColossiansStudySectionPage({ content }: Props) {
</article>
{/* Community shortcut */}
{isEnrolled && (
{isEnrolled && discussionOpen && (
<article className="study-class-side-block study-class-side-block--community">
<Link to={`/study/${study.slug}/community?sectionId=${section.id}`} className="study-community-shortcut">
<svg viewBox="0 0 24 24" aria-hidden="true" className="study-community-shortcut-icon"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H5.17L4 17.17V4h16v12z" /></svg>
@@ -4169,6 +4175,7 @@ export function StudyDiscussionHubPage({ content }: Props) {
}, [])
usePageMeta('Study Discussion | Bible Study', 'Pick a study track and join the conversation with other students.')
const openDiscussionStudies = studies.filter(study => isDiscussionOpen(study))
if (!auth.checked) {
return (
@@ -4197,15 +4204,15 @@ export function StudyDiscussionHubPage({ content }: Props) {
<div className="section-inner study-course-hero-inner">
<p className="eyebrow">Student Community</p>
<h1>Study Discussion</h1>
<p className="study-course-hero-copy">Pick a study track to see what other students are saying, ask questions, and share what God is teaching you.</p>
<p className="study-course-hero-copy">Pick an active study to see what other students are saying, ask questions, and share what God is teaching you. Discussion is open while a study is active.</p>
</div>
</section>
<section className="section-inner" style={{ paddingTop: '1rem', paddingBottom: '4rem' }}>
{studies.length === 0 ? (
<p className="study-detail-copy">No study tracks are available yet.</p>
{openDiscussionStudies.length === 0 ? (
<p className="study-detail-copy">Discussion opens while a study is active. There are no active studies right now — check back when the next one starts.</p>
) : (
<div className="study-module-list">
{studies.map(study => {
{openDiscussionStudies.map(study => {
const enrolled = isEnrolledInStudy(auth, study.slug)
return (
<article key={study.slug} className="study-module-row">
@@ -4281,6 +4288,24 @@ export function StudyCommunityPage({ content }: Props) {
)
}
if (!isDiscussionOpen(study)) {
return (
<main className="auth-page" aria-label="Discussion closed">
<div className="auth-shell auth-shell--single">
<div className="auth-card auth-card--center">
<p className="eyebrow">{study.title}</p>
<h1>Discussion Is Closed</h1>
<p>Discussion is only open while a study is active, and this study isn't active right now.</p>
<div className="study-signup-actions">
<Link to={`/study/${study.slug}`} className="btn-primary">Back to Study</Link>
</div>
<p className="auth-footer-links"><Link to="/study/discussion">← Study Discussion</Link></p>
</div>
</div>
</main>
)
}
const isEnrolled = isEnrolledInStudy(auth, study.slug)
return (