recreate project

This commit is contained in:
root
2026-02-10 22:11:06 -05:00
commit 663c0cdbda
10149 changed files with 1379710 additions and 0 deletions
@@ -0,0 +1,157 @@
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container mt-4">
<?php $isEdit = ($mode ?? 'create') === 'edit'; ?>
<?php $isLocked = $isEdit && !empty($competition['is_locked']); ?>
<?php $lockedAttr = $isLocked ? 'disabled' : ''; ?>
<h3><?= esc($isEdit ? 'Edit Competition' : 'Create Competition') ?></h3>
<?php if ($isLocked): ?>
<div class="alert alert-warning">This competition is locked. Unlock it to make changes.</div>
<?php endif; ?>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<ul class="mb-0">
<?php foreach ($errors as $e): ?><li><?= esc($e) ?></li><?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<form method="post" action="<?= $isEdit ? '/admin/competition-winners/' . $competition['id'] . '/update' : '/admin/competition-winners/store' ?>" class="row g-3">
<?= csrf_field() ?>
<div class="col-md-8">
<label class="form-label">Title *</label>
<input class="form-control" name="title" value="<?= esc(old('title', $competition['title'] ?? '')) ?>" required <?= $lockedAttr ?>>
</div>
<div class="col-md-6">
<label class="form-label">Class Section (optional)</label>
<?php $oldSection = (string) old('class_section_id', (string) ($competition['class_section_id'] ?? '')); ?>
<select class="form-select" name="class_section_id" <?= $lockedAttr ?>>
<option value="">All classes</option>
<?php foreach ($classSections as $section): ?>
<?php
$value = (string) ($section['class_section_id'] ?? '');
$label = $section['class_section_name'] ?? $value;
$selected = $value !== '' && $value === $oldSection ? 'selected' : '';
?>
<option value="<?= esc($value) ?>" <?= $selected ?>><?= esc($label) ?></option>
<?php endforeach; ?>
</select>
<div class="form-text">Leave empty to manage winners for all classes.</div>
</div>
<div class="col-md-3">
<label class="form-label">Semester</label>
<input class="form-control" name="semester" value="<?= esc(old('semester', $competition['semester'] ?? $defaultSemester ?? '')) ?>" <?= $lockedAttr ?>>
</div>
<div class="col-md-3">
<label class="form-label">School Year</label>
<input class="form-control" name="school_year" value="<?= esc(old('school_year', $competition['school_year'] ?? $defaultSchoolYear ?? '')) ?>" placeholder="2025-2026" <?= $lockedAttr ?>>
<div class="form-text">Counts use the school year above.</div>
</div>
<div class="col-md-4">
<label class="form-label">Start Date</label>
<input class="form-control" name="start_date" type="date" value="<?= esc(old('start_date', $competition['start_date'] ?? '')) ?>" <?= $lockedAttr ?>>
</div>
<div class="col-md-4">
<label class="form-label">End Date</label>
<input class="form-control" name="end_date" type="date" value="<?= esc(old('end_date', $competition['end_date'] ?? '')) ?>" <?= $lockedAttr ?>>
</div>
<div class="col-12">
<h5 class="mt-2">Winners per Class</h5>
<div class="table-responsive">
<table class="table table-bordered table-sm" data-no-mgmt-sticky>
<thead class="table-light">
<tr>
<th>Class</th>
<th style="width:140px;">Students</th>
<th style="width:140px;">Auto Winners</th>
<th style="width:150px;">Questions</th>
<th style="width:120px;">1st</th>
<th style="width:120px;">2nd</th>
<th style="width:120px;">3rd</th>
<th style="width:120px;">4th</th>
<th style="width:120px;">5th</th>
<th style="width:120px;">6th</th>
<th style="width:160px;">Override</th>
<th style="width:140px;">Final Winners</th>
</tr>
</thead>
<tbody>
<?php foreach ($classRows as $row): ?>
<tr>
<td><?= esc($row['class_section_name']) ?></td>
<td><?= esc($row['student_count']) ?></td>
<td><?= esc($row['auto_winners']) ?></td>
<td>
<input class="form-control form-control-sm" type="number" min="1"
name="question_counts[<?= esc($row['class_section_id']) ?>]"
value="<?= esc($row['question_count'] ?? '') ?>"
placeholder="Questions" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" step="0.01" min="0"
name="prizes[<?= esc($row['class_section_id']) ?>][1]"
value="<?= esc($row['prize_1'] ?? '') ?>"
placeholder="$" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" step="0.01" min="0"
name="prizes[<?= esc($row['class_section_id']) ?>][2]"
value="<?= esc($row['prize_2'] ?? '') ?>"
placeholder="$" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" step="0.01" min="0"
name="prizes[<?= esc($row['class_section_id']) ?>][3]"
value="<?= esc($row['prize_3'] ?? '') ?>"
placeholder="$" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" step="0.01" min="0"
name="prizes[<?= esc($row['class_section_id']) ?>][4]"
value="<?= esc($row['prize_4'] ?? '') ?>"
placeholder="$" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" step="0.01" min="0"
name="prizes[<?= esc($row['class_section_id']) ?>][5]"
value="<?= esc($row['prize_5'] ?? '') ?>"
placeholder="$" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" step="0.01" min="0"
name="prizes[<?= esc($row['class_section_id']) ?>][6]"
value="<?= esc($row['prize_6'] ?? '') ?>"
placeholder="$" <?= $lockedAttr ?>>
</td>
<td>
<input class="form-control form-control-sm" type="number" min="1"
name="winner_overrides[<?= esc($row['class_section_id']) ?>]"
value="<?= esc($row['override_winners'] ?? '') ?>"
placeholder="Auto" <?= $lockedAttr ?>>
</td>
<td><?= esc($row['final_winners']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary" <?= $lockedAttr ?>><?= esc($isEdit ? 'Update' : 'Create') ?></button>
<a class="btn btn-outline-secondary" href="/admin/competition-winners">Cancel</a>
</div>
</form>
</div>
<?= $this->endSection() ?>
@@ -0,0 +1,70 @@
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="mb-0">Competition Winners</h3>
<a class="btn btn-primary" href="/admin/competition-winners/create">+ New Competition</a>
</div>
<?php if (session('success')): ?>
<div class="alert alert-success"><?= esc(session('success')) ?></div>
<?php endif; ?>
<?php if (session('error')): ?>
<div class="alert alert-danger"><?= esc(session('error')) ?></div>
<?php endif; ?>
<table class="table table-bordered table-sm" data-no-mgmt-sticky>
<thead class="table-light">
<tr>
<th>ID</th>
<th>Title</th>
<th>Class Section</th>
<th>Winners Rule</th>
<th>Published</th>
<th>Locked</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($competitions as $c): ?>
<?php
$sectionId = (int) ($c['class_section_id'] ?? 0);
$sectionName = $sectionId > 0 ? ($sectionMap[$sectionId] ?? $sectionId) : 'All';
$isLocked = !empty($c['is_locked']);
?>
<tr>
<td><?= esc($c['id']) ?></td>
<td><?= esc($c['title']) ?></td>
<td><?= esc($sectionName) ?></td>
<td>Tiered per class</td>
<td><?= $c['is_published'] ? 'Yes' : 'No' ?></td>
<td><?= $isLocked ? 'Yes' : 'No' ?></td>
<td>
<a class="btn btn-sm btn-outline-secondary" href="/admin/competition-winners/<?= $c['id'] ?>/settings">Settings</a>
<a class="btn btn-sm btn-outline-primary" href="/admin/competition-winners/<?= $c['id'] ?>">Enter Scores</a>
<a class="btn btn-sm btn-outline-secondary" href="/admin/competition-winners/<?= $c['id'] ?>/preview">Preview</a>
<a class="btn btn-sm btn-outline-secondary" href="/admin/competition-winners/<?= $c['id'] ?>/winners">Winners</a>
<form method="post" action="/admin/competition-winners/<?= $c['id'] ?>/export-quiz" class="d-inline">
<?= csrf_field() ?>
<button class="btn btn-sm btn-outline-success" type="submit">Export Scores to Quiz</button>
</form>
<?php if ($isLocked): ?>
<form method="post" action="/admin/competition-winners/<?= $c['id'] ?>/unlock" class="d-inline">
<?= csrf_field() ?>
<button class="btn btn-sm btn-outline-warning" type="submit" onclick="return confirm('Unlock this competition to allow edits?')">Unlock</button>
</form>
<?php else: ?>
<form method="post" action="/admin/competition-winners/<?= $c['id'] ?>/lock" class="d-inline">
<?= csrf_field() ?>
<button class="btn btn-sm btn-outline-danger" type="submit" onclick="return confirm('Lock this competition to prevent edits?')">Lock</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?= $this->endSection() ?>
@@ -0,0 +1,86 @@
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="mb-0">Preview Winners</h3>
<div class="d-flex gap-2">
<a class="btn btn-outline-secondary" href="/admin/competition-winners/<?= $competition['id'] ?>">Edit Scores</a>
<a class="btn btn-outline-secondary" href="/admin/competition-winners/<?= $competition['id'] ?>/settings">Settings</a>
<a class="btn btn-outline-secondary" href="/admin/competition-winners">Back</a>
</div>
</div>
<div class="mb-3">
<div><strong>Competition:</strong> <?= esc($competition['title']) ?></div>
<div><strong>School Year:</strong> <?= esc($competition['school_year'] ?? '-') ?></div>
</div>
<?php if (empty($rankedByClass)): ?>
<div class="alert alert-warning">No scores entered yet.</div>
<?php else: ?>
<?php foreach ($rankedByClass as $classId => $rows): ?>
<?php
$classLabel = $classMap[$classId] ?? ('Class ' . $classId);
$topRows = $topByClass[$classId] ?? [];
$winnerPrizeByStudent = [];
foreach ($topRows as $winnerRow) {
$studentId = $winnerRow['student_id'] ?? null;
if ($studentId !== null) {
$winnerPrizeByStudent[(int) $studentId] = $winnerRow['prize_amount'] ?? null;
}
}
$studentCount = $classCounts[$classId] ?? count($rows);
$override = $overrideMap[$classId] ?? null;
$questions = $questionCounts[$classId] ?? null;
$prizes = $prizeMap[$classId] ?? [];
$finalWinners = $winnersCountByClass[$classId] ?? 0;
?>
<h5 class="mt-4">Top Winners - <?= esc($classLabel) ?></h5>
<div class="text-muted mb-2">
Students: <?= esc($studentCount) ?> | Questions: <?= esc($questions ?? '-') ?> | Override: <?= esc($override ?? '-') ?> | Final Winners: <?= esc($finalWinners) ?>
</div>
<table class="table table-bordered table-sm" data-no-mgmt-sticky>
<thead class="table-light">
<tr><th>Rank</th><th>Student</th><th>Score</th><th>Prize</th></tr>
</thead>
<tbody>
<?php foreach ($topRows as $row): ?>
<tr>
<td><?= esc($row['rank']) ?></td>
<td><?= esc($row['name']) ?></td>
<td><?= esc($row['score']) ?></td>
<td><?= esc(!empty($row['prize_amount']) ? $row['prize_amount'] : '-') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h6>All Ranked Scores - <?= esc($classLabel) ?></h6>
<table class="table table-striped table-sm" data-no-mgmt-sticky>
<thead><tr><th>#</th><th>Student</th><th>Score</th><th>Prize</th></tr></thead>
<tbody>
<?php $i = 1; foreach ($rows as $row): ?>
<?php
$studentId = (int) ($row['student_id'] ?? 0);
$prizeVal = $winnerPrizeByStudent[$studentId] ?? null;
?>
<tr>
<td><?= $i++ ?></td>
<td><?= esc($row['name']) ?></td>
<td><?= esc($row['score']) ?></td>
<td><?= esc(!empty($prizeVal) ? $prizeVal : '-') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endforeach; ?>
<?php endif; ?>
<form method="post" action="/admin/competition-winners/<?= $competition['id'] ?>/publish" class="mt-3">
<?= csrf_field() ?>
<button class="btn btn-success">Publish Winners</button>
</form>
</div>
<?= $this->endSection() ?>
@@ -0,0 +1,135 @@
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="mb-0">Enter Scores</h3>
<a class="btn btn-outline-secondary" href="/admin/competition-winners">Back</a>
</div>
<?php $isLocked = !empty($competition['is_locked']); ?>
<?php $lockedAttr = $isLocked ? 'disabled' : ''; ?>
<?php if ($isLocked): ?>
<div class="alert alert-warning">This competition is locked. Unlock it to update scores.</div>
<?php endif; ?>
<div class="mb-3">
<div><strong>Competition:</strong> <?= esc($competition['title']) ?></div>
<?php if (!empty($classSectionName)): ?>
<div><strong>Class Section:</strong> <?= esc($classSectionName) ?></div>
<div>
<strong>Students:</strong> <?= esc($classStudentCount ?? 0) ?> |
<strong>Auto Winners:</strong> <?= esc($classAutoWinners ?? 0) ?> |
<strong>Override:</strong> <?= esc($classOverrideWinners ?? '-') ?> |
<strong>Final Winners:</strong> <?= esc($classFinalWinners ?? 0) ?> |
<strong>Questions:</strong> <?= esc($classQuestionCount ?? '-') ?>
</div>
<?php endif; ?>
</div>
<?php if (!$classSelectionLocked): ?>
<form method="get" class="row g-2 align-items-end mb-3">
<div class="col-md-6">
<label class="form-label">Select Class Section</label>
<select class="form-select" name="class_section_id" onchange="this.form.submit()" <?= $lockedAttr ?>>
<option value="">Choose a class</option>
<?php foreach ($classSections as $section): ?>
<?php
$value = (string) ($section['class_section_id'] ?? '');
$label = $section['class_section_name'] ?? $value;
$selected = $value !== '' && (int) $value === (int) $activeClassSectionId ? 'selected' : '';
?>
<option value="<?= esc($value) ?>" <?= $selected ?>><?= esc($label) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<div class="form-text">Pick a class to load its students for score entry.</div>
</div>
</form>
<?php endif; ?>
<?php if (session('success')): ?>
<div class="alert alert-success"><?= esc(session('success')) ?></div>
<?php endif; ?>
<form method="post" action="/admin/competition-winners/<?= $competition['id'] ?>/scores">
<?= csrf_field() ?>
<input type="hidden" name="class_section_id" value="<?= esc($activeClassSectionId ?? '') ?>">
<?php if (empty($activeClassSectionId)): ?>
<div class="alert alert-warning">Select a class section to load students.</div>
<?php else: ?>
<link rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-2.1.8/r-3.0.3/datatables.min.css">
<?php $scoreMax = ($classQuestionCount !== null && (int) $classQuestionCount > 0) ? (int) $classQuestionCount : null; ?>
<table class="table table-bordered table-sm" data-no-mgmt-sticky id="scoresTable">
<thead class="table-light">
<tr>
<th style="width:140px;">School ID</th>
<th>Student</th>
<th style="width:180px;">
Score<?= $scoreMax !== null ? ' (max ' . esc($scoreMax) . ')' : '' ?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($students as $s):
$name = trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
$studentId = $s['id'] ?? $s['student_id'] ?? null;
$schoolId = $s['school_id'] ?? null;
$val = $studentId !== null ? ($scoreMap[$studentId] ?? '') : '';
?>
<tr>
<td><?= esc($schoolId ?: $studentId) ?></td>
<td><?= esc($name !== '' ? $name : ('Student #' . $studentId)) ?></td>
<td data-order="<?= esc($val) ?>">
<input class="form-control form-control-sm"
name="scores[<?= esc($studentId) ?>]"
type="number" step="0.01" min="0"
value="<?= esc($val) ?>"
<?= $scoreMax !== null ? 'max="' . esc($scoreMax) . '"' : '' ?>
<?= $lockedAttr ?>>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<div class="d-flex gap-2">
<button class="btn btn-primary" <?= $lockedAttr ?>>Save Scores</button>
<a class="btn btn-outline-secondary" href="/admin/competition-winners/<?= $competition['id'] ?>/preview">Preview Winners</a>
</div>
</form>
</div>
<script src="https://cdn.datatables.net/v/bs5/dt-2.1.8/r-3.0.3/datatables.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const tableEl = document.getElementById('scoresTable');
if (!tableEl) {
return;
}
new DataTable(tableEl, {
responsive: true,
paging: false,
searching: false,
info: false,
order: [[1, 'asc']],
});
tableEl.addEventListener('input', function (event) {
const target = event.target;
if (target && target.matches('input')) {
const cell = target.closest('td');
if (cell) {
cell.setAttribute('data-order', target.value.trim());
}
}
});
});
</script>
<?= $this->endSection() ?>
@@ -0,0 +1,110 @@
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="mb-0">School Winners</h3>
<div class="d-flex gap-2">
<a class="btn btn-outline-secondary" href="/admin/competition-winners/<?= $competition['id'] ?>/preview">Preview</a>
<a class="btn btn-outline-secondary" href="/admin/competition-winners">Back</a>
</div>
</div>
<div class="mb-3">
<div><strong>Competition:</strong> <?= esc($competition['title']) ?></div>
<div><strong>School Year:</strong> <?= esc($competition['school_year'] ?? '-') ?></div>
<div><strong>Published:</strong> <?= !empty($competition['is_published']) ? 'Yes' : 'No' ?></div>
</div>
<?php
$palette = [
['bg' => '#fde2c2', 'hover' => '#f8c996'],
['bg' => '#cfe6ff', 'hover' => '#b5d6ff'],
['bg' => '#c9f2e7', 'hover' => '#a6e6d4'],
['bg' => '#f7c8c7', 'hover' => '#f1a6a3'],
['bg' => '#fff1a8', 'hover' => '#ffe38a'],
['bg' => '#e4c7f2', 'hover' => '#d1a9e8'],
['bg' => '#d6d9de', 'hover' => '#c2c8cf'],
['bg' => '#c9efc5', 'hover' => '#aee3a9'],
];
$paletteCount = count($palette);
?>
<style>
<?php foreach ($palette as $index => $colors): ?>
.class-color-<?= $index ?> td { background-color: <?= $colors['bg'] ?>; }
.class-color-<?= $index ?>:hover td { background-color: <?= $colors['hover'] ?>; }
<?php endforeach; ?>
</style>
<?php if (empty($rows)): ?>
<div class="alert alert-warning">No published winners yet. Publish winners to see the list.</div>
<?php else: ?>
<table class="table table-bordered table-sm" data-no-mgmt-sticky>
<thead class="table-light">
<tr>
<th>Class</th>
<th>School ID</th>
<th>Student</th>
<th>Photo Consent</th>
<th>Rank</th>
<th>Score</th>
<th>Prize</th>
</tr>
</thead>
<tbody>
<?php $totalPrize = 0.0; ?>
<?php foreach ($rows as $row): ?>
<?php
$classId = (int) ($row['class_section_id'] ?? 0);
$classLabel = $row['class_section_name'] ?? ($classMap[$classId] ?? ('Class ' . $classId));
$name = trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? ''));
$studentLabel = $name !== '' ? $name : ('Student #' . ($row['student_id'] ?? ''));
$colorIndex = $paletteCount > 0 ? ($classId % $paletteCount) : 0;
$questionCount = $questionCounts[$classId] ?? null;
$scoreValue = $row['score'] ?? null;
$scoreLabel = '-';
$prizeValue = null;
$photoConsentLabel = '-';
if (array_key_exists('photo_consent', $row)) {
$photoConsentLabel = ((int) $row['photo_consent'] === 1) ? 'Yes' : 'No';
}
if (isset($row['prize_amount']) && $row['prize_amount'] !== '' && is_numeric($row['prize_amount'])) {
$prizeValue = (float) $row['prize_amount'];
$totalPrize += $prizeValue;
}
if ($scoreValue !== null && $scoreValue !== '' && is_numeric($scoreValue)) {
$scoreDisplay = number_format((float) $scoreValue, 0, '.', '');
$scoreLabel = $scoreDisplay;
if ($questionCount !== null) {
$scoreLabel = $scoreDisplay . '/' . $questionCount;
}
}
?>
<tr class="class-color-<?= esc((string) $colorIndex) ?>">
<td><?= esc($classLabel) ?></td>
<td><?= esc($row['school_id'] ?? $row['student_id'] ?? '-') ?></td>
<td><?= esc($studentLabel) ?></td>
<td><?= esc($photoConsentLabel) ?></td>
<td><?= esc($row['rank'] ?? '-') ?></td>
<td><?= esc($scoreLabel) ?></td>
<td><?= esc($prizeValue !== null ? $prizeValue : '-') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<th colspan="6" class="text-end">Total Prizes</th>
<th><?= esc(number_format($totalPrize, 2, '.', '')) ?></th>
</tr>
</tfoot>
</table>
<div class="d-flex justify-content-end mt-3">
<a class="btn btn-primary external-link" href="/admin/competition-winners/<?= $competition['id'] ?>/recognition-pdf" target="_blank" rel="noopener">
Generate Recognition PDF
</a>
</div>
<?php endif; ?>
</div>
<?= $this->endSection() ?>