1.2
This commit is contained in:
parent
d63bd85799
commit
e6e98182ba
@ -1,4 +1,16 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Fetch existing courses
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT id, name FROM courses ORDER BY name");
|
||||
$courses = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
$courses = [];
|
||||
// Silently fail, the JS will handle the empty state
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@ -36,9 +48,33 @@
|
||||
<div class="card p-4">
|
||||
<h1 class="text-center mb-4">Enter Round Score</h1>
|
||||
|
||||
<div class="form-check form-switch mb-4 d-flex justify-content-center">
|
||||
<input class="form-check-input" type="checkbox" id="holesToggle">
|
||||
<label class="form-check-label ms-2" for="holesToggle">Toggle for 18 Holes (9 by default)</label>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="playerName" class="form-label">Player Name</label>
|
||||
<input type="text" class="form-control" id="playerName" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="teamName" class="form-label">Team Name (Optional)</label>
|
||||
<input type="text" class="form-control" id="teamName">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="courseSelect" class="form-label">Select Course</label>
|
||||
<select class="form-select" id="courseSelect">
|
||||
<option value="">-- Select a Course --</option>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<option value="<?php echo $course['id']; ?>"><?php echo htmlspecialchars($course['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 d-flex align-items-end justify-content-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="holesToggle">
|
||||
<label class="form-check-label ms-2" for="holesToggle">Play 18 Holes (9 by default)</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="scoreForm">
|
||||
@ -47,7 +83,9 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Hole</th>
|
||||
<th scope="col">Par</th>
|
||||
<th scope="col">Score</th>
|
||||
<th scope="col">Vs Par</th>
|
||||
<th scope="col">Putts</th>
|
||||
<th scope="col">Penalties</th>
|
||||
<th scope="col">Sand Lie</th>
|
||||
@ -68,6 +106,7 @@
|
||||
<div class="card totals-card bg-light p-3">
|
||||
<h4 class="text-center">Round Totals</h4>
|
||||
<div class="row text-center">
|
||||
<div class="col"><strong>To Par:</strong> <span id="totalToPar">E</span></div>
|
||||
<div class="col"><strong>Score:</strong> <span id="totalScore">0</span></div>
|
||||
<div class="col"><strong>Putts:</strong> <span id="totalPutts">0</span></div>
|
||||
<div class="col"><strong>Penalties:</strong> <span id="totalPenalties">0</span></div>
|
||||
|
||||
187
admin.php
Normal file
187
admin.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Handle form submission for adding a new course
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_course'])) {
|
||||
$courseName = trim($_POST['courseName']);
|
||||
$pars = [];
|
||||
$isValid = true;
|
||||
|
||||
if (empty($courseName)) {
|
||||
$error = "Course name is required.";
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
for ($i = 1; $i <= 18; $i++) {
|
||||
$par_value = filter_input(INPUT_POST, 'par_hole_' . $i, FILTER_VALIDATE_INT);
|
||||
if ($par_value === false || $par_value < 1 || $par_value > 7) {
|
||||
$error = "Invalid par value for hole " . $i . ". Please enter a number between 1 and 7.";
|
||||
$isValid = false;
|
||||
break;
|
||||
}
|
||||
$pars[] = $par_value;
|
||||
}
|
||||
|
||||
if ($isValid) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "INSERT INTO courses (name, par_hole_1, par_hole_2, par_hole_3, par_hole_4, par_hole_5, par_hole_6, par_hole_7, par_hole_8, par_hole_9, par_hole_10, par_hole_11, par_hole_12, par_hole_13, par_hole_14, par_hole_15, par_hole_16, par_hole_17, par_hole_18) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute(array_merge([$courseName], $pars));
|
||||
$_SESSION['success_message'] = "Course '{$courseName}' added successfully!";
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$error = "Database error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch existing courses
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT id, name FROM courses ORDER BY name");
|
||||
$courses = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
$courses = [];
|
||||
$error = "Could not fetch courses: " . $e->getMessage();
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Dashboard - Golf Tournament</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php">Golf Tournament</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="add_score.php">Add Score</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="admin.php">Admin</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="coach.php">Coach</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="results.php">Results</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-5">
|
||||
<h1 class="text-center mb-4">Admin Dashboard</h1>
|
||||
|
||||
<?php if (isset($error)): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
if (isset($_SESSION['success_message'])) {
|
||||
echo '<div class="alert alert-success">' . htmlspecialchars($_SESSION['success_message']) . '</div>';
|
||||
unset($_SESSION['success_message']);
|
||||
}
|
||||
?>
|
||||
|
||||
<ul class="nav nav-tabs" id="adminTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="courses-tab" data-bs-toggle="tab" data-bs-target="#courses" type="button" role="tab" aria-controls="courses" aria-selected="true">Manage Courses</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="teams-tab" data-bs-toggle="tab" data-bs-target="#teams" type="button" role="tab" aria-controls="teams" aria-selected="false">Manage Teams</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="players-tab" data-bs-toggle="tab" data-bs-target="#players" type="button" role="tab" aria-controls="players" aria-selected="false">Manage Players</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="adminTabContent">
|
||||
<!-- Courses Tab -->
|
||||
<div class="tab-pane fade show active" id="courses" role="tabpanel" aria-labelledby="courses-tab">
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Add New Course</h2>
|
||||
<form method="POST" action="admin.php">
|
||||
<div class="mb-3">
|
||||
<label for="courseName" class="form-label">Course Name</label>
|
||||
<input type="text" class="form-control" id="courseName" name="courseName" placeholder="e.g., Pebble Beach" required>
|
||||
</div>
|
||||
<div class="row">
|
||||
<?php for ($i = 1; $i <= 18; $i++): ?>
|
||||
<div class="col-md-2 col-sm-4 mb-3">
|
||||
<label for="par_hole_<?php echo $i; ?>" class="form-label">Hole <?php echo $i; ?> Par</label>
|
||||
<input type="number" class="form-control" id="par_hole_<?php echo $i; ?>" name="par_hole_<?php echo $i; ?>" min="1" max="7" value="4" required>
|
||||
</div>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
<button type="submit" name="add_course" class="btn btn-primary">Add Course</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Existing Courses</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Course Name</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($courses)): ?>
|
||||
<tr><td colspan="2">No courses found.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($course['name']); ?></td>
|
||||
<td><button class="btn btn-sm btn-danger">Delete</button></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Teams Tab -->
|
||||
<div class="tab-pane fade" id="teams" role="tabpanel" aria-labelledby="teams-tab">
|
||||
...
|
||||
</div>
|
||||
|
||||
<!-- Players Tab -->
|
||||
<div class="tab-pane fade" id="players" role="tabpanel" aria-labelledby="players-tab">
|
||||
...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-light text-center text-lg-start mt-5">
|
||||
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.05);">
|
||||
© 2025 Golf Tournament
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
30
api/get_course_pars.php
Normal file
30
api/get_course_pars.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
if (!isset($_GET['course_id'])) {
|
||||
echo json_encode(['error' => 'Course ID is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$courseId = filter_input(INPUT_GET, 'course_id', FILTER_VALIDATE_INT);
|
||||
|
||||
if ($courseId === false) {
|
||||
echo json_encode(['error' => 'Invalid Course ID.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT * FROM courses WHERE id = ?");
|
||||
$stmt->execute([$courseId]);
|
||||
$course = $stmt->fetch();
|
||||
|
||||
if ($course) {
|
||||
echo json_encode($course);
|
||||
} else {
|
||||
echo json_encode(['error' => 'Course not found.']);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
|
||||
}
|
||||
@ -1,16 +1,19 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const holesToggle = document.getElementById('holesToggle');
|
||||
const scoreTable = document.getElementById('scoreTable');
|
||||
const form = document.getElementById('scoreForm');
|
||||
const courseSelect = document.getElementById('courseSelect');
|
||||
|
||||
if (!holesToggle || !scoreTable || !form) return;
|
||||
if (!holesToggle || !scoreTable || !form || !courseSelect) return;
|
||||
|
||||
let coursePars = null;
|
||||
|
||||
const updateTotal = () => {
|
||||
let totalScore = 0;
|
||||
let totalPutts = 0;
|
||||
let totalPenalties = 0;
|
||||
let totalSandLies = 0;
|
||||
let totalToPar = 0;
|
||||
|
||||
const holes = holesToggle.checked ? 18 : 9;
|
||||
|
||||
@ -24,12 +27,56 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
totalPutts += putts;
|
||||
totalPenalties += penalties;
|
||||
if (sandLie) totalSandLies++;
|
||||
|
||||
if (coursePars && score > 0) {
|
||||
const par = coursePars[`par_hole_${i}`];
|
||||
totalToPar += score - par;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('totalScore').textContent = totalScore;
|
||||
document.getElementById('totalPutts').textContent = totalPutts;
|
||||
document.getElementById('totalPenalties').textContent = totalPenalties;
|
||||
document.getElementById('totalSandLies').textContent = totalSandLies;
|
||||
|
||||
const toParElement = document.getElementById('totalToPar');
|
||||
if (totalToPar > 0) {
|
||||
toParElement.textContent = `+${totalToPar}`;
|
||||
toParElement.classList.add('text-danger');
|
||||
toParElement.classList.remove('text-success');
|
||||
} else if (totalToPar < 0) {
|
||||
toParElement.textContent = totalToPar;
|
||||
toParElement.classList.add('text-success');
|
||||
toParElement.classList.remove('text-danger');
|
||||
} else {
|
||||
toParElement.textContent = 'E';
|
||||
toParElement.classList.remove('text-danger', 'text-success');
|
||||
}
|
||||
};
|
||||
|
||||
const updateVsPar = (holeNumber) => {
|
||||
if (!coursePars) return;
|
||||
const scoreInput = document.getElementById(`hole${holeNumber}_score`);
|
||||
const score = parseInt(scoreInput.value) || 0;
|
||||
const vsParCell = document.getElementById(`hole${holeNumber}_vs_par`);
|
||||
|
||||
if (score > 0) {
|
||||
const par = coursePars[`par_hole_${holeNumber}`];
|
||||
const diff = score - par;
|
||||
if (diff > 0) {
|
||||
vsParCell.textContent = `+${diff}`;
|
||||
vsParCell.className = 'text-danger fw-bold';
|
||||
} else if (diff < 0) {
|
||||
vsParCell.textContent = diff;
|
||||
vsParCell.className = 'text-success fw-bold';
|
||||
} else {
|
||||
vsParCell.textContent = 'E';
|
||||
vsParCell.className = 'text-muted';
|
||||
}
|
||||
} else {
|
||||
vsParCell.textContent = '-';
|
||||
vsParCell.className = '';
|
||||
}
|
||||
};
|
||||
|
||||
const renderTable = () => {
|
||||
@ -37,13 +84,16 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
let html = '';
|
||||
for (let i = 1; i <= 18; i++) {
|
||||
const hidden = i > holes ? ' style="display: none;"' : '';
|
||||
const parValue = coursePars ? coursePars[`par_hole_${i}`] : '-';
|
||||
html += `
|
||||
<tr id="hole_row_${i}" ${hidden}>
|
||||
<th scope="row">${i}</th>
|
||||
<td><input type="number" class="form-control" id="hole${i}_score" min="1"></td>
|
||||
<td><input type="number" class="form-control" id="hole${i}_putts" min="0"></td>
|
||||
<td><input type="number" class="form-control" id="hole${i}_penalties" min="0"></td>
|
||||
<td><div class="form-check form-switch"><input class="form-check-input" type="checkbox" id="hole${i}_sand"></div></td>
|
||||
<td id="hole${i}_par">${parValue}</td>
|
||||
<td><input type="number" class="form-control" id="hole${i}_score" min="1" disabled></td>
|
||||
<td id="hole${i}_vs_par">-</td>
|
||||
<td><input type="number" class="form-control" id="hole${i}_putts" min="0" disabled></td>
|
||||
<td><input type="number" class="form-control" id="hole${i}_penalties" min="0" disabled></td>
|
||||
<td><div class="form-check form-switch"><input class="form-check-input" type="checkbox" id="hole${i}_sand" disabled></div></td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
@ -52,11 +102,59 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
};
|
||||
|
||||
const attachInputListeners = () => {
|
||||
form.querySelectorAll('input').forEach(input => {
|
||||
form.querySelectorAll('input[type="number"]').forEach(input => {
|
||||
input.addEventListener('input', () => {
|
||||
const holeNumber = input.id.match(/\d+/)[0];
|
||||
updateVsPar(holeNumber);
|
||||
updateTotal();
|
||||
});
|
||||
});
|
||||
form.querySelectorAll('input[type="checkbox"]').forEach(input => {
|
||||
input.addEventListener('input', updateTotal);
|
||||
});
|
||||
};
|
||||
|
||||
const toggleInputs = (disabled) => {
|
||||
form.querySelectorAll('input').forEach(input => {
|
||||
if(input.id !== 'holesToggle') {
|
||||
input.disabled = disabled;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
courseSelect.addEventListener('change', async () => {
|
||||
const courseId = courseSelect.value;
|
||||
if (courseId) {
|
||||
try {
|
||||
const response = await fetch(`api/get_course_pars.php?course_id=${courseId}`);
|
||||
if(response.ok) {
|
||||
coursePars = await response.json();
|
||||
if(coursePars.error) {
|
||||
console.error(coursePars.error);
|
||||
coursePars = null;
|
||||
toggleInputs(true);
|
||||
} else {
|
||||
renderTable();
|
||||
toggleInputs(false);
|
||||
}
|
||||
} else {
|
||||
console.error('Failed to fetch par data');
|
||||
coursePars = null;
|
||||
toggleInputs(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching par data:', error);
|
||||
coursePars = null;
|
||||
toggleInputs(true);
|
||||
}
|
||||
} else {
|
||||
coursePars = null;
|
||||
renderTable();
|
||||
toggleInputs(true);
|
||||
}
|
||||
updateTotal();
|
||||
});
|
||||
|
||||
holesToggle.addEventListener('change', () => {
|
||||
const holes = holesToggle.checked ? 18 : 9;
|
||||
for (let i = 1; i <= 18; i++) {
|
||||
@ -68,16 +166,61 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
updateTotal();
|
||||
});
|
||||
|
||||
form.addEventListener('submit', function(e) {
|
||||
form.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
const successToast = document.getElementById('successToast');
|
||||
if (successToast) {
|
||||
const toast = new bootstrap.Toast(successToast);
|
||||
toast.show();
|
||||
|
||||
const playerName = document.getElementById('playerName').value;
|
||||
if (!playerName) {
|
||||
alert('Player name is required.');
|
||||
return;
|
||||
}
|
||||
|
||||
const holes = holesToggle.checked ? 18 : 9;
|
||||
const scores = {};
|
||||
for (let i = 1; i <= holes; i++) {
|
||||
scores[`hole${i}_score`] = parseInt(document.getElementById(`hole${i}_score`).value) || 0;
|
||||
}
|
||||
|
||||
const data = {
|
||||
playerName: playerName,
|
||||
teamName: document.getElementById('teamName').value,
|
||||
courseId: courseSelect.value,
|
||||
holes: holes,
|
||||
scores: scores,
|
||||
totalScore: parseInt(document.getElementById('totalScore').textContent) || 0,
|
||||
totalToPar: document.getElementById('totalToPar').textContent || 'E',
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('submit_score.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
const successToast = document.getElementById('successToast');
|
||||
if (successToast) {
|
||||
const toast = new bootstrap.Toast(successToast);
|
||||
toast.show();
|
||||
}
|
||||
form.reset();
|
||||
courseSelect.value = '';
|
||||
coursePars = null;
|
||||
renderTable();
|
||||
toggleInputs(true);
|
||||
updateTotal();
|
||||
} else {
|
||||
alert(`Error: ${result.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Submission error:', error);
|
||||
alert('An error occurred while submitting the score.');
|
||||
}
|
||||
form.reset();
|
||||
renderTable();
|
||||
updateTotal();
|
||||
});
|
||||
|
||||
renderTable();
|
||||
|
||||
106
coach.php
Normal file
106
coach.php
Normal file
@ -0,0 +1,106 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Coach Dashboard - Golf Tournament</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php">Golf Tournament</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="add_score.php">Add Score</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="admin.php">Admin</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="coach.php">Coach</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="results.php">Results</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-5">
|
||||
<h1 class="text-center mb-4">Coach's Dashboard</h1>
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Team: Sharks</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Player</th>
|
||||
<th>Last Round Score</th>
|
||||
<th>Handicap</th>
|
||||
<th>View History</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Jane Smith</td>
|
||||
<td>85</td>
|
||||
<td>12</td>
|
||||
<td><a href="#" class="btn btn-sm btn-primary">View Details</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mike Johnson</td>
|
||||
<td>92</td>
|
||||
<td>18</td>
|
||||
<td><a href="#" class="btn btn-sm btn-primary">View Details</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Team: Bears</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Player</th>
|
||||
<th>Last Round Score</th>
|
||||
<th>Handicap</th>
|
||||
<th>View History</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Peter Jones</td>
|
||||
<td>88</td>
|
||||
<td>14</td>
|
||||
<td><a href="#" class="btn btn-sm btn-primary">View Details</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-light text-center text-lg-start mt-5">
|
||||
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.05);">
|
||||
© 2025 Golf Tournament
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
68
db/setup.php
Normal file
68
db/setup.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS courses (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
par_hole_1 INT NOT NULL,
|
||||
par_hole_2 INT NOT NULL,
|
||||
par_hole_3 INT NOT NULL,
|
||||
par_hole_4 INT NOT NULL,
|
||||
par_hole_5 INT NOT NULL,
|
||||
par_hole_6 INT NOT NULL,
|
||||
par_hole_7 INT NOT NULL,
|
||||
par_hole_8 INT NOT NULL,
|
||||
par_hole_9 INT NOT NULL,
|
||||
par_hole_10 INT NOT NULL,
|
||||
par_hole_11 INT NOT NULL,
|
||||
par_hole_12 INT NOT NULL,
|
||||
par_hole_13 INT NOT NULL,
|
||||
par_hole_14 INT NOT NULL,
|
||||
par_hole_15 INT NOT NULL,
|
||||
par_hole_16 INT NOT NULL,
|
||||
par_hole_17 INT NOT NULL,
|
||||
par_hole_18 INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
");
|
||||
echo "Table 'courses' created successfully or already exists.<br>";
|
||||
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS scores (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
player_name VARCHAR(255) NOT NULL,
|
||||
team_name VARCHAR(255),
|
||||
course_id INT NOT NULL,
|
||||
holes_played INT NOT NULL DEFAULT 9,
|
||||
hole_1_score INT,
|
||||
hole_2_score INT,
|
||||
hole_3_score INT,
|
||||
hole_4_score INT,
|
||||
hole_5_score INT,
|
||||
hole_6_score INT,
|
||||
hole_7_score INT,
|
||||
hole_8_score INT,
|
||||
hole_9_score INT,
|
||||
hole_10_score INT,
|
||||
hole_11_score INT,
|
||||
hole_12_score INT,
|
||||
hole_13_score INT,
|
||||
hole_14_score INT,
|
||||
hole_15_score INT,
|
||||
hole_16_score INT,
|
||||
hole_17_score INT,
|
||||
hole_18_score INT,
|
||||
total_score INT,
|
||||
total_to_par INT,
|
||||
played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (course_id) REFERENCES courses(id)
|
||||
)
|
||||
");
|
||||
echo "Table 'scores' created successfully or already exists.<br>";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("DB ERROR: " . $e->getMessage());
|
||||
}
|
||||
48
index.php
48
index.php
@ -22,9 +22,9 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="#">GolfTracker</a>
|
||||
<a class="navbar-brand" href="index.php">GolfTracker</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
@ -36,6 +36,15 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="add_score.php">Enter Score</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="results.php">Results</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="coach.php">Coach</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="admin.php">Admin</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,6 +80,41 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="py-5 bg-light">
|
||||
<div class="container">
|
||||
<h2 class="text-center mb-4">Interfaces for Every Role</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Admin</h5>
|
||||
<p class="card-text">Manage courses, teams, and players.</p>
|
||||
<a href="admin.php" class="btn btn-primary">Go to Admin</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Coach</h5>
|
||||
<p class="card-text">View player scores and team progress.</p>
|
||||
<a href="coach.php" class="btn btn-primary">Go to Coach</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Viewer</h5>
|
||||
<p class="card-text">See live tournament leaderboards.</p>
|
||||
<a href="results.php" class="btn btn-primary">View Results</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="py-4 bg-light text-center">
|
||||
<div class="container">
|
||||
<p class="mb-0">© <?php echo date("Y"); ?> GolfTracker. All Rights Reserved.</p>
|
||||
|
||||
97
player.php
Normal file
97
player.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
$playerName = $_GET['player'] ?? null;
|
||||
|
||||
if (!$playerName) {
|
||||
header("Location: results.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$rounds = [];
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT s.*, c.name as course_name
|
||||
FROM scores s
|
||||
JOIN courses c ON s.course_id = c.id
|
||||
WHERE s.player_name = :player_name
|
||||
ORDER BY s.played_at DESC
|
||||
");
|
||||
$stmt->execute([':player_name' => $playerName]);
|
||||
$rounds = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
// Handle DB error
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Player Stats - <?php echo htmlspecialchars($playerName); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php">Golf Tournament</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="add_score.php">Add Score</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="results.php">Results</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-5">
|
||||
<h1 class="mb-4">Stats for <?php echo htmlspecialchars($playerName); ?></h1>
|
||||
|
||||
<?php if (empty($rounds)): ?>
|
||||
<div class="alert alert-warning">No rounds found for this player.</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($rounds as $round): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5><?php echo htmlspecialchars($round['course_name']); ?> - <?php echo date("M d, Y", strtotime($round['played_at'])); ?></h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hole</th>
|
||||
<?php for ($i = 1; $i <= $round['holes_played']; $i++): ?>
|
||||
<th><?php echo $i; ?></th>
|
||||
<?php endfor; ?>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Score</td>
|
||||
<?php for ($i = 1; $i <= $round['holes_played']; $i++): ?>
|
||||
<td><?php echo $round["hole_{$i}_score"]; ?></td>
|
||||
<?php endfor; ?>
|
||||
<td><?php echo $round['total_score']; ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<footer class="bg-light text-center text-lg-start mt-5">
|
||||
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.05);">
|
||||
© 2025 Golf Tournament
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
146
results.php
Normal file
146
results.php
Normal file
@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Live Results - Golf Tournament</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php">Golf Tournament</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="add_score.php">Add Score</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="admin.php">Admin</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="coach.php">Coach</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="results.php">Results</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-5">
|
||||
<h1 class="text-center mb-4">Tournament Leaderboard</h1>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Individual Standings</h2>
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("
|
||||
SELECT player_name, team_name, SUM(total_score) as total_score, SUM(total_to_par) as total_to_par
|
||||
FROM scores
|
||||
GROUP BY player_name, team_name
|
||||
ORDER BY total_to_par ASC
|
||||
");
|
||||
$results = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
$results = [];
|
||||
}
|
||||
?>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Player</th>
|
||||
<th>Team</th>
|
||||
<th>Total Score</th>
|
||||
<th>To Par</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($results)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">No results yet.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($results as $index => $row): ?>
|
||||
<tr>
|
||||
<td><?php echo $index + 1; ?></td>
|
||||
<td><a href="player.php?player=<?php echo urlencode($row['player_name']); ?>"><?php echo htmlspecialchars($row['player_name']); ?></a></td>
|
||||
<td><?php echo htmlspecialchars($row['team_name']); ?></td>
|
||||
<td><?php echo $row['total_score']; ?></td>
|
||||
<td><?php echo ($row['total_to_par'] > 0 ? '+' : '') . $row['total_to_par']; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Team Standings</h2>
|
||||
<?php
|
||||
try {
|
||||
$stmt = $pdo->query("
|
||||
SELECT team_name, SUM(total_score) as total_score
|
||||
FROM scores
|
||||
WHERE team_name IS NOT NULL AND team_name != ''
|
||||
GROUP BY team_name
|
||||
ORDER BY total_score ASC
|
||||
");
|
||||
$team_results = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
$team_results = [];
|
||||
}
|
||||
?>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Team</th>
|
||||
<th>Total Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($team_results)): ?>
|
||||
<tr>
|
||||
<td colspan="3" class="text-center">No team results yet.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($team_results as $index => $row): ?>
|
||||
<tr>
|
||||
<td><?php echo $index + 1; ?></td>
|
||||
<td><?php echo htmlspecialchars($row['team_name']); ?></td>
|
||||
<td><?php echo $row['total_score']; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-light text-center text-lg-start mt-5">
|
||||
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.05);">
|
||||
© 2025 Golf Tournament
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
56
submit_score.php
Normal file
56
submit_score.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method Not Allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (!$data) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid data']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$required_fields = ['playerName', 'courseId', 'holes', 'scores'];
|
||||
foreach ($required_fields as $field) {
|
||||
if (empty($data[$field])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => "Missing required field: {$field}"]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$sql = "INSERT INTO scores (player_name, team_name, course_id, holes_played, total_score, total_to_par";
|
||||
$params = [
|
||||
':player_name' => $data['playerName'],
|
||||
':team_name' => $data['teamName'] ?? null,
|
||||
':course_id' => $data['courseId'],
|
||||
':holes_played' => $data['holes'],
|
||||
':total_score' => $data['totalScore'],
|
||||
':total_to_par' => $data['totalToPar']
|
||||
];
|
||||
|
||||
for ($i = 1; $i <= $data['holes']; $i++) {
|
||||
$sql .= ", hole_{$i}_score";
|
||||
$params[":hole_{$i}_score"] = $data['scores']["hole{$i}_score"] ?? null;
|
||||
}
|
||||
|
||||
$sql .= ") VALUES (" . implode(', ', array_keys($params)) . ")";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
http_response_code(201);
|
||||
echo json_encode(['success' => 'Score submitted successfully']);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user