From e6e98182ba1779e1d614824442073044bfaf6e0a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 24 Sep 2025 13:47:38 +0000 Subject: [PATCH] 1.2 --- add_score.php | 47 +++++++++- admin.php | 187 ++++++++++++++++++++++++++++++++++++++++ api/get_course_pars.php | 30 +++++++ assets/js/main.js | 175 +++++++++++++++++++++++++++++++++---- coach.php | 106 +++++++++++++++++++++++ db/setup.php | 68 +++++++++++++++ index.php | 48 ++++++++++- player.php | 97 +++++++++++++++++++++ results.php | 146 +++++++++++++++++++++++++++++++ submit_score.php | 56 ++++++++++++ 10 files changed, 938 insertions(+), 22 deletions(-) create mode 100644 admin.php create mode 100644 api/get_course_pars.php create mode 100644 coach.php create mode 100644 db/setup.php create mode 100644 player.php create mode 100644 results.php create mode 100644 submit_score.php diff --git a/add_score.php b/add_score.php index 896bf70..89df036 100644 --- a/add_score.php +++ b/add_score.php @@ -1,4 +1,16 @@ +query("SELECT id, name FROM courses ORDER BY name"); + $courses = $stmt->fetchAll(); +} catch (PDOException $e) { + $courses = []; + // Silently fail, the JS will handle the empty state +} +?> @@ -36,9 +48,33 @@

Enter Round Score

-
- - +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ + +
+
@@ -47,7 +83,9 @@ Hole + Par Score + Vs Par Putts Penalties Sand Lie @@ -68,6 +106,7 @@

Round Totals

+
To Par: E
Score: 0
Putts: 0
Penalties: 0
@@ -91,4 +130,4 @@ - + \ No newline at end of file diff --git a/admin.php b/admin.php new file mode 100644 index 0000000..09f1d57 --- /dev/null +++ b/admin.php @@ -0,0 +1,187 @@ + 7) { + $error = "Invalid par value for hole " . $i . ". Please enter a number between 1 and 7."; + $isValid = false; + break; + } + $pars[] = $par_value; + } + + if ($isValid) { + try { + $pdo = db(); + $sql = "INSERT INTO courses (name, par_hole_1, par_hole_2, par_hole_3, par_hole_4, par_hole_5, par_hole_6, par_hole_7, par_hole_8, par_hole_9, par_hole_10, par_hole_11, par_hole_12, par_hole_13, par_hole_14, par_hole_15, par_hole_16, par_hole_17, par_hole_18) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + $stmt = $pdo->prepare($sql); + $stmt->execute(array_merge([$courseName], $pars)); + $_SESSION['success_message'] = "Course '{$courseName}' added successfully!"; + header("Location: admin.php"); + exit; + } catch (PDOException $e) { + $error = "Database error: " . $e->getMessage(); + } + } +} + +// Fetch existing courses +try { + $pdo = db(); + $stmt = $pdo->query("SELECT id, name FROM courses ORDER BY name"); + $courses = $stmt->fetchAll(); +} catch (PDOException $e) { + $courses = []; + $error = "Could not fetch courses: " . $e->getMessage(); +} + +?> + + + + + + Admin Dashboard - Golf Tournament + + + + + + + + +
+

Admin Dashboard

+ + +
+ + ' . htmlspecialchars($_SESSION['success_message']) . '
'; + unset($_SESSION['success_message']); + } + ?> + + + +
+ +
+
+
+

Add New Course

+ +
+ + +
+
+ +
+ + +
+ +
+ + +
+
+
+
+

Existing Courses

+ + + + + + + + + + + + + + + + + + + +
Course NameAction
No courses found.
+
+
+
+ + +
+ ... +
+ + +
+ ... +
+
+
+ +
+
+ © 2025 Golf Tournament +
+
+ + + + \ No newline at end of file diff --git a/api/get_course_pars.php b/api/get_course_pars.php new file mode 100644 index 0000000..bc7e3e0 --- /dev/null +++ b/api/get_course_pars.php @@ -0,0 +1,30 @@ + '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()]); +} diff --git a/assets/js/main.js b/assets/js/main.js index d1f9474..1506c7a 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,16 +1,19 @@ - document.addEventListener('DOMContentLoaded', function () { const holesToggle = document.getElementById('holesToggle'); const scoreTable = document.getElementById('scoreTable'); const form = document.getElementById('scoreForm'); + const courseSelect = document.getElementById('courseSelect'); - if (!holesToggle || !scoreTable || !form) return; + if (!holesToggle || !scoreTable || !form || !courseSelect) return; + + let coursePars = null; const updateTotal = () => { let totalScore = 0; let totalPutts = 0; let totalPenalties = 0; let totalSandLies = 0; + let totalToPar = 0; const holes = holesToggle.checked ? 18 : 9; @@ -24,12 +27,56 @@ document.addEventListener('DOMContentLoaded', function () { totalPutts += putts; totalPenalties += penalties; if (sandLie) totalSandLies++; + + if (coursePars && score > 0) { + const par = coursePars[`par_hole_${i}`]; + totalToPar += score - par; + } } document.getElementById('totalScore').textContent = totalScore; document.getElementById('totalPutts').textContent = totalPutts; document.getElementById('totalPenalties').textContent = totalPenalties; document.getElementById('totalSandLies').textContent = totalSandLies; + + const toParElement = document.getElementById('totalToPar'); + if (totalToPar > 0) { + toParElement.textContent = `+${totalToPar}`; + toParElement.classList.add('text-danger'); + toParElement.classList.remove('text-success'); + } else if (totalToPar < 0) { + toParElement.textContent = totalToPar; + toParElement.classList.add('text-success'); + toParElement.classList.remove('text-danger'); + } else { + toParElement.textContent = 'E'; + toParElement.classList.remove('text-danger', 'text-success'); + } + }; + + const updateVsPar = (holeNumber) => { + if (!coursePars) return; + const scoreInput = document.getElementById(`hole${holeNumber}_score`); + const score = parseInt(scoreInput.value) || 0; + const vsParCell = document.getElementById(`hole${holeNumber}_vs_par`); + + if (score > 0) { + const par = coursePars[`par_hole_${holeNumber}`]; + const diff = score - par; + if (diff > 0) { + vsParCell.textContent = `+${diff}`; + vsParCell.className = 'text-danger fw-bold'; + } else if (diff < 0) { + vsParCell.textContent = diff; + vsParCell.className = 'text-success fw-bold'; + } else { + vsParCell.textContent = 'E'; + vsParCell.className = 'text-muted'; + } + } else { + vsParCell.textContent = '-'; + vsParCell.className = ''; + } }; const renderTable = () => { @@ -37,13 +84,16 @@ document.addEventListener('DOMContentLoaded', function () { let html = ''; for (let i = 1; i <= 18; i++) { const hidden = i > holes ? ' style="display: none;"' : ''; + const parValue = coursePars ? coursePars[`par_hole_${i}`] : '-'; html += ` ${i} - - - -
+ ${parValue} + + - + + +
`; } @@ -52,11 +102,59 @@ document.addEventListener('DOMContentLoaded', function () { }; const attachInputListeners = () => { - form.querySelectorAll('input').forEach(input => { + form.querySelectorAll('input[type="number"]').forEach(input => { + input.addEventListener('input', () => { + const holeNumber = input.id.match(/\d+/)[0]; + updateVsPar(holeNumber); + updateTotal(); + }); + }); + form.querySelectorAll('input[type="checkbox"]').forEach(input => { input.addEventListener('input', updateTotal); }); }; + const toggleInputs = (disabled) => { + form.querySelectorAll('input').forEach(input => { + if(input.id !== 'holesToggle') { + input.disabled = disabled; + } + }); + }; + + courseSelect.addEventListener('change', async () => { + const courseId = courseSelect.value; + if (courseId) { + try { + const response = await fetch(`api/get_course_pars.php?course_id=${courseId}`); + if(response.ok) { + coursePars = await response.json(); + if(coursePars.error) { + console.error(coursePars.error); + coursePars = null; + toggleInputs(true); + } else { + renderTable(); + toggleInputs(false); + } + } else { + console.error('Failed to fetch par data'); + coursePars = null; + toggleInputs(true); + } + } catch (error) { + console.error('Error fetching par data:', error); + coursePars = null; + toggleInputs(true); + } + } else { + coursePars = null; + renderTable(); + toggleInputs(true); + } + updateTotal(); + }); + holesToggle.addEventListener('change', () => { const holes = holesToggle.checked ? 18 : 9; for (let i = 1; i <= 18; i++) { @@ -68,18 +166,63 @@ document.addEventListener('DOMContentLoaded', function () { updateTotal(); }); - form.addEventListener('submit', function(e) { + form.addEventListener('submit', async function(e) { e.preventDefault(); - const successToast = document.getElementById('successToast'); - if (successToast) { - const toast = new bootstrap.Toast(successToast); - toast.show(); + + const playerName = document.getElementById('playerName').value; + if (!playerName) { + alert('Player name is required.'); + return; + } + + const holes = holesToggle.checked ? 18 : 9; + const scores = {}; + for (let i = 1; i <= holes; i++) { + scores[`hole${i}_score`] = parseInt(document.getElementById(`hole${i}_score`).value) || 0; + } + + const data = { + playerName: playerName, + teamName: document.getElementById('teamName').value, + courseId: courseSelect.value, + holes: holes, + scores: scores, + totalScore: parseInt(document.getElementById('totalScore').textContent) || 0, + totalToPar: document.getElementById('totalToPar').textContent || 'E', + }; + + try { + const response = await fetch('submit_score.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + + const result = await response.json(); + + if (response.ok) { + const successToast = document.getElementById('successToast'); + if (successToast) { + const toast = new bootstrap.Toast(successToast); + toast.show(); + } + form.reset(); + courseSelect.value = ''; + coursePars = null; + renderTable(); + toggleInputs(true); + updateTotal(); + } else { + alert(`Error: ${result.error}`); + } + } catch (error) { + console.error('Submission error:', error); + alert('An error occurred while submitting the score.'); } - form.reset(); - renderTable(); - updateTotal(); }); renderTable(); updateTotal(); -}); +}); \ No newline at end of file diff --git a/coach.php b/coach.php new file mode 100644 index 0000000..83af4f8 --- /dev/null +++ b/coach.php @@ -0,0 +1,106 @@ + + + + + + Coach Dashboard - Golf Tournament + + + + + + + + +
+

Coach's Dashboard

+
+
+

Team: Sharks

+ + + + + + + + + + + + + + + + + + + + + + + +
PlayerLast Round ScoreHandicapView History
Jane Smith8512View Details
Mike Johnson9218View Details
+
+
+ +
+
+

Team: Bears

+ + + + + + + + + + + + + + + + + +
PlayerLast Round ScoreHandicapView History
Peter Jones8814View Details
+
+
+
+ +
+
+ © 2025 Golf Tournament +
+
+ + + + diff --git a/db/setup.php b/db/setup.php new file mode 100644 index 0000000..e0cb0ca --- /dev/null +++ b/db/setup.php @@ -0,0 +1,68 @@ +exec(" + CREATE TABLE IF NOT EXISTS courses ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + par_hole_1 INT NOT NULL, + par_hole_2 INT NOT NULL, + par_hole_3 INT NOT NULL, + par_hole_4 INT NOT NULL, + par_hole_5 INT NOT NULL, + par_hole_6 INT NOT NULL, + par_hole_7 INT NOT NULL, + par_hole_8 INT NOT NULL, + par_hole_9 INT NOT NULL, + par_hole_10 INT NOT NULL, + par_hole_11 INT NOT NULL, + par_hole_12 INT NOT NULL, + par_hole_13 INT NOT NULL, + par_hole_14 INT NOT NULL, + par_hole_15 INT NOT NULL, + par_hole_16 INT NOT NULL, + par_hole_17 INT NOT NULL, + par_hole_18 INT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + "); + echo "Table 'courses' created successfully or already exists.
"; + + $pdo->exec(" + CREATE TABLE IF NOT EXISTS scores ( + id INT AUTO_INCREMENT PRIMARY KEY, + player_name VARCHAR(255) NOT NULL, + team_name VARCHAR(255), + course_id INT NOT NULL, + holes_played INT NOT NULL DEFAULT 9, + hole_1_score INT, + hole_2_score INT, + hole_3_score INT, + hole_4_score INT, + hole_5_score INT, + hole_6_score INT, + hole_7_score INT, + hole_8_score INT, + hole_9_score INT, + hole_10_score INT, + hole_11_score INT, + hole_12_score INT, + hole_13_score INT, + hole_14_score INT, + hole_15_score INT, + hole_16_score INT, + hole_17_score INT, + hole_18_score INT, + total_score INT, + total_to_par INT, + played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (course_id) REFERENCES courses(id) + ) + "); + echo "Table 'scores' created successfully or already exists.
"; + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/index.php b/index.php index a12f676..b7966c2 100644 --- a/index.php +++ b/index.php @@ -22,9 +22,9 @@ -
@@ -71,6 +80,41 @@
+
+
+

Interfaces for Every Role

+
+
+
+
+
Admin
+

Manage courses, teams, and players.

+ Go to Admin +
+
+
+
+
+
+
Coach
+

View player scores and team progress.

+ Go to Coach +
+
+
+
+
+
+
Viewer
+

See live tournament leaderboards.

+ View Results +
+
+
+
+
+
+