feat: add tee selection and skip hole button
Co-authored-by: aider (openrouter/thinkingmachines/inkling-small:free) <aider@aider.chat>
This commit is contained in:
1 parent
935f5bd85b
commit
ad0032bea1
3 files changed
+30
-12
No files matched your search
+6
-4
@@ -37,6 +37,7 @@ class Round(Base):
|
|||||||
user_id = Column(Integer, ForeignKey("users.id"))
|
user_id = Column(Integer, ForeignKey("users.id"))
|
||||||
course_id = Column(Integer, ForeignKey("courses.id"))
|
course_id = Column(Integer, ForeignKey("courses.id"))
|
||||||
status = Column(String, default="in_progress")
|
status = Column(String, default="in_progress")
|
||||||
|
tee = Column(String, default="White")
|
||||||
|
|
||||||
class HoleScore(Base):
|
class HoleScore(Base):
|
||||||
__tablename__ = "hole_scores"
|
__tablename__ = "hole_scores"
|
||||||
@@ -82,7 +83,6 @@ HoleScore.round = relationship("Round", back_populates="hole_scores")
|
|||||||
HoleScore.putts = relationship("Putt", back_populates="hole_score")
|
HoleScore.putts = relationship("Putt", back_populates="hole_score")
|
||||||
Putt.hole_score = relationship("HoleScore", back_populates="putts")
|
Putt.hole_score = relationship("HoleScore", back_populates="putts")
|
||||||
|
|
||||||
# Recreate DB for prototype if schema changed
|
|
||||||
if os.path.exists("backend/golf.db"):
|
if os.path.exists("backend/golf.db"):
|
||||||
os.remove("backend/golf.db")
|
os.remove("backend/golf.db")
|
||||||
|
|
||||||
@@ -133,11 +133,12 @@ def signup(req: SignupRequest):
|
|||||||
class StartRoundRequest(BaseModel):
|
class StartRoundRequest(BaseModel):
|
||||||
user_id: int
|
user_id: int
|
||||||
course_id: int
|
course_id: int
|
||||||
|
tee: str = "White"
|
||||||
|
|
||||||
@app.post("/round")
|
@app.post("/round")
|
||||||
def start_round(req: StartRoundRequest):
|
def start_round(req: StartRoundRequest):
|
||||||
db = SessionLocal()
|
db = SessionLocal()
|
||||||
round_obj = Round(user_id=req.user_id, course_id=req.course_id, status="in_progress")
|
round_obj = Round(user_id=req.user_id, course_id=req.course_id, status="in_progress", tee=req.tee)
|
||||||
db.add(round_obj)
|
db.add(round_obj)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(round_obj)
|
db.refresh(round_obj)
|
||||||
@@ -147,7 +148,7 @@ def start_round(req: StartRoundRequest):
|
|||||||
db.add(hs)
|
db.add(hs)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
return {"id": round_obj.id, "status": round_obj.status}
|
return {"id": round_obj.id, "status": round_obj.status, "tee": round_obj.tee}
|
||||||
|
|
||||||
@app.get("/course")
|
@app.get("/course")
|
||||||
def get_course():
|
def get_course():
|
||||||
@@ -174,6 +175,7 @@ def get_round(round_id: int):
|
|||||||
"user_id": round_obj.user_id,
|
"user_id": round_obj.user_id,
|
||||||
"course_id": round_obj.course_id,
|
"course_id": round_obj.course_id,
|
||||||
"status": round_obj.status,
|
"status": round_obj.status,
|
||||||
|
"tee": round_obj.tee,
|
||||||
"holes": []
|
"holes": []
|
||||||
}
|
}
|
||||||
for hs in hole_scores:
|
for hs in hole_scores:
|
||||||
@@ -197,7 +199,7 @@ def get_round(round_id: int):
|
|||||||
"hole_info": {
|
"hole_info": {
|
||||||
"par": hole.par if hole else None,
|
"par": hole.par if hole else None,
|
||||||
"yardage_meters": hole.yardage_meters if hole else 0,
|
"yardage_meters": hole.yardage_meters if hole else 0,
|
||||||
"tee": hole.tee if hole else "White"
|
"tee": round_obj.tee
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
db.close()
|
db.close()
|
||||||
|
|||||||
+22
-6
@@ -26,10 +26,11 @@ async function loadCourse() {
|
|||||||
async function startRound() {
|
async function startRound() {
|
||||||
const res = await fetch('/course');
|
const res = await fetch('/course');
|
||||||
const course = await res.json();
|
const course = await res.json();
|
||||||
|
const tee = document.getElementById('tee-select').value;
|
||||||
const res2 = await fetch('/round', {
|
const res2 = await fetch('/round', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({user_id: currentUser.id, course_id: course.id})
|
body: JSON.stringify({user_id: currentUser.id, course_id: course.id, tee: tee})
|
||||||
});
|
});
|
||||||
currentRound = await res2.json();
|
currentRound = await res2.json();
|
||||||
document.getElementById('start-section').style.display = 'none';
|
document.getElementById('start-section').style.display = 'none';
|
||||||
@@ -54,8 +55,6 @@ function renderHole(hole) {
|
|||||||
document.getElementById('hole-label').textContent = `Hole ${hole.hole_number}`;
|
document.getElementById('hole-label').textContent = `Hole ${hole.hole_number}`;
|
||||||
document.getElementById('strokes').value = hole.strokes || 1;
|
document.getElementById('strokes').value = hole.strokes || 1;
|
||||||
document.getElementById('unfinished').checked = hole.unfinished || false;
|
document.getElementById('unfinished').checked = hole.unfinished || false;
|
||||||
document.getElementById('skipped').checked = hole.skipped || false;
|
|
||||||
document.getElementById('completed').checked = hole.completed || false;
|
|
||||||
document.getElementById('fairway').checked = hole.fairway_hit || false;
|
document.getElementById('fairway').checked = hole.fairway_hit || false;
|
||||||
document.getElementById('gir-display').textContent = hole.gir ? 'Yes' : 'No';
|
document.getElementById('gir-display').textContent = hole.gir ? 'Yes' : 'No';
|
||||||
|
|
||||||
@@ -102,8 +101,6 @@ async function saveHole() {
|
|||||||
const id = document.getElementById('hole-score-id').value;
|
const id = document.getElementById('hole-score-id').value;
|
||||||
const strokes = parseInt(document.getElementById('strokes').value) || 1;
|
const strokes = parseInt(document.getElementById('strokes').value) || 1;
|
||||||
const unfinished = document.getElementById('unfinished').checked;
|
const unfinished = document.getElementById('unfinished').checked;
|
||||||
const skipped = document.getElementById('skipped').checked;
|
|
||||||
const completed = document.getElementById('completed').checked;
|
|
||||||
const fairway = document.getElementById('fairway').checked;
|
const fairway = document.getElementById('fairway').checked;
|
||||||
|
|
||||||
const puttsGreen = parseInt(document.getElementById('putts-green').value) || 0;
|
const puttsGreen = parseInt(document.getElementById('putts-green').value) || 0;
|
||||||
@@ -120,7 +117,7 @@ async function saveHole() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
strokes, skipped, completed, fairway_hit: fairway, unfinished,
|
strokes, skipped: false, completed: false, fairway_hit: fairway, unfinished,
|
||||||
putts_green: puttsGreen, putts_off_green: puttsOffGreen,
|
putts_green: puttsGreen, putts_off_green: puttsOffGreen,
|
||||||
penalty_water: penWater, penalty_ob: penOb, penalty_lost: penLost,
|
penalty_water: penWater, penalty_ob: penOb, penalty_lost: penLost,
|
||||||
bunker_greenside: bunkerGreenside, bunker_fairway: bunkerFairway
|
bunker_greenside: bunkerGreenside, bunker_fairway: bunkerFairway
|
||||||
@@ -131,6 +128,25 @@ async function saveHole() {
|
|||||||
loadRound();
|
loadRound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function skipHole() {
|
||||||
|
const id = document.getElementById('hole-score-id').value;
|
||||||
|
await fetch(`/hole/${id}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify({
|
||||||
|
strokes: 0, skipped: true, completed: false, fairway_hit: false, unfinished: false,
|
||||||
|
putts_green: 0, putts_off_green: 0,
|
||||||
|
penalty_water: false, penalty_ob: false, penalty_lost: false,
|
||||||
|
bunker_greenside: false, bunker_fairway: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const holes = currentData.holes.sort((a,b) => a.hole_number - b.hole_number);
|
||||||
|
if (currentIndex < holes.length - 1) {
|
||||||
|
currentIndex++;
|
||||||
|
loadRound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadStats() {
|
async function loadStats() {
|
||||||
const res = await fetch(`/stats/${currentRound.id}`);
|
const res = await fetch(`/stats/${currentRound.id}`);
|
||||||
const stats = await res.json();
|
const stats = await res.json();
|
||||||
|
|||||||
+2
-2
@@ -27,6 +27,7 @@ button { padding: 0.4rem 0.8rem; margin-right: 0.5rem; cursor: pointer; }
|
|||||||
<section id="start-section" style="display:none;">
|
<section id="start-section" style="display:none;">
|
||||||
<h2>Course</h2>
|
<h2>Course</h2>
|
||||||
<p id="course-info"></p>
|
<p id="course-info"></p>
|
||||||
|
<label>Tee: <select id="tee-select"><option>White</option><option>Yellow</option><option>Blue</option><option>Red</option></select></label><br>
|
||||||
<button onclick="startRound()">Start Round</button>
|
<button onclick="startRound()">Start Round</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -36,14 +37,13 @@ button { padding: 0.4rem 0.8rem; margin-right: 0.5rem; cursor: pointer; }
|
|||||||
<button id="prev-btn" onclick="prevHole()">Prev</button>
|
<button id="prev-btn" onclick="prevHole()">Prev</button>
|
||||||
<strong id="hole-label">Hole 1</strong>
|
<strong id="hole-label">Hole 1</strong>
|
||||||
<button id="next-btn" onclick="nextHole()">Next</button>
|
<button id="next-btn" onclick="nextHole()">Next</button>
|
||||||
|
<button onclick="skipHole()">Skip</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="hole-info"></div>
|
<div id="hole-info"></div>
|
||||||
<form id="hole-form" onsubmit="event.preventDefault(); saveHole();">
|
<form id="hole-form" onsubmit="event.preventDefault(); saveHole();">
|
||||||
<input type="hidden" id="hole-score-id" />
|
<input type="hidden" id="hole-score-id" />
|
||||||
<label>Strokes (1+): <input id="strokes" type="number" value="1" min="1" /></label><br>
|
<label>Strokes (1+): <input id="strokes" type="number" value="1" min="1" /></label><br>
|
||||||
<label>Unfinished (X): <input id="unfinished" type="checkbox" /></label><br>
|
<label>Unfinished (X): <input id="unfinished" type="checkbox" /></label><br>
|
||||||
<label>Skipped: <input id="skipped" type="checkbox" /></label><br>
|
|
||||||
<label>Completed: <input id="completed" type="checkbox" /></label><br>
|
|
||||||
<label>Fairway Hit: <input id="fairway" type="checkbox" /></label><br>
|
<label>Fairway Hit: <input id="fairway" type="checkbox" /></label><br>
|
||||||
<label>Putts on Green: <input id="putts-green" type="number" value="0" min="0" /></label><br>
|
<label>Putts on Green: <input id="putts-green" type="number" value="0" min="0" /></label><br>
|
||||||
<label>Putts Off Green: <input id="putts-off-green" type="number" value="0" min="0" /></label><br>
|
<label>Putts Off Green: <input id="putts-off-green" type="number" value="0" min="0" /></label><br>
|
||||||
|
|||||||
Reference in new issue
Block a user