phase5: add saved searches, watchlist, and authenticated htmx flows
This commit is contained in:
@ -4,7 +4,25 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<h1>Scouting</h1>
|
||||
<p>Scouting module scaffolding for upcoming phases.</p>
|
||||
<div class="row-between wrap-gap">
|
||||
<div>
|
||||
<h1>Scouting Workspace</h1>
|
||||
<p class="muted-text">Manage saved searches and your player watchlist.</p>
|
||||
</div>
|
||||
<div class="row-gap">
|
||||
<a class="button ghost" href="{% url 'scouting:saved_search_list' %}">All saved searches</a>
|
||||
<a class="button ghost" href="{% url 'scouting:watchlist' %}">Watchlist</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel mt-16">
|
||||
<h2>Saved Searches</h2>
|
||||
{% include "scouting/partials/saved_search_table.html" with saved_searches=saved_searches %}
|
||||
</section>
|
||||
|
||||
<section class="panel mt-16">
|
||||
<h2>Watchlist</h2>
|
||||
{% include "scouting/partials/watchlist_table.html" with favorites=favorites %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
16
templates/scouting/partials/favorite_button.html
Normal file
16
templates/scouting/partials/favorite_button.html
Normal file
@ -0,0 +1,16 @@
|
||||
<form
|
||||
id="favorite-form-{{ player.id }}"
|
||||
method="post"
|
||||
action="{% url 'scouting:favorite_toggle' player.id %}"
|
||||
hx-post="{% url 'scouting:favorite_toggle' player.id %}"
|
||||
hx-target="#favorite-form-{{ player.id }}"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="next" value="{{ next_url }}">
|
||||
{% if is_favorite %}
|
||||
<button type="submit" class="button ghost">Remove favorite</button>
|
||||
{% else %}
|
||||
<button type="submit" class="button ghost">Add favorite</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
3
templates/scouting/partials/save_search_feedback.html
Normal file
3
templates/scouting/partials/save_search_feedback.html
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="message {% if ok %}success{% else %}error{% endif %}">
|
||||
{{ message }}
|
||||
</div>
|
||||
27
templates/scouting/partials/save_search_form.html
Normal file
27
templates/scouting/partials/save_search_form.html
Normal file
@ -0,0 +1,27 @@
|
||||
<div class="panel mt-16">
|
||||
<h3>Save Current Search</h3>
|
||||
<p class="muted-text">Store current filters and replay them later.</p>
|
||||
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'scouting:saved_search_create' %}"
|
||||
class="row-gap"
|
||||
hx-post="{% url 'scouting:saved_search_create' %}"
|
||||
hx-target="#saved-search-feedback"
|
||||
hx-swap="innerHTML"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<input type="text" name="name" placeholder="Search name" required>
|
||||
<label class="inline-label">
|
||||
<input type="checkbox" name="is_public">
|
||||
Public
|
||||
</label>
|
||||
|
||||
{% for key, value in request.GET.items %}
|
||||
<input type="hidden" name="{{ key }}" value="{{ value }}">
|
||||
{% endfor %}
|
||||
|
||||
<button class="button" type="submit">Save search</button>
|
||||
</form>
|
||||
<div id="saved-search-feedback" class="mt-16"></div>
|
||||
</div>
|
||||
37
templates/scouting/partials/saved_search_table.html
Normal file
37
templates/scouting/partials/saved_search_table.html
Normal file
@ -0,0 +1,37 @@
|
||||
{% if saved_searches %}
|
||||
<div class="table-wrap mt-16">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Visibility</th>
|
||||
<th>Updated</th>
|
||||
<th>Last run</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for saved_search in saved_searches %}
|
||||
<tr>
|
||||
<td>{{ saved_search.name }}</td>
|
||||
<td>{% if saved_search.is_public %}Public{% else %}Private{% endif %}</td>
|
||||
<td>{{ saved_search.updated_at|date:"Y-m-d H:i" }}</td>
|
||||
<td>{{ saved_search.last_run_at|date:"Y-m-d H:i"|default:"-" }}</td>
|
||||
<td>
|
||||
<div class="row-gap">
|
||||
<a class="button ghost" href="{% url 'scouting:saved_search_run' saved_search.pk %}">Run</a>
|
||||
<a class="button ghost" href="{% url 'scouting:saved_search_edit' saved_search.pk %}">Edit</a>
|
||||
<form method="post" action="{% url 'scouting:saved_search_delete' saved_search.pk %}">
|
||||
{% csrf_token %}
|
||||
<button class="button ghost" type="submit">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mt-16">No saved searches yet.</p>
|
||||
{% endif %}
|
||||
35
templates/scouting/partials/watchlist_table.html
Normal file
35
templates/scouting/partials/watchlist_table.html
Normal file
@ -0,0 +1,35 @@
|
||||
{% if favorites %}
|
||||
<div class="table-wrap mt-16">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Player</th>
|
||||
<th>Nationality</th>
|
||||
<th>Position / Role</th>
|
||||
<th>Added</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for favorite in favorites %}
|
||||
<tr>
|
||||
<td><a href="{% url 'players:detail' favorite.player_id %}">{{ favorite.player.full_name }}</a></td>
|
||||
<td>{{ favorite.player.nationality.name|default:"-" }}</td>
|
||||
<td>
|
||||
{{ favorite.player.nominal_position.code|default:"-" }}
|
||||
/ {{ favorite.player.inferred_role.name|default:"-" }}
|
||||
</td>
|
||||
<td>{{ favorite.created_at|date:"Y-m-d" }}</td>
|
||||
<td>
|
||||
<div id="favorite-toggle-{{ favorite.player_id }}">
|
||||
{% include "scouting/partials/favorite_button.html" with player=favorite.player is_favorite=True next_url=request.get_full_path %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mt-16">No players in your watchlist yet.</p>
|
||||
{% endif %}
|
||||
17
templates/scouting/saved_search_edit.html
Normal file
17
templates/scouting/saved_search_edit.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}HoopScout | Edit Saved Search{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="panel narrow">
|
||||
<h1>Edit Saved Search</h1>
|
||||
<form method="post" class="stack">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="row-gap">
|
||||
<button type="submit" class="button">Update</button>
|
||||
<a class="button ghost" href="{% url 'scouting:index' %}">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
13
templates/scouting/saved_search_list.html
Normal file
13
templates/scouting/saved_search_list.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}HoopScout | Saved Searches{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<div class="row-between wrap-gap">
|
||||
<h1>Saved Searches</h1>
|
||||
<a class="button ghost" href="{% url 'scouting:index' %}">Back to scouting</a>
|
||||
</div>
|
||||
{% include "scouting/partials/saved_search_table.html" with saved_searches=saved_searches %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
13
templates/scouting/watchlist.html
Normal file
13
templates/scouting/watchlist.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}HoopScout | Watchlist{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<div class="row-between wrap-gap">
|
||||
<h1>Watchlist</h1>
|
||||
<a class="button ghost" href="{% url 'scouting:index' %}">Back to scouting</a>
|
||||
</div>
|
||||
{% include "scouting/partials/watchlist_table.html" with favorites=favorites %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user