Songs & dates
This commit is contained in:
@@ -78,6 +78,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Worship Songs Section -->
|
||||||
|
<section v-if="worshipSongs.length > 0" class="mb-8">
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Worship Songs</h2>
|
||||||
|
<div class="bg-yellow-50 rounded-lg p-6">
|
||||||
|
<ul class="space-y-3">
|
||||||
|
<li
|
||||||
|
v-for="(song, index) in worshipSongs"
|
||||||
|
:key="index"
|
||||||
|
:class="['text-gray-800', fontSizeClasses]"
|
||||||
|
>
|
||||||
|
<span class="font-semibold">{{ song.name }}</span>
|
||||||
|
<span v-if="song.artist" class="text-gray-600"> - {{ song.artist }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Back Button -->
|
<!-- Back Button -->
|
||||||
<div class="border-t pt-6">
|
<div class="border-t pt-6">
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
@@ -132,6 +149,15 @@ const bibleReferences = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const worshipSongs = computed(() => {
|
||||||
|
if (!sermon.value?.worship_songs) return []
|
||||||
|
try {
|
||||||
|
return JSON.parse(sermon.value.worship_songs)
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Font size classes
|
// Font size classes
|
||||||
const fontSizeClasses = computed(() => {
|
const fontSizeClasses = computed(() => {
|
||||||
switch (fontSize.value) {
|
switch (fontSize.value) {
|
||||||
|
|||||||
130
pages/admin.vue
130
pages/admin.vue
@@ -111,7 +111,7 @@
|
|||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="date" class="block text-sm font-medium text-gray-700 mb-2">
|
<label for="date" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Sermon Date
|
Primary Sermon Date
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="date"
|
id="date"
|
||||||
@@ -120,6 +120,37 @@
|
|||||||
required
|
required
|
||||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
|
||||||
/>
|
/>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">This date will be used for the sermon URL and sorting</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Additional Dates Section -->
|
||||||
|
<div class="border-t pt-6">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-2">Additional Dates</h3>
|
||||||
|
<p class="text-sm text-gray-600 mb-4">Add more dates if this sermon will be presented multiple times (e.g., Saturday and Sunday services)</p>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div v-for="(date, index) in sermonDates" :key="index" class="flex gap-3">
|
||||||
|
<input
|
||||||
|
v-model="sermonDates[index]"
|
||||||
|
type="date"
|
||||||
|
class="flex-1 px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
v-if="sermonDates.length > 1"
|
||||||
|
type="button"
|
||||||
|
@click="removeDate(index)"
|
||||||
|
class="px-3 py-2 bg-red-100 text-red-700 rounded-md hover:bg-red-200"
|
||||||
|
>
|
||||||
|
−
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="addDate"
|
||||||
|
class="px-4 py-2 bg-blue-100 text-blue-700 rounded-md hover:bg-blue-200 font-medium"
|
||||||
|
>
|
||||||
|
+ Add Date
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -231,6 +262,57 @@
|
|||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Worship Songs Section -->
|
||||||
|
<div class="border-t pt-6">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4">Worship Songs</h2>
|
||||||
|
<p class="text-sm text-gray-600 mb-4">Add songs that were sung during this service (optional)</p>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div v-for="(song, index) in worshipSongs" :key="index" class="border border-gray-200 rounded-lg p-4 space-y-3">
|
||||||
|
<div class="flex flex-col md:flex-row gap-3">
|
||||||
|
<div class="flex-1">
|
||||||
|
<label :for="`song-name-${index}`" class="block text-sm font-medium text-gray-700 mb-1">
|
||||||
|
Song Name
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
:id="`song-name-${index}`"
|
||||||
|
v-model="song.name"
|
||||||
|
type="text"
|
||||||
|
placeholder="e.g., Amazing Grace"
|
||||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<label :for="`song-artist-${index}`" class="block text-sm font-medium text-gray-700 mb-1">
|
||||||
|
Artist/Composer
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
:id="`song-artist-${index}`"
|
||||||
|
v-model="song.artist"
|
||||||
|
type="text"
|
||||||
|
placeholder="e.g., John Newton"
|
||||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
v-if="worshipSongs.length > 1"
|
||||||
|
type="button"
|
||||||
|
@click="removeSong(index)"
|
||||||
|
class="self-end px-3 py-2 bg-red-100 text-red-700 rounded-md hover:bg-red-200"
|
||||||
|
>
|
||||||
|
−
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="addSong"
|
||||||
|
class="px-4 py-2 bg-blue-100 text-blue-700 rounded-md hover:bg-blue-200 font-medium"
|
||||||
|
>
|
||||||
|
+ Add Song
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Error/Success Messages -->
|
<!-- Error/Success Messages -->
|
||||||
<div v-if="error" class="text-red-600 text-sm">
|
<div v-if="error" class="text-red-600 text-sm">
|
||||||
{{ error }}
|
{{ error }}
|
||||||
@@ -280,6 +362,8 @@ const archiveSuccess = ref('')
|
|||||||
// Create sermon form state
|
// Create sermon form state
|
||||||
const editingSermonId = ref<number | null>(null)
|
const editingSermonId = ref<number | null>(null)
|
||||||
const bibleReferences = ref([{ version: 'ESV', reference: '', text: '' }])
|
const bibleReferences = ref([{ version: 'ESV', reference: '', text: '' }])
|
||||||
|
const sermonDates = ref([''])
|
||||||
|
const worshipSongs = ref([{ name: '', artist: '' }])
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
date: '',
|
date: '',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -305,6 +389,22 @@ function removeReference(index: number) {
|
|||||||
bibleReferences.value.splice(index, 1)
|
bibleReferences.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addDate() {
|
||||||
|
sermonDates.value.push('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDate(index: number) {
|
||||||
|
sermonDates.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSong() {
|
||||||
|
worshipSongs.value.push({ name: '', artist: '' })
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSong(index: number) {
|
||||||
|
worshipSongs.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
function formatDateToSlug(date: string) {
|
function formatDateToSlug(date: string) {
|
||||||
// Convert YYYY-MM-DD to MMDDYYYY
|
// Convert YYYY-MM-DD to MMDDYYYY
|
||||||
const [year, month, day] = date.split('-')
|
const [year, month, day] = date.split('-')
|
||||||
@@ -324,13 +424,23 @@ async function handleSubmit() {
|
|||||||
)
|
)
|
||||||
const bible_references = JSON.stringify(validReferences)
|
const bible_references = JSON.stringify(validReferences)
|
||||||
|
|
||||||
|
// Filter valid dates and serialize as JSON
|
||||||
|
const validDates = sermonDates.value.filter(d => d)
|
||||||
|
const dates = validDates.length > 0 ? JSON.stringify(validDates) : null
|
||||||
|
|
||||||
|
// Filter valid songs and serialize as JSON
|
||||||
|
const validSongs = worshipSongs.value.filter(s => s.name)
|
||||||
|
const worship_songs = validSongs.length > 0 ? JSON.stringify(validSongs) : null
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
slug,
|
slug,
|
||||||
title: formData.value.title,
|
title: formData.value.title,
|
||||||
date: formData.value.date,
|
date: formData.value.date,
|
||||||
bible_references,
|
bible_references,
|
||||||
personal_appliance: formData.value.personal_appliance,
|
personal_appliance: formData.value.personal_appliance,
|
||||||
pastors_challenge: formData.value.pastors_challenge
|
pastors_challenge: formData.value.pastors_challenge,
|
||||||
|
dates,
|
||||||
|
worship_songs
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editingSermonId.value) {
|
if (editingSermonId.value) {
|
||||||
@@ -382,6 +492,8 @@ function cancelEdit() {
|
|||||||
pastors_challenge: ''
|
pastors_challenge: ''
|
||||||
}
|
}
|
||||||
bibleReferences.value = [{ version: 'ESV', reference: '', text: '' }]
|
bibleReferences.value = [{ version: 'ESV', reference: '', text: '' }]
|
||||||
|
sermonDates.value = ['']
|
||||||
|
worshipSongs.value = [{ name: '', artist: '' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEdit() {
|
function handleEdit() {
|
||||||
@@ -408,6 +520,20 @@ function handleEdit() {
|
|||||||
// Fallback for old format
|
// Fallback for old format
|
||||||
bibleReferences.value = [{ version: 'ESV', reference: sermon.bible_references, text: '' }]
|
bibleReferences.value = [{ version: 'ESV', reference: sermon.bible_references, text: '' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse and load additional dates
|
||||||
|
try {
|
||||||
|
sermonDates.value = sermon.dates ? JSON.parse(sermon.dates) : ['']
|
||||||
|
} catch {
|
||||||
|
sermonDates.value = ['']
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and load worship songs
|
||||||
|
try {
|
||||||
|
worshipSongs.value = sermon.worship_songs ? JSON.parse(sermon.worship_songs) : [{ name: '', artist: '' }]
|
||||||
|
} catch {
|
||||||
|
worshipSongs.value = [{ name: '', artist: '' }]
|
||||||
|
}
|
||||||
|
|
||||||
// Scroll to form (just below the management section)
|
// Scroll to form (just below the management section)
|
||||||
const formElement = document.querySelector('form')
|
const formElement = document.querySelector('form')
|
||||||
|
|||||||
@@ -123,9 +123,26 @@ const todaysSermon = computed(() => {
|
|||||||
today.setHours(0, 0, 0, 0)
|
today.setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
return activeSermons.value.find((s: any) => {
|
return activeSermons.value.find((s: any) => {
|
||||||
|
// Check primary date
|
||||||
const sermonDate = new Date(s.date + 'T00:00:00')
|
const sermonDate = new Date(s.date + 'T00:00:00')
|
||||||
sermonDate.setHours(0, 0, 0, 0)
|
sermonDate.setHours(0, 0, 0, 0)
|
||||||
return sermonDate.getTime() === today.getTime()
|
if (sermonDate.getTime() === today.getTime()) return true
|
||||||
|
|
||||||
|
// Check additional dates if they exist
|
||||||
|
if (s.dates) {
|
||||||
|
try {
|
||||||
|
const additionalDates = JSON.parse(s.dates)
|
||||||
|
return additionalDates.some((dateStr: string) => {
|
||||||
|
const additionalDate = new Date(dateStr + 'T00:00:00')
|
||||||
|
additionalDate.setHours(0, 0, 0, 0)
|
||||||
|
return additionalDate.getTime() === today.getTime()
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}) || null
|
}) || null
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -137,9 +154,26 @@ const upcomingSermons = computed(() => {
|
|||||||
today.setHours(0, 0, 0, 0)
|
today.setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
return activeSermons.value.filter((s: any) => {
|
return activeSermons.value.filter((s: any) => {
|
||||||
|
// Check primary date
|
||||||
const sermonDate = new Date(s.date + 'T00:00:00')
|
const sermonDate = new Date(s.date + 'T00:00:00')
|
||||||
sermonDate.setHours(0, 0, 0, 0)
|
sermonDate.setHours(0, 0, 0, 0)
|
||||||
return sermonDate.getTime() > today.getTime()
|
if (sermonDate.getTime() > today.getTime()) return true
|
||||||
|
|
||||||
|
// Check additional dates if they exist
|
||||||
|
if (s.dates) {
|
||||||
|
try {
|
||||||
|
const additionalDates = JSON.parse(s.dates)
|
||||||
|
return additionalDates.some((dateStr: string) => {
|
||||||
|
const additionalDate = new Date(dateStr + 'T00:00:00')
|
||||||
|
additionalDate.setHours(0, 0, 0, 0)
|
||||||
|
return additionalDate.getTime() > today.getTime()
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const body = await readBody(event)
|
const body = await readBody(event)
|
||||||
const { slug, title, date, bible_references, personal_appliance, pastors_challenge } = body
|
const { slug, title, date, dates, bible_references, personal_appliance, pastors_challenge, worship_songs } = body
|
||||||
|
|
||||||
if (!slug || !title || !date || !bible_references || !personal_appliance || !pastors_challenge) {
|
if (!slug || !title || !date || !bible_references || !personal_appliance || !pastors_challenge) {
|
||||||
throw createError({
|
throw createError({
|
||||||
@@ -25,9 +25,11 @@ export default defineEventHandler(async (event) => {
|
|||||||
slug,
|
slug,
|
||||||
title,
|
title,
|
||||||
date,
|
date,
|
||||||
|
dates,
|
||||||
bible_references,
|
bible_references,
|
||||||
personal_appliance,
|
personal_appliance,
|
||||||
pastors_challenge
|
pastors_challenge,
|
||||||
|
worship_songs
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const body = await readBody(event)
|
const body = await readBody(event)
|
||||||
const { slug, title, date, bible_references, personal_appliance, pastors_challenge } = body
|
const { slug, title, date, dates, bible_references, personal_appliance, pastors_challenge, worship_songs } = body
|
||||||
|
|
||||||
if (!slug || !title || !date || !bible_references || !personal_appliance || !pastors_challenge) {
|
if (!slug || !title || !date || !bible_references || !personal_appliance || !pastors_challenge) {
|
||||||
throw createError({
|
throw createError({
|
||||||
@@ -33,10 +33,10 @@ export default defineEventHandler(async (event) => {
|
|||||||
const db = getDatabase()
|
const db = getDatabase()
|
||||||
const result = db.prepare(`
|
const result = db.prepare(`
|
||||||
UPDATE sermons
|
UPDATE sermons
|
||||||
SET slug = ?, title = ?, date = ?, bible_references = ?,
|
SET slug = ?, title = ?, date = ?, dates = ?, bible_references = ?,
|
||||||
personal_appliance = ?, pastors_challenge = ?
|
personal_appliance = ?, pastors_challenge = ?, worship_songs = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`).run(slug, title, date, bible_references, personal_appliance, pastors_challenge, parseInt(id))
|
`).run(slug, title, date, dates || null, bible_references, personal_appliance, pastors_challenge, worship_songs || null, parseInt(id))
|
||||||
|
|
||||||
if (result.changes === 0) {
|
if (result.changes === 0) {
|
||||||
throw createError({
|
throw createError({
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ export interface Sermon {
|
|||||||
slug: string
|
slug: string
|
||||||
title: string
|
title: string
|
||||||
date: string
|
date: string
|
||||||
|
dates?: string
|
||||||
bible_references: string
|
bible_references: string
|
||||||
personal_appliance: string
|
personal_appliance: string
|
||||||
pastors_challenge: string
|
pastors_challenge: string
|
||||||
|
worship_songs?: string
|
||||||
created_at?: string
|
created_at?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,9 +34,11 @@ export function getDatabase() {
|
|||||||
slug TEXT UNIQUE NOT NULL,
|
slug TEXT UNIQUE NOT NULL,
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
date TEXT NOT NULL,
|
date TEXT NOT NULL,
|
||||||
|
dates TEXT,
|
||||||
bible_references TEXT NOT NULL,
|
bible_references TEXT NOT NULL,
|
||||||
personal_appliance TEXT NOT NULL,
|
personal_appliance TEXT NOT NULL,
|
||||||
pastors_challenge TEXT NOT NULL,
|
pastors_challenge TEXT NOT NULL,
|
||||||
|
worship_songs TEXT,
|
||||||
archived INTEGER DEFAULT 0,
|
archived INTEGER DEFAULT 0,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
@@ -87,16 +91,18 @@ export function getSermonBySlug(slug: string) {
|
|||||||
export function createSermon(sermon: Sermon) {
|
export function createSermon(sermon: Sermon) {
|
||||||
const db = getDatabase()
|
const db = getDatabase()
|
||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
INSERT INTO sermons (slug, title, date, bible_references, personal_appliance, pastors_challenge)
|
INSERT INTO sermons (slug, title, date, dates, bible_references, personal_appliance, pastors_challenge, worship_songs)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`)
|
`)
|
||||||
return stmt.run(
|
return stmt.run(
|
||||||
sermon.slug,
|
sermon.slug,
|
||||||
sermon.title,
|
sermon.title,
|
||||||
sermon.date,
|
sermon.date,
|
||||||
|
sermon.dates || null,
|
||||||
sermon.bible_references,
|
sermon.bible_references,
|
||||||
sermon.personal_appliance,
|
sermon.personal_appliance,
|
||||||
sermon.pastors_challenge
|
sermon.pastors_challenge,
|
||||||
|
sermon.worship_songs || null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user