antragstracker/frontend/src/routes/+page.svelte

146 lines
4.6 KiB
Svelte
Raw Normal View History

<script lang="ts">
import '../app.css';
interface Vorlage {
id: number;
aktenzeichen: string;
typ: string;
betreff: string;
datum_eingang: string;
ist_verwaltungsvorlage: boolean;
}
interface Stats {
vorlagen: number;
beratungen: number;
ketten: number;
gremien: number;
}
let stats = $state<Stats>({ vorlagen: 0, beratungen: 0, ketten: 0, gremien: 0 });
let antraege = $state<Vorlage[]>([]);
let loading = $state(true);
let error = $state('');
// API-Base: In Produktion relativ, in Dev mit Port
const API_BASE = typeof window !== 'undefined'
? (window.location.port === '5173'
? `http://${window.location.hostname}:8099/api`
: '/api')
: '/api';
async function loadData() {
console.log('API_BASE:', API_BASE);
try {
// Stats laden
console.log('Fetching health...');
const statsRes = await fetch(`${API_BASE}/health`);
console.log('Health response:', statsRes.status);
if (statsRes.ok) {
// Vorlagen zählen
console.log('Fetching vorlagen...');
const vorlagenRes = await fetch(`${API_BASE}/vorlagen?page_size=1`);
console.log('Vorlagen response:', vorlagenRes.status);
const vorlagenData = await vorlagenRes.json();
stats.vorlagen = vorlagenData.total;
// Ketten zählen
const kettenRes = await fetch(`${API_BASE}/ketten?page_size=1`);
const kettenData = await kettenRes.json();
stats.ketten = kettenData.total;
} else {
error = `Health check failed: ${statsRes.status}`;
}
// Letzte 10 Anträge laden
const antraegeRes = await fetch(`${API_BASE}/vorlagen?typ=antrag&page_size=10`);
console.log('Antraege response:', antraegeRes.status);
if (antraegeRes.ok) {
const data = await antraegeRes.json();
console.log('Antraege data:', data.items.length);
antraege = data.items;
}
} catch (e) {
console.error('API Fehler:', e);
error = `Fehler: ${e}`;
} finally {
loading = false;
console.log('Loading done, antraege:', antraege.length);
}
}
loadData();
</script>
<svelte:head>
<title>Antragstracker Hagen</title>
</svelte:head>
<main class="min-h-screen bg-gray-50">
<!-- Header -->
<header class="bg-green-700 text-white py-6 shadow-lg">
<div class="max-w-6xl mx-auto px-4">
<h1 class="text-2xl sm:text-3xl font-bold">🏛️ Antragstracker Hagen</h1>
<p class="text-green-100 mt-1">Kommunale Anträge & Anfragen nachverfolgen</p>
</div>
</header>
<div class="max-w-6xl mx-auto px-4 py-8">
<!-- Stats Cards -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
<div class="bg-white rounded-lg shadow p-4 text-center">
<div class="text-3xl font-bold text-green-600">{stats.vorlagen.toLocaleString()}</div>
<div class="text-gray-500 text-sm">Vorlagen</div>
</div>
<div class="bg-white rounded-lg shadow p-4 text-center">
<div class="text-3xl font-bold text-blue-600">{stats.ketten.toLocaleString()}</div>
<div class="text-gray-500 text-sm">Ketten</div>
</div>
<div class="bg-white rounded-lg shadow p-4 text-center">
<div class="text-3xl font-bold text-purple-600">41</div>
<div class="text-gray-500 text-sm">Gremien</div>
</div>
<div class="bg-white rounded-lg shadow p-4 text-center">
<div class="text-3xl font-bold text-orange-600">20042026</div>
<div class="text-gray-500 text-sm">Zeitraum</div>
</div>
</div>
<!-- Aktuelle Anträge -->
<section class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-xl font-semibold text-gray-800">📋 Aktuelle Anträge</h2>
</div>
{#if error}
<div class="p-6 text-center text-red-500">{error}</div>
{:else if loading}
<div class="p-6 text-center text-gray-500">Lade Daten... (API: {API_BASE})</div>
{:else if antraege.length === 0}
<div class="p-6 text-center text-gray-500">Keine Anträge gefunden</div>
{:else}
<ul class="divide-y divide-gray-100">
{#each antraege as antrag}
<li class="px-6 py-4 hover:bg-gray-50 cursor-pointer">
<div class="flex justify-between items-start">
<div class="flex-1">
<div class="flex items-center gap-2">
<span class="font-mono text-sm text-green-700 bg-green-50 px-2 py-0.5 rounded">
{antrag.aktenzeichen}
</span>
<span class="text-xs text-gray-400">{antrag.datum_eingang}</span>
</div>
<p class="mt-1 text-gray-700 line-clamp-2">{antrag.betreff}</p>
</div>
<span class="text-xs px-2 py-1 rounded-full bg-yellow-100 text-yellow-800">
⏳ offen
</span>
</div>
</li>
{/each}
</ul>
{/if}
</section>
</div>
</main>