Add complete edit functionality for sermons with update API endpoint and enhanced Bible reference management
This commit is contained in:
114
pages/admin.vue
114
pages/admin.vue
@@ -20,13 +20,13 @@
|
|||||||
<main class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
<main class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||||
<!-- Manage Existing Sermons Section -->
|
<!-- Manage Existing Sermons Section -->
|
||||||
<div class="bg-white shadow-lg rounded-lg p-8 mb-8">
|
<div class="bg-white shadow-lg rounded-lg p-8 mb-8">
|
||||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Manage Existing Sermons</h2>
|
<h2 class="text-2xl font-bold text-gray-900 mb-6">Select Sermon to Manage</h2>
|
||||||
|
|
||||||
<div v-if="allSermons && allSermons.length > 0" class="space-y-4">
|
<div v-if="allSermons && allSermons.length > 0" class="space-y-4">
|
||||||
<div class="flex gap-4 items-end">
|
<div class="flex gap-4 items-end">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<label for="sermon-select" class="block text-sm font-medium text-gray-700 mb-2">
|
<label for="sermon-select" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Select Sermon to Delete
|
Choose a Sermon
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="sermon-select"
|
id="sermon-select"
|
||||||
@@ -39,13 +39,21 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="handleEdit"
|
||||||
|
:disabled="!selectedSermonId"
|
||||||
|
class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed font-medium"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="handleDelete"
|
@click="handleDelete"
|
||||||
:disabled="!selectedSermonId || deleting"
|
:disabled="!selectedSermonId || deleting"
|
||||||
class="px-6 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 disabled:opacity-50 disabled:cursor-not-allowed font-medium"
|
class="px-6 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 disabled:opacity-50 disabled:cursor-not-allowed font-medium"
|
||||||
>
|
>
|
||||||
{{ deleting ? 'Deleting...' : 'Delete Sermon' }}
|
{{ deleting ? 'Deleting...' : 'Delete' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -62,9 +70,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Create New Sermon Form -->
|
<!-- Create/Edit Sermon Form -->
|
||||||
<form @submit.prevent="handleSubmit" class="bg-white shadow-lg rounded-lg p-8 space-y-8">
|
<form @submit.prevent="handleSubmit" class="bg-white shadow-lg rounded-lg p-8 space-y-8">
|
||||||
<h2 class="text-2xl font-bold text-gray-900">Create New Sermon</h2>
|
<div class="flex items-center justify-between">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900">
|
||||||
|
{{ editingSermonId ? 'Edit Sermon' : 'Create New Sermon' }}
|
||||||
|
</h2>
|
||||||
|
<button
|
||||||
|
v-if="editingSermonId"
|
||||||
|
type="button"
|
||||||
|
@click="cancelEdit"
|
||||||
|
class="text-sm text-gray-600 hover:text-gray-800"
|
||||||
|
>
|
||||||
|
Cancel Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
@@ -202,7 +222,7 @@
|
|||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
class="flex-1 py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
|
class="flex-1 py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{{ loading ? 'Creating...' : 'Create Sermon' }}
|
{{ loading ? (editingSermonId ? 'Updating...' : 'Creating...') : (editingSermonId ? 'Update Sermon' : 'Create Sermon') }}
|
||||||
</button>
|
</button>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/"
|
to="/"
|
||||||
@@ -231,6 +251,7 @@ const deleteSuccess = ref('')
|
|||||||
const deleting = ref(false)
|
const deleting = ref(false)
|
||||||
|
|
||||||
// Create sermon form state
|
// Create sermon form state
|
||||||
|
const editingSermonId = ref<number | null>(null)
|
||||||
const bibleReferences = ref([{ version: 'ESV', reference: '', text: '' }])
|
const bibleReferences = ref([{ version: 'ESV', reference: '', text: '' }])
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
date: '',
|
date: '',
|
||||||
@@ -269,21 +290,33 @@ async function handleSubmit() {
|
|||||||
)
|
)
|
||||||
const bible_references = JSON.stringify(validReferences)
|
const bible_references = JSON.stringify(validReferences)
|
||||||
|
|
||||||
await $fetch('/api/sermons', {
|
const body = {
|
||||||
method: 'POST',
|
slug,
|
||||||
body: {
|
title: formData.value.title,
|
||||||
slug,
|
date: formData.value.date,
|
||||||
title: formData.value.title,
|
bible_references,
|
||||||
date: formData.value.date,
|
personal_appliance: formData.value.personal_appliance,
|
||||||
bible_references,
|
pastors_challenge: formData.value.pastors_challenge
|
||||||
personal_appliance: formData.value.personal_appliance,
|
}
|
||||||
pastors_challenge: formData.value.pastors_challenge
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
success.value = 'Sermon created successfully!'
|
if (editingSermonId.value) {
|
||||||
|
// Update existing sermon
|
||||||
|
await $fetch(`/api/sermons/update/${editingSermonId.value}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body
|
||||||
|
})
|
||||||
|
success.value = 'Sermon updated successfully!'
|
||||||
|
} else {
|
||||||
|
// Create new sermon
|
||||||
|
await $fetch('/api/sermons', {
|
||||||
|
method: 'POST',
|
||||||
|
body
|
||||||
|
})
|
||||||
|
success.value = 'Sermon created successfully!'
|
||||||
|
}
|
||||||
|
|
||||||
// Reset form
|
// Reset form
|
||||||
|
editingSermonId.value = null
|
||||||
formData.value = {
|
formData.value = {
|
||||||
date: '',
|
date: '',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -291,18 +324,61 @@ async function handleSubmit() {
|
|||||||
pastors_challenge: ''
|
pastors_challenge: ''
|
||||||
}
|
}
|
||||||
bibleReferences.value = [{ version: 'ESV', reference: '', text: '' }]
|
bibleReferences.value = [{ version: 'ESV', reference: '', text: '' }]
|
||||||
|
|
||||||
|
// Refresh sermon list
|
||||||
|
await refreshSermons()
|
||||||
|
|
||||||
// Redirect after 2 seconds
|
// Redirect after 2 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigateTo('/')
|
navigateTo('/')
|
||||||
}, 2000)
|
}, 2000)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
error.value = e.data?.message || 'Failed to create sermon'
|
error.value = e.data?.message || `Failed to ${editingSermonId.value ? 'update' : 'create'} sermon`
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cancelEdit() {
|
||||||
|
editingSermonId.value = null
|
||||||
|
formData.value = {
|
||||||
|
date: '',
|
||||||
|
title: '',
|
||||||
|
personal_appliance: '',
|
||||||
|
pastors_challenge: ''
|
||||||
|
}
|
||||||
|
bibleReferences.value = [{ version: 'ESV', reference: '', text: '' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEdit() {
|
||||||
|
if (!selectedSermonId.value) return
|
||||||
|
|
||||||
|
const sermon = allSermons.value?.find((s: any) => s.id === parseInt(selectedSermonId.value))
|
||||||
|
if (!sermon) return
|
||||||
|
|
||||||
|
// Set editing mode
|
||||||
|
editingSermonId.value = sermon.id
|
||||||
|
|
||||||
|
// Load sermon data into form
|
||||||
|
formData.value = {
|
||||||
|
date: sermon.date,
|
||||||
|
title: sermon.title,
|
||||||
|
personal_appliance: sermon.personal_appliance,
|
||||||
|
pastors_challenge: sermon.pastors_challenge
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and load Bible references
|
||||||
|
try {
|
||||||
|
bibleReferences.value = JSON.parse(sermon.bible_references)
|
||||||
|
} catch {
|
||||||
|
// Fallback for old format
|
||||||
|
bibleReferences.value = [{ version: 'ESV', reference: sermon.bible_references, text: '' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll to form
|
||||||
|
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' })
|
||||||
|
}
|
||||||
|
|
||||||
async function handleDelete() {
|
async function handleDelete() {
|
||||||
if (!selectedSermonId.value) return
|
if (!selectedSermonId.value) return
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
to="/admin"
|
to="/admin"
|
||||||
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 font-medium text-sm"
|
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 font-medium text-sm"
|
||||||
>
|
>
|
||||||
Create New Sermon
|
Manage Sermons
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<button
|
<button
|
||||||
@click="handleLogout"
|
@click="handleLogout"
|
||||||
|
|||||||
58
server/api/sermons/update/[id].put.ts
Normal file
58
server/api/sermons/update/[id].put.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { isAuthenticated } from '~/server/utils/auth'
|
||||||
|
import { getDatabase } from '~/server/utils/database'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
// Check authentication
|
||||||
|
if (!isAuthenticated(event)) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 401,
|
||||||
|
message: 'Unauthorized'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = getRouterParam(event, 'id')
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
message: 'Sermon ID is required'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await readBody(event)
|
||||||
|
const { slug, title, date, bible_references, personal_appliance, pastors_challenge } = body
|
||||||
|
|
||||||
|
if (!slug || !title || !date || !bible_references || !personal_appliance || !pastors_challenge) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
message: 'All fields are required'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const db = getDatabase()
|
||||||
|
const result = db.prepare(`
|
||||||
|
UPDATE sermons
|
||||||
|
SET slug = ?, title = ?, date = ?, bible_references = ?,
|
||||||
|
personal_appliance = ?, pastors_challenge = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`).run(slug, title, date, bible_references, personal_appliance, pastors_challenge, parseInt(id))
|
||||||
|
|
||||||
|
if (result.changes === 0) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 404,
|
||||||
|
message: 'Sermon not found'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'Sermon updated successfully'
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 500,
|
||||||
|
message: error.message || 'Failed to update sermon'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user