Files
alrahma_sunday_school/app/Views/family/card.php
T

378 lines
18 KiB
PHP

<?php
// Expects: $f (array) — single family enriched as in FamilyAdminController
// Quick helpers
$gCount = count($f['guardians'] ?? []);
$sCount = count($f['students'] ?? []);
$sum = $f['finance_summary'] ?? ['invoices_count'=>0,'total_amount'=>0,'paid_amount'=>0,'balance'=>0];
// Title: prefer provided household_name unless it's generic like "Family of User 53" or empty.
$titleRaw = trim((string)($f['household_name'] ?? ''));
$title = $titleRaw;
if ($title === '' || preg_match('/^\s*Family\s+of\s+User\s*\d+\s*$/i', $title)) {
// Derive from primary guardian last name, else first guardian's last name
$lastName = '';
$primary = null;
foreach (($f['guardians'] ?? []) as $g) {
if (!empty($g['is_primary'])) { $primary = $g; break; }
}
$pick = $primary ?: (($f['guardians'][0] ?? null) ?: null);
if ($pick) {
$ln = trim((string)($pick['lastname'] ?? ''));
if ($ln !== '') $lastName = $ln;
}
$title = $lastName !== '' ? ('Family of ' . $lastName) : 'Family';
}
$returnUrl = trim((string)service('request')->getServer('HTTP_REFERER'));
if ($returnUrl === '') {
$returnUrl = site_url('family');
}
?>
<div class="family-card-root" data-family-title="<?= esc($title) ?>">
<style>
/* Scoped styles for Family Card only */
.family-card-root { font-size: 1rem; color: #12344d; }
.family-card-root .fc-header {
background: linear-gradient(135deg, #2d89ec, #2161a7);
color: #fff;
border-bottom: 0;
border-radius: .5rem .5rem 0 0;
}
.family-card-root .fc-title { font-size: 1.3rem; letter-spacing: .2px; }
.family-card-root .fc-name { font-size: 1.08rem; font-weight: 600; color: #0b5ed7; }
.family-card-root .fc-name:hover { color: #084298; text-decoration: underline; }
.family-card-root .fc-badges .badge { background: rgba(255,255,255,.18); color: #fff; font-weight: 500; }
.family-card-root .nav-tabs { padding-left: .5rem; padding-right: .5rem; }
.family-card-root .nav-tabs .nav-link { color: #2161a7; font-weight: 600; }
.family-card-root .nav-tabs .nav-link:hover { color: #0b5ed7; }
.family-card-root .nav-tabs .nav-link.active { color: #0b5ed7; border-color: #2d89ec #2d89ec #fff; }
.family-card-root h6 { font-size: 1.05rem; color: #143b63; }
.family-card-root .table thead th { background: #f1f5fb; color: #143b63; font-size: .9rem; }
.family-card-root .table tbody td { font-size: 1rem; }
.family-card-root .list-group-item { font-size: 1rem; }
.family-card-root .badge { font-size: .75rem; }
.family-card-root .nav-tabs::-webkit-scrollbar { height: 6px; }
.family-card-root .nav-tabs { overflow-x: auto; overflow-y: hidden; white-space: nowrap; }
.family-card-root .fc-table-stack thead { display: table-header-group; }
.family-card-root .fc-table-stack td { vertical-align: top; }
.family-card-root .fc-table-stack td[data-label] { word-break: break-word; }
/* Mobile stacking */
@media (max-width: 576px) {
.family-card-root { font-size: .98rem; }
.family-card-root .fc-header { border-radius: .5rem .5rem 0 0; }
.family-card-root .fc-header .d-flex { flex-direction: column; align-items: flex-start !important; }
.family-card-root .fc-badges { width: 100%; }
.family-card-root .fc-badges .badge { width: 100%; text-align: left; }
.family-card-root .nav-tabs { gap: .25rem; }
.family-card-root .nav-tabs .nav-link { padding: .45rem .65rem; font-size: .9rem; }
.family-card-root .table-responsive { margin: 0 -0.5rem; padding: 0 .5rem; }
.family-card-root .fc-table-stack thead { display: none; }
.family-card-root .fc-table-stack tbody tr { display: block; border: 1px solid #e5e7eb; border-radius: .65rem; padding: .75rem; margin-bottom: .75rem; }
.family-card-root .fc-table-stack tbody tr:last-child { margin-bottom: 0; }
.family-card-root .fc-table-stack tbody td { display: block; width: 100%; border: 0 !important; padding: .15rem 0; }
.family-card-root .fc-table-stack tbody td[data-label]::before {
content: attr(data-label);
display: block;
font-size: .78rem;
text-transform: uppercase;
letter-spacing: .5px;
color: #6b7280;
margin-bottom: .05rem;
font-weight: 600;
}
}
</style>
<!-- Header strip -->
<div class="p-3 fc-header">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2">
<div class="me-3">
<div class="fw-semibold fc-title"><?= esc($title) ?></div>
</div>
<div class="d-flex flex-wrap gap-2 fc-badges">
<span class="badge">Guardians: <?= (int)$gCount ?></span>
<span class="badge">Students: <?= (int)$sCount ?></span>
<span class="badge">Invoices: <?= (int)($sum['invoices_count'] ?? 0) ?></span>
<span class="badge">
Balance: $<?= number_format((float)($sum['balance'] ?? 0), 2) ?>
</span>
</div>
</div>
</div>
<!-- Tabs -->
<ul class="nav nav-tabs small px-3 pt-2" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="fc-tab-overview" data-bs-toggle="tab" data-bs-target="#fc-overview" type="button" role="tab">Students</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="fc-tab-guardians" data-bs-toggle="tab" data-bs-target="#fc-guardians" type="button" role="tab">Parents/Guardians</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="fc-tab-ec" data-bs-toggle="tab" data-bs-target="#fc-ec" type="button" role="tab">Emergency</button>
</li>
<!--li class="nav-item" role="presentation">
<button class="nav-link" id="fc-tab-fin" data-bs-toggle="tab" data-bs-target="#fc-fin" type="button" role="tab">Financials</button>
</li-->
</ul>
<div class="tab-content">
<!-- Overview -->
<div class="tab-pane fade show active" id="fc-overview" role="tabpanel" aria-labelledby="fc-tab-overview">
<div class="p-3">
<div class="row g-3">
<div class="col-12">
<h6 class="mb-2">Students</h6>
<?php if (empty($f['students'])): ?>
<div class="text-muted small">No students linked.</div>
<?php else: ?>
<ul class="list-group">
<?php foreach ($f['students'] as $s): ?>
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<a href="#" class="text-decoration-none fc-name" data-family-student-id="<?= (int)($s['id'] ?? 0) ?>">
<?= esc(($s['firstname'] ?? '').' '.($s['lastname'] ?? '')) ?>
</a>
</div>
<?php if (!empty($s['grade'])): ?>
<span class="badge text-bg-secondary"><?= esc($s['grade']) ?></span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- Guardians -->
<div class="tab-pane fade" id="fc-guardians" role="tabpanel" aria-labelledby="fc-tab-guardians">
<div class="p-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Guardians</h6>
<span class="text-muted small">Total: <?= (int)$gCount ?></span>
</div>
<?php if (empty($f['guardians'])): ?>
<div class="alert alert-light border">No guardians yet.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm align-middle guardians-table fc-table-stack">
<thead class="table-light">
<tr>
<th style="min-width: 220px;">Guardian</th>
<th style="min-width: 220px;">Contact</th>
<th style="min-width: 260px;">Address</th>
</tr>
</thead>
<tbody>
<?php foreach ($f['guardians'] as $g): ?>
<tr>
<td data-label="Guardian">
<div>
<strong>
<a href="#" class="text-decoration-none fc-name" data-family-guardian-id="<?= (int)($g['user_id'] ?? 0) ?>">
<?= esc(($g['firstname'] ?? '').' '.($g['lastname'] ?? '')) ?>
</a>
</strong>
<?php if (!empty($g['is_primary'])): ?>
<span class="badge text-bg-primary ms-1"><i class="bi bi-star-fill"></i> Primary</span>
<?php endif; ?>
</div>
<?php
$relRaw = (string)($g['relation'] ?? '');
$rel = strtolower(trim($relRaw));
if ($rel === 'guardian') $relLabel = 'second parent';
elseif ($rel === 'primary') $relLabel = 'first parent';
else $relLabel = $relRaw;
?>
<div class="text-muted small">Relation: <?= esc($relLabel) ?></div>
</td>
<td class="small" data-label="Contact">
<div>
<i class="bi bi-envelope me-1 text-muted"></i>
<?php
$gEmail = trim((string)($g['email'] ?? ''));
$gName = trim((string)($g['firstname'] ?? '') . ' ' . (string)($g['lastname'] ?? ''));
$composeUrl = $gEmail !== ''
? site_url('family/compose-email?to=' . rawurlencode($gEmail) . '&name=' . rawurlencode($gName) . '&return_url=' . rawurlencode($returnUrl))
: '';
?>
<?= $gEmail !== '' ? ('<a href="' . esc($composeUrl) . '" target="_blank" rel="noopener">' . esc($gEmail) . '</a>') : '<span class="text-muted">—</span>' ?>
</div>
<div class="mt-1">
<i class="bi bi-telephone me-1 text-muted"></i>
<?= !empty($g['cellphone']) ? ('<a href="tel:'.esc($g['cellphone']).'">'.esc($g['cellphone']).'</a>') : '<span class="text-muted">—</span>' ?>
</div>
</td>
<td class="small" data-label="Address">
<i class="bi bi-geo-alt me-1 text-muted"></i>
<?php
$addrParts = array_filter([
$g['address_street'] ?? '',
trim(($g['city'] ?? '').' '.($g['state'] ?? '')),
$g['zip'] ?? ''
], fn($x)=>trim((string)$x) !== '');
?>
<?= esc(implode(', ', $addrParts) ?: '—') ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<!-- Emergency Contacts -->
<div class="tab-pane fade" id="fc-ec" role="tabpanel" aria-labelledby="fc-tab-ec">
<div class="p-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Emergency Contacts</h6>
<span class="text-muted small">Linked to parents/guardians</span>
</div>
<?php $ecs = $f['emergency_contacts'] ?? []; ?>
<?php if (empty($ecs)): ?>
<div class="alert alert-light border">No emergency contacts on file.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm table-striped table-hover align-middle fc-table-stack">
<thead class="table-light">
<tr>
<th>Parent</th>
<th>Contact Name</th>
<th>Relation</th>
<th>Phone</th>
<th>Email</th>
<th>Updated</th>
</tr>
</thead>
<tbody>
<?php foreach ($ecs as $ec): ?>
<tr>
<td data-label="Parent">
<?php $pid = (int)($ec['parent_id'] ?? 0); $pl = trim((string)($ec['parent_label'] ?? '')); ?>
<a href="#" class="text-decoration-none fc-name" data-family-guardian-id="<?= $pid ?>">
<?= esc($pl ?: ('Parent #'.$pid)) ?>
</a>
</td>
<td data-label="Contact Name"><span class="fc-name"><?= esc($ec['emergency_contact_name'] ?? '') ?></span></td>
<td data-label="Relation"><?= esc($ec['relation'] ?? '') ?></td>
<td data-label="Phone">
<?php $ph = trim((string)($ec['cellphone'] ?? '')); ?>
<?= $ph !== '' ? ('<a href="tel:'.esc($ph).'">'.esc($ph).'</a>') : '<span class="text-muted">—</span>' ?>
</td>
<td data-label="Email">
<?php $em = trim((string)($ec['email'] ?? '')); ?>
<?= $em !== '' ? ('<a href="mailto:'.esc($em).'">'.esc($em).'</a>') : '<span class="text-muted">—</span>' ?>
</td>
<td data-label="Updated">
<?php $ud = (string)($ec['updated_at'] ?? $ec['created_at'] ?? ''); ?>
<?= esc($ud ? local_date($ud, 'm-d-Y') : '—') ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<!-- Financials -->
<div class="tab-pane fade" id="fc-fin" role="tabpanel" aria-labelledby="fc-tab-fin">
<div class="p-3">
<div class="row g-3 mb-2">
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center bg-light">
<div class="text-muted small">Invoices</div>
<div class="fw-semibold"><?= (int)($sum['invoices_count'] ?? 0) ?></div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center bg-light">
<div class="text-muted small">Total</div>
<div class="fw-semibold">$<?= number_format((float)($sum['total_amount'] ?? 0), 2) ?></div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center bg-light">
<div class="text-muted small">Paid</div>
<div class="fw-semibold">$<?= number_format((float)($sum['paid_amount'] ?? 0), 2) ?></div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="border rounded p-2 text-center <?= ((float)($sum['balance'] ?? 0) > 0) ? 'bg-danger-subtle' : 'bg-success-subtle' ?>">
<div class="text-muted small">Balance</div>
<div class="fw-semibold">$<?= number_format((float)($sum['balance'] ?? 0), 2) ?></div>
</div>
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<h6 class="mb-2">Invoices</h6>
<?php if (empty($f['invoices'])): ?>
<div class="alert alert-light border">No invoices on record.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm table-striped table-hover align-middle fc-table-stack">
<thead class="table-light">
<tr>
<th>#</th><th>Status</th><th>Total</th><th>Paid</th><th>Balance</th><th>Date</th>
</tr>
</thead>
<tbody>
<?php foreach ($f['invoices'] as $iv): ?>
<tr>
<td data-label="Invoice"><?= esc($iv['invoice_number']) ?></td>
<td data-label="Status"><?= esc($iv['status']) ?></td>
<td data-label="Total">$<?= number_format((float)($iv['total_amount'] ?? 0), 2) ?></td>
<td data-label="Paid">$<?= number_format((float)($iv['paid_amount'] ?? 0), 2) ?></td>
<td data-label="Balance">$<?= number_format((float)($iv['balance'] ?? 0), 2) ?></td>
<td data-label="Date"><?= esc(!empty($iv['issue_date']) ? local_date($iv['issue_date'], 'm-d-Y') : '') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<div class="col-md-6">
<h6 class="mb-2">Recent Payments</h6>
<?php if (empty($f['payments'])): ?>
<div class="alert alert-light border">No payments on record.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm table-striped table-hover align-middle fc-table-stack">
<thead class="table-light">
<tr>
<th>Invoice</th><th>Amount</th><th>Balance</th><th>Method</th><th>Date</th><th>Status</th>
</tr>
</thead>
<tbody>
<?php $imap = $f['invoice_map'] ?? []; ?>
<?php foreach ($f['payments'] as $p): ?>
<tr>
<td data-label="Invoice"><?php $iid = (int)($p['invoice_id'] ?? 0); echo esc($imap[$iid] ?? ('#'.$iid)); ?></td>
<td data-label="Amount">$<?= number_format((float)($p['paid_amount'] ?? 0), 2) ?></td>
<td data-label="Balance">$<?= number_format((float)($p['balance'] ?? 0), 2) ?></td>
<td data-label="Method"><?= esc($p['payment_method'] ?? '') ?></td>
<td data-label="Date"><?= esc(!empty($p['payment_date']) ? local_date($p['payment_date'], 'm-d-Y') : '') ?></td>
<td data-label="Status"><?= esc($p['status'] ?? '') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
</div>