Add release date and episode # columns to admin lesson list with inline date editing; use local time for release dates; v2.8.2
Publish Container / build (push) Successful in 18m28s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-07 14:46:25 -04:00
1 parent 0ff0b32b97
commit b1695b2b59
6 files changed
+58 -8

No files matched your search

+30 -5
View File
@@ -14,22 +14,43 @@ import InboxPanel, { type InboxSubmission } from './InboxPanel'
import AssetManager, { type AdminAsset } from './AssetManager'
function toLocalInputValue(iso?: string): string {
if (!iso) return ''
const d = new Date(iso)
if (isNaN(d.getTime())) return ''
const pad = (n: number) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}
function fromLocalInputValue(val: string): string {
return val ? new Date(val).toISOString() : ''
}
interface SortableLessonRowProps {
section: ColossiansStudySection
study: StudyProgram
onEdit: () => void
removeStudySection: (studyId: string, sectionId: string) => void
onReleaseChange: (value: string) => void
}
function SortableLessonRow({ section, study, onEdit, removeStudySection }: SortableLessonRowProps) {
function SortableLessonRow({ section, study, onEdit, removeStudySection, onReleaseChange }: SortableLessonRowProps) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: section.id })
const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.4 : 1 }
const isLive = section.releasedAt ? new Date(section.releasedAt) <= new Date() : false
return (
<div ref={setNodeRef} style={style} className="study-lesson-row">
<span className="study-lesson-drag" {...attributes} {...listeners} title="Drag to reorder">⠿</span>
<span className="study-lesson-ep">{section.episodeNumber || '—'}</span>
<span className="study-lesson-ref">{section.reference || '—'}</span>
<span className="study-lesson-title">{section.title || <em style={{ opacity: 0.5 }}>Untitled</em>}</span>
<input
type="datetime-local"
className="study-lesson-release"
aria-label={`Release date for ${section.title || 'lesson'}`}
value={toLocalInputValue(section.releasedAt)}
onChange={e => onReleaseChange(fromLocalInputValue(e.target.value))}
/>
<span className={`study-lesson-pill ${isLive ? 'live' : 'draft'}`}>{isLive ? 'Live' : 'Draft'}</span>
<div className="study-lesson-actions">
<button type="button" className="btn-admin-ghost" onClick={onEdit}>Edit</button>
@@ -5043,8 +5064,10 @@ const [dashboardNow, setDashboardNow] = useState(() => new Date())
<div className="study-lesson-list-header">
<span style={{ width: 28 }} />
<span style={{ width: 44 }}>Ep #</span>
<span style={{ width: 80 }}>Reference</span>
<span style={{ flex: 1 }}>Title</span>
<span style={{ width: 190 }}>Release</span>
<span style={{ width: 60 }}>Status</span>
<span style={{ width: 160 }} />
</div>
@@ -5075,6 +5098,7 @@ const [dashboardNow, setDashboardNow] = useState(() => new Date())
study={activeStudy}
onEdit={() => setSelectedLessonId(section.id)}
removeStudySection={removeStudySection}
onReleaseChange={value => updateStudySection(activeStudy.id, section.id, 'releasedAt', value)}
/>
))}
</SortableContext>
@@ -5109,6 +5133,10 @@ const [dashboardNow, setDashboardNow] = useState(() => new Date())
</div>
<div className="admin-array-fields">
<div className="admin-field">
<label htmlFor={`sl-episode-${activeLesson.id}`}>Episode # (admin reference only)</label>
<input id={`sl-episode-${activeLesson.id}`} type="text" value={activeLesson.episodeNumber ?? ''} placeholder="12" maxLength={20} onChange={e => updateStudySection(activeStudy.id, activeLesson.id, 'episodeNumber', e.target.value)} />
</div>
<div className="admin-field">
<label htmlFor={`sl-chapter-${activeLesson.id}`}>Chapter</label>
<select id={`sl-chapter-${activeLesson.id}`} value={activeLesson.chapter} onChange={e => updateStudySection(activeStudy.id, activeLesson.id, 'chapter', Number(e.target.value) || 1)}>
@@ -5137,10 +5165,7 @@ const [dashboardNow, setDashboardNow] = useState(() => new Date())
</div>
<div className="admin-field">
<label htmlFor={`sl-released-${activeLesson.id}`}>Release Date (optional)</label>
<input id={`sl-released-${activeLesson.id}`} type="datetime-local" value={activeLesson.releasedAt ? new Date(activeLesson.releasedAt).toISOString().slice(0, 16) : ''} onChange={e => {
const val = e.target.value
updateStudySection(activeStudy.id, activeLesson.id, 'releasedAt', val ? new Date(val + ':00Z').toISOString() : '')
}} />
<input id={`sl-released-${activeLesson.id}`} type="datetime-local" value={toLocalInputValue(activeLesson.releasedAt)} onChange={e => updateStudySection(activeStudy.id, activeLesson.id, 'releasedAt', fromLocalInputValue(e.target.value))} />
</div>
<div className="admin-field">
<label htmlFor={`sl-summary-${activeLesson.id}`}>Short Summary</label>