diff --git a/data/study-reminders.json b/data/study-reminders.json index 419e498..6974f84 100644 --- a/data/study-reminders.json +++ b/data/study-reminders.json @@ -1,4 +1,4 @@ { "users": {}, - "updatedAt": "2026-06-03T20:07:22.259Z" + "updatedAt": "2026-06-04T13:16:50.352Z" } \ No newline at end of file diff --git a/server/email.js b/server/email.js index d980b00..72b9300 100644 --- a/server/email.js +++ b/server/email.js @@ -142,7 +142,7 @@ export function buildContactWelcomeEmailTemplate({ welcomeScripture, welcomeScriptureRef, welcomeSignoff, - welcomeHeading, + welcomeGreetingPrefix = "Glad you're here", welcomeSpotifyUrl, welcomeAppleUrl, welcomeAmazonUrl, @@ -153,89 +153,159 @@ export function buildContactWelcomeEmailTemplate({ welcomeAppleBtnLabel = 'Apple Podcasts', welcomeStartHereLinkLabel = 'Open Start Here page', }) { - const welcomeSignoffHtml = escapeHtml(welcomeSignoff).replace(/\n/g, '
') + const heading = greetingName + ? `${escapeHtml(welcomeGreetingPrefix)}, ${escapeHtml(greetingName)}.` + : `${escapeHtml(welcomeGreetingPrefix)}.` return { text: `Welcome to Verse by Verse with Nate!\n\n` + - `${greetingName ? `Glad you're here, ${greetingName}.` : "Glad you're here."}\n\n` + + `${heading}\n\n` + `${welcomeIntro}\n\n` + `${welcomeCurrentSeries}\n\n` + `Start here: ${welcomeEpisodeUrl}\n` + `${welcomeStartHereTitle}\n` + `${welcomeStartHereSummary}\n` + - `Spotify: ${welcomeSpotifyUrl}\n` + - `Apple Podcasts: ${welcomeAppleUrl}\n` + + `${welcomeSpotifyBtnLabel}: ${welcomeSpotifyUrl}\n` + + `${welcomeAppleBtnLabel}: ${welcomeAppleUrl}\n` + `Amazon Music: ${welcomeAmazonUrl}\n` + `Website: ${welcomeWebsiteUrl}\n\n` + `What to expect:\n` + `- ${welcomeExpect1}\n` + `- ${welcomeExpect2}\n` + `- ${welcomeExpect3}\n\n` + - `${welcomeScripture}\n${welcomeScriptureRef}\n\n` + + `"${welcomeScripture}"\n${welcomeScriptureRef}\n\n` + `${welcomeSignoff}`, - html: - `
` + - `` + - `
` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `
` + - `Verse by Verse with Nate` + - `

Verse by Verse with Nate

` + - `

Verse by verse. Nugget by nugget.

` + - `
` + - `

Welcome

` + - `

${welcomeHeading}

` + - `
` + - `
` + - `

${escapeHtml(welcomeIntro)}

` + - `

${escapeHtml(welcomeCurrentSeries)}

` + - `

If you’re just joining us, the best place to start is Episode 1. It sets the table for everything that follows.

` + - `
` + - `

Start here

` + - `

${escapeHtml(welcomeStartHereTitle)}

` + - `

${escapeHtml(welcomeStartHereSummary)}

` + - `` + - `` + - `` + - `
${escapeHtml(welcomeSpotifyBtnLabel)}${escapeHtml(welcomeAppleBtnLabel)}
` + - `

${escapeHtml(welcomeStartHereLinkLabel)}

` + - `
` + - `

What to expect

` + - `

${escapeHtml(welcomeExpect1)}

` + - `

${escapeHtml(welcomeExpect2)}

` + - `

${escapeHtml(welcomeExpect3)}

` + - `
` + - `
` + - `

“${escapeHtml(welcomeScripture)}”

` + - `

${escapeHtml(welcomeScriptureRef)}

` + - `
` + - `
` + - `

Find the podcast on

` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `
Spotify·Apple Podcasts·Amazon Music·Website
` + - `

You’re receiving this because you subscribed to Verse by Verse with Nate.

` + - `

${welcomeSignoffHtml}

` + - `
` + - `
` + - `
`, + html: ` + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Verse by Verse with Nate +

Verse by Verse with Nate

+

Verse by verse. Nugget by nugget.

+
+

Welcome

+

${heading}

+
+
+

${escapeHtml(welcomeIntro)}

+

${escapeHtml(welcomeCurrentSeries)}

+

If you’re just joining us, the best place to start is Episode 1. It sets the table for everything that follows.

+
+

Start here

+

${escapeHtml(welcomeStartHereTitle)}

+

${escapeHtml(welcomeStartHereSummary)}

+ + + + + + + +
+ ${escapeHtml(welcomeSpotifyBtnLabel)} + + ${escapeHtml(welcomeAppleBtnLabel)} +
+
+

What to expect

+ + + + + +

${escapeHtml(welcomeExpect1)}

+ + + + + +

${escapeHtml(welcomeExpect2)}

+ + + + + +

${escapeHtml(welcomeExpect3)}

+
+ + + + +
+

“${escapeHtml(welcomeScripture)}”

+

${escapeHtml(welcomeScriptureRef)}

+
+
+

Find the podcast on

+ + + + + + + + + + +
Spotify·Apple Podcasts·Amazon Music·Website
+

You’re receiving this because you subscribed to Verse by Verse with Nate.

+

Unsubscribe

+

“Your word is a lamp to my feet and a light to my path.” — Psalm 119:105

+
+
+
+
+ +`, } } diff --git a/server/routes/contact.js b/server/routes/contact.js index b87d7fe..41d7111 100644 --- a/server/routes/contact.js +++ b/server/routes/contact.js @@ -191,12 +191,10 @@ export function register(app) { : DEFAULT_SEO.canonicalUrl const welcomeSubject = process.env.RESEND_WELCOME_SUBJECT ?? emailConfig.welcomeEmailSubject ?? 'Welcome to Verse by Verse with Nate' const welcomeGreetingPrefix = emailConfig.welcomeEmailGreetingPrefix?.trim() || "Glad you're here" - const welcomeHeading = greetingName - ? `${escapeHtml(welcomeGreetingPrefix)}, ${escapeHtml(greetingName)}.` - : `${escapeHtml(welcomeGreetingPrefix)}.` const { buildAbsoluteUrl } = await import('../helpers.js') const welcomeTemplate = buildContactWelcomeEmailTemplate({ greetingName, + welcomeGreetingPrefix, welcomeIntro: emailConfig.welcomeEmailIntro?.trim() || 'Thanks for subscribing to Verse by Verse with Nate - a Bible teaching podcast where we slow down, dig into the text, and pull out the nuggets God has for us word by word.', welcomeCurrentSeries: emailConfig.welcomeEmailCurrentSeries?.trim() || "Right now we're working through the book of Titus - a short letter packed with practical wisdom about grace, godliness, and what the Christian life looks like when it's rooted in sound doctrine.", welcomeStartHereTitle: emailConfig.welcomeEmailStartHereTitle?.trim() || 'Episode 1 - Introduction to Titus', @@ -207,7 +205,6 @@ export function register(app) { welcomeScripture: emailConfig.welcomeEmailScripture?.trim() || 'For the grace of God has appeared, bringing salvation to all people.', welcomeScriptureRef: emailConfig.welcomeEmailScriptureRef?.trim() || 'Titus 2:11 - BSB', welcomeSignoff: emailConfig.welcomeEmailSignoff?.trim() || 'Grace and peace,\nNate', - welcomeHeading, welcomeSpotifyUrl: buildAbsoluteUrl(welcomeBaseUrl, process.env.RESEND_WELCOME_SPOTIFY_URL ?? emailConfig.welcomeEmailSpotifyUrl ?? '/spotify'), welcomeAppleUrl: buildAbsoluteUrl(welcomeBaseUrl, process.env.RESEND_WELCOME_APPLE_URL ?? emailConfig.welcomeEmailAppleUrl ?? '/apple'), welcomeAmazonUrl: buildAbsoluteUrl(welcomeBaseUrl, process.env.RESEND_WELCOME_AMAZON_URL ?? emailConfig.welcomeEmailAmazonUrl ?? '/amazon'), diff --git a/src/App.css b/src/App.css index 4aae5cf..187227f 100644 --- a/src/App.css +++ b/src/App.css @@ -1112,6 +1112,41 @@ } /* ── Home Jump Section ── */ +/* ── Truth For Life Widget ── */ +.section-tfl { + background: #080808; + border-top: 1px solid rgba(201, 168, 76, 0.18); + border-bottom: 1px solid rgba(201, 168, 76, 0.18); + padding: 5rem 0; + text-align: center; +} + +.tfl-attribution { + color: #8a7f5a; + font-size: 0.9rem; + margin: -0.5rem 0 2.5rem; +} + +.tfl-link { + color: #c9a84c; + text-decoration: none; +} + +.tfl-link:hover { + text-decoration: underline; +} + +.tfl-widget-wrap { + max-width: 760px; + margin: 0 auto; + text-align: left; +} + +/* Scope TFL widget styles to avoid bleed */ +.tfl-widget-wrap * { + box-sizing: border-box; +} + .section-share { background: #080808; border-top: 1px solid rgba(201, 168, 76, 0.18); diff --git a/src/App.tsx b/src/App.tsx index 200c41e..f197cf9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1056,6 +1056,57 @@ function HomepageNewsletterSection() { ) } +type TflWidgetType = 'audiodevo' | 'abdevotional' + +function TruthForLifeWidget({ type = 'audiodevo' }: { type?: TflWidgetType }) { + const containerId = `tfl-syndicate-container-${type}` + + useEffect(() => { + // Remove any previous instance of this script to allow re-init on re-mount + const existingScript = document.getElementById('tfl-syn-script-' + type) + if (existingScript) existingScript.remove() + + // Clear the container so the widget can repopulate it + const container = document.getElementById(containerId) + if (container) container.innerHTML = '' + + const script = document.createElement('script') + script.id = 'tfl-syn-script-' + type + script.src = `https://www.truthforlife.org/static/js/responsive/lib/syndicate.js?type=${type}&id=458890` + script.type = 'text/javascript' + // The TFL script looks for #tfl-syndicate-container by ID — temporarily + // rename our container to match, then rename back after the script fires + if (container) container.id = 'tfl-syndicate-container' + document.body.appendChild(script) + + // Restore the namespaced id after a tick so React doesn't lose track + const restore = setTimeout(() => { + const el = document.getElementById('tfl-syndicate-container') + if (el) el.id = containerId + }, 2000) + + return () => { + clearTimeout(restore) + script.remove() + } + }, [type]) + + return ( +
+
+

Daily Devotional

+

+ Truth For Life +

+

+ Teaching from Truth For Life with Alistair Begg +

+
+
+
+ ) +} + function HomepageQACallout() { const [questions, setQuestions] = useState<{ id: string; firstName: string; question: string; answer: string }[]>([]) @@ -1213,6 +1264,8 @@ function LandingPage({ content }: { content: SiteContent }) { + +