Publier Globinours 1.0.0-rc.3
This commit is contained in:
parent
ea8c24d622
commit
9a2b4068da
325 changed files with 38230 additions and 20 deletions
314
app/Views/admin_grants.php
Normal file
314
app/Views/admin_grants.php
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
<?php $money = static fn ($v) => number_format((float)$v, 2, ',', ' ') . ' €';
|
||||
$date = static fn ($v) => $v ? (new DateTimeImmutable($v))->format('d/m/Y') : '—'; ?>
|
||||
<?php if ($saved): ?><div class="alert alert-success"><?= h(t('grant.saved')) ?></div><?php endif; ?>
|
||||
<?php if ($error): ?><div class="alert alert-danger"><?= h(t('grant.save_error')) ?></div><?php endif; ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body d-flex flex-wrap align-items-end gap-3">
|
||||
<form method="get" action="/admin/grants" class="d-flex align-items-end gap-2">
|
||||
<div><label class="form-label"><?= h(t('grant.file_year')) ?></label><select class="form-select"
|
||||
name="year"><?php for ($y = (int)date('Y') + 1;$y >= (int)date('Y') - 10;$y--): ?><option
|
||||
value="<?= $y ?>" <?= $y === $year ? 'selected' : '' ?>><?= $y ?></option>
|
||||
<?php endfor; ?></select></div><button class="btn btn-primary"><?= h(t('common.show')) ?></button>
|
||||
</form>
|
||||
<div class="ms-auto d-flex gap-2"><a class="btn btn-outline-secondary"
|
||||
href="/admin/register?year=<?= $year ?>"><?= h(t('grant.register', ['year' => $year])) ?></a><a
|
||||
class="btn btn-dark" target="_blank" href="/admin/grants/print?year=<?= $year ?>">🖨
|
||||
<?= h(t('grant.print_report')) ?></a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row row-cards mb-4">
|
||||
<?php foreach ([[t('grant.entries'),$stats['entries'],'green'],[t('grant.exits'),$stats['exits'],'red'],[t('grant.adoptions'),$stats['adoptions'],'blue'],[t('grant.deaths'),$stats['deaths'],'dark'],[t('grant.births'),$stats['births'],'purple'],[t('grant.vaccinations'),$stats['vaccinations'],'cyan'],[t('grant.treatments'),$stats['treatments'],'orange'],[t('grant.current'),$stats['current'],'azure']] as [$label,$value,$color]): ?>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-status-top bg-<?= $color ?>"></div>
|
||||
<div class="card-body">
|
||||
<div class="text-muted small text-uppercase"><?= h($label) ?></div>
|
||||
<div class="display-6 fw-bold"><?= (int)$value ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div><?php endforeach; ?>
|
||||
</div>
|
||||
<div class="alert alert-info"><?= h(t('grant.indicators_help', ['year' => $year])) ?> <?= h(t('grant.avg_adoption')) ?>
|
||||
: <strong><?= $stats['avg'] > 0 ? h(t('common.days', ['count' => round($stats['avg'])])) : '—' ?></strong>.</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<h3 class="card-title"><?= h(t('grant.comparison', ['year' => $year - 1])) ?></h3>
|
||||
<div class="text-muted small"><?= h(t('grant.comparison_help')) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= h(t('grant.indicator')) ?></th>
|
||||
<th class="text-end"><?= $year - 1 ?></th>
|
||||
<th class="text-end"><?= $year ?></th>
|
||||
<th class="text-end"><?= h(t('grant.evolution')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach (['entries' => t('grant.entries'),'exits' => t('grant.exits'),'adoptions' => t('grant.adoptions'),'deaths' => t('grant.deaths'),'births' => t('grant.births'),'vaccinations' => t('grant.vaccinations'),'treatments' => t('grant.treatments'),'avg' => t('grant.avg_adoption')] as $key => $label): $c = $comparison[$key]; ?>
|
||||
<tr>
|
||||
<td><?= h($label) ?></td>
|
||||
<td class="text-end"><?= (int)round($c['previous']) ?></td>
|
||||
<td class="text-end fw-bold"><?= (int)round($c['current']) ?></td>
|
||||
<td class="text-end"><span
|
||||
class="badge <?= $c['difference'] > 0 ? 'bg-blue-lt' : ($c['difference'] < 0 ? 'bg-orange-lt' : 'bg-secondary-lt') ?>"><?= $c['difference'] > 0 ? '+' : '' ?><?= (int)round($c['difference']) ?><?= $c['percent'] !== null ? ' · ' . ($c['percent'] > 0 ? '+' : '') . number_format($c['percent'], 1, ',', ' ') . ' %' : '' ?></span>
|
||||
</td>
|
||||
</tr><?php endforeach; ?></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$detailGroups = [
|
||||
[t('grant.sex_entries'),$details['sex'],[]],
|
||||
[t('grant.age_entry'),$details['ages'],[]],
|
||||
[t('grant.origins'),$details['origins'],[]],
|
||||
[t('grant.death_causes'),$details['deathCauses'],array_combine(array_keys(DeathController::CAUSES), array_map(static fn ($key) => DeathController::causeLabel($key), array_keys(DeathController::CAUSES)))],
|
||||
[t('grant.adoption_stay'),$details['stays'],[]],
|
||||
];
|
||||
?>
|
||||
<div class="row row-cards mb-4">
|
||||
<?php foreach ($detailGroups as [$groupTitle,$items,$labels]): $maximum = $items ? max($items) : 0; ?><div
|
||||
class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><?= h($groupTitle) ?></h3>
|
||||
</div>
|
||||
<div class="card-body"><?php if (!$items): ?><div class="text-muted">
|
||||
<?= h(t('grant.no_data_year', ['year' => $year])) ?></div><?php else: ?><div class="vstack gap-3"><?php foreach ($items as $label => $total): $display = $labels[$label] ?? $label;
|
||||
$width = $maximum > 0 ? max(5, round($total / $maximum * 100)) : 0; ?><div>
|
||||
<div class="d-flex justify-content-between gap-3 mb-1">
|
||||
<span><?= h($display) ?></span><strong><?= (int)$total ?></strong></div>
|
||||
<div class="progress progress-sm">
|
||||
<div class="progress-bar bg-primary" style="width:<?= $width ?>%" role="progressbar"
|
||||
aria-label="<?= h($display) ?>"></div>
|
||||
</div>
|
||||
</div><?php endforeach; ?></div><?php endif; ?></div>
|
||||
</div>
|
||||
</div><?php endforeach; ?></div>
|
||||
|
||||
<form method="post" action="/admin/grants/save" class="card mb-4"><input type="hidden" name="csrf"
|
||||
value="<?= h(Auth::csrf()) ?>"><input type="hidden" name="year" value="<?= $year ?>">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><?= h(t('grant.annual_report', ['year' => $year])) ?></h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-6 col-lg-3"><label class="form-label"><?= h(t('grant.members')) ?></label><input
|
||||
class="form-control" type="number" min="0" name="members_count"
|
||||
value="<?= (int)$annual['members_count'] ?>"></div>
|
||||
<div class="col-sm-6 col-lg-3"><label class="form-label"><?= h(t('grant.volunteers')) ?></label><input
|
||||
class="form-control" type="number" min="0" name="volunteers_count"
|
||||
value="<?= (int)$annual['volunteers_count'] ?>"></div>
|
||||
<div class="col-sm-6 col-lg-3"><label class="form-label"><?= h(t('grant.employees')) ?></label><input
|
||||
class="form-control" type="number" min="0" name="employees_count"
|
||||
value="<?= (int)$annual['employees_count'] ?>"></div>
|
||||
<div class="col-sm-6 col-lg-3"><label class="form-label"><?= h(t('grant.employee_fte')) ?></label><input
|
||||
class="form-control" type="number" min="0" step="0.01" name="employees_fte"
|
||||
value="<?= h($annual['employees_fte']) ?>"></div>
|
||||
<div class="col-md-4"><label class="form-label"><?= h(t('grant.last_ag')) ?></label><input
|
||||
class="form-control" type="date" lang="fr" name="last_ag_date"
|
||||
value="<?= h($annual['last_ag_date']) ?>"></div>
|
||||
<div class="col-md-8"><label class="form-label"><?= h(t('grant.beneficiaries')) ?></label><input
|
||||
class="form-control" name="beneficiaries" value="<?= h($annual['beneficiaries']) ?>"
|
||||
placeholder="<?= h(t('grant.beneficiaries_placeholder')) ?>"></div>
|
||||
<?php foreach (['annual_report' => t('grant.activity_summary'),'completed_actions' => t('grant.completed_actions'),'planned_actions' => t('grant.planned_actions'),'officers_notes' => t('grant.officers'),'in_kind_support' => t('grant.in_kind')] as $field => $label): ?>
|
||||
<div class="col-md-6"><label class="form-label"><?= h($label) ?></label><textarea class="form-control"
|
||||
rows="4" name="<?= $field ?>"><?= h($annual[$field]) ?></textarea></div><?php endforeach; ?>
|
||||
</div>
|
||||
<hr>
|
||||
<h3 class="mb-3"><?= h(t('grant.financial_summary')) ?></h3>
|
||||
<div class="row g-3">
|
||||
<?php foreach (['actual_expenses' => t('grant.actual_expenses'),'actual_income' => t('grant.actual_income'),'forecast_expenses' => t('grant.forecast_expenses'),'forecast_income' => t('grant.forecast_income'),'treasury_amount' => t('grant.treasury'),'voluntary_contributions' => t('grant.voluntary')] as $field => $label): ?>
|
||||
<div class="col-sm-6 col-lg-4"><label class="form-label"><?= h($label) ?></label>
|
||||
<div class="input-group"><input class="form-control" inputmode="decimal" name="<?= $field ?>"
|
||||
value="<?= h((string)$annual[$field]) ?>"><span class="input-group-text">€</span></div>
|
||||
</div><?php endforeach; ?></div>
|
||||
</div>
|
||||
<div class="card-footer text-end"><button class="btn btn-primary"><?= h(t('grant.save_report')) ?></button></div>
|
||||
</form>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><?= h(t('grant.applications')) ?></h3>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= h(t('grant.organization')) ?></th>
|
||||
<th><?= h(t('grant.deadline')) ?></th>
|
||||
<th><?= h(t('grant.requested')) ?></th>
|
||||
<th><?= h(t('grant.previous_aid')) ?></th>
|
||||
<th><?= h(t('grant.decision')) ?></th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><?php if (!$applications): ?><tr>
|
||||
<td colspan="6" class="text-muted text-center py-4">
|
||||
<?= h(t('grant.no_application', ['year' => $year])) ?></td>
|
||||
</tr><?php endif; ?><?php foreach ($applications as $a): ?><tr>
|
||||
<td class="fw-bold"><?= h($a['organization_name']) ?></td>
|
||||
<td><?= $date($a['deadline']) ?></td>
|
||||
<td><?= $money($a['requested_amount']) ?></td>
|
||||
<td><?= $money($a['previous_amount']) ?></td>
|
||||
<td>
|
||||
<form method="post" action="/admin/grants/application" class="d-flex flex-wrap gap-1"><input
|
||||
type="hidden" name="csrf" value="<?= h(Auth::csrf()) ?>"><input type="hidden"
|
||||
name="year" value="<?= $year ?>"><input type="hidden" name="application_id"
|
||||
value="<?= (int)$a['id'] ?>"><select class="form-select form-select-sm" name="status"
|
||||
style="width:auto"><?php foreach (GrantService::STATUSES as $key => $label): ?><option
|
||||
value="<?= h($key) ?>" <?= $a['status'] === $key ? 'selected' : '' ?>>
|
||||
<?= h(GrantService::statusLabel($key)) ?></option><?php endforeach; ?></select>
|
||||
<div class="input-group input-group-sm" style="width:130px"><input class="form-control"
|
||||
inputmode="decimal" name="awarded_amount"
|
||||
value="<?= h((string)($a['awarded_amount'] ?? '')) ?>"
|
||||
placeholder="<?= h(t('grant.awarded')) ?>"><span class="input-group-text">€</span>
|
||||
</div><button class="btn btn-outline-primary btn-sm">OK</button>
|
||||
</form>
|
||||
</td>
|
||||
<td class="text-muted"><?= nl2br(h($a['notes'])) ?></td>
|
||||
</tr><?php endforeach; ?></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-body border-top">
|
||||
<form method="post" action="/admin/grants/application" class="row g-3"><input type="hidden" name="csrf"
|
||||
value="<?= h(Auth::csrf()) ?>"><input type="hidden" name="year" value="<?= $year ?>">
|
||||
<div class="col-md-4"><label class="form-label"><?= h(t('grant.organization_required')) ?></label><input
|
||||
required class="form-control" name="organization_name"></div>
|
||||
<div class="col-md-2"><label class="form-label"><?= h(t('grant.deadline')) ?></label><input
|
||||
class="form-control" type="date" lang="fr" name="deadline"></div>
|
||||
<div class="col-md-2"><label class="form-label"><?= h(t('grant.requested_amount')) ?></label><input
|
||||
class="form-control" inputmode="decimal" name="requested_amount"></div>
|
||||
<div class="col-md-2"><label class="form-label"><?= h(t('grant.previous_aid')) ?></label><input
|
||||
class="form-control" inputmode="decimal" name="previous_amount"></div>
|
||||
<div class="col-md-2"><label class="form-label"><?= h(t('grant.state')) ?></label><select
|
||||
class="form-select" name="status"><?php foreach (GrantService::STATUSES as $key => $label): ?>
|
||||
<option value="<?= h($key) ?>"><?= h($label) ?></option><?php endforeach; ?></select></div>
|
||||
<div class="col-md-10"><label class="form-label"><?= h(t('grant.notes')) ?></label><input
|
||||
class="form-control" name="notes"></div>
|
||||
<div class="col-md-2 d-flex align-items-end"><button
|
||||
class="btn btn-primary w-100"><?= h(t('common.add')) ?></button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<h3 class="card-title"><?= h(t('grant.checklist')) ?></h3>
|
||||
<div class="text-muted small"><?= h(t('grant.checklist_help')) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row row-cards"><?php if (!$applications): ?><div class="text-muted"><?= h(t('grant.add_first')) ?>
|
||||
</div>
|
||||
<?php endif; ?><?php foreach ($applications as $application): $check = $checklist[(int)$application['id']] ?? ['items' => [],'valid' => 0,'total' => count(GrantService::REQUIRED),'complete' => false]; ?>
|
||||
<div class="col-lg-6">
|
||||
<div class="card h-100 <?= $check['complete'] ? 'border-success' : 'border-warning' ?>">
|
||||
<div class="card-status-top <?= $check['complete'] ? 'bg-green' : 'bg-orange' ?>"></div>
|
||||
<div class="card-header">
|
||||
<div class="me-auto">
|
||||
<h3 class="card-title mb-1"><?= h($application['organization_name']) ?></h3>
|
||||
<div class="text-muted small">
|
||||
<?= h(t('grant.valid_parts', ['valid' => (int)$check['valid'],'total' => (int)$check['total']])) ?>
|
||||
</div>
|
||||
</div><span
|
||||
class="badge <?= $check['complete'] ? 'bg-green-lt' : 'bg-orange-lt' ?>"><?= $check['complete'] ? t('grant.complete') : t('grant.incomplete') ?></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2"><?php foreach ($check['items'] as $category => $item): $state = $item['state'];
|
||||
$meta = match($state) {
|
||||
'valid' => ['✓','bg-green-lt',t('grant.valid')],'expiring' => ['⌛','bg-yellow-lt',t('grant.expiring')],'expired' => ['!','bg-red-lt',t('grant.expired')],default => ['×','bg-secondary-lt',t('grant.missing')]
|
||||
}; ?><div class="col-sm-6">
|
||||
<div class="d-flex align-items-center gap-2 py-1"><span class="badge <?= $meta[1] ?>"
|
||||
title="<?= h($meta[2]) ?>"><?= $meta[0] ?></span><span
|
||||
class="small"><?= h(GrantService::categoryLabel($category)) ?></span></div>
|
||||
</div><?php endforeach; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div><?php endforeach; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<h3 class="card-title"><?= h(t('grant.vault')) ?></h3>
|
||||
<div class="text-muted small"><?= h(t('grant.vault_help')) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3 mb-4"><?php foreach ($documents as $d): ?><div class="col-md-6 col-lg-4"><a
|
||||
class="card card-link h-100" target="_blank" href="/admin/grants/document?id=<?= (int)$d['id'] ?>">
|
||||
<div class="card-body">
|
||||
<div class="d-flex gap-3"><span
|
||||
class="avatar bg-purple-lt"><?= strtoupper(pathinfo($d['original_name'], PATHINFO_EXTENSION)) ?></span>
|
||||
<div>
|
||||
<div class="fw-bold"><?= h($d['title']) ?></div>
|
||||
<div class="text-muted small"><?= h(GrantService::categoryLabel($d['category'])) ?> ·
|
||||
<?= $d['year'] ?: t('grant.permanent') ?></div><?php if ($d['application_name']): ?>
|
||||
<div class="small text-blue">
|
||||
<?= h(t('grant.folder', ['name' => $d['application_name']])) ?></div><?php endif; ?><?php if ($d['valid_until']): $expired = $d['valid_until'] < date('Y-m-d');
|
||||
$expiring = !$expired && $d['valid_until'] <= date('Y-m-d', strtotime('+30 days')); ?><div
|
||||
class="small mt-1 <?= $expired ? 'text-danger fw-bold' : ($expiring ? 'text-warning' : '') ?>">
|
||||
<?= $expired ? t('grant.expired_on') : t('grant.valid_until') ?>
|
||||
<?= $date($d['valid_until']) ?></div><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div><?php endforeach; ?><?php if (!$documents): ?><div class="text-muted">
|
||||
<?= h(t('grant.no_document')) ?></div><?php endif; ?></div>
|
||||
<form method="post" action="/admin/grants/document" enctype="multipart/form-data"
|
||||
class="row g-3 border-top pt-3"><input type="hidden" name="csrf" value="<?= h(Auth::csrf()) ?>"><input
|
||||
type="hidden" name="year" value="<?= $year ?>">
|
||||
<div class="col-md-3"><label class="form-label"><?= h(t('grant.category')) ?></label><select
|
||||
class="form-select" name="category"
|
||||
id="grantDocumentCategory"><?php foreach (GrantService::CATEGORIES as $key => $label): ?><option
|
||||
value="<?= h($key) ?>"><?= h(GrantService::categoryLabel($key)) ?></option>
|
||||
<?php endforeach; ?></select></div>
|
||||
<div class="col-md-3"><label class="form-label"><?= h(t('grant.related_folder')) ?></label><select
|
||||
class="form-select" name="application_id" id="grantDocumentApplication">
|
||||
<option value=""><?= h(t('grant.common_part')) ?></option>
|
||||
<?php foreach ($applications as $application): ?><option value="<?= (int)$application['id'] ?>">
|
||||
<?= h($application['organization_name']) ?></option><?php endforeach; ?>
|
||||
</select></div>
|
||||
<div class="col-md-3"><label class="form-label"><?= h(t('grant.document_title')) ?></label><input
|
||||
class="form-control" name="title"></div>
|
||||
<div class="col-md-3"><label class="form-label"><?= h(t('grant.pdf_odt')) ?></label><input required
|
||||
class="form-control" type="file" name="document"
|
||||
accept=".pdf,.odt,application/pdf,application/vnd.oasis.opendocument.text"></div>
|
||||
<div class="col-md-3"><label class="form-label"><?= h(t('grant.valid_until')) ?></label><input
|
||||
class="form-control" type="date" lang="fr" name="valid_until"></div>
|
||||
<div class="col-md-6 d-flex align-items-end"><label class="form-check mb-2"><input class="form-check-input"
|
||||
type="checkbox" name="global_document" value="1" id="grantDocumentGlobal"><span
|
||||
class="form-check-label"><?= h(t('grant.permanent_document')) ?></span></label></div>
|
||||
<div class="col-md-3 d-flex align-items-end"><button
|
||||
class="btn btn-primary w-100"><?= h(t('grant.add_document')) ?></button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const category = document.getElementById('grantDocumentCategory'),
|
||||
application = document.getElementById('grantDocumentApplication'),
|
||||
global = document.getElementById('grantDocumentGlobal');
|
||||
const sync = () => {
|
||||
const official = category?.value === 'official_form';
|
||||
if (application) application.required = official;
|
||||
if (global) {
|
||||
global.disabled = official || Boolean(application?.value);
|
||||
if (global.disabled) global.checked = false;
|
||||
}
|
||||
};
|
||||
category?.addEventListener('change', sync);
|
||||
application?.addEventListener('change', sync);
|
||||
sync();
|
||||
});
|
||||
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue