import React, { useEffect, useRef, useState } from 'react' import { DndContext, closestCenter, PointerSensor, useSensor, useSensors } from '@dnd-kit/core' import { arrayMove, SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' import type { ChangeEvent } from 'react' import { Link } from 'react-router-dom' import type { SiteContent, CustomLink, CustomBlock, ColossiansStudySection, StudyProgram, RedirectRule, PodcastFeaturedLink, SeoSettings, LegalSettings } from './content' import { DEFAULTS } from './content' import { AnalyticsPanel } from './components/AnalyticsPanel' import { AdminCollapsibleCard } from './components/AdminCollapsibleCard' import { useAutosave } from './hooks/useAutosave' import QRCode from 'qrcode' interface SortableLessonSectionProps { section: ColossiansStudySection study: StudyProgram updateStudySection: (studyId: string, sectionId: string, field: keyof ColossiansStudySection, value: string | string[] | number) => void removeStudySection: (studyId: string, sectionId: string) => void rssEpisodes: Array<{ title: string; audioUrl: string; duration: string; episode: string }> } function SortableLessonSection({ section, study, updateStudySection, removeStudySection, rssEpisodes }: SortableLessonSectionProps) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: section.id }) const [bsbFetching, setBsbFetching] = useState(false) const [bsbMsg, setBsbMsg] = useState('') async function fetchBsbPassage() { const bookKey = (study.bibleBook?.trim() || study.slug).toLowerCase() const reference = section.reference?.trim() if (!bookKey || !reference) { setBsbMsg('Set the passage reference first.'); return } setBsbFetching(true) setBsbMsg('') try { const params = new URLSearchParams({ book: bookKey, reference }) const res = await fetch(`/api/bible-passage?${params}`) const data = await res.json() as { text?: string; message?: string } if (!res.ok || !data.text) { setBsbMsg(data.message ?? 'Passage not found.'); return } updateStudySection(study.id, section.id, 'passageText', data.text) setBsbMsg('Passage filled from BSB.') } catch { setBsbMsg('Could not reach the BSB API.') } finally { setBsbFetching(false) } } const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, background: isDragging ? '#f8f7f2' : undefined, border: isDragging ? '2px solid #e0c070' : undefined, marginBottom: '0.5rem', } return (
Lesson {section.reference || section.id}

{section.title || 'Untitled section'}

e.stopPropagation()}>Preview Expand to edit lesson
updateStudySection(study.id, section.id, 'reference', e.target.value)} />
updateStudySection(study.id, section.id, 'title', e.target.value)} />
{ const val = e.target.value; if (val) { const date = new Date(val + ':00Z'); updateStudySection(study.id, section.id, 'releasedAt', date.toISOString()); } else { updateStudySection(study.id, section.id, 'releasedAt', ''); } }} />