"Bewerbung senden" now asks for an extra confirmation (with the recipient) before dispatching. Job offers gain adresse and ansprechpartner fields — shown, editable, and carried through the REST API upsert (Swagger updated). Taking an offer over now writes the employer address (street, number, city) and the contact person into the application's AI notes (llm_notizen), so the LLM can use them for the letter's Anschriftfeld and salutation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
164 lines
12 KiB
Plaintext
164 lines
12 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<%- include('partials/head') %>
|
|
</head>
|
|
<body class="min-h-screen transition-colors duration-300 bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100" id="body">
|
|
<%- include('partials/header') %>
|
|
|
|
<main class="container mx-auto px-4 py-8 max-w-5xl">
|
|
<!-- Back link -->
|
|
<a href="/jobangebote" class="inline-flex items-center gap-2 text-sm text-blue-600 dark:text-blue-400 hover:underline mb-6">
|
|
<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="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
|
</svg>
|
|
Zurück zu den Jobangeboten
|
|
</a>
|
|
|
|
<!-- Tabs: open offers vs. taken-over offers -->
|
|
<div class="flex flex-wrap items-center gap-2 mb-6">
|
|
<a href="/jobangebote" class="px-3 py-1.5 rounded-md text-sm font-medium bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
Offen (<%= offenCount %>)
|
|
</a>
|
|
<a href="/jobangebote/uebernommen" class="px-3 py-1.5 rounded-md text-sm font-medium bg-blue-600 text-white shadow-sm">
|
|
Übernommen (<%= uebernommen.length %>)
|
|
</a>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-8">
|
|
<div class="flex flex-wrap items-start justify-between gap-3 mb-2">
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-gray-800 dark:text-white">Übernommene Jobangebote</h2>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1 max-w-2xl">
|
|
Diese Angebote wurden bereits als Bewerbung übernommen. Über „Zur Bewerbung“
|
|
gelangst du direkt zur jeweiligen Bewerbung.
|
|
</p>
|
|
</div>
|
|
<span class="shrink-0 inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-blue-50 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300 border border-blue-200 dark:border-blue-800">
|
|
<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="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
|
<%= uebernommen.length %> übernommen
|
|
</span>
|
|
</div>
|
|
|
|
<% if (uebernommen && uebernommen.length) { %>
|
|
<ul class="mt-4 space-y-4">
|
|
<% uebernommen.forEach(function(j){ %>
|
|
<li class="rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 px-4 py-4">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div class="min-w-0 flex-1">
|
|
<div class="flex flex-wrap items-center gap-2 mb-1">
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/50 dark:text-blue-200">Übernommen</span>
|
|
<% if (j.bewerbung_status) { %>
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200">Status: <%= j.bewerbung_status %></span>
|
|
<% } %>
|
|
<% if (j.quelle && j.quelle !== 'drittanbieter') { %>
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200">Quelle: <%= j.quelle %></span>
|
|
<% } %>
|
|
</div>
|
|
<p class="text-base font-semibold text-gray-800 dark:text-gray-100 break-words"><%= j.firma %></p>
|
|
<p class="text-sm text-gray-700 dark:text-gray-200 break-words"><%= j.stelle %></p>
|
|
<% if (j.ort || j.gehalt) { %>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
|
|
<% if (j.ort) { %><%= j.ort %><% } %>
|
|
<% if (j.ort && j.gehalt) { %> · <% } %>
|
|
<% if (j.gehalt) { %><%= j.gehalt %><% } %>
|
|
</p>
|
|
<% } %>
|
|
<% if (j.adresse) { %>
|
|
<p class="text-sm mt-1 flex items-start gap-1.5 min-w-0">
|
|
<span class="text-gray-500 dark:text-gray-400 shrink-0">Anschrift:</span>
|
|
<span class="text-gray-700 dark:text-gray-200 break-words whitespace-pre-line"><%= j.adresse %></span>
|
|
</p>
|
|
<% } %>
|
|
<% if (j.ansprechpartner) { %>
|
|
<p class="text-sm mt-1 flex items-start gap-1.5 min-w-0">
|
|
<span class="text-gray-500 dark:text-gray-400 shrink-0">Ansprechpartner:</span>
|
|
<span class="text-gray-700 dark:text-gray-200 break-words"><%= j.ansprechpartner %></span>
|
|
</p>
|
|
<% } %>
|
|
<% if (j.quelle_url) { %>
|
|
<a href="<%= j.quelle_url %>" target="_blank" rel="noopener noreferrer"
|
|
class="inline-flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400 hover:underline mt-2 break-all">
|
|
<svg class="w-3.5 h-3.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
|
|
<span class="truncate"><%= j.quelle_url %></span>
|
|
</a>
|
|
<% } %>
|
|
<p class="text-xs text-gray-400 dark:text-gray-500 mt-2 flex flex-wrap gap-x-3 gap-y-1">
|
|
<% if (j.verknuepfte_bewerbung_id && j.bewerbung_datum) { %>
|
|
<span title="Datum der aus diesem Angebot erstellten Bewerbung">
|
|
Bewerbung vom: <span class="text-gray-500 dark:text-gray-400"><%= new Date(j.bewerbung_datum).toLocaleDateString('de-DE') %></span>
|
|
</span>
|
|
<% } %>
|
|
<span title="Wann das Angebot über die REST-API eingespielt wurde">
|
|
Einspielung: <span class="text-gray-500 dark:text-gray-400"><%= j.created_at ? new Date(j.created_at + 'Z').toLocaleString('de-DE') : '' %></span>
|
|
</span>
|
|
<span title="Wann das Angebot übernommen wurde">
|
|
Übernommen: <span class="text-gray-500 dark:text-gray-400"><%= j.updated_at ? new Date(j.updated_at + 'Z').toLocaleString('de-DE') : '' %></span>
|
|
</span>
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="shrink-0 flex flex-col gap-2 self-start">
|
|
<% if (j.verknuepfte_bewerbung_id) { %>
|
|
<a href="/bewerbung/<%= j.verknuepfte_bewerbung_id %>"
|
|
class="inline-flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors">
|
|
<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="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
|
Zur Bewerbung #<%= j.verknuepfte_bewerbung_id %>
|
|
</a>
|
|
<% } else { %>
|
|
<span class="inline-flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-amber-50 dark:bg-amber-900/40 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-800" title="Die verknüpfte Bewerbung wurde gelöscht">
|
|
<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="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"></path></svg>
|
|
Bewerbung gelöscht
|
|
</span>
|
|
<% } %>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<% }); %>
|
|
</ul>
|
|
<% } else { %>
|
|
<div class="text-center py-12">
|
|
<svg class="w-14 h-14 mx-auto text-gray-300 dark:text-gray-600 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
</svg>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Noch keine Angebote übernommen.</p>
|
|
<p class="text-xs text-gray-400 dark:text-gray-500">
|
|
Übernimm ein offenes Angebot im Tab
|
|
<a href="/jobangebote" class="text-blue-600 dark:text-blue-400 hover:underline">„Offen“</a>.
|
|
</p>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
</main>
|
|
|
|
<%- include('partials/footer') %>
|
|
|
|
<script>
|
|
(function () {
|
|
const root = document.documentElement;
|
|
const dm = localStorage.getItem('darkMode');
|
|
if (dm === 'enabled' || (!dm && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
root.classList.add('dark');
|
|
}
|
|
const toggle = document.getElementById('darkModeToggle');
|
|
const sun = document.getElementById('sunIcon');
|
|
const moon = document.getElementById('moonIcon');
|
|
function sync() {
|
|
const d = root.classList.contains('dark');
|
|
if (sun) sun.classList.toggle('hidden', d);
|
|
if (moon) moon.classList.toggle('hidden', !d);
|
|
}
|
|
sync();
|
|
if (toggle) toggle.addEventListener('click', () => {
|
|
root.classList.toggle('dark');
|
|
localStorage.setItem('darkMode', root.classList.contains('dark') ? 'enabled' : 'disabled');
|
|
sync();
|
|
});
|
|
const cy = document.getElementById('currentYear');
|
|
if (cy) cy.textContent = new Date().getFullYear();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|