Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f8fd03d51 | ||
|
|
6424a2c0f6 | ||
|
|
354c764c97 | ||
|
|
1268ae0578 | ||
|
|
3cef421e69 | ||
|
|
6915e64858 | ||
|
|
e6e98182ba | ||
|
|
d63bd85799 |
46
add_player.php
Normal file
46
add_player.php
Normal 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
153
add_score.php
Normal 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
305
admin.php
Normal 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
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()]);
|
||||
}
|
||||
47
assets/css/custom.css
Normal file
47
assets/css/custom.css
Normal 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
238
assets/js/main.js
Normal 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
167
coach.php
Normal 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
26
create_team.php
Normal 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
56
db/migrate.php
Normal 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());
|
||||
}
|
||||
?>
|
||||
15
db/migrations/20250924_add_player_details.php
Normal file
15
db/migrations/20250924_add_player_details.php
Normal 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());
|
||||
}
|
||||
?>
|
||||
12
db/migrations/20250925_add_team_id_to_players.php
Normal file
12
db/migrations/20250925_add_team_id_to_players.php
Normal 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");
|
||||
}
|
||||
|
||||
12
db/migrations/20250926_drop_team_members_table.php
Normal file
12
db/migrations/20250926_drop_team_members_table.php
Normal 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
142
db/setup.php
Normal 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
21
delete_player.php
Normal 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
33
delete_score.php
Normal 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
95
edit_player.php
Normal 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
60
edit_score.php
Normal 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
247
index.php
@ -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">© <?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
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>
|
||||
223
results.php
Normal file
223
results.php
Normal 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
144
submit_score.php
Normal 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()]);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user