Interne Notizen: Anhang-Upload repariert + schöneres Design

Der Upload- und Lösch-Formular war versehentlich inside des
Bewerbungsdaten-Formulars verschachtelt – HTML lässt verschachtelte
Formulare nicht zu, weshalb der Browser das multipart-Formular
ignorierte und die Datei nie gesendet wurde. Formulare jetzt outside
des Speichern-Formulars. Dazu ansprechendere Karte-Optik mit
Öffnen-/Download-/Löschen-Aktionen.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-09 04:46:33 +02:00
co-authored by Claude
parent 0b44f04456
commit 306026b0a1
+96 -47
View File
@@ -93,53 +93,6 @@
<textarea name="interne_notizen" rows="4"
class="w-full px-3 py-2 border border-amber-300 dark:border-amber-700 rounded-md bg-amber-50 dark:bg-gray-700 text-gray-800 dark:text-white leading-relaxed"
placeholder="Nur für dich erscheint nicht im Export..."><%= application.interne_notizen || '' %></textarea>
<!-- Private attachments: for the user only, never exported/sent -->
<div class="mt-3">
<div class="flex items-center justify-between gap-2 mb-2">
<span class="text-xs font-medium text-amber-700 dark:text-amber-400">Eigene Anhänge (nur für dich)</span>
</div>
<% if (interneAnhaenge && interneAnhaenge.length) { %>
<ul class="space-y-2 mb-3">
<% interneAnhaenge.forEach(a => { %>
<li class="flex items-center justify-between gap-3 rounded-lg border border-amber-200 dark:border-amber-800/60 bg-amber-50/60 dark:bg-gray-700/40 px-3 py-2">
<a href="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/download?inline=1" target="_blank" rel="noopener"
class="flex items-center gap-2 min-w-0 group" title="Öffnen">
<svg class="w-5 h-5 text-amber-600 dark:text-amber-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>
<span class="text-sm font-medium text-gray-800 dark:text-gray-100 truncate group-hover:text-blue-600 dark:group-hover:text-blue-400 group-hover:underline"><%= a.name || a.dateiname %></span>
</a>
<div class="flex items-center gap-2 shrink-0">
<a href="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/download"
class="text-xs text-blue-600 hover:text-blue-800 dark:text-blue-400 hover:underline">Download</a>
<form action="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/delete" method="POST"
onsubmit="return confirm('Diesen Anhang löschen?');">
<button type="submit" class="text-red-500 hover:text-red-700 dark:text-red-400" aria-label="Anhang löschen">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
</svg>
</button>
</form>
</div>
</li>
<% }); %>
</ul>
<% } %>
<form action="/bewerbung/<%= application.id %>/interne-anhaenge" method="POST" enctype="multipart/form-data" class="space-y-2">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
<input type="file" name="datei" required
class="w-full text-xs text-gray-700 dark:text-gray-300 file:mr-2 file:py-1.5 file:px-2.5 file:rounded-md file:border-0 file:bg-amber-600 file:text-white hover:file:bg-amber-700">
<input type="text" name="name" placeholder="Bezeichnung (optional)"
class="w-full px-2.5 py-1.5 text-sm border border-amber-300 dark:border-amber-700 rounded-md bg-white dark:bg-gray-700 text-gray-800 dark:text-white">
</div>
<div class="flex justify-end">
<button type="submit" class="px-3 py-1.5 text-sm bg-amber-600 hover:bg-amber-700 text-white rounded-md transition-colors">
Anhang hochladen
</button>
</div>
</form>
</div>
</div>
<div class="flex justify-end">
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors">
@@ -147,6 +100,102 @@
</button>
</div>
</form>
<!-- Eigene Anhänge: private files for the user only, never exported/sent.
Kept außerhalb des Bewerbungsdaten-Formulars, damit der Upload
(multipart) und das Löschen als eigene Formulare funktionieren. -->
<div class="mt-5 rounded-lg border border-amber-200 dark:border-amber-900/50 bg-amber-50/40 dark:bg-amber-900/10 p-4">
<div class="flex items-center gap-2 mb-3">
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-amber-100 dark:bg-amber-900/40 text-amber-600 dark:text-amber-400 shrink-0">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.586a6 6 0 108.486 8.486L20.5 13"></path>
</svg>
</span>
<div class="min-w-0">
<h3 class="text-sm font-semibold text-amber-800 dark:text-amber-300 leading-tight">Eigene Anhänge</h3>
<p class="text-xs text-amber-700/80 dark:text-amber-400/70 leading-tight">Nur für dich erscheinen nicht im PDF und werden nicht mitversendet.</p>
</div>
</div>
<% if (interneAnhaenge && interneAnhaenge.length) { %>
<ul class="space-y-2 mb-3">
<% interneAnhaenge.forEach(a => { %>
<% const isPdf = (a.mime === 'application/pdf') || /\.pdf$/i.test(a.dateiname || ''); %>
<li class="group flex items-center gap-3 rounded-lg border border-amber-200/70 dark:border-amber-800/50 bg-white/70 dark:bg-gray-800/60 px-3 py-2.5 hover:border-amber-300 dark:hover:border-amber-700 transition-colors">
<a href="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/download?inline=1" target="_blank" rel="noopener"
class="flex items-center gap-3 min-w-0 flex-1" title="<%= isPdf ? 'PDF im neuen Tab öffnen' : 'Im neuen Tab öffnen' %>">
<span class="inline-flex items-center justify-center w-9 h-9 rounded-md bg-red-50 dark:bg-red-900/30 text-red-500 dark:text-red-400 shrink-0">
<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="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>
</span>
<span class="min-w-0">
<span class="block text-sm font-medium text-gray-800 dark:text-gray-100 truncate group-hover:text-blue-600 dark:group-hover:text-blue-400 group-hover:underline"><%= a.name || a.dateiname %></span>
<span class="block text-xs text-gray-500 dark:text-gray-400 truncate"><%= a.dateiname %></span>
</span>
</a>
<div class="flex items-center gap-1 shrink-0">
<a href="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/download?inline=1" target="_blank" rel="noopener"
class="inline-flex items-center justify-center w-8 h-8 rounded-md text-gray-500 dark:text-gray-400 hover:bg-amber-100 dark:hover:bg-amber-900/40 hover:text-amber-700 dark:hover:text-amber-300 transition-colors"
title="Öffnen" aria-label="Öffnen">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
</svg>
</a>
<a href="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/download"
class="inline-flex items-center justify-center w-8 h-8 rounded-md text-gray-500 dark:text-gray-400 hover:bg-amber-100 dark:hover:bg-amber-900/40 hover:text-amber-700 dark:hover:text-amber-300 transition-colors"
title="Herunterladen" aria-label="Herunterladen">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
</svg>
</a>
<form action="/bewerbung/<%= application.id %>/interne-anhaenge/<%= a.id %>/delete" method="POST"
onsubmit="return confirm('Diesen Anhang löschen?');" class="inline-block">
<button type="submit"
class="inline-flex items-center justify-center w-8 h-8 rounded-md text-gray-400 hover:bg-red-50 dark:hover:bg-red-900/30 hover:text-red-600 dark:hover:text-red-400 transition-colors"
title="Löschen" aria-label="Löschen">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
</svg>
</button>
</form>
</div>
</li>
<% }); %>
</ul>
<% } else { %>
<p class="text-xs text-amber-700/70 dark:text-amber-400/60 mb-3">Noch keine eigenen Anhänge.</p>
<% } %>
<form action="/bewerbung/<%= application.id %>/interne-anhaenge" method="POST" enctype="multipart/form-data" class="space-y-3 border-t border-amber-200/70 dark:border-amber-800/50 pt-3">
<div class="grid grid-cols-1 sm:grid-cols-[1fr_auto] gap-3 items-start">
<div class="space-y-2">
<label class="block">
<span class="sr-only">Datei</span>
<input type="file" name="datei" required
accept="application/pdf,image/*,.doc,.docx,.xls,.xlsx,.txt,.zip"
class="block w-full text-sm text-gray-600 dark:text-gray-300 file:mr-3 file:py-2 file:px-4 file:rounded-md file:border-0 file:font-medium file:bg-amber-600 file:text-white hover:file:bg-amber-700 file:cursor-pointer file:transition-colors">
</label>
<label class="block">
<span class="sr-only">Bezeichnung (optional)</span>
<input type="text" name="name" placeholder="Bezeichnung (optional) z. B. Arbeitszeugnis"
class="w-full px-3 py-2 text-sm border border-amber-200 dark:border-amber-800/60 rounded-md bg-white dark:bg-gray-700 text-gray-800 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-amber-400/40 focus:border-amber-400">
</label>
</div>
<div class="flex sm:items-end">
<button type="submit"
class="w-full sm:w-auto inline-flex items-center justify-center gap-1.5 px-4 py-2 text-sm font-medium bg-amber-600 hover:bg-amber-700 text-white rounded-md transition-colors shadow-sm">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
</svg>
Hochladen
</button>
</div>
</div>
<p class="text-xs text-amber-700/60 dark:text-amber-400/50">PDFs lassen sich per Klick direkt öffnen. Max. 15 MB.</p>
</form>
</div>
</section>
<!-- Bewerbungsunterlagen (KI-generiert) -->