Compare commits

...

8 Commits

Author SHA1 Message Date
Flatlogic Bot
0f8fd03d51 1.3 2025-09-24 21:22:36 +00:00
Flatlogic Bot
6424a2c0f6 1.3 2025-09-24 19:44:13 +00:00
Flatlogic Bot
354c764c97 1.3 2025-09-24 18:59:48 +00:00
Flatlogic Bot
1268ae0578 1.2 2025-09-24 18:20:56 +00:00
Flatlogic Bot
3cef421e69 1.2 2025-09-24 14:03:58 +00:00
Flatlogic Bot
6915e64858 1.2 2025-09-24 13:52:45 +00:00
Flatlogic Bot
e6e98182ba 1.2 2025-09-24 13:47:38 +00:00
Flatlogic Bot
d63bd85799 1.0 2025-09-24 12:46:41 +00:00
21 changed files with 2043 additions and 126 deletions

46
add_player.php Normal file
View File

@ -0,0 +1,46 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$team_id = $_POST['team_id'];
$player_name = trim($_POST['player_name']);
$player_email = trim($_POST['player_email']);
$high_school_year = trim($_POST['high_school_year']);
$season_year = trim($_POST['season_year']);
if (!empty($player_name) && !empty($player_email) && !empty($team_id)) {
try {
$pdo = db();
// Check if player already exists
$stmt = $pdo->prepare("SELECT id FROM players WHERE email = ?");
$stmt->execute([$player_email]);
$player = $stmt->fetch();
if ($player) {
$player_id = $player['id'];
} else {
// Insert new player
$stmt = $pdo->prepare("INSERT INTO players (name, email, high_school_year, season_year, team_id) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$player_name, $player_email, $high_school_year, $season_year, $team_id]);
$player_id = $pdo->lastInsertId();
}
// Update player's team_id if they already existed but weren't assigned to this team
$stmt = $pdo->prepare("UPDATE players SET team_id = ? WHERE id = ?");
$stmt->execute([$team_id, $player_id]);
$_SESSION['success_message'] = 'Player added successfully!';
} catch (PDOException $e) {
$_SESSION['error_message'] = 'Error adding player: ' . $e->getMessage();
}
}
header('Location: coach.php');
exit;
}
?>

153
add_score.php Normal file
View File

