projectbased/app/Views/projects/view.php
SHA-256: 3e7dcf776e76052790064957d62cf0bf84f871381e8949859d4e8e213a1c323f
<?php
use App\Lib\Url;
use App\Lib\ProjectPhases;
$phase = (string)($project['phase'] ?? 'idea');
$phaseLabel = ProjectPhases::label($phase);
$progress = ProjectPhases::progress($phase);
function roleLabel(string $r): string {
return match($r) {
'initiator' => 'Initiator',
'coordinator' => 'Koordinator',
'member' => 'Mitwirkend',
'observer' => 'Beobachter',
default => $r
};
}
$coordinator = null;
$initiator = null;
foreach(($roles ?? []) as $r){
if(($r['role'] ?? '')==='coordinator' && (int)($r['active'] ?? 1)===1 && !$coordinator) $coordinator=$r;
if(($r['role'] ?? '')==='initiator' && (int)($r['active'] ?? 1)===1 && !$initiator) $initiator=$r;
}
?>
<div class="d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3">
<div>
<h1 class="h4 mb-1"><?= htmlspecialchars($project['title'] ?? '') ?></h1>
<div class="muted">
Kategorie: <span class="chip"><?= htmlspecialchars($project['category'] ?? 'general') ?></span>
· Region: <span class="chip"><?= htmlspecialchars($project['region'] ?? '') ?></span>
· Owner: <span class="chip"><?= htmlspecialchars($project['owner_name'] ?? '') ?></span>
</div>
</div>
<div class="d-flex gap-2">
<a class="btn btn-outline-light btn-sm" href="<?= Url::route('projects') ?>">← Zur Liste</a>
</div>
</div>
<div class="row g-3">
<div class="col-12 col-lg-7">
<div class="card p-4 mb-3">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
<div class="d-flex align-items-center gap-2">
<span class="badge badge-soft">Phase: <?= htmlspecialchars($phaseLabel) ?></span>
<span class="badge badge-soft">Score: <?= (int)$score ?></span>
</div>
<?php if (!empty($canManage)): ?>
<button class="btn btn-primary btn-sm" data-bs-toggle="collapse" data-bs-target="#phasePanel">Phase ändern</button>
<?php endif; ?>
</div>
<div class="mt-3">
<div class="muted small mb-1">Fortschritt (Demo-Indikator)</div>
<div class="progress" style="height:10px;">
<div class="progress-bar" role="progressbar" style="width: <?= (int)$progress ?>%"></div>
</div>
</div>
<?php if (!empty($project['description'])): ?>
<div class="mt-3"><?= nl2br(htmlspecialchars($project['description'])) ?></div>
<?php else: ?>
<div class="mt-3 muted">Keine Beschreibung hinterlegt.</div>
<?php endif; ?>
<?php if (!empty($canManage)): ?>
<div class="collapse mt-3" id="phasePanel">
<div class="card p-3">
<form method="post" action="<?= Url::route('project_phase') ?>" class="row g-2">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<div class="col-12 col-md-4">
<label class="form-label">Neue Phase</label>
<select class="form-select" name="phase">
<?php foreach(($phases ?? []) as $ph): ?>
<option value="<?= htmlspecialchars($ph) ?>" <?= $ph===$phase?'selected':'' ?>><?= htmlspecialchars(ProjectPhases::label($ph)) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 col-md-8">
<label class="form-label">Begründung (optional)</label>
<input class="form-control" name="reason" placeholder="z. B. Planung abgeschlossen, Umsetzung startet…">
</div>
<div class="col-12">
<button class="btn btn-primary btn-sm" type="submit">Speichern</button>
</div>
</form>
</div>
</div>
<?php endif; ?>
</div>
<div class="card p-4 mb-3">
<h2 class="h6 mb-3">Meilensteine</h2>
<?php if (empty($milestones)): ?>
<div class="muted">Noch keine Meilensteine. (v9 macht Projekte planbar.)</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm align-middle mb-0">
<thead><tr><th>Titel</th><th>Status</th><th style="width:160px;"></th></tr></thead>
<tbody>
<?php foreach($milestones as $m): ?>
<tr>
<td>
<div class="fw-semibold"><?= htmlspecialchars($m['title'] ?? '') ?></div>
<?php if (!empty($m['description'])): ?>
<div class="muted small"><?= htmlspecialchars($m['description']) ?></div>
<?php endif; ?>
</td>
<td><span class="badge badge-soft"><?= htmlspecialchars($m['status'] ?? 'open') ?></span></td>
<td class="text-end">
<?php if (!empty($canManage)): ?>
<form method="post" action="<?= Url::route('project_milestone_status') ?>" class="d-inline">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="milestone_id" value="<?= (int)$m['id'] ?>">
<input type="hidden" name="status" value="active">
<button class="btn btn-outline-light btn-sm" type="submit">Aktiv</button>
</form>
<form method="post" action="<?= Url::route('project_milestone_status') ?>" class="d-inline">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="milestone_id" value="<?= (int)$m['id'] ?>">
<input type="hidden" name="status" value="done">
<button class="btn btn-outline-light btn-sm" type="submit">Erledigt</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php if (!empty($canManage)): ?>
<div class="mt-3">
<div class="muted small mb-2">Neuen Meilenstein anlegen</div>
<form method="post" action="<?= Url::route('project_milestone_add') ?>" class="row g-2">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<div class="col-12 col-md-5"><input class="form-control" name="title" placeholder="Titel" required></div>
<div class="col-12 col-md-5"><input class="form-control" name="description" placeholder="Kurzbeschreibung (optional)"></div>
<div class="col-6 col-md-1"><input class="form-control" name="order_index" type="number" value="0"></div>
<div class="col-6 col-md-1"><button class="btn btn-primary w-100" type="submit">+</button></div>
</form>
</div>
<?php endif; ?>
</div>
<div class="card p-4">
<h2 class="h6 mb-3">Abstimmung & Veto</h2>
<div class="d-flex gap-2 flex-wrap align-items-center mb-3">
<form method="post" action="<?= Url::route('project_vote') ?>" class="d-inline">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<input type="hidden" name="value" value="1">
<button class="btn btn-outline-light btn-sm" type="submit">👍 Unterstützen</button>
</form>
<form method="post" action="<?= Url::route('project_vote') ?>" class="d-inline">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<input type="hidden" name="value" value="-1">
<button class="btn btn-outline-light btn-sm" type="submit">👎 Ablehnen</button>
</form>
<span class="muted small">Gesamt-Score: <b><?= (int)$score ?></b></span>
</div>
<form method="post" action="<?= Url::route('project_veto') ?>" class="row g-2">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<div class="col-12">
<label class="form-label">Veto (Begründung, min. 10 Zeichen)</label>
<textarea class="form-control" name="reason" rows="2" placeholder="Warum sollte dieses Projekt so nicht gestartet werden? (konkret)"></textarea>
</div>
<div class="col-12">
<button class="btn btn-primary btn-sm" type="submit">Veto einreichen</button>
</div>
</form>
<?php if (!empty($vetoes)): ?>
<hr class="my-3">
<div class="muted small mb-2">Letzte Vetos</div>
<?php foreach($vetoes as $v): ?>
<div class="card p-3 mb-2">
<div class="d-flex justify-content-between flex-wrap gap-2">
<div class="fw-semibold"><?= htmlspecialchars($v['display_name'] ?? '') ?></div>
<div class="muted small"><?= htmlspecialchars($v['created_at'] ?? '') ?></div>
</div>
<div class="mt-2"><?= nl2br(htmlspecialchars($v['reason'] ?? '')) ?></div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<div class="col-12 col-lg-5">
<div class="card p-4 mb-3">
<h2 class="h6 mb-3">Rollen & Beteiligung</h2>
<div class="d-flex flex-wrap gap-2 mb-3">
<span class="badge badge-soft">Initiator: <?= htmlspecialchars($initiator['display_name'] ?? ($project['owner_name'] ?? '')) ?></span>
<span class="badge badge-soft">Koordinator: <?= htmlspecialchars($coordinator['display_name'] ?? '—') ?></span>
<?php if (!empty($coordinator['rotation_due_at'])): ?>
<span class="badge badge-soft">Rotation: <?= htmlspecialchars($coordinator['rotation_due_at']) ?></span>
<?php endif; ?>
</div>
<div class="muted small mb-2">Aktive Rollen</div>
<div class="table-responsive">
<table class="table table-sm align-middle mb-0">
<thead><tr><th>Person</th><th>Rolle</th></tr></thead>
<tbody>
<?php foreach(($roles ?? []) as $r): ?>
<?php if((int)($r['active'] ?? 1) !== 1) continue; ?>
<tr>
<td><?= htmlspecialchars($r['display_name'] ?? '') ?></td>
<td><span class="badge badge-soft"><?= htmlspecialchars(roleLabel((string)($r['role'] ?? ''))) ?></span></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<hr class="my-3">
<h3 class="h6 mb-2">Beitritt (verbindlich, aber freiwillig)</h3>
<?php if (!empty($commitment)): ?>
<div class="card p-3">
<div class="fw-semibold">Dein Commitment</div>
<div class="muted small">
Rolle: <?= htmlspecialchars(roleLabel((string)($commitment['role'] ?? 'member'))) ?>
· <?= (int)($commitment['hours_per_week'] ?? 0) ?> h/Woche
· bis <?= htmlspecialchars($commitment['until_date'] ?? '') ?>
</div>
</div>
<?php else: ?>
<form method="post" action="<?= Url::route('project_commit') ?>" class="row g-2">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<div class="col-12 col-md-6">
<label class="form-label">Rolle</label>
<select class="form-select" name="role">
<option value="member">Mitwirkend</option>
<option value="observer">Beobachter</option>
<option value="coordinator">Koordinator (nur wenn passend)</option>
</select>
</div>
<div class="col-6 col-md-3">
<label class="form-label">h/Woche</label>
<input class="form-control" type="number" name="hours_per_week" value="2" min="1" max="40">
</div>
<div class="col-6 col-md-3">
<label class="form-label">Tage</label>
<input class="form-control" type="number" name="days" value="30" min="7" max="365">
</div>
<div class="col-12">
<button class="btn btn-primary btn-sm" type="submit">Ich trete bei</button>
</div>
</form>
<?php endif; ?>
</div>
<div class="card p-4 mb-3">
<h2 class="h6 mb-3">Mitwirkende</h2>
<?php if (empty($members)): ?>
<div class="muted">Noch keine Mitglieder.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm align-middle mb-0">
<thead><tr><th>Name</th><th>R</th><th>Seit</th></tr></thead>
<tbody>
<?php foreach($members as $m): ?>
<tr>
<td><?= htmlspecialchars($m['display_name'] ?? '') ?></td>
<td><span class="badge badge-soft"><?= (int)($m['r_index'] ?? 0) ?></span></td>
<td class="muted small"><?= htmlspecialchars($m['joined_at'] ?? '') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<div class="card p-4 mb-3">
<h2 class="h6 mb-3">Gesuchte Skills</h2>
<?php if (empty($skillNeeds)): ?>
<div class="muted">Noch keine Skill-Bedarfe definiert. (v11 Matching wird besser, wenn du hier Skills einträgst.)</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm align-middle mb-0">
<thead><tr><th>Skill</th><th>Benötigt</th><th>Prio</th><th style="width:70px;"></th></tr></thead>
<tbody>
<?php foreach($skillNeeds as $sn): ?>
<tr>
<td><?= htmlspecialchars($sn['name'] ?? '') ?></td>
<td><span class="badge badge-soft"><?= (int)($sn['needed_count'] ?? 1) ?></span></td>
<td><span class="badge badge-soft"><?= (int)($sn['priority'] ?? 3) ?></span></td>
<td class="text-end">
<?php if (!empty($canManage)): ?>
<form method="post" action="<?= \App\Lib\Url::route('project_skill_need_remove') ?>" class="d-inline">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<input type="hidden" name="id" value="<?= (int)$sn['id'] ?>">
<button class="btn btn-outline-light btn-sm" type="submit">×</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php if (!empty($canManage)): ?>
<hr class="my-3">
<div class="muted small mb-2">Skill-Bedarf hinzufügen</div>
<form method="post" action="<?= \App\Lib\Url::route('project_skill_need_add') ?>" class="row g-2">
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
<input type="hidden" name="project_id" value="<?= (int)$project['id'] ?>">
<div class="col-12 col-md-6"><input class="form-control" name="skill" placeholder="z. B. Elektriker, Statik, Pflege" required></div>
<div class="col-6 col-md-3"><input class="form-control" name="needed_count" type="number" value="1" min="1" max="999"></div>
<div class="col-6 col-md-3">
<select class="form-select" name="priority">
<option value="5">Prio 5</option>
<option value="4">Prio 4</option>
<option value="3" selected>Prio 3</option>
<option value="2">Prio 2</option>
<option value="1">Prio 1</option>
</select>
</div>
<div class="col-12">
<button class="btn btn-primary btn-sm" type="submit">Hinzufügen</button>
</div>
</form>
<?php endif; ?>
</div>
<div class="card p-4">
<h2 class="h6 mb-3">Phase-Historie</h2>
<?php if (empty($phaseHistory)): ?>
<div class="muted">Noch keine Historie.</div>
<?php else: ?>
<?php foreach($phaseHistory as $h): ?>
<div class="card p-3 mb-2">
<div class="d-flex justify-content-between flex-wrap gap-2">
<div class="fw-semibold"><?= htmlspecialchars(ProjectPhases::label((string)($h['phase'] ?? ''))) ?></div>
<div class="muted small"><?= htmlspecialchars($h['changed_at'] ?? '') ?></div>
</div>
<div class="muted small">von <?= htmlspecialchars($h['display_name'] ?? '') ?></div>
<?php if (!empty($h['reason'])): ?>
<div class="mt-2"><?= nl2br(htmlspecialchars($h['reason'])) ?></div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>