Implement status toggle functionality for contact requests, updating the status display and adding error handling. Enhance the UI with a new button for marking requests as completed or reopening them.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 56s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 56s
This commit is contained in:
@@ -58,7 +58,7 @@
|
|||||||
class="px-2.5 py-1 rounded-full text-xs font-semibold"
|
class="px-2.5 py-1 rounded-full text-xs font-semibold"
|
||||||
:class="request.status === 'beantwortet' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'"
|
:class="request.status === 'beantwortet' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'"
|
||||||
>
|
>
|
||||||
{{ request.status === 'beantwortet' ? 'Beantwortet' : 'Offen' }}
|
{{ request.status === 'beantwortet' ? 'Erledigt' : 'Offen' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -87,7 +87,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 flex justify-end">
|
<div class="mt-4 flex justify-end gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50"
|
||||||
|
:disabled="togglingId === request.id"
|
||||||
|
@click="toggleStatus(request)"
|
||||||
|
>
|
||||||
|
{{ togglingId === request.id ? '…' : (request.status === 'beantwortet' ? 'Wieder öffnen' : 'Als erledigt markieren') }}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700"
|
||||||
@click="openReplyModal(request)"
|
@click="openReplyModal(request)"
|
||||||
@@ -154,6 +162,7 @@ const replyText = ref('')
|
|||||||
const isSendingReply = ref(false)
|
const isSendingReply = ref(false)
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
const showAnswered = ref(false)
|
const showAnswered = ref(false)
|
||||||
|
const togglingId = ref(null)
|
||||||
|
|
||||||
const filteredRequests = computed(() => {
|
const filteredRequests = computed(() => {
|
||||||
if (showAnswered.value) return requests.value
|
if (showAnswered.value) return requests.value
|
||||||
@@ -191,6 +200,23 @@ const closeReplyModal = () => {
|
|||||||
errorMessage.value = ''
|
errorMessage.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleStatus = async (request) => {
|
||||||
|
togglingId.value = request.id
|
||||||
|
try {
|
||||||
|
await $fetch(`/api/cms/contact-requests/${request.id}/toggle-status`, {
|
||||||
|
method: 'PATCH'
|
||||||
|
})
|
||||||
|
await loadRequests()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Umschalten des Status:', error)
|
||||||
|
if (window.showErrorModal) {
|
||||||
|
window.showErrorModal('Fehler', error?.data?.statusMessage || 'Status konnte nicht geändert werden.')
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
togglingId.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const sendReply = async () => {
|
const sendReply = async () => {
|
||||||
if (!selectedRequest.value) return
|
if (!selectedRequest.value) return
|
||||||
const text = replyText.value.trim()
|
const text = replyText.value.trim()
|
||||||
|
|||||||
33
server/api/cms/contact-requests/[id]/toggle-status.patch.js
Normal file
33
server/api/cms/contact-requests/[id]/toggle-status.patch.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { getUserFromToken, hasAnyRole } from '../../../../utils/auth.js'
|
||||||
|
import { readContactRequests, updateContactRequestStatus } from '../../../../utils/contact-requests.js'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const token = getCookie(event, 'auth_token')
|
||||||
|
const currentUser = token ? await getUserFromToken(token) : null
|
||||||
|
|
||||||
|
if (!currentUser || !hasAnyRole(currentUser, 'admin', 'vorstand', 'trainer')) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 403,
|
||||||
|
statusMessage: 'Zugriff verweigert'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestId = getRouterParam(event, 'id')
|
||||||
|
if (!requestId) {
|
||||||
|
throw createError({ statusCode: 400, statusMessage: 'Anfrage-ID fehlt' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const all = await readContactRequests()
|
||||||
|
const target = all.find((r) => r.id === requestId)
|
||||||
|
if (!target) {
|
||||||
|
throw createError({ statusCode: 404, statusMessage: 'Anfrage nicht gefunden' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const newStatus = target.status === 'beantwortet' ? 'offen' : 'beantwortet'
|
||||||
|
const updated = await updateContactRequestStatus(requestId, newStatus)
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
request: updated
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -77,3 +77,22 @@ export async function addContactReply({ requestId, replyText, responderEmail })
|
|||||||
await writeContactRequests(current)
|
await writeContactRequests(current)
|
||||||
return current[index]
|
return current[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function updateContactRequestStatus(requestId, newStatus) {
|
||||||
|
const validStatuses = ['offen', 'beantwortet']
|
||||||
|
if (!validStatuses.includes(newStatus)) return null
|
||||||
|
|
||||||
|
const current = await readContactRequests()
|
||||||
|
const index = current.findIndex((r) => r.id === requestId)
|
||||||
|
if (index === -1) return null
|
||||||
|
|
||||||
|
const now = new Date().toISOString()
|
||||||
|
current[index] = {
|
||||||
|
...current[index],
|
||||||
|
status: newStatus,
|
||||||
|
updatedAt: now
|
||||||
|
}
|
||||||
|
|
||||||
|
await writeContactRequests(current)
|
||||||
|
return current[index]
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user