E-Mail generierung
This commit is contained in:
Binary file not shown.
@@ -20,7 +20,7 @@
|
||||
wunsch3?: { id: number; name: string };
|
||||
timestamp: number;
|
||||
id: number;
|
||||
status?: 'pending' | 'accepted' | 'rejected'; // processing entfernt
|
||||
status?: 'pending' | 'accepted' | 'rejected';
|
||||
assignedDienststelle?: { id: number; name: string };
|
||||
processedBy?: string;
|
||||
processedAt?: number;
|
||||
@@ -35,7 +35,7 @@
|
||||
let isLoading = true;
|
||||
let error = '';
|
||||
|
||||
// Filter für Status (processing entfernt)
|
||||
// Filter für Status
|
||||
let statusFilter: 'all' | 'pending' | 'accepted' | 'rejected' = 'all';
|
||||
let filteredAnmeldungen: Anmeldung[] = [];
|
||||
|
||||
@@ -63,7 +63,16 @@ Ihr Praktikumsteam`;
|
||||
let isLoadingEmailConfig = false;
|
||||
let isSavingEmailConfig = false;
|
||||
|
||||
// Status-Badge Funktionen (processing entfernt)
|
||||
// E-Mail Preview Modal State
|
||||
let showEmailPreview = false;
|
||||
let emailPreviewData: {
|
||||
to: string;
|
||||
subject: string;
|
||||
body: string;
|
||||
} | null = null;
|
||||
let emailCopied = false;
|
||||
|
||||
// Status-Badge Funktionen
|
||||
function getStatusColor(status: string): string {
|
||||
switch (status) {
|
||||
case 'pending': return 'bg-yellow-100 text-yellow-800';
|
||||
@@ -110,7 +119,6 @@ Ihr Praktikumsteam`;
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// Prüfen ob es ein Array ist
|
||||
if (!Array.isArray(data)) {
|
||||
console.error('❌ Antwort ist kein Array:', data);
|
||||
throw new Error('Antwort vom Server ist kein Array');
|
||||
@@ -143,7 +151,6 @@ Ihr Praktikumsteam`;
|
||||
emailTemplate = config.template;
|
||||
} catch (err) {
|
||||
console.error('Fehler beim Laden der E-Mail-Konfiguration:', err);
|
||||
// Fallback auf Standard-Werte bei Fehler
|
||||
} finally {
|
||||
isLoadingEmailConfig = false;
|
||||
}
|
||||
@@ -208,8 +215,8 @@ Ihr Praktikumsteam`;
|
||||
|
||||
showDialog = false;
|
||||
|
||||
// E-Mail senden nach erfolgreichem Annehmen
|
||||
await sendAcceptanceEmail(selectedAnmeldungId, event.detail.dienststelleId);
|
||||
// E-Mail Vorschau öffnen nach erfolgreichem Annehmen
|
||||
openEmailPreview(selectedAnmeldungId, event.detail.dienststelleId);
|
||||
|
||||
selectedAnmeldungId = null;
|
||||
await loadAnmeldungen();
|
||||
@@ -219,13 +226,15 @@ Ihr Praktikumsteam`;
|
||||
}
|
||||
}
|
||||
|
||||
async function sendAcceptanceEmail(anmeldungId: number, dienststelleId: number) {
|
||||
function openEmailPreview(anmeldungId: number, dienststelleId: number) {
|
||||
const anmeldung = anmeldungen.find(a => a.id === anmeldungId);
|
||||
if (!anmeldung) return;
|
||||
|
||||
// Dienststelle finden
|
||||
const dienststelle = availableWishes.find(w => w.id === dienststelleId);
|
||||
const dienststelleName = dienststelle ? dienststelle.name.replace(/^\d+\.\s*Wunsch:\s*/, '') : 'Unbekannte Dienststelle';
|
||||
const dienststelleName = dienststelle
|
||||
? dienststelle.name.replace(/^\d+\.\s*Wunsch:\s*/, '')
|
||||
: 'Unbekannte Dienststelle';
|
||||
|
||||
// E-Mail Text personalisieren
|
||||
const personalizedEmail = emailTemplate
|
||||
@@ -234,11 +243,43 @@ Ihr Praktikumsteam`;
|
||||
.replace(/\{nachname\}/g, anmeldung.nachname)
|
||||
.replace(/\{dienststelle\}/g, dienststelleName);
|
||||
|
||||
// mailto: Link erstellen
|
||||
const mailtoLink = `mailto:${anmeldung.email}?subject=${encodeURIComponent(emailSubject)}&body=${encodeURIComponent(personalizedEmail)}`;
|
||||
// Modal mit Vorschau öffnen
|
||||
emailPreviewData = {
|
||||
to: anmeldung.email,
|
||||
subject: emailSubject,
|
||||
body: personalizedEmail
|
||||
};
|
||||
emailCopied = false;
|
||||
showEmailPreview = true;
|
||||
}
|
||||
|
||||
async function copyAndOpenMail() {
|
||||
if (!emailPreviewData) return;
|
||||
|
||||
// Standard E-Mail Client öffnen
|
||||
window.location.href = mailtoLink;
|
||||
try {
|
||||
await navigator.clipboard.writeText(emailPreviewData.body);
|
||||
emailCopied = true;
|
||||
|
||||
// Kurz warten, dann Mail öffnen
|
||||
setTimeout(() => {
|
||||
const mailtoLink = `mailto:${emailPreviewData!.to}?subject=${encodeURIComponent(emailPreviewData!.subject)}`;
|
||||
window.location.href = mailtoLink;
|
||||
}, 500);
|
||||
|
||||
// Modal nach 2 Sekunden schließen
|
||||
setTimeout(() => {
|
||||
closeEmailPreview();
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Clipboard-Fehler:', err);
|
||||
error = 'Konnte Text nicht kopieren. Bitte manuell markieren und kopieren.';
|
||||
}
|
||||
}
|
||||
|
||||
function closeEmailPreview() {
|
||||
showEmailPreview = false;
|
||||
emailPreviewData = null;
|
||||
emailCopied = false;
|
||||
}
|
||||
|
||||
async function handleReject(event: CustomEvent<{id: number}>) {
|
||||
@@ -305,7 +346,7 @@ Ihr Praktikumsteam`;
|
||||
<main class="max-w-7xl mx-auto px-4 py-6">
|
||||
<!-- Filter und E-Mail Konfiguration -->
|
||||
<div class="mb-6 flex justify-between items-center">
|
||||
<!-- Status Filter (processing entfernt) -->
|
||||
<!-- Status Filter -->
|
||||
<div class="flex items-center space-x-4">
|
||||
<label for="status-filter" class="text-sm font-medium text-gray-700">Filter:</label>
|
||||
<select
|
||||
@@ -337,7 +378,7 @@ Ihr Praktikumsteam`;
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Status Übersicht (processing entfernt) -->
|
||||
<!-- Status Übersicht -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||||
<div class="bg-white rounded-lg border border-gray-200 p-4">
|
||||
<div class="flex items-center">
|
||||
@@ -504,6 +545,7 @@ Ihr Praktikumsteam`;
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Dienststellen Dialog -->
|
||||
{#if showDialog}
|
||||
<DienststellenDialog
|
||||
wishes={availableWishes}
|
||||
@@ -511,4 +553,119 @@ Ihr Praktikumsteam`;
|
||||
on:confirm={handleConfirmAccept}
|
||||
on:cancel={closeDialog}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<!-- E-Mail Vorschau Modal -->
|
||||
{#if showEmailPreview && emailPreviewData}
|
||||
<div class="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div class="flex min-h-screen items-center justify-center p-4">
|
||||
<!-- Backdrop -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="fixed inset-0 bg-black bg-opacity-50 transition-opacity"
|
||||
on:click={closeEmailPreview}
|
||||
></div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="relative bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-hidden">
|
||||
<!-- Header -->
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center bg-white">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-medium text-gray-900">E-Mail Vorschau</h3>
|
||||
</div>
|
||||
<button
|
||||
on:click={closeEmailPreview}
|
||||
class="text-gray-400 hover:text-gray-600 transition-colors"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="px-6 py-4 overflow-y-auto max-h-[60vh]">
|
||||
<div class="space-y-4">
|
||||
<!-- Empfänger -->
|
||||
<div class="flex items-center space-x-3 p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm font-medium text-gray-500 w-16">An:</span>
|
||||
<span class="text-sm text-gray-900">{emailPreviewData.to}</span>
|
||||
</div>
|
||||
|
||||
<!-- Betreff -->
|
||||
<div class="flex items-center space-x-3 p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm font-medium text-gray-500 w-16">Betreff:</span>
|
||||
<span class="text-sm text-gray-900">{emailPreviewData.subject}</span>
|
||||
</div>
|
||||
|
||||
<!-- Nachricht (editierbar) -->
|
||||
<div>
|
||||
<label for="email-body" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Nachricht
|
||||
<span class="font-normal text-gray-500">(kann bearbeitet werden)</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="email-body"
|
||||
bind:value={emailPreviewData.body}
|
||||
rows="14"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none"
|
||||
disabled={emailCopied}
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="px-6 py-4 border-t border-gray-200 bg-gray-50">
|
||||
{#if emailCopied}
|
||||
<div class="flex items-center justify-center py-3">
|
||||
<div class="flex items-center space-x-3 text-green-600">
|
||||
<div class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="font-medium">Text kopiert – Outlook öffnet sich...</span>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
||||
<div class="flex items-start space-x-2 text-sm text-gray-600">
|
||||
<svg class="w-5 h-5 text-blue-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>
|
||||
Der Text wird kopiert und Outlook geöffnet.<br class="hidden sm:inline" />
|
||||
Dann mit <kbd class="px-1.5 py-0.5 bg-gray-200 rounded text-xs font-mono">Strg</kbd> + <kbd class="px-1.5 py-0.5 bg-gray-200 rounded text-xs font-mono">V</kbd> einfügen.
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex space-x-3 w-full sm:w-auto">
|
||||
<button
|
||||
on:click={closeEmailPreview}
|
||||
class="flex-1 sm:flex-none px-4 py-2.5 text-sm text-gray-600 hover:text-gray-800 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
Abbrechen
|
||||
</button>
|
||||
<button
|
||||
on:click={copyAndOpenMail}
|
||||
class="flex-1 sm:flex-none bg-blue-600 hover:bg-blue-700 text-white px-5 py-2.5 rounded-lg text-sm font-medium inline-flex items-center justify-center transition-colors"
|
||||
>
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
|
||||
</svg>
|
||||
Kopieren & E-Mail öffnen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user