diff --git a/app.vue b/app.vue index be9cfa7..e583034 100644 --- a/app.vue +++ b/app.vue @@ -5,10 +5,12 @@ + diff --git a/components/ModalDialog.vue b/components/ModalDialog.vue new file mode 100644 index 0000000..7ffdf36 --- /dev/null +++ b/components/ModalDialog.vue @@ -0,0 +1,165 @@ + + + + + + + + + + + + + {{ successTitle }} + {{ successMessage }} + + + OK + + + + + + + + + + + + + + + + + + {{ errorTitle }} + {{ errorMessage }} + + + OK + + + + + + + + + + + + + + + + + + {{ confirmTitle }} + {{ confirmMessage }} + + + Abbrechen + + + Bestätigen + + + + + + + + diff --git a/pages/cms/benutzer.vue b/pages/cms/benutzer.vue index 1f0c2e2..0e7cf42 100644 --- a/pages/cms/benutzer.vue +++ b/pages/cms/benutzer.vue @@ -225,24 +225,20 @@ const approveUser = async (user) => { } const rejectUser = async (user) => { - if (!confirm(`Möchten Sie die Registrierung von ${user.name} wirklich ablehnen?`)) { - return - } - - try { - await $fetch('/api/cms/users/reject', { - method: 'POST', - body: { userId: user.id } - }) - - successMessage.value = `Registrierung von ${user.name} wurde abgelehnt` - setTimeout(() => successMessage.value = '', 3000) - - await loadUsers() - } catch (error) { - errorMessage.value = 'Fehler beim Ablehnen der Registrierung' - setTimeout(() => errorMessage.value = '', 3000) - } + window.showConfirmModal('Registrierung ablehnen', `Möchten Sie die Registrierung von ${user.name} wirklich ablehnen?`, async () => { + try { + await $fetch('/api/cms/users/reject', { + method: 'POST', + body: { userId: user.id } + }) + + await loadUsers() + window.showSuccessModal('Erfolg', `Registrierung von ${user.name} wurde abgelehnt`) + } catch (error) { + console.error('Fehler beim Ablehnen:', error) + window.showErrorModal('Fehler', 'Fehler beim Ablehnen der Registrierung') + } + }) } const updateUserRole = async (user) => { @@ -265,24 +261,20 @@ const updateUserRole = async (user) => { } const deactivateUser = async (user) => { - if (!confirm(`Möchten Sie ${user.name} wirklich deaktivieren?`)) { - return - } - - try { - await $fetch('/api/cms/users/deactivate', { - method: 'POST', - body: { userId: user.id } - }) - - successMessage.value = `Benutzer ${user.name} wurde deaktiviert` - setTimeout(() => successMessage.value = '', 3000) - - await loadUsers() - } catch (error) { - errorMessage.value = 'Fehler beim Deaktivieren des Benutzers' - setTimeout(() => errorMessage.value = '', 3000) - } + window.showConfirmModal('Benutzer deaktivieren', `Möchten Sie ${user.name} wirklich deaktivieren?`, async () => { + try { + await $fetch('/api/cms/users/deactivate', { + method: 'POST', + body: { userId: user.id } + }) + + await loadUsers() + window.showSuccessModal('Erfolg', `Benutzer ${user.name} wurde deaktiviert`) + } catch (error) { + console.error('Fehler beim Deaktivieren:', error) + window.showErrorModal('Fehler', 'Fehler beim Deaktivieren des Benutzers') + } + }) } onMounted(async () => { diff --git a/pages/cms/mitgliedschaftsantraege.vue b/pages/cms/mitgliedschaftsantraege.vue index a5898e4..ba7176e 100644 --- a/pages/cms/mitgliedschaftsantraege.vue +++ b/pages/cms/mitgliedschaftsantraege.vue @@ -238,7 +238,7 @@ const loadApplications = async () => { applications.value = response } catch (error) { console.error('Fehler beim Laden der Anträge:', error) - alert('Fehler beim Laden der Anträge') + window.showErrorModal('Fehler', 'Fehler beim Laden der Anträge') } finally { loading.value = false } @@ -257,35 +257,35 @@ const closeModal = () => { } const approveApplication = async (id) => { - if (confirm('Antrag genehmigen?')) { + window.showConfirmModal('Bestätigung erforderlich', 'Möchten Sie diesen Antrag wirklich genehmigen?', async () => { try { await $fetch('/api/membership/update-status', { method: 'PUT', body: { id, status: 'approved' } }) await loadApplications() - alert('Antrag wurde genehmigt') + window.showSuccessModal('Erfolg', 'Antrag wurde erfolgreich genehmigt') } catch (error) { console.error('Fehler beim Genehmigen:', error) - alert('Fehler beim Genehmigen des Antrags') + window.showErrorModal('Fehler', 'Fehler beim Genehmigen des Antrags') } - } + }) } const rejectApplication = async (id) => { - if (confirm('Antrag ablehnen?')) { + window.showConfirmModal('Bestätigung erforderlich', 'Möchten Sie diesen Antrag wirklich ablehnen?', async () => { try { await $fetch('/api/membership/update-status', { method: 'PUT', body: { id, status: 'rejected' } }) await loadApplications() - alert('Antrag wurde abgelehnt') + window.showSuccessModal('Erfolg', 'Antrag wurde erfolgreich abgelehnt') } catch (error) { console.error('Fehler beim Ablehnen:', error) - alert('Fehler beim Ablehnen des Antrags') + window.showErrorModal('Fehler', 'Fehler beim Ablehnen des Antrags') } - } + }) } const downloadPDF = async (id) => { @@ -308,9 +308,11 @@ const downloadPDF = async (id) => { a.click() window.URL.revokeObjectURL(url) document.body.removeChild(a) + + window.showSuccessModal('Erfolg', 'PDF wurde erfolgreich heruntergeladen') } catch (error) { console.error('Fehler beim Herunterladen:', error) - alert('Fehler beim Herunterladen des PDFs') + window.showErrorModal('Fehler', 'Fehler beim Herunterladen des PDFs') } } diff --git a/pages/cms/termine.vue b/pages/cms/termine.vue index 157efca..2172d1c 100644 --- a/pages/cms/termine.vue +++ b/pages/cms/termine.vue @@ -238,26 +238,26 @@ const saveTermin = async () => { } const confirmDelete = async (termin) => { - if (!confirm(`Möchten Sie den Termin "${termin.titel}" wirklich löschen?`)) { - return - } + window.showConfirmModal('Termin löschen', `Möchten Sie den Termin "${termin.titel}" wirklich löschen?`, async () => { + try { + const params = new URLSearchParams({ + datum: termin.datum, + titel: termin.titel, + beschreibung: termin.beschreibung || '', + kategorie: termin.kategorie || 'Sonstiges' + }) + + await $fetch(`/api/termine-manage?${params.toString()}`, { + method: 'DELETE' + }) - try { - const params = new URLSearchParams({ - datum: termin.datum, - titel: termin.titel, - beschreibung: termin.beschreibung || '', - kategorie: termin.kategorie || 'Sonstiges' - }) - - await $fetch(`/api/termine-manage?${params.toString()}`, { - method: 'DELETE' - }) - - await loadTermine() - } catch (error) { - alert('Fehler beim Löschen des Termins.') - } + await loadTermine() + window.showSuccessModal('Erfolg', 'Termin wurde erfolgreich gelöscht') + } catch (error) { + console.error('Fehler beim Löschen:', error) + window.showErrorModal('Fehler', 'Fehler beim Löschen des Termins') + } + }) } const formatDate = (dateString) => { diff --git a/pages/mitgliederbereich/mitglieder.vue b/pages/mitgliederbereich/mitglieder.vue index 1e994bf..e6db8b4 100644 --- a/pages/mitgliederbereich/mitglieder.vue +++ b/pages/mitgliederbereich/mitglieder.vue @@ -407,20 +407,20 @@ const saveMember = async () => { } const confirmDelete = async (member) => { - if (!confirm(`Möchten Sie "${member.name}" wirklich löschen?`)) { - return - } + window.showConfirmModal('Mitglied löschen', `Möchten Sie "${member.name}" wirklich löschen?`, async () => { + try { + await $fetch('/api/members', { + method: 'DELETE', + body: { id: member.id } + }) - try { - await $fetch('/api/members', { - method: 'DELETE', - body: { id: member.id } - }) - - await loadMembers() - } catch (error) { - alert('Fehler beim Löschen des Mitglieds.') - } + await loadMembers() + window.showSuccessModal('Erfolg', 'Mitglied wurde erfolgreich gelöscht') + } catch (error) { + console.error('Fehler beim Löschen:', error) + window.showErrorModal('Fehler', 'Fehler beim Löschen des Mitglieds') + } + }) } const formatDate = (dateString) => { diff --git a/pages/mitgliederbereich/news.vue b/pages/mitgliederbereich/news.vue index a70f23b..e5d4be3 100644 --- a/pages/mitgliederbereich/news.vue +++ b/pages/mitgliederbereich/news.vue @@ -264,26 +264,25 @@ const confirmDelete = async (item) => { console.log('Delete item:', item) console.log('Delete item.id:', item.id) - if (!confirm(`Möchten Sie die News "${item.title}" wirklich löschen?`)) { - return - } + window.showConfirmModal('News löschen', `Möchten Sie die News "${item.title}" wirklich löschen?`, async () => { + if (!item.id) { + window.showErrorModal('Fehler', 'News-ID fehlt!') + return + } - if (!item.id) { - alert('Fehler: News-ID fehlt!') - return - } + try { + console.log('Deleting with ID:', item.id) + await $fetch(`/api/news?id=${encodeURIComponent(item.id)}`, { + method: 'DELETE' + }) - try { - console.log('Deleting with ID:', item.id) - await $fetch(`/api/news?id=${encodeURIComponent(item.id)}`, { - method: 'DELETE' - }) - - await loadNews() - } catch (error) { - console.error('Delete error:', error) - alert('Fehler beim Löschen der News: ' + (error.data?.message || error.message)) - } + await loadNews() + window.showSuccessModal('Erfolg', 'News wurde erfolgreich gelöscht') + } catch (error) { + console.error('Delete error:', error) + window.showErrorModal('Fehler', 'Fehler beim Löschen der News: ' + (error.data?.message || error.message)) + } + }) } const formatDate = (dateString) => { diff --git a/pages/mitgliedschaft.vue b/pages/mitgliedschaft.vue index bd511c8..e371fa1 100644 --- a/pages/mitgliedschaft.vue +++ b/pages/mitgliedschaft.vue @@ -482,13 +482,14 @@ onMounted(() => { window.URL.revokeObjectURL(url) document.body.removeChild(a) - alert('Beitrittsformular erfolgreich erstellt und heruntergeladen!') + // Globale Modal-Funktionen verwenden + window.showSuccessModal('Beitrittsformular erfolgreich erstellt!', 'Das Formular wurde heruntergeladen und Ihre Daten wurden an den Vereinsvorstand weitergeleitet.') } else { - alert('Fehler beim Erstellen des Formulars: ' + (result.error || 'Unbekannter Fehler')) + window.showErrorModal('Fehler beim Erstellen des Formulars', result.error || 'Unbekannter Fehler') } } catch (error) { console.error('Fehler:', error) - alert('Fehler beim Senden des Formulars: ' + error.message) + window.showErrorModal('Fehler beim Senden des Formulars', error.message) } finally { submitBtn.disabled = false submitBtn.textContent = 'Beitrittsformular erstellen' diff --git a/server/data/members.json b/server/data/members.json index 075928a..5e84b3d 100644 --- a/server/data/members.json +++ b/server/data/members.json @@ -27,5 +27,16 @@ "source": "membership_application", "applicationId": "1761225361334", "id": "c209cb36-3aca-4ab2-b463-061e41f97d6d" + }, + { + "firstName": "Final", + "lastName": "Test", + "email": "final@test.de", + "phone": "", + "address": "Finalstr 1, 60437 Frankfurt", + "notes": "Mitgliedschaftsart: aktiv | Genehmigt: 23.10.2025", + "source": "membership_application", + "applicationId": "1761225630365", + "id": "952c3d3f-c73a-43ed-ae21-76387948c030" } ] \ No newline at end of file diff --git a/server/data/membership-applications/1761225630365.json b/server/data/membership-applications/1761225630365.json index 8112d51..5f85479 100644 --- a/server/data/membership-applications/1761225630365.json +++ b/server/data/membership-applications/1761225630365.json @@ -1,11 +1,12 @@ { "id": "1761225630365", "timestamp": "2025-10-23T13:20:30.435Z", - "status": "pending", + "status": "approved", "metadata": { "mitgliedschaftsart": "aktiv", "isVolljaehrig": true, "pdfGenerated": true }, - "encryptedData": "7/HlHstjzGZ1wJtrtCxa7B3gfqBxm19LkzNAItSM9rMGDvRoiQNrHIpxdlUSTOTkeYwfW3cvKhrBsXHZxU4P64HdFzVdK255kgN1Yqy2ZqS6oZ6mp8xwHVIUypfbwEZI22gWbxue9Y+29rn9VYSBuKjtZd2pi/8Qjohps4wchzXdP5fiRJxx3vwDHPQ08i+qAcxatIwYLt4Iu46pFSAEQkUhDbdki7OWgzeU4YW8L9UufPMMv01m2rG48GnnM/GglIkz2VchqQsNqsDmm35OUmg6LoETGs6TSgBiLr0LV+ZFO29D9W7WIP+hZDVmhfii8PNcAGvvKpJvpJSbNeswaSF4zV7k3+gxkcGZBy+hG+ta3pXhzzuaGqQUvyg+jx5YkMTVRh0kcQlmNME8/7UW5vrC+Qe/pU5K2t0URwxxHTYnLyTk0FLMrs6nCtaSSoDC+t26j8GarAGGF9AvKDaVxkFq4B9B0uw6mQPhETX8IeAynihKkk/ZMzIXB0LaO+hxW2YEKrKfFMSAVcFrVOjVJtz4k+5ZTRlKnjkunl2P45h+Fjt69OQNffg2F0Fa1Or9nrPOrbake7g+NEtAgohdQd7qddvpSBfJC3vDQv5TG2CONFIoSBHnpR3io7uuiI6Ct/mu/LBLfDa9d0/TjkOWdDVYnb+V+beh/At+oMUGKI8=" + "encryptedData": "7/HlHstjzGZ1wJtrtCxa7B3gfqBxm19LkzNAItSM9rMGDvRoiQNrHIpxdlUSTOTkeYwfW3cvKhrBsXHZxU4P64HdFzVdK255kgN1Yqy2ZqS6oZ6mp8xwHVIUypfbwEZI22gWbxue9Y+29rn9VYSBuKjtZd2pi/8Qjohps4wchzXdP5fiRJxx3vwDHPQ08i+qAcxatIwYLt4Iu46pFSAEQkUhDbdki7OWgzeU4YW8L9UufPMMv01m2rG48GnnM/GglIkz2VchqQsNqsDmm35OUmg6LoETGs6TSgBiLr0LV+ZFO29D9W7WIP+hZDVmhfii8PNcAGvvKpJvpJSbNeswaSF4zV7k3+gxkcGZBy+hG+ta3pXhzzuaGqQUvyg+jx5YkMTVRh0kcQlmNME8/7UW5vrC+Qe/pU5K2t0URwxxHTYnLyTk0FLMrs6nCtaSSoDC+t26j8GarAGGF9AvKDaVxkFq4B9B0uw6mQPhETX8IeAynihKkk/ZMzIXB0LaO+hxW2YEKrKfFMSAVcFrVOjVJtz4k+5ZTRlKnjkunl2P45h+Fjt69OQNffg2F0Fa1Or9nrPOrbake7g+NEtAgohdQd7qddvpSBfJC3vDQv5TG2CONFIoSBHnpR3io7uuiI6Ct/mu/LBLfDa9d0/TjkOWdDVYnb+V+beh/At+oMUGKI8=", + "updatedAt": "2025-10-23T13:23:26.963Z" } \ No newline at end of file diff --git a/server/data/membership-applications/1761225852269.json b/server/data/membership-applications/1761225852269.json new file mode 100644 index 0000000..1b7e2ce --- /dev/null +++ b/server/data/membership-applications/1761225852269.json @@ -0,0 +1,17 @@ +{ + "id": "1761225852269", + "timestamp": "2025-10-23T13:24:12.319Z", + "status": "pending", + "metadata": { + "mitgliedschaftsart": "aktiv", + "isVolljaehrig": true, + "pdfGenerated": true + }, + "personalData": { + "nachname": "A", + "vorname": "B", + "email": "tsschulz@gmx.net", + "telefon_privat": "01795094148", + "telefon_mobil": "0179 5094148" + } +} \ No newline at end of file diff --git a/server/data/membership-applications/1761225990109.json b/server/data/membership-applications/1761225990109.json new file mode 100644 index 0000000..5ea0735 --- /dev/null +++ b/server/data/membership-applications/1761225990109.json @@ -0,0 +1,15 @@ +{ + "id": "1761225990109", + "timestamp": "2025-10-23T13:26:30.166Z", + "status": "pending", + "metadata": { + "mitgliedschaftsart": "aktiv", + "isVolljaehrig": true, + "pdfGenerated": true + }, + "personalData": { + "nachname": "Test", + "vorname": "Modal", + "email": "modal@test.de" + } +} \ No newline at end of file diff --git a/server/data/membership-applications/1761226071296.json b/server/data/membership-applications/1761226071296.json new file mode 100644 index 0000000..e960abb --- /dev/null +++ b/server/data/membership-applications/1761226071296.json @@ -0,0 +1,15 @@ +{ + "id": "1761226071296", + "timestamp": "2025-10-23T13:27:51.339Z", + "status": "pending", + "metadata": { + "mitgliedschaftsart": "aktiv", + "isVolljaehrig": true, + "pdfGenerated": true + }, + "personalData": { + "nachname": "Modal", + "vorname": "Global", + "email": "global@modal.de" + } +} \ No newline at end of file
{{ successMessage }}
{{ errorMessage }}
{{ confirmMessage }}