Reorganize into monorepo layout, move mitarbeiter-app to legacy reference

Consolidates the previously separate omsorgapp and omsorgCore repos
(each had their own nested .git with GitHub history) plus the old
root-level website/mitarbeiter-app into a single monorepo, matching
the structure already documented in the root CLAUDE.md. Also moves
the PHP employee app aside as omsorgWeb/mitarbeiter-app-legacy/ to
serve as a template for a ground-up rewrite.

Fixes .gitignore in the same pass: the config-secrets/uploads/data
patterns were unanchored (relative to repo root, not depth-agnostic),
so they silently stopped matching once the app moved under omsorgWeb/.
Patterns are now **/-prefixed and cover both mitarbeiter-app and
mitarbeiter-app-legacy, keeping DB/SMTP credentials and uploaded
employee documents out of version control.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Felix Kemmler
2026-08-07 14:21:37 +02:00
co-authored by Claude Sonnet 5
parent 8beb0fcf52
commit b6c1389c55
355 changed files with 24348 additions and 361 deletions
@@ -0,0 +1,165 @@
<?php
require_once __DIR__ . '/../lib/auth.php';
require_once __DIR__ . '/../lib/db.php';
require_once __DIR__ . '/../lib/layout.php';
require_login();
$user_id = current_user()['id'];
$stmt = db()->prepare('SELECT * FROM requests_abwesenheitsantrag WHERE user_id = ? ORDER BY created_at DESC');
$stmt->execute([$user_id]);
$requests = $stmt->fetchAll();
$grund_labels = [
'krankheit' => 'Krankheit',
'arztbesuch' => 'Arztbesuch',
'behoerdengang' => 'Behördengang',
'sonderurlaub' => 'Sonderurlaub',
'elternzeit_pflegezeit' => 'Elternzeit / Pflegezeit',
'sonstiges' => 'Sonstiges',
];
$status_labels = ['pending' => 'Ausstehend', 'accepted' => 'Akzeptiert', 'rejected' => 'Abgelehnt'];
layout_start('OMSORG Abwesenheitsantrag', 'abwesenheitsantrag');
?>
<style>
.modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.55);display:none;align-items:center;justify-content:center;z-index:1000}
.modal-box{background:var(--glass-bg,#1e2235);border:1px solid var(--border,rgba(255,255,255,.1));border-radius:14px;padding:28px 32px;max-width:480px;width:90%;position:relative}
.modal-box h3{margin:0 0 20px;font-family:'KindelSerif',Georgia,serif;font-size:1.3rem}
.modal-close{position:absolute;top:12px;right:16px;background:none;border:none;font-size:1.5rem;cursor:pointer;color:var(--muted,#888);line-height:1}
.modal-dl{display:grid;grid-template-columns:auto 1fr;gap:8px 16px;font-size:.95rem}
.modal-dl dt{color:var(--muted,#888);white-space:nowrap}
.modal-dl dd{margin:0;font-weight:500}
.btn-sm{display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border-radius:9px;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.08);color:#fff;font-weight:600;font-size:.82rem;cursor:pointer;font:inherit;transition:background .15s}
.btn-sm:hover{background:rgba(255,255,255,.15)}
</style>
<h1 class="main-title">📅 Abwesenheitsantrag</h1>
<p class="main-sub">Melde eine geplante Abwesenheit. Das Startdatum muss vor dem Enddatum liegen.</p>
<?php if (isset($_GET['success'])): ?>
<div class="success" style="margin-top:16px">Antrag erfolgreich eingereicht.</div>
<?php elseif (isset($_GET['error'])): ?>
<div class="error" style="margin-top:16px"><?= e(urldecode($_GET['error'])) ?></div>
<?php endif; ?>
<div id="abw-modal" class="modal-backdrop" onclick="if(event.target===this)this.style.display='none'">
<div class="modal-box glass">
<button class="modal-close" onclick="document.getElementById('abw-modal').style.display='none'">&times;</button>
<h3>Antrag Details</h3>
<dl class="modal-dl">
<dt>Von</dt> <dd id="abw-von"></dd>
<dt>Bis</dt> <dd id="abw-bis"></dd>
<dt>Grund</dt> <dd id="abw-grund"></dd>
<dt>Vertretung</dt> <dd id="abw-vertretung"></dd>
<dt>Nachricht</dt> <dd id="abw-nachricht"></dd>
<dt>Eingereicht</dt><dd id="abw-eingereicht"></dd>
<dt>Status</dt> <dd id="abw-status"></dd>
<dt>Admin-Notiz</dt><dd id="abw-note"></dd>
</dl>
</div>
</div>
<div class="page-split">
<div class="page-split-list">
<h2>Meine Anträge</h2>
<?php if (empty($requests)): ?>
<p style="color:var(--muted)">Noch keine Anträge gestellt.</p>
<?php else: ?>
<table class="requests-table">
<thead>
<tr>
<th>Von</th>
<th>Bis</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($requests as $r): ?>
<tr>
<td><?= e(date('d.m.Y', strtotime($r['von']))) ?></td>
<td><?= e(date('d.m.Y', strtotime($r['bis']))) ?></td>
<td><span class="badge badge-<?= e($r['status']) ?>"><?= e($status_labels[$r['status']] ?? $r['status']) ?></span></td>
<td>
<button class="btn-sm js-abw-details"
data-von="<?= e(date('d.m.Y', strtotime($r['von']))) ?>"
data-bis="<?= e(date('d.m.Y', strtotime($r['bis']))) ?>"
data-grund="<?= e($grund_labels[$r['grund']] ?? $r['grund']) ?>"
data-vertretung="<?= e($r['vertretung'] !== '' ? $r['vertretung'] : '') ?>"
data-nachricht="<?= e($r['nachricht'] !== '' ? $r['nachricht'] : '') ?>"
data-eingereicht="<?= e(date('d.m.Y', strtotime($r['created_at']))) ?>"
data-status-label="<?= e($status_labels[$r['status']] ?? $r['status']) ?>"
data-status-key="<?= e($r['status']) ?>"
data-note="<?= e($r['admin_note'] !== '' ? $r['admin_note'] : '') ?>"
>Details</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<div class="page-split-form">
<div class="glass detail-card">
<h2>Neuer Abwesenheitsantrag</h2>
<form action="../actions/submit-abwesenheitsantrag.php" method="post">
<?= csrf_field() ?>
<label>
<span>Von <span style="color:#ff8080">*</span></span>
<input type="date" name="von" required>
</label>
<label>
<span>Bis <span style="color:#ff8080">*</span></span>
<input type="date" name="bis" required>
</label>
<label>
<span>Grund <span style="color:#ff8080">*</span></span>
<select name="grund" required>
<option value=""> Bitte wählen </option>
<option value="krankheit">Krankheit</option>
<option value="arztbesuch">Arztbesuch</option>
<option value="behoerdengang">Behördengang</option>
<option value="sonderurlaub">Sonderurlaub</option>
<option value="elternzeit_pflegezeit">Elternzeit / Pflegezeit</option>
<option value="sonstiges">Sonstiges</option>
</select>
</label>
<label>
<span>Vertretung</span>
<input type="text" name="vertretung" placeholder="Name der Vertretung">
</label>
<label>
Nachricht
<textarea name="nachricht" rows="4" placeholder="Optionale Anmerkungen"></textarea>
</label>
<button type="submit" class="btn" style="margin-top:6px">Antrag einreichen</button>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('click', function(e) {
var btn = e.target.closest('.js-abw-details');
if (!btn) return;
var d = btn.dataset;
document.getElementById('abw-von').textContent = d.von;
document.getElementById('abw-bis').textContent = d.bis;
document.getElementById('abw-grund').textContent = d.grund;
document.getElementById('abw-vertretung').textContent = d.vertretung;
document.getElementById('abw-nachricht').textContent = d.nachricht;
document.getElementById('abw-eingereicht').textContent = d.eingereicht;
document.getElementById('abw-status').innerHTML =
'<span class="badge badge-' + d.statusKey + '">' + d.statusLabel + '</span>';
document.getElementById('abw-note').textContent = d.note;
document.getElementById('abw-modal').style.display = 'flex';
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') document.getElementById('abw-modal').style.display = 'none';
});
</script>
<?php layout_end(); ?>