One companion study guide per series; v2.9.8
Publish Container / build (push) Successful in 21m12s

- Second series gets its own guide (Resources page card, download page, admin fields)
- When a series ends (scheduled or manual) its guide moves onto its Finished Book, which shows a guide button; the main series' guide is cleared unless the launch supplies a new one
- Lane B launch schedule can supply the incoming series' guide
- Download lookup covers second-series and finished-book guides; guide URLs are sanitized on save and on use

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-08 16:00:52 -04:00
1 parent 39691aedb3
commit e2150e1cd7
7 files changed
+244 -4

No files matched your search

+20
View File
@@ -297,6 +297,22 @@ function sanitizeIsoDate(value) {
return Number.isFinite(time) ? new Date(time).toISOString() : ''
}
function sanitizeStudyGuide(value) {
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
const str = (v, max) => (typeof v === 'string' ? v.trim().slice(0, max) : '')
const title = str(value.title, 140)
if (!title) return undefined
return {
title,
description: str(value.description, 4000),
downloadUrl: sanitizeUrl(value.downloadUrl),
amazonUrl: sanitizeUrl(value.amazonUrl),
amazonLabel: str(value.amazonLabel, 80),
appleBooksUrl: sanitizeUrl(value.appleBooksUrl),
appleBooksLabel: str(value.appleBooksLabel, 80),
}
}
function sanitizeSecondSeries(value) {
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
const str = (v, max) => (typeof v === 'string' ? v.trim().slice(0, max) : '')
@@ -310,6 +326,7 @@ function sanitizeSecondSeries(value) {
listenBtnLabel: str(value.listenBtnLabel, 80),
studySlug: str(value.studySlug, 120).toLowerCase().replace(/[^a-z0-9-]/g, '-'),
...(season ? { season } : {}),
...(sanitizeStudyGuide(value.guide) ? { guide: sanitizeStudyGuide(value.guide) } : {}),
}
}
@@ -410,6 +427,9 @@ export function sanitizeSiteContent(siteContent) {
archivedSeries: sanitizeArchivedSeries(siteContent.archivedSeries),
studies: sanitizeStudies(siteContent.studies),
secondSeries: sanitizeSecondSeries(siteContent.secondSeries),
finishedBooks: Array.isArray(siteContent.finishedBooks)
? siteContent.finishedBooks.map(book => (book && typeof book === 'object' ? { ...book, guide: sanitizeStudyGuide(book.guide) } : book))
: siteContent.finishedBooks,
colossiansStudySections: sanitizeColossiansStudySections(siteContent.colossiansStudySections),
redirects: sanitizeRedirectRules(siteContent.redirects),
podcastFeaturedLinks: sanitizeFeaturedLinks(siteContent.podcastFeaturedLinks ?? DEFAULT_PODCAST_FEATURED_LINKS),