Import gender tees + front/back split ratings; front/back/9 hole selection

Course import now fetches both male and female tees, each with their own
per-tee stroke indices extracted from the holes array. Front and back 9
slope/rating are stored per tee for more accurate WHS handicap calculation.

New game creation replaces the 9/18 radio with a course-aware selector:
18-hole courses offer 18 holes, Front 9, or Back 9; 9-hole courses auto-
select. start_hole is stored on the game and used throughout scoring,
handicap calculation, and scorecard rendering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Rolf
2026-03-23 22:37:20 +01:00
parent 5432734240
commit 3e98f5ae54
6 changed files with 211 additions and 78 deletions
+53
View File
@@ -83,8 +83,11 @@
<div x-show="!editing" style="display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap;">
<span style="font-weight:500; min-width:5rem;">{{ t.name }}</span>
{% if t.gender %}<span style="font-size:0.75rem; padding:0.1rem 0.4rem; border-radius:0.25rem; background:var(--surface2); color:var(--text-muted);">{{ t.gender }}</span>{% endif %}
<span style="color:var(--text-muted); font-size:0.85rem;">Slope {{ t.slope }}</span>
<span style="color:var(--text-muted); font-size:0.85rem;">Rating {{ t.rating }}</span>
{% if t.front_slope and t.front_rating %}<span style="color:var(--text-muted); font-size:0.8rem;">· F {{ t.front_slope }}/{{ t.front_rating }}</span>{% endif %}
{% if t.back_slope and t.back_rating %}<span style="color:var(--text-muted); font-size:0.8rem;">B {{ t.back_slope }}/{{ t.back_rating }}</span>{% endif %}
<span style="margin-left:auto; display:flex; gap:0.4rem;">
<button type="button" @click="editing = true" class="btn-table-action">Edit</button>
<form method="post" action="/admin/courses/{{ course.id }}/tees/{{ t.id }}/delete"
@@ -102,6 +105,13 @@
<label style="font-size:0.8rem;">Name</label>
<input type="text" name="name" value="{{ t.name }}" required style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:6.5rem;">
<label style="font-size:0.8rem;">Gender</label>
<select name="gender" style="padding:0.4rem 0.6rem; border-radius:0.4rem; border:1px solid var(--border); background:var(--surface); color:var(--text); font-size:0.9rem;">
<option value="male" {% if t.gender == 'male' or not t.gender %}selected{% endif %}>Male</option>
<option value="female" {% if t.gender == 'female' %}selected{% endif %}>Female</option>
</select>
</div>
<div class="form-group" style="margin:0; width:6rem;">
<label style="font-size:0.8rem;">Slope</label>
<input type="number" name="slope" value="{{ t.slope }}" min="55" max="155" required style="padding:0.4rem 0.6rem;">
@@ -112,6 +122,24 @@
min="{{ '29' if course.holes == 9 else '60' }}" max="{{ '40' if course.holes == 9 else '80' }}"
required style="padding:0.4rem 0.6rem;">
</div>
{% if course.holes == 18 %}
<div class="form-group" style="margin:0; width:5.5rem;">
<label style="font-size:0.8rem;">Front slope</label>
<input type="number" name="front_slope" value="{{ t.front_slope or '' }}" min="55" max="155" style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:6rem;">
<label style="font-size:0.8rem;">Front rating</label>
<input type="number" step="0.1" name="front_rating" value="{{ t.front_rating or '' }}" min="29" max="45" style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:5.5rem;">
<label style="font-size:0.8rem;">Back slope</label>
<input type="number" name="back_slope" value="{{ t.back_slope or '' }}" min="55" max="155" style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:6rem;">
<label style="font-size:0.8rem;">Back rating</label>
<input type="number" step="0.1" name="back_rating" value="{{ t.back_rating or '' }}" min="29" max="45" style="padding:0.4rem 0.6rem;">
</div>
{% endif %}
<div style="display:flex; gap:0.4rem; padding-bottom:0.1rem;">
<button type="submit" class="btn btn-primary" style="padding:0.4rem 0.75rem; font-size:0.85rem;">Save</button>
<button type="button" @click="editing = false"
@@ -134,6 +162,13 @@
<label style="font-size:0.8rem;">Name</label>
<input type="text" name="name" placeholder="e.g. White" required style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:6.5rem;">
<label style="font-size:0.8rem;">Gender</label>
<select name="gender" style="padding:0.4rem 0.6rem; border-radius:0.4rem; border:1px solid var(--border); background:var(--surface); color:var(--text); font-size:0.9rem;">
<option value="male">Male</option>
<option value="female">Female</option>
</select>
</div>
<div class="form-group" style="margin:0; width:6rem;">
<label style="font-size:0.8rem;">Slope</label>
<input type="number" name="slope" placeholder="113" min="55" max="155" required style="padding:0.4rem 0.6rem;">
@@ -145,6 +180,24 @@
min="{{ '29' if course.holes == 9 else '60' }}" max="{{ '40' if course.holes == 9 else '80' }}"
required style="padding:0.4rem 0.6rem;">
</div>
{% if course.holes == 18 %}
<div class="form-group" style="margin:0; width:5.5rem;">
<label style="font-size:0.8rem;">Front slope</label>
<input type="number" name="front_slope" placeholder="—" min="55" max="155" style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:6rem;">
<label style="font-size:0.8rem;">Front rating</label>
<input type="number" step="0.1" name="front_rating" placeholder="—" min="29" max="45" style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:5.5rem;">
<label style="font-size:0.8rem;">Back slope</label>
<input type="number" name="back_slope" placeholder="—" min="55" max="155" style="padding:0.4rem 0.6rem;">
</div>
<div class="form-group" style="margin:0; width:6rem;">
<label style="font-size:0.8rem;">Back rating</label>
<input type="number" step="0.1" name="back_rating" placeholder="—" min="29" max="45" style="padding:0.4rem 0.6rem;">
</div>
{% endif %}
<div style="padding-bottom:0.1rem;">
<button type="submit" class="btn btn-primary" style="padding:0.4rem 0.75rem; font-size:0.85rem;">Add tee</button>
</div>