import { useEffect, useState } from 'react' import type { ReactNode } from 'react' import { Link } from 'react-router-dom' import type { SiteContent } from '../content' import { StoreLink } from './StoreLink' type TabKey = 'downloads' | 'books' | 'recommended' interface Props { content: SiteContent downloadPath: (resourceId: string) => string // Shown when there are no downloads, books or recommended resources at all fallback: ReactNode } // A description that stays short in the grid; long ones get a Read more toggle function ClampedText({ text, className, lines = 3, threshold = 150 }: { text: string; className: string; lines?: number; threshold?: number }) { const [open, setOpen] = useState(false) const long = text.length > threshold return ( <>

{text}

{long && ( )} ) } export function ResourcesHub({ content, downloadPath, fallback }: Props) { const links = content.customLinks ?? [] // Ask for name and email before sending visitors to Amazon / Apple Books (on unless switched off in the admin) const gated = content.gateStoreLinks !== false const resources = links.filter(l => l.placement === 'resources') const books = links.filter(l => l.placement === 'books') const recommended = links.filter(l => l.placement === 'recommended') const featured: { key: string; to: string; title: string; description: string; image: string; alt: string }[] = [] if (content.studyGuideTitle) { featured.push({ key: 'primary', to: '/downloads/primary-guide', title: content.studyGuideTitle, description: content.studyGuideDescription ?? '', image: content.seriesImageUrl || '/images/titus-cover.png', alt: content.seriesTitle, }) } if (content.secondSeries?.guide?.title) { featured.push({ key: 'second', to: '/downloads/second-guide', title: content.secondSeries.guide.title, description: content.secondSeries.guide.description ?? '', image: content.secondSeries.imageUrl ?? '', alt: content.secondSeries.title, }) } const counts: Record = { downloads: featured.length + resources.length, books: books.length, recommended: recommended.length, } const available = (Object.keys(counts) as TabKey[]).filter(k => counts[k] > 0) const fromHash = (): TabKey | null => { const h = typeof window !== 'undefined' ? window.location.hash.replace('#', '') : '' return h === 'downloads' || h === 'books' || h === 'recommended' ? h : null } const [picked, setPicked] = useState(fromHash) const [activeTag, setActiveTag] = useState(null) // Links like /resources#books, and the browser's back/forward buttons, switch the tab too useEffect(() => { const onHash = () => setPicked(fromHash()) window.addEventListener('hashchange', onHash) return () => window.removeEventListener('hashchange', onHash) }, []) if (available.length === 0) return <>{fallback} const tab: TabKey = picked && counts[picked] > 0 ? picked : available[0] const choose = (k: TabKey) => { setPicked(k) try { window.history.replaceState(null, '', `#${k}`) } catch { /* ignore */ } } const tags = Array.from(new Set(resources.flatMap(r => r.tags ?? []))).filter(Boolean) const shownResources = resources.filter(r => !activeTag || (r.tags ?? []).includes(activeTag)) const labels: Record = { downloads: 'Downloads', books: 'Reading List', recommended: 'Recommended' } return (
{available.length > 1 && (
{available.map(k => ( ))}
)}
{tab === 'downloads' && ( <> {featured.length > 0 && (
{featured.map(f => ( {f.image && {f.alt}}
Featured {f.title} {f.description &&

{f.description}

} Download free guide โ†’
))}
)} {tags.length > 0 && (
{tags.map(t => ( ))}
)} {shownResources.length > 0 ? (
{shownResources.map(r => ( {r.imageUrl && {r.label}}
{r.label} {r.description &&

{r.description}

} {(r.tags ?? []).length > 0 && {(r.tags ?? []).join(' ยท ')}} Open download โ†’
))}
) : ( resources.length > 0 &&

No downloads tagged "{activeTag}".

)} )} {tab === 'books' && (
{books.map(book => (
{book.imageUrl && {book.label}}
{book.label} {book.description && }
{(book.amazonUrl || book.url) && ( {book.amazonUrl ? (book.amazonLabel || 'View on Amazon') : (book.amazonLabel || 'Learn More')} )} {book.appleBooksUrl && ( {book.appleBooksLabel || 'Apple Books'} )}
))}
)} {tab === 'recommended' && ( )}
) }