feat: add golf prototype with hole navigation and stats
Co-authored-by: aider (openrouter/thinkingmachines/inkling-small:free) <aider@aider.chat>
This commit is contained in:
1 parent
6be02b9a23
commit
e164b1958c
3 files changed
+448
No files matched your search
+133
@@ -0,0 +1,133 @@
|
||||
let currentUser = null;
|
||||
let currentRound = null;
|
||||
let currentData = null;
|
||||
let currentIndex = 0;
|
||||
|
||||
async function signup() {
|
||||
const name = document.getElementById('name').value;
|
||||
const hcp = parseInt(document.getElementById('hcp').value) || 0;
|
||||
const res = await fetch('/signup', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({name, handicap: hcp})
|
||||
});
|
||||
currentUser = await res.json();
|
||||
document.getElementById('signup-section').style.display = 'none';
|
||||
document.getElementById('start-section').style.display = 'block';
|
||||
loadCourse();
|
||||
}
|
||||
|
||||
async function loadCourse() {
|
||||
const res = await fetch('/course');
|
||||
const course = await res.json();
|
||||
document.getElementById('course-info').textContent = `${course.name} — ${course.holes.length} holes`;
|
||||
}
|
||||
|
||||
async function startRound() {
|
||||
const res = await fetch('/course');
|
||||
const course = await res.json();
|
||||
const res2 = await fetch('/round', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({user_id: currentUser.id, course_id: course.id})
|
||||
});
|
||||
currentRound = await res2.json();
|
||||
document.getElementById('start-section').style.display = 'none';
|
||||
document.getElementById('round-section').style.display = 'block';
|
||||
document.getElementById('stats-section').style.display = 'block';
|
||||
loadRound();
|
||||
}
|
||||
|
||||
async function loadRound() {
|
||||
const res = await fetch(`/round/${currentRound.id}`);
|
||||
currentData = await res.json();
|
||||
const holes = currentData.holes.sort((a,b) => a.hole_number - b.hole_number);
|
||||
if (holes.length === 0) return;
|
||||
if (currentIndex >= holes.length) currentIndex = 0;
|
||||
renderHole(holes[currentIndex]);
|
||||
renderNav(holes);
|
||||
loadStats();
|
||||
}
|
||||
|
||||
function renderHole(hole) {
|
||||
document.getElementById('hole-score-id').value = hole.hole_score_id;
|
||||
document.getElementById('hole-label').textContent = `Hole ${hole.hole_number}`;
|
||||
document.getElementById('strokes').value = hole.strokes || 0;
|
||||
document.getElementById('fairway').checked = hole.fairway_hit;
|
||||
document.getElementById('skipped').checked = hole.skipped;
|
||||
document.getElementById('completed').checked = hole.completed;
|
||||
document.getElementById('gir-display').textContent = hole.gir ? 'Yes' : 'No';
|
||||
|
||||
const putts = hole.putts || [];
|
||||
document.getElementById('putts-input').value = putts.map(p => p.location).join(',');
|
||||
|
||||
const pens = (hole.penalties || []).map(p => p.type).join(',');
|
||||
document.getElementById('penalties-input').value = pens;
|
||||
|
||||
const buns = (hole.bunkers || []).map(b => b.location).join(',');
|
||||
document.getElementById('bunkers-input').value = buns;
|
||||
}
|
||||
|
||||
function renderNav(holes) {
|
||||
document.getElementById('prev-btn').disabled = currentIndex <= 0;
|
||||
document.getElementById('next-btn').disabled = currentIndex >= holes.length - 1;
|
||||
}
|
||||
|
||||
function prevHole() {
|
||||
if (currentIndex > 0) {
|
||||
currentIndex--;
|
||||
const holes = currentData.holes.sort((a,b) => a.hole_number - b.hole_number);
|
||||
renderHole(holes[currentIndex]);
|
||||
renderNav(holes);
|
||||
}
|
||||
}
|
||||
|
||||
function nextHole() {
|
||||
const holes = currentData.holes.sort((a,b) => a.hole_number - b.hole_number);
|
||||
if (currentIndex < holes.length - 1) {
|
||||
currentIndex++;
|
||||
renderHole(holes[currentIndex]);
|
||||
renderNav(holes);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveHole() {
|
||||
const id = document.getElementById('hole-score-id').value;
|
||||
const strokes = parseInt(document.getElementById('strokes').value) || 0;
|
||||
const fairway = document.getElementById('fairway').checked;
|
||||
const skipped = document.getElementById('skipped').checked;
|
||||
const completed = document.getElementById('completed').checked;
|
||||
|
||||
const puttsStr = document.getElementById('putts-input').value;
|
||||
const putts = puttsStr.split(',').filter(s => s.trim()).map(s => ({location: s.trim()}));
|
||||
|
||||
const pensStr = document.getElementById('penalties-input').value;
|
||||
const penalties = pensStr.split(',').filter(s => s.trim()).map(s => ({type: s.trim()}));
|
||||
|
||||
const bunsStr = document.getElementById('bunkers-input').value;
|
||||
const bunkers = bunsStr.split(',').filter(s => s.trim()).map(s => ({location: s.trim()}));
|
||||
|
||||
const res = await fetch(`/hole/${id}`, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
strokes, skipped, completed, fairway_hit: fairway,
|
||||
putts, penalties, bunkers
|
||||
})
|
||||
});
|
||||
const result = await res.json();
|
||||
document.getElementById('gir-display').textContent = result.gir ? 'Yes' : 'No';
|
||||
loadRound();
|
||||
}
|
||||
|
||||
async function loadStats() {
|
||||
const res = await fetch(`/stats/${currentRound.id}`);
|
||||
const stats = await res.json();
|
||||
document.getElementById('stats-display').innerHTML = `
|
||||
<p><strong>Total Strokes:</strong> ${stats.total_strokes}</p>
|
||||
<p><strong>Total Putts:</strong> ${stats.total_putts}</p>
|
||||
<p><strong>Fairways Hit:</strong> ${stats.fairways_hit}</p>
|
||||
<p><strong>GIR:</strong> ${stats.gir}</p>
|
||||
<p><strong>Holes Played:</strong> ${stats.holes_played}</p>
|
||||
`;
|
||||
}
|
||||
Reference in new issue
Block a user