8601584099
- Playing handicap: computed at game creation (WHS formula), stored on game_players alongside per-hole strokes allocation; displayed on game summary with HC card and / markers on scorecard (only when SI defined); live game shows +N per player card when SI exists, HC total otherwise; new game confirmation previews computed HC per player - Login: 6-digit code sent alongside magic link in every auth email; check_email page has auto-advancing digit inputs with paste support; new POST /auth/verify-code route handles code verification - Game view: Score/Card toggle fixed with position:fixed to always show above nav bar on mobile; swipe on score view changes holes, swipe on scorecard switches tabs; dirty tracking prevents saving unmodified holes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
155 lines
7.7 KiB
HTML
155 lines
7.7 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Edit Course – Skins & Pins{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="page">
|
||
<div class="page-header">
|
||
<a href="/admin/courses" style="color:var(--text-muted); font-size:0.9rem;">← Courses</a>
|
||
<h1 style="margin-top:0.25rem;">{{ course.name }}</h1>
|
||
</div>
|
||
|
||
{% if request.query_params.get('success') %}
|
||
<div class="alert alert-success">{{ request.query_params.get('success') }}</div>
|
||
{% endif %}
|
||
|
||
{# ── Course info + hole pars ── #}
|
||
<form method="post" action="/admin/courses/{{ course.id }}/edit">
|
||
<div class="card">
|
||
<h2 style="font-size:0.95rem; color:var(--text-muted); margin-bottom:1rem;">Course info</h2>
|
||
|
||
<div class="form-group">
|
||
<label for="name">Course name</label>
|
||
{% if errors and errors.name %}<div class="alert alert-error">{{ errors.name }}</div>{% endif %}
|
||
<input type="text" id="name" name="name" value="{{ course.name }}" required>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="location">Location <span style="color:var(--text-muted); font-size:0.8rem;">(optional)</span></label>
|
||
<input type="text" id="location" name="location" value="{{ course.location or '' }}"
|
||
placeholder="e.g. Augusta, Georgia">
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Holes</label>
|
||
<div style="display:flex; gap:0.75rem;">
|
||
<label class="radio-card">
|
||
<input type="radio" name="holes" value="9" {% if course.holes == 9 %}checked{% endif %}>
|
||
<span>9 holes</span>
|
||
</label>
|
||
<label class="radio-card">
|
||
<input type="radio" name="holes" value="18" {% if course.holes == 18 %}checked{% endif %}>
|
||
<span>18 holes</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card"
|
||
x-data="{ pars: { {% for h in holes %}'{{ h.hole_number }}': {{ h.par or 4 }}{% if not loop.last %}, {% endif %}{% endfor %} }, coursePar() { return Object.values(this.pars).reduce((a, b) => a + parseInt(b), 0); } }">
|
||
<h2 style="font-size:0.95rem; color:var(--text-muted); margin-bottom:0.75rem;">
|
||
Hole details <span style="font-weight:400;">— Course par: <strong x-text="coursePar()"></strong></span>
|
||
</h2>
|
||
<div class="hole-pars-grid">
|
||
{% for h in holes %}
|
||
<div class="hole-par-cell">
|
||
<div class="hole-par-label">{{ h.hole_number }}</div>
|
||
<select name="par_{{ h.hole_number }}" class="hole-par-select" x-model="pars['{{ h.hole_number }}']">
|
||
<option value="3" {% if h.par == 3 %}selected{% endif %}>3</option>
|
||
<option value="4" {% if h.par == 4 %}selected{% endif %}>4</option>
|
||
<option value="5" {% if h.par == 5 %}selected{% endif %}>5</option>
|
||
</select>
|
||
<select name="si_{{ h.hole_number }}" class="hole-par-select">
|
||
<option value="">—</option>
|
||
{% for s in range(1, course.holes + 1) %}
|
||
<option value="{{ s }}" {% if h.stroke_index == s %}selected{% endif %}>{{ s }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn btn-primary" style="margin-bottom:1.5rem;">Save changes</button>
|
||
</form>
|
||
|
||
{# ── Tees ── #}
|
||
<div class="card">
|
||
<h2 style="font-size:0.95rem; color:var(--text-muted); margin-bottom:1rem;">Tees</h2>
|
||
|
||
{% if tees %}
|
||
<div style="margin-bottom:1.25rem;">
|
||
{% for t in tees %}
|
||
<div x-data="{ editing: false }" style="border-bottom:1px solid var(--border); padding:0.6rem 0;">
|
||
|
||
<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>
|
||
<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>
|
||
<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"
|
||
style="display:inline;"
|
||
onsubmit="return confirm('Delete {{ t.name }} tee?')">
|
||
<button type="submit" class="btn-table-action danger">Delete</button>
|
||
</form>
|
||
</span>
|
||
</div>
|
||
|
||
<form x-show="editing" method="post"
|
||
action="/admin/courses/{{ course.id }}/tees/{{ t.id }}/edit"
|
||
style="display:flex; gap:0.5rem; align-items:flex-end; flex-wrap:wrap; padding-top:0.4rem;">
|
||
<div class="form-group" style="margin:0; flex:1; min-width:7rem;">
|
||
<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: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;">
|
||
</div>
|
||
<div class="form-group" style="margin:0; width:7rem;">
|
||
<label style="font-size:0.8rem;">Rating</label>
|
||
<input type="number" step="0.1" name="rating" value="{{ t.rating }}"
|
||
min="{{ '29' if course.holes == 9 else '60' }}" max="{{ '40' if course.holes == 9 else '80' }}"
|
||
required style="padding:0.4rem 0.6rem;">
|
||
</div>
|
||
<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"
|
||
style="padding:0.4rem 0.75rem; font-size:0.85rem; background:none; border:1px solid var(--border); border-radius:0.4rem; color:var(--text-muted); cursor:pointer;">Cancel</button>
|
||
</div>
|
||
</form>
|
||
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% else %}
|
||
<p style="color:var(--text-muted); font-size:0.9rem; margin-bottom:1rem;">No tees yet. Add at least one tee so players can start a game on this course.</p>
|
||
{% endif %}
|
||
|
||
{# Add tee form #}
|
||
<h3 style="font-size:0.85rem; color:var(--text-muted); margin-bottom:0.75rem; text-transform:uppercase; letter-spacing:0.05em;">Add tee</h3>
|
||
<form method="post" action="/admin/courses/{{ course.id }}/tees/new"
|
||
style="display:flex; gap:0.5rem; align-items:flex-end; flex-wrap:wrap;">
|
||
<div class="form-group" style="margin:0; flex:1; min-width:7rem;">
|
||
<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: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;">
|
||
</div>
|
||
<div class="form-group" style="margin:0; width:7rem;">
|
||
<label style="font-size:0.8rem;">Rating</label>
|
||
<input type="number" step="0.1" name="rating"
|
||
placeholder="{{ '35.0' if course.holes == 9 else '72.0' }}"
|
||
min="{{ '29' if course.holes == 9 else '60' }}" max="{{ '40' if course.holes == 9 else '80' }}"
|
||
required style="padding:0.4rem 0.6rem;">
|
||
</div>
|
||
<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>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|