Enforce study lesson release locks and schedule biweekly Monday dates
This commit is contained in:
+38
-7
@@ -78,6 +78,13 @@ function isComingSoon(section: StudySection): boolean {
|
||||
return releaseDate > now
|
||||
}
|
||||
|
||||
function isSectionReleased(section: StudySection): boolean {
|
||||
if (!section.releasedAt) return true
|
||||
const releaseDate = new Date(section.releasedAt)
|
||||
if (Number.isNaN(releaseDate.getTime())) return true
|
||||
return releaseDate <= new Date()
|
||||
}
|
||||
|
||||
function getReleaseDateDisplay(section: StudySection): string {
|
||||
if (!section.releasedAt) return ''
|
||||
const date = new Date(section.releasedAt)
|
||||
@@ -102,6 +109,7 @@ export function StudyLandingPage({ content }: Props) {
|
||||
const activeStudies = studies.filter(study => study.status !== 'planned')
|
||||
const plannedStudies = studies.filter(study => study.status === 'planned')
|
||||
const firstActiveStudy = activeStudies[0]
|
||||
const firstActiveStudyFirstReleasedSection = firstActiveStudy?.sections.find(isSectionReleased)
|
||||
|
||||
return (
|
||||
<main className="study-index-page" aria-label="Study hub">
|
||||
@@ -117,7 +125,7 @@ export function StudyLandingPage({ content }: Props) {
|
||||
<span>Audio + commentary</span>
|
||||
</div>
|
||||
<div className="study-course-hero-actions">
|
||||
{firstActiveStudy && <Link to={`/study/${firstActiveStudy.slug}`} className="btn-primary">Start Learning</Link>}
|
||||
{firstActiveStudyFirstReleasedSection && <Link to={`/study/${firstActiveStudy.slug}/${firstActiveStudyFirstReleasedSection.id}`} className="btn-primary">Start Learning</Link>}
|
||||
<Link to="#study-tracks" className="btn-secondary">Browse Tracks</Link>
|
||||
<Link to="/study/signup" className="btn-primary">Create Account or Login</Link>
|
||||
</div>
|
||||
@@ -158,6 +166,9 @@ export function StudyLandingPage({ content }: Props) {
|
||||
</div>
|
||||
<div className="study-module-list">
|
||||
{activeStudies.map(study => (
|
||||
(() => {
|
||||
const releasedCount = study.sections.filter(isSectionReleased).length
|
||||
return (
|
||||
<Link key={study.id} to={`/study/${study.slug}`} className="study-module-row">
|
||||
<div className="study-module-row-left">
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '0.5rem', flexWrap: 'wrap' }}>
|
||||
@@ -170,11 +181,13 @@ export function StudyLandingPage({ content }: Props) {
|
||||
</div>
|
||||
<div className="study-module-row-right">
|
||||
<p className="study-module-focus">Track Snapshot</p>
|
||||
<p>{study.sections.length > 0 ? `${study.sections.length} lessons available` : 'Lessons will be published soon.'}</p>
|
||||
<p>{study.sections.length > 0 ? 'Estimated pace: 1-2 lessons per week' : 'Pacing details coming with first lesson release.'}</p>
|
||||
<p>{releasedCount > 0 ? `${releasedCount} lessons available now` : 'Lessons will be published soon.'}</p>
|
||||
<p>{study.sections.length > 0 ? 'Estimated pace: every other Monday' : 'Pacing details coming with first lesson release.'}</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
)
|
||||
})()
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -357,6 +370,8 @@ export function ColossiansStudyIndexPage({ content }: Props) {
|
||||
|
||||
const sections = study.sections
|
||||
const chapterSummaries = getChapterSummaries(study)
|
||||
const releasedSections = sections.filter(isSectionReleased)
|
||||
const firstReleasedSection = releasedSections[0]
|
||||
const populatedChapterCount = chapterSummaries.filter(chapter => chapter.lessonCount > 0).length
|
||||
|
||||
return (
|
||||
@@ -367,14 +382,14 @@ export function ColossiansStudyIndexPage({ content }: Props) {
|
||||
<h1>{study.title}</h1>
|
||||
<p className="study-course-hero-copy">{study.description}</p>
|
||||
<div className="study-course-meta">
|
||||
<span>{sections.length} lessons</span>
|
||||
<span>{releasedSections.length} lessons available now</span>
|
||||
<span>{chapterSummaries.length} chapters</span>
|
||||
<span>{populatedChapterCount} chapters with lessons</span>
|
||||
<span>Text + commentary + discussion</span>
|
||||
<span>Student notes enabled</span>
|
||||
</div>
|
||||
<div className="study-course-hero-actions">
|
||||
{sections.length > 0 && <Link to={`/study/${study.slug}/${sections[0].id}`} className="btn-primary">Start Class</Link>}
|
||||
{firstReleasedSection && <Link to={`/study/${study.slug}/${firstReleasedSection.id}`} className="btn-primary">Start Class</Link>}
|
||||
<Link to={`/study/${study.slug}/notes`} className="btn-secondary">My Notes</Link>
|
||||
<Link to="/study" className="btn-secondary">Back to Studies</Link>
|
||||
</div>
|
||||
@@ -446,6 +461,7 @@ export function ColossiansStudySectionPage({ content }: Props) {
|
||||
const lessonNumber = getLessonNumber(sections, sectionId)
|
||||
const previousSection = sectionIndex > 0 ? sections[sectionIndex - 1] : null
|
||||
const nextSection = sectionIndex >= 0 && sectionIndex < sections.length - 1 ? sections[sectionIndex + 1] : null
|
||||
const sectionIsReleased = section ? isSectionReleased(section) : false
|
||||
|
||||
const [auth, setAuth] = useState<StudyAuthState>({ checked: false, authenticated: false, username: '' })
|
||||
const [usernameInput, setUsernameInput] = useState('')
|
||||
@@ -587,6 +603,19 @@ export function ColossiansStudySectionPage({ content }: Props) {
|
||||
)
|
||||
}
|
||||
|
||||
if (!sectionIsReleased) {
|
||||
return (
|
||||
<main className="thanks-page" aria-label="Lesson not yet available">
|
||||
<div className="thanks-card">
|
||||
<p className="eyebrow">{study.title}</p>
|
||||
<h1>Lesson Coming Soon</h1>
|
||||
<p>This lesson will be available on {getReleaseDateDisplay(section)}.</p>
|
||||
<Link to={`/study/${study.slug}`} className="btn-primary">Back to Lessons</Link>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="study-section-page" aria-label={section.title}>
|
||||
<section className="section-study-classroom">
|
||||
@@ -697,8 +726,10 @@ export function ColossiansStudySectionPage({ content }: Props) {
|
||||
{previousSection ? (
|
||||
<Link to={`/study/${study.slug}/${previousSection.id}`} className="btn-secondary">Previous Lesson</Link>
|
||||
) : <span className="study-nav-placeholder" />}
|
||||
{nextSection ? (
|
||||
{nextSection && isSectionReleased(nextSection) ? (
|
||||
<Link to={`/study/${study.slug}/${nextSection.id}`} className="btn-secondary">Next Lesson</Link>
|
||||
) : nextSection ? (
|
||||
<span className="study-nav-placeholder">Available {getReleaseDateDisplay(nextSection)}</span>
|
||||
) : <span className="study-nav-placeholder" />}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
Reference in New Issue
Block a user