@ -0,0 +1,153 @@
<?php
require_once 'db/config.php';
$courses = [];
$players = [];
try {
$pdo = db();
$stmt = $pdo->query("SELECT id, name FROM courses ORDER BY name");
$courses = $stmt->fetchAll();
$stmt = $pdo->query("SELECT p.id, p.team_id, p.name AS player_name, t.name AS team_name FROM players p JOIN teams t ON p.team_id = t.id ORDER BY team_name, player_name");
$players = $stmt->fetchAll();
} catch (PDOException $e) {
// If something goes wrong, we'll have empty arrays.
// For debugging, you might want to log the error:
// error_log($e->getMessage());
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Enter Golf Score</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<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>
<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 active" href="add_score.php">Enter Score</a>
</li>
</ul>
</div>
</div>
</nav>
<main class="container my-5">
<div class="card p-4">
<h1 class="text-center mb-4">Enter Round Score</h1>
<div class="row mb-3">
<div class="col-md-6">
<label for="playerSelect" class="form-label">Select Player</label>
<select class="form-select" id="playerSelect" required>
<option value="">-- Select a Player --</option>
<?php
$current_team = null;
foreach ($players as $player):
if ($player['team_name'] !== $current_team):
if ($current_team !== null):
echo '</optgroup>';
endif;
$current_team = $player['team_name'];
echo '<optgroup label="' . htmlspecialchars($current_team) . '">';
endif;
?>
<option value="<?php echo $player['id']; ?>" data-team-id="<?php echo $player['team_id']; ?>"><?php echo htmlspecialchars($player['player_name']); ?></option>
<?php endforeach;
if ($current_team !== null):
echo '</optgroup>';
endif;
?>
</select>
</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">
<div class="table-responsive">
<table class="table table-hover">
<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>
</tr>
</thead>
<tbody id="scoreTable">
<!-- JS will render rows here -->
</tbody>
</table>
</div>
<div class="text-center mt-4">
<button type="submit" class="btn btn-primary btn-lg">Submit Score</button>
</div>
</form>
</div>
</main>
<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>
<div class="col"><strong>Sand Lies:</strong> <span id="totalSandLies">0</span></div>
</div>
</div>
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header text-white" style="background-color: #0D47A1;">
<strong class="me-auto">Success</strong>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
Score submitted successfully.
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

305
admin.php Normal file
View File

@ -0,0 +1,305 @@
<?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']);
$hole_count = filter_input(INPUT_POST, 'hole_count', FILTER_VALIDATE_INT);
$tournament_date = $_POST['tournament_date'];
$pars = [];
$isValid = true;
if (empty($courseName)) {
$error = "Course name is required.";
$isValid = false;
}
if (empty($tournament_date)) {
$tournament_date = null;
}
if ($isValid) {
for ($i = 1; $i <= 18; $i++) {
if ($hole_count == 9 && $i > 9) {
$pars[] = 0;
} else {
$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, hole_count, tournament_date, 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);
$params = array_merge([$courseName, $hole_count, $tournament_date], $pars);
$stmt->execute($params);
$_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, hole_count, tournament_date FROM courses ORDER BY name");
$courses = $stmt->fetchAll();
} catch (PDOException $e) {
$courses = [];
$error = "Could not fetch courses: " . $e->getMessage();
}
// Fetch players with their team names
try {
$pdo = db();
$stmt = $pdo->query("
SELECT p.id, p.name, p.email, p.high_school_year, p.season_year, t.name as team_name
FROM players p
LEFT JOIN teams t ON p.team_id = t.id
ORDER BY p.name
");
$players = $stmt->fetchAll();
} catch (PDOException $e) {
$players = [];
$error = "Could not fetch players: " . $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">
<div class="col-md-6 mb-3">
<label for="hole_count" class="form-label">Number of Holes</label>
<select class="form-select" id="hole_count" name="hole_count">
<option value="9">9 Holes</option>
<option value="18" selected>18 Holes</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="tournament_date" class="form-label">Tournament Date</label>
<input type="date" class="form-control" id="tournament_date" name="tournament_date">
</div>
</div>
<h5 class="mt-3">Par Values</h5>
<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>Holes</th>
<th>Tournament Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php if (empty($courses)): ?>
<tr><td colspan="4">No courses found.</td></tr>
<?php else: ?>
<?php foreach ($courses as $course): ?>
<tr>
<td><?php echo htmlspecialchars($course['name']); ?></td>
<td><?php echo htmlspecialchars($course['hole_count']); ?></td>
<td><?php echo htmlspecialchars($course['tournament_date'] ? date('M j, Y', strtotime($course['tournament_date'])) : 'N/A'); ?></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 class="card shadow-sm mt-4">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="card-title mb-0">Manage Players</h2>
<a href="add_player.php" class="btn btn-primary">Add New Player</a>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>High School Year</th>
<th>Season Year</th>
<th>Team</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($players)): ?>
<tr><td colspan="6">No players found.</td></tr>
<?php else: ?>
<?php foreach ($players as $player): ?>
<tr>
<td><?php echo htmlspecialchars($player['name']); ?></td>
<td><?php echo htmlspecialchars($player['email']); ?></td>
<td><?php echo htmlspecialchars($player['high_school_year']); ?></td>
<td><?php echo htmlspecialchars($player['season_year']); ?></td>
<td><?php echo htmlspecialchars($player['team_name'] ?? 'N/A'); ?></td>
<td>
<a href="edit_player.php?id=<?php echo $player['id']; ?>" class="btn btn-sm btn-warning">Edit</a>
<a href="delete_player.php?id=<?php echo $player['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this player?');">Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</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>
<script>
document.addEventListener('DOMContentLoaded', function () {
const holeCountSelect = document.getElementById('hole_count');
function toggleParHoles() {
const selectedHoles = parseInt(holeCountSelect.value, 10);
for (let i = 1; i <= 18; i++) {
const holeInput = document.getElementById('par_hole_' + i);
const holeInputDiv = holeInput.parentElement;
if (i > 9) {
if (selectedHoles === 9) {
holeInputDiv.style.display = 'none';
holeInput.value = 0;
holeInput.required = false;
holeInput.min = 0;
} else {
holeInputDiv.style.display = '';
if (holeInput.value == 0) { // Only reset if it was 0
holeInput.value = 4; // reset to default
}
holeInput.required = true;
holeInput.min = 1;
}
}
}
}
holeCountSelect.addEventListener('change', toggleParHoles);
// Initial check on page load
toggleParHoles();
});
</script>
</body>
</html>

30
api/get_course_pars.php Normal file
View 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()]);
}

47
assets/css/custom.css Normal file
View File

@ -0,0 +1,47 @@
body {
font-family: 'Roboto', sans-serif;
background-color: #F5F5F5;
}
.navbar-brand {
font-weight: 700;
color: #0D47A1 !important;
}
.btn-primary {
background-color: #0D47A1;
border-color: #0D47A1;
}
.btn-primary:hover {
background-color: #0a3a82;
border-color: #0a3a82;
}
.btn-danger {
background-color: #D32F2F;
border-color: #D32F2F;
}
.btn-danger:hover {
background-color: #a32424;
border-color: #a32424;
}
.card {
border-radius: 0.5rem;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
border: none;
}
.form-check-input:checked {
background-color: #0D47A1;
border-color: #0D47A1;
}
.totals-card {
position: sticky;
bottom: 1rem;
z-index: 1020;
}

238
assets/js/main.js Normal file
View File

@ -0,0 +1,238 @@
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 || !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;
for (let i = 1; i <= holes; i++) {
const score = parseInt(document.getElementById(`hole${i}_score`).value) || 0;
const putts = parseInt(document.getElementById(`hole${i}_putts`).value) || 0;
const penalties = parseInt(document.getElementById(`hole${i}_penalties`).value) || 0;
const sandLie = document.getElementById(`hole${i}_sand`).checked;
totalScore += score;
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 = () => {
const holes = holesToggle.checked ? 18 : 9;
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 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>
`;
}
scoreTable.innerHTML = html;
attachInputListeners();
};
const attachInputListeners = () => {
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++) {
const row = document.getElementById(`hole_row_${i}`);
if (row) {
row.style.display = i > holes ? 'none' : 'table-row';
}
}
updateTotal();
});
form.addEventListener('submit', async function(e) {
e.preventDefault();
const playerSelect = document.getElementById('playerSelect');
const playerId = playerSelect.value;
if (!playerId) {
alert('Please select a player.');
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 selectedOption = playerSelect.options[playerSelect.selectedIndex];
const teamId = selectedOption.dataset.teamId;
const data = {
playerId: playerId,
teamId: teamId,
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 playerName = selectedOption.text;
const toastBody = successToast.querySelector('.toast-body');
if (toastBody) {
toastBody.textContent = `Score submitted successfully for ${playerName}.`;
}
const toast = new bootstrap.Toast(successToast);
toast.show();
}
form.reset();
courseSelect.value = '';
playerSelect.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.');
}
});
renderTable();
updateTotal();
});

167
coach.php Normal file
View File

@ -0,0 +1,167 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
// Assume a logged-in coach with ID 1
$coach_id = 1;
$pdo = db();
// Get teams for the coach
$stmt = $pdo->prepare('SELECT * FROM teams WHERE coach_id = ?');
$stmt->execute([$coach_id]);
$teams = $stmt->fetchAll();
$success_message = $_SESSION['success_message'] ?? null;
$error_message = $_SESSION['error_message'] ?? null;
unset($_SESSION['success_message']);
unset($_SESSION['error_message']);
?>
<!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="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" 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>
<?php if ($success_message): ?>
<div class="alert alert-success">
<?= $success_message ?>
</div>
<?php endif; ?>
<?php if ($error_message): ?>
<div class="alert alert-danger">
<?= $error_message ?>
</div>
<?php endif; ?>
<div class="card shadow-sm mb-4">
<div class="card-body">
<h2 class="card-title">Create New Team</h2>
<form action="create_team.php" method="post">
<div class="input-group">
<input type="text" name="team_name" class="form-control" placeholder="Enter new team name" required>
<button type="submit" class="btn btn-primary">Create Team</button>
</div>
</form>
</div>
</div>
<?php foreach ($teams as $team): ?>
<div class="card shadow-sm mt-4">
<div class="card-body">
<h2 class="card-title">Team: <?= htmlspecialchars($team['name']) ?></h2>
<h3 class="mt-4">Players</h3>
<?php
$stmt = $pdo->prepare('SELECT * FROM players WHERE team_id = ?');
$stmt->execute([$team['id']]);
$players = $stmt->fetchAll();
?>
<?php if ($players): ?>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>High School Year</th>
<th>Season Year</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($players as $player): ?>
<tr>
<td><?= htmlspecialchars($player['name']) ?></td>
<td><?= htmlspecialchars($player['email']) ?></td>
<td><?= htmlspecialchars($player['high_school_year']) ?></td>
<td><?= htmlspecialchars($player['season_year']) ?></td>
<td>
<a href="edit_player.php?id=<?= $player['id'] ?>" class="btn btn-sm btn-primary">Edit</a>
<a href="delete_player.php?player_id=<?= $player['id'] ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to remove this player from the team?')">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<p>No players in this team yet.</p>
<?php endif; ?>
<hr>
<h3 class="mt-4">Add Player to Team</h3>
<form action="add_player.php" method="post">
<input type="hidden" name="team_id" value="<?= $team['id'] ?>">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="player_name">Player Name</label>
<input type="text" name="player_name" class="form-control" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="player_email">Player Email</label>
<input type="email" name="player_email" class="form-control" required>
</div>
</div>
</div>
<div class="row mt-2">
<div class="col-md-6">
<div class="form-group">
<label for="high_school_year">High School Year</label>
<input type="text" name="high_school_year" class="form-control">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="season_year">Season Year</label>
<input type="text" name="season_year" class="form-control">
</div>
</div>
</div>
<button type="submit" class="btn btn-primary mt-3">Add Player</button>
</form>
</div>
</div>
<?php endforeach; ?>
</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>

26
create_team.php Normal file
View File

@ -0,0 +1,26 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
// Assuming a logged-in coach with ID 1
$coach_id = 1;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$team_name = trim($_POST['team_name']);
if (!empty($team_name)) {
try {
$pdo = db();
$stmt = $pdo->prepare("INSERT INTO teams (name, coach_id) VALUES (?, ?)");
$stmt->execute([$team_name, $coach_id]);
$_SESSION['success_message'] = 'Team created successfully!';
} catch (PDOException $e) {
$_SESSION['error_message'] = 'Error creating team: ' . $e->getMessage();
}
}
header('Location: coach.php');
exit;
}
?>

56
db/migrate.php Normal file
View File

@ -0,0 +1,56 @@
<?php
require_once __DIR__ . '/config.php';
try {
$pdo = db();
// Alter table engine to InnoDB
$pdo->exec("ALTER TABLE scores ENGINE=InnoDB");
echo "Table 'scores' engine converted to InnoDB.<br>";
// Check if player_id column exists
$stmt = $pdo->query("SHOW COLUMNS FROM scores LIKE 'player_id'");
if ($stmt->rowCount() == 0) {
// Add player_id column
$pdo->exec("ALTER TABLE scores ADD COLUMN player_id INT NOT NULL AFTER course_id");
// Add foreign key constraint
$pdo->exec("ALTER TABLE scores ADD FOREIGN KEY (player_id) REFERENCES players(id)");
echo "Column 'player_id' added to 'scores' table and foreign key created.<br>";
} else {
echo "Column 'player_id' already exists in 'scores' table.<br>";
}
// Check if team_id column exists
$stmt = $pdo->query("SHOW COLUMNS FROM scores LIKE 'team_id'");
if ($stmt->rowCount() == 0) {
// Add team_id column
$pdo->exec("ALTER TABLE scores ADD COLUMN team_id INT NOT NULL AFTER player_id");
// Add foreign key constraint
$pdo->exec("ALTER TABLE scores ADD FOREIGN KEY (team_id) REFERENCES teams(id)");
echo "Column 'team_id' added to 'scores' table and foreign key created.<br>";
} else {
echo "Column 'team_id' already exists in 'scores' table.<br>";
}
// Safely remove player_name and team_name if they exist
$stmt = $pdo->query("SHOW COLUMNS FROM scores LIKE 'player_name'");
if ($stmt->rowCount() > 0) {
$pdo->exec("ALTER TABLE scores DROP COLUMN player_name");
echo "Column 'player_name' removed from 'scores' table.<br>";
}
$stmt = $pdo->query("SHOW COLUMNS FROM scores LIKE 'team_name'");
if ($stmt->rowCount() > 0) {
$pdo->exec("ALTER TABLE scores DROP COLUMN team_name");
echo "Column 'team_name' removed from 'scores' table.<br>";
}
} catch (PDOException $e) {
die("DB ERROR: " . $e->getMessage());
}
?>

View File

@ -0,0 +1,15 @@
<?php
require_once __DIR__ . '/../config.php';
try {
$pdo = db();
$pdo->exec("
ALTER TABLE players
ADD COLUMN high_school_year VARCHAR(255),
ADD COLUMN season_year VARCHAR(255);
");
echo "Table 'players' updated successfully with 'high_school_year' and 'season_year' columns.\n";
} catch (PDOException $e) {
die("DB ERROR: " . $e->getMessage());
}
?>

View File

@ -0,0 +1,12 @@
<?php
require_once __DIR__ . '/../config.php';
try {
$pdo = db();
$sql = "ALTER TABLE players ADD COLUMN team_id INT NULL AFTER season_year";
$pdo->exec($sql);
echo "Migration successful: added team_id to players table.\n";
} catch (PDOException $e) {
die("Migration failed: " . $e->getMessage() . "\n");
}

View File

@ -0,0 +1,12 @@
<?php
require_once __DIR__ . '/../config.php';
try {
$pdo = db();
$sql = "DROP TABLE IF EXISTS team_members";
$pdo->exec($sql);
echo "Migration successful: dropped team_members table.\n";
} catch (PDOException $e) {
die("Migration failed: " . $e->getMessage() . "\n");
}

142
db/setup.php Normal file
View File

@ -0,0 +1,142 @@
<?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,
hole_count INT NOT NULL DEFAULT 18,
tournament_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
");
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)
) ENGINE=InnoDB;
");
echo "Table 'scores' created successfully or already exists.<br>";
// Add hole_count to courses if it doesn't exist
$stmt = $pdo->query("SHOW COLUMNS FROM courses LIKE 'hole_count'");
if ($stmt->rowCount() == 0) {
$pdo->exec("ALTER TABLE courses ADD COLUMN hole_count INT NOT NULL DEFAULT 18");
echo "Column 'hole_count' added to 'courses' table.<br>";
}
// Add tournament_date to courses if it doesn't exist
$stmt = $pdo->query("SHOW COLUMNS FROM courses LIKE 'tournament_date'");
if ($stmt->rowCount() == 0) {
$pdo->exec("ALTER TABLE courses ADD COLUMN tournament_date DATE");
echo "Column 'tournament_date' added to 'courses' table.<br>";
}
} catch (PDOException $e) {
die("DB ERROR: " . $e->getMessage());
}
// New tables for coaches and players
try {
$pdo = db();
// Coaches table
$pdo->exec("
CREATE TABLE IF NOT EXISTS coaches (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL, -- Hashed password
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
");
echo "Table 'coaches' created successfully or already exists.<br>";
// Players table
$pdo->exec("
CREATE TABLE IF NOT EXISTS players (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
handicap INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
");
echo "Table 'players' created successfully or already exists.<br>";
// Team table to link coaches and players
$pdo->exec("
CREATE TABLE IF NOT EXISTS teams (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
coach_id INT NOT NULL,
FOREIGN KEY (coach_id) REFERENCES coaches(id)
) ENGINE=InnoDB;
");
echo "Table 'teams' created successfully or already exists.<br>";
// Team_members table to link players to a team
$pdo->exec("
CREATE TABLE IF NOT EXISTS team_members (
id INT AUTO_INCREMENT PRIMARY KEY,
team_id INT NOT NULL,
player_id INT NOT NULL,
FOREIGN KEY (team_id) REFERENCES teams(id),
FOREIGN KEY (player_id) REFERENCES players(id)
) ENGINE=InnoDB;
");
echo "Table 'team_members' created successfully or already exists.<br>";
} catch (PDOException $e) {
die("DB ERROR: " . $e->getMessage());
}
?>

21
delete_player.php Normal file
View File

@ -0,0 +1,21 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
$player_id = $_GET['player_id'] ?? null;
if ($player_id) {
try {
$pdo = db();
$stmt = $pdo->prepare("UPDATE players SET team_id = NULL WHERE id = ?");
$stmt->execute([$player_id]);
$_SESSION['success_message'] = 'Player removed from team successfully!';
} catch (PDOException $e) {
$_SESSION['error_message'] = 'Error removing player: ' . $e->getMessage();
}
}
header('Location: coach.php');
exit;
?>

33
delete_score.php Normal file
View File

@ -0,0 +1,33 @@
<?php
// TODO: Add authentication to ensure only admin users can access this page.
// For example:
// session_start();
// if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== 'admin') {
// die('Access Denied: You do not have permission to perform this action.');
// }
require_once 'db/config.php';
if (isset($_GET['score_id']) && !empty($_GET['score_id'])) {
$score_id = (int)$_GET['score_id'];
try {
$pdo = db();
$stmt = $pdo->prepare("DELETE FROM scores WHERE id = ?");
$stmt->execute([$score_id]);
// Redirect back to the results page
header("Location: results.php?delete_success=1");
exit;
} catch (PDOException $e) {
// Optional: handle error, e.g., log it or show a generic error message
die("Error: Could not delete the score. " . $e->getMessage());
}
} else {
// No score_id provided
header("Location: results.php?delete_error=1");
exit;
}
?>

95
edit_player.php Normal file
View File

@ -0,0 +1,95 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
$player_id = $_GET['id'] ?? null;
if (!$player_id) {
header('Location: admin.php'); // Redirect to admin page if no player ID
exit;
}
$pdo = db();
// Fetch player details
$stmt = $pdo->prepare("SELECT * FROM players WHERE id = ?");
$stmt->execute([$player_id]);
$player = $stmt->fetch();
if (!$player) {
header('Location: admin.php'); // Redirect if player not found
exit;
}
// Fetch all teams
$teams_stmt = $pdo->query("SELECT id, team_name FROM teams ORDER BY team_name");
$teams = $teams_stmt->fetchAll();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$player_name = trim($_POST['player_name']);
$player_email = trim($_POST['player_email']);
$high_school_year = trim($_POST['high_school_year']);
$season_year = trim($_POST['season_year']);
$team_id = $_POST['team_id'] ?? null; // Get team_id from form
if (!empty($player_name) && !empty($player_email)) {
try {
// Update player details, including team_id
$stmt = $pdo->prepare("UPDATE players SET name = ?, email = ?, high_school_year = ?, season_year = ?, team_id = ? WHERE id = ?");
$stmt->execute([$player_name, $player_email, $high_school_year, $season_year, $team_id, $player_id]);
$_SESSION['success_message'] = 'Player updated successfully!';
} catch (PDOException $e) {
$_SESSION['error_message'] = 'Error updating player: ' . $e->getMessage();
}
}
header('Location: admin.php'); // Redirect back to admin page
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit Player</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<h2>Edit Player</h2>
<form action="edit_player.php?id=<?php echo $player_id; ?>" method="post">
<div class="form-group">
<label for="player_name">Player Name</label>
<input type="text" name="player_name" id="player_name" class="form-control" value="<?php echo htmlspecialchars($player['name']); ?>" required>
</div>
<div class="form-group">
<label for="player_email">Player Email</label>
<input type="email" name="player_email" id="player_email" class="form-control" value="<?php echo htmlspecialchars($player['email']); ?>" required>
</div>
<div class="form-group">
<label for="high_school_year">High School Year</label>
<input type="text" name="high_school_year" id="high_school_year" class="form-control" value="<?php echo htmlspecialchars($player['high_school_year']); ?>">
</div>
<div class="form-group">
<label for="season_year">Season Year</label>
<input type="text" name="season_year" id="season_year" class="form-control" value="<?php echo htmlspecialchars($player['season_year']); ?>">
</div>
<div class="form-group">
<label for="team_id">Team</label>
<select name="team_id" id="team_id" class="form-control">
<option value="">Select a team</option>
<?php foreach ($teams as $team): ?>
<option value="<?php echo $team['id']; ?>" <?php echo ($player['team_id'] == $team['id']) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($team['team_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<button type="submit" class="btn btn-primary">Update Player</button>
</form>
</div>
</body>
</html>

60
edit_score.php Normal file
View File

@ -0,0 +1,60 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
// TODO: Add role-based authentication check here.
// For example, check if $_SESSION['user_role'] is 'admin' or 'coach'.
// if (!isset($_SESSION['user_role']) || !in_array($_SESSION['user_role'], ['admin', 'coach'])) {
// die('Access denied. You do not have permission to edit scores.');
// }
$score_id = $_GET['score_id'] ?? null;
if (!$score_id) {
die('Score ID is required.');
}
$pdoc = db();
$stmt = $pdoc->prepare('SELECT s.*, p.name as player_name, c.name as course_name, c.hole_count FROM scores s JOIN players p ON s.player_id = p.id JOIN courses c ON s.course_id = c.id WHERE s.id = ?');
$stmt->execute([$score_id]);
$score = $stmt->fetch();
if (!$score) {
die('Score not found.');
}
$pars = [];
$stmt = $pdoc->prepare('SELECT * FROM courses WHERE id = ?');
$stmt->execute([$score['course_id']]);
$course = $stmt->fetch();
for ($i = 1; $i <= 18; $i++) {
$pars[$i] = $course['par_hole_' . $i];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Score</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1>Edit Score for <?= htmlspecialchars($score['player_name']) ?> on <?= htmlspecialchars($score['course_name']) ?></h1>
<form action="submit_score.php" method="post">
<input type="hidden" name="score_id" value="<?= $score_id ?>">
<input type="hidden" name="action" value="update">
<div class="row">
<?php for ($i = 1; $i <= $score['hole_count']; $i++): ?>
<div class="col-md-4 mb-3">
<label for="hole_<?= $i ?>" class="form-label">Hole <?= $i ?> (Par <?= $pars[$i] ?>)</label>
<input type="number" class="form-control" id="hole_<?= $i ?>" name="scores[<?= $i ?>]" value="<?= htmlspecialchars($score['hole_' . $i . '_score']) ?>" min="1" required>
</div>
<?php endfor; ?>
</div>
<button type="submit" class="btn btn-primary">Update Score</button>
</form>
</div>
</body>
</html>

247
index.php
View File

@ -1,131 +1,126 @@
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GolfTracker - Home</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<style>
.hero {
background: linear-gradient(rgba(13, 71, 161, 0.7), rgba(13, 71, 161, 0.7)), url('https://picsum.photos/seed/golf/1600/900');
background-size: cover;
background-position: center;
color: white;
padding: 8rem 0;
text-align: center;
}
</style>
</head>
<body>
<main>
<div class="card">
<h1>Analyzing your requirements and generating your website…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
</div>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWiZZy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will update automatically as the plan is implemented.</p>
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
</div>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
</footer>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm">
<div class="container">
<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>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href="index.php">Home</a>
</li>
<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>
</nav>
<header class="hero">
<div class="container">
<h1 class="display-4 fw-bold">Track Your Golf Season</h1>
<p class="lead">An interactive golf tournament calculator that tracks stroke averages and number of putts per round for a golf team.</p>
<a href="add_score.php" class="btn btn-danger btn-lg mt-3">Enter a New Score</a>
</div>
</header>
<section class="py-5">
<div class="container">
<div class="row text-center">
<div class="col-md-4">
<img src="https://picsum.photos/seed/golfer/400/300" class="img-fluid rounded-circle mb-3" alt="A focused golfer taking a shot.">
<h3>Enter Scores Easily</h3>
<p>A simple form lets you enter scores, putts, penalties, and more for every hole.</p>
</div>
<div class="col-md-4">
<img src="https://picsum.photos/seed/analysis/400/300" class="img-fluid rounded-circle mb-3" alt="A tablet showing golf analytics.">
<h3>Instant Analysis</h3>
<p>Get real-time totals for your round as you enter data, helping you track performance instantly.</p>
</div>
<div class="col-md-4">
<img src="https://picsum.photos/seed/team/400/300" class="img-fluid rounded-circle mb-3" alt="A golf team celebrating.">
<h3>Track Your Team</h3>
<p>All statistics are tracked for the entire season, giving coaches and players valuable insights.</p>
</div>
</div>
</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">&copy; <?php echo date("Y"); ?> GolfTracker. All Rights Reserved.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
</html>

97
player.php Normal file
View 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>

223
results.php Normal file
View File

@ -0,0 +1,223 @@
<!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>
<?php
require_once 'db/config.php';
$pdo = db();
// Fetch all courses for the dropdown
$courses_stmt = $pdo->query("SELECT id, name FROM courses ORDER BY name ASC");
$courses = $courses_stmt->fetchAll();
$selected_course_id = isset($_GET['course_id']) ? (int)$_GET['course_id'] : ($courses[0]['id'] ?? 0);
?>
<div class="row mb-4">
<div class="col-md-6 mx-auto">
<form action="results.php" method="GET" class="d-flex">
<select name="course_id" class="form-select me-2">
<?php foreach ($courses as $course): ?>
<option value="<?php echo $course['id']; ?>" <?php echo $selected_course_id == $course['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($course['name']); ?>
</option>
<?php endforeach; ?>
</select>
<button type="submit" class="btn btn-primary">View</button>
</form>
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<h2 class="card-title text-center">Individual Standings</h2>
<?php
if ($selected_course_id) {
try {
// Fetch course details for pars
$course_stmt = $pdo->prepare("SELECT * FROM courses WHERE id = ?");
$course_stmt->execute([$selected_course_id]);
$course_details = $course_stmt->fetch();
// Fetch scores for the selected course
$stmt = $pdo->prepare("
SELECT s.*, p.name as player_name
FROM scores s
JOIN players p ON s.player_id = p.id
WHERE s.course_id = ?
ORDER BY s.total_to_par ASC
");
$stmt->execute([$selected_course_id]);
$results = $stmt->fetchAll();
} catch (PDOException $e) {
$results = [];
$course_details = null;
echo "<p class='text-danger text-center'>Database error: " . $e->getMessage() . "</p>";
}
} else {
$results = [];
$course_details = null;
}
?>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th>Rank</th>
<th>Player</th>
<?php if ($course_details): ?>
<?php for ($i = 1; $i <= 18; $i++): ?>
<th class="text-center">
<?php echo $i; ?><br>
<small>(<?php echo $course_details['par_hole_' . $i]; ?>)</small>
</th>
<?php endfor; ?>
<?php endif; ?>
<th>Total</th>
<th>To Par</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($results)): ?>
<tr>
<td colspan="<?php echo $course_details ? 23 : 5; ?>" class="text-center">No results yet for this course.</td>
</tr>
<?php else: ?>
<?php foreach ($results as $index => $row): ?>
<tr>
<td><?php echo $index + 1; ?></td>
<td><a href="player.php?id=<?php echo $row['player_id']; ?>"><?php echo htmlspecialchars($row['player_name']); ?></a></td>
<?php if ($course_details): ?>
<?php for ($i = 1; $i <= 18; $i++): ?>
<td class="text-center">
<?php
$score = $row['hole_' . $i . '_score'];
$par = $course_details['par_hole_' . $i];
$class = '';
if ($score !== null) {
if ($score < $par) $class = 'bg-success text-white'; // Birdie or better
elseif ($score > $par) $class = 'bg-warning'; // Bogey
else $class = 'bg-light'; // Par
}
echo "<span class='{$class} d-block'>{$score}</span>";
?>
</td>
<?php endfor; ?>
<?php endif; ?>
<td><?php echo $row['total_score']; ?></td>
<td><?php echo ($row['total_to_par'] > 0 ? '+' : '') . $row['total_to_par']; ?></td>
<td>
<a href="edit_score.php?score_id=<?php echo $row['id']; ?>" class="btn btn-sm btn-primary">Edit</a>
<a href="delete_score.php?score_id=<?php echo $row['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this score?');">Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="card shadow-sm mt-4">
<div class="card-body">
<h2 class="card-title text-center">Team Standings</h2>
<?php
if ($selected_course_id) {
try {
$stmt = $pdo->prepare("
SELECT t.name as team_name, SUM(s.total_score) as total_score
FROM scores s
JOIN teams t ON s.team_id = t.id
WHERE s.course_id = ?
GROUP BY s.team_id, t.name
ORDER BY total_score ASC
");
$stmt->execute([$selected_course_id]);
$team_results = $stmt->fetchAll();
} catch (PDOException $e) {
$team_results = [];
echo "<p class='text-danger text-center'>Database error: " . $e->getMessage() . "</p>";
}
} else {
$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>

144
submit_score.php Normal file
View File

@ -0,0 +1,144 @@
<?php
require_once 'db/config.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
die('Method Not Allowed');
}
// Handle score update from edit_score.php
if (isset($_POST['action']) && $_POST['action'] === 'update') {
session_start();
// TODO: Add role-based authentication check here.
// For example, check if $_SESSION['user_role'] is 'admin' or 'coach'.
// if (!isset($_SESSION['user_role']) || !in_array($_SESSION['user_role'], ['admin', 'coach'])) {
// die('Access denied. You do not have permission to edit scores.');
// }
$score_id = $_POST['score_id'] ?? null;
$scores = $_POST['scores'] ?? [];
if (!$score_id || empty($scores)) {
die('Invalid data for update.');
}
try {
$pdo = db();
// Get course and existing score details
$stmt = $pdo->prepare('SELECT course_id, holes_played FROM scores WHERE id = ?');
$stmt->execute([$score_id]);
$score_info = $stmt->fetch();
if (!$score_info) {
die('Score not found.');
}
$stmt = $pdo->prepare('SELECT * FROM courses WHERE id = ?');
$stmt->execute([$score_info['course_id']]);
$course = $stmt->fetch();
$total_score = 0;
$total_par = 0;
$update_sql_parts = [];
$params = [];
for ($i = 1; $i <= $score_info['holes_played']; $i++) {
$hole_score = $scores[$i] ?? 0;
$total_score += $hole_score;
$total_par += $course['par_hole_' . $i];
$update_sql_parts[] = "hole_{$i}_score = :hole_{$i}_score";
$params[":hole_{$i}_score"] = $hole_score;
}
$total_to_par = $total_score - $total_par;
$sql = "UPDATE scores SET total_score = :total_score, total_to_par = :total_to_par, " . implode(', ', $update_sql_parts) . " WHERE id = :score_id";
$params[':total_score'] = $total_score;
$params[':total_to_par'] = $total_to_par;
$params[':score_id'] = $score_id;
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
header('Location: results.php?course_id=' . $score_info['course_id']);
exit;
} catch (PDOException $e) {
die("Database error: " . $e->getMessage());
}
}
// Existing logic for new score submission (API-style)
$data = json_decode(file_get_contents('php://input'), true);
if (!$data) {
http_response_code(400);
echo json_encode(['error' => 'Invalid data']);
exit;
}
$required_fields = ['playerId', '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();
$stmt = $pdo->prepare("SELECT name, team_id FROM players WHERE id = ?");
$stmt->execute([$data['playerId']]);
$player = $stmt->fetch();
if (!$player) {
http_response_code(404);
echo json_encode(['error' => 'Player not found']);
exit;
}
$team_id = $player['team_id'];
$player_name = $player['name'];
$stmt = $pdo->prepare("SELECT name FROM teams WHERE id = ?");
$stmt->execute([$team_id]);
$team = $stmt->fetch();
if (!$team) {
http_response_code(404);
echo json_encode(['error' => 'Team not found']);
exit;
}
$team_name = $team['name'];
$sql = "INSERT INTO scores (player_id, team_id, course_id, holes_played, total_score, total_to_par";
$params = [
':player_id' => $data['playerId'],
':team_id' => $team_id,
':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()]);
}