Add all trades, rename trades_list -> my_trades_list, and fix bottom dock bar for sm screen users

This commit is contained in:
badblocks 2025-03-12 00:37:55 -07:00
parent d62956d465
commit 0990340cbc
7 changed files with 114 additions and 28 deletions

View file

@ -4,19 +4,19 @@
{% block head_title %}{% trans "Settings" %}{% endblock %} {% block head_title %}{% trans "Settings" %}{% endblock %}
{% block content %} {% block content %}
<div class="container mx-auto flex items-center justify-center min-h-screen"> <div class="container mx-auto">
<div class="w-full max-w-sm p-6 bg-base-100 shadow rounded-box"> <h1 class="text-3xl font-bold text-center mb-6">{% trans "Settings" %}</h1>
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Settings" %}</h1> <div class="card card-border bg-base-100 shadow-lg w-4/5 mx-auto">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-6 w-full mx-auto p-6">
<a href="{% url 'list_friend_codes' %}" class="btn btn-primary w-full"> <a href="https://gravatar.com/profile/" target="_blank" rel="noopener noreferrer" class="btn btn-secondary">
{% trans "Profile" %}
</a>
<a href="{% url 'list_friend_codes' %}" class="btn btn-primary">
{% trans "Friend Codes" %} {% trans "Friend Codes" %}
</a> </a>
<a href="{% url 'account_logout' %}" class="btn btn-warning w-full"> <a href="{% url 'account_logout' %}" class="btn btn-warning">
{% trans "Logout" %} {% trans "Logout" %}
</a> </a>
<a href="https://www.gravatar.com/profile/" target="_blank" rel="noopener noreferrer" class="btn btn-secondary w-full">
{% trans "Profile" %}
</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -51,7 +51,7 @@
<a>Trade</a> <a>Trade</a>
<ul class="p-2"> <ul class="p-2">
<li><a href="{% url 'trade_offer_list' %}">All Offers</a></li> <li><a href="{% url 'trade_offer_list' %}">All Offers</a></li>
<li><a href="{% url 'trade_offer_list' %}?my_trades=true">My Trades</a></li> <li><a href="{% url 'trade_offer_my_list' %}">My Trades</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -72,22 +72,16 @@
<li><a href="{% url 'home' %}">Home</a></li> <li><a href="{% url 'home' %}">Home</a></li>
<li> <li>
<details> <details>
<summary>Trade</summary> <summary>Trades</summary>
<ul class="p-2 w-32 z-10"> <ul class="p-2 w-32 z-10">
<li><a href="{% url 'trade_offer_list' %}">All Offers</a></li> <li><a href="{% url 'trade_offer_list' %}">All Offers</a></li>
<li><a href="{% url 'trade_offer_list' %}?my_trades=true">My Trades</a></li> <li><a href="{% url 'trade_offer_my_list' %}">My Trades</a></li>
</ul> </ul>
</details> </details>
</li> </li>
</ul> </ul>
</div> </div>
<div class="navbar-end"> <div class="navbar-end">
<!-- <button class="btn btn-ghost btn-circle hidden sm:flex">
<div class="indicator">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" /> </svg>
<div aria-label="success" class="status status-success"></div>
</div>
</button> -->
<button id="theme-toggle-btn" class="btn btn-ghost btn-circle me-2" title="Toggle Theme"> <button id="theme-toggle-btn" class="btn btn-ghost btn-circle me-2" title="Toggle Theme">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 dark:hidden"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 dark:hidden">
@ -98,7 +92,7 @@
</svg> </svg>
</button> </button>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<div class="dropdown dropdown-end"> <div class="dropdown dropdown-end hidden sm:block">
<div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar"> <div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar">
<div class="w-10 rounded-full"> <div class="w-10 rounded-full">
{{ user.email|gravatar:40 }} {{ user.email|gravatar:40 }}
@ -143,7 +137,7 @@
</footer> </footer>
<!-- Dock --> <!-- Dock -->
<div x-data class="dock bg-neutral text-neutral-content"> <div x-data class="dock bg-neutral text-neutral-content sm:hidden">
<button @click="window.location.href = '{% url 'home' %}'" class="{% if request.path == '/' %}dock-active{% endif %}"> <button @click="window.location.href = '{% url 'home' %}'" class="{% if request.path == '/' %}dock-active{% endif %}">
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><polyline points="1 11 12 2 23 11" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><path d="m5,13v7c0,1.105.895,2,2,2h10c1.105,0,2-.895,2-2v-7" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path><line x1="12" y1="22" x2="12" y2="18" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></line></g></svg> <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><polyline points="1 11 12 2 23 11" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><path d="m5,13v7c0,1.105.895,2,2,2h10c1.105,0,2-.895,2-2v-7" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path><line x1="12" y1="22" x2="12" y2="18" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></line></g></svg>
<span class="dock-label">Home</span> <span class="dock-label">Home</span>
@ -152,7 +146,7 @@
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.625 4.5h12.75a1.875 1.875 0 0 1 0 3.75H5.625a1.875 1.875 0 0 1 0-3.75Z" /></svg> <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.625 4.5h12.75a1.875 1.875 0 0 1 0 3.75H5.625a1.875 1.875 0 0 1 0-3.75Z" /></svg>
<span class="dock-label">All Offers</span> <span class="dock-label">All Offers</span>
</button> </button>
<button @click="window.location.href = '{% url 'trade_offer_list' %}?my_trades=true'" class="{% if '/trades/my/' in request.path %}dock-active{% endif %}"> <button @click="window.location.href = '{% url 'trade_offer_my_list' %}'" class="{% if '/trades/my/' in request.path %}dock-active{% endif %}">
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" /></svg> <svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" /></svg>
<span class="dock-label">My Trades</span> <span class="dock-label">My Trades</span>
</button> </button>

View file

@ -20,7 +20,7 @@
{% for code in friend_codes %} {% for code in friend_codes %}
<li class="flex items-center justify-between {% if user.default_friend_code and code.id == user.default_friend_code.id %}bg-green-100{% else %}bg-base-100{% endif %} p-4 rounded shadow"> <li class="flex items-center justify-between {% if user.default_friend_code and code.id == user.default_friend_code.id %}bg-green-100{% else %}bg-base-100{% endif %} p-4 rounded shadow">
<div> <div>
<span class="font-mono">{{ code.friend_code }}</span> <span class="font-mono dark:text-base-100">{{ code.friend_code }}</span>
{% if user.default_friend_code and code.id == user.default_friend_code.id %} {% if user.default_friend_code and code.id == user.default_friend_code.id %}
<span class="badge badge-success ml-2">Default</span> <span class="badge badge-success ml-2">Default</span>
{% endif %} {% endif %}

View file

@ -0,0 +1,44 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}All Trade Offers{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-4xl mt-6">
<div class="flex justify-end mb-4">
<form method="get" class="flex items-center space-x-4">
<label class="cursor-pointer flex items-center space-x-2">
<span class="font-medium">Only Closed</span>
<input type="checkbox" name="show_closed" value="true" class="toggle toggle-primary" {% if show_closed %}checked{% endif %}>
</label>
<button type="submit" class="btn btn-primary">Apply</button>
</form>
</div>
<!-- Trade Offers -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">All Trade Offers</h2>
{% if all_trade_offers_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=all_trade_offers_paginated %}
<div class="flex justify-between items-center mt-4">
{% if all_trade_offers_paginated.has_previous %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'offers_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}offers_page={{ all_trade_offers_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ all_trade_offers_paginated.number }} of {{ all_trade_offers_paginated.paginator.num_pages }}</span>
{% if all_trade_offers_paginated.has_next %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'offers_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}offers_page={{ all_trade_offers_paginated.next_page_number }}" class="btn btn-sm">Next</a>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p>No trade offers found.</p>
{% endif %}
</section>
<div class="mt-6">
<a href="{% url 'trade_offer_create' %}" class="btn btn-success">Create New Offer</a>
</div>
</div>
{% endblock content %}

View file

@ -2,7 +2,8 @@ from django.urls import path
from .views import ( from .views import (
TradeOfferCreateView, TradeOfferCreateView,
TradeOfferListView, TradeOfferAllListView,
TradeOfferMyListView,
TradeOfferDetailView, TradeOfferDetailView,
TradeAcceptanceCreateView, TradeAcceptanceCreateView,
TradeAcceptanceUpdateView, TradeAcceptanceUpdateView,
@ -12,10 +13,11 @@ from .views import (
urlpatterns = [ urlpatterns = [
path("create/", TradeOfferCreateView.as_view(), name="trade_offer_create"), path("create/", TradeOfferCreateView.as_view(), name="trade_offer_create"),
path("", TradeOfferListView.as_view(), name="trade_offer_list"), path("all/", TradeOfferAllListView.as_view(), name="trade_offer_list"),
path("my/", TradeOfferMyListView.as_view(), name="trade_offer_my_list"),
path("search/", TradeOfferSearchView.as_view(), name="trade_offer_search"), path("search/", TradeOfferSearchView.as_view(), name="trade_offer_search"),
path("<int:pk>/", TradeOfferDetailView.as_view(), name="trade_offer_detail"), path("<int:pk>/", TradeOfferDetailView.as_view(), name="trade_offer_detail"),
path("delete/<int:pk>/", TradeOfferDeleteView.as_view(), name="trade_offer_delete"), path("delete/<int:pk>/", TradeOfferDeleteView.as_view(), name="trade_offer_delete"),
path("offer/<int:offer_pk>/accept/", TradeAcceptanceCreateView.as_view(), name="trade_acceptance_create"), path("offer/<int:offer_pk>", TradeAcceptanceCreateView.as_view(), name="trade_acceptance_create"),
path("acceptance/<int:pk>/", TradeAcceptanceUpdateView.as_view(), name="trade_acceptance_update"), path("accept/<int:pk>/", TradeAcceptanceUpdateView.as_view(), name="trade_acceptance_update"),
] ]

View file

@ -68,9 +68,55 @@ class TradeOfferCreateView(LoginRequiredMixin, CreateView):
self.object = form.save() self.object = form.save()
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
class TradeOfferListView(LoginRequiredMixin, ListView): class TradeOfferAllListView(ListView):
model = TradeOffer
template_name = "trades/trade_offer_all_list.html"
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
request = self.request
show_closed = request.GET.get("show_closed", "false").lower() == "true"
context["show_closed"] = show_closed
queryset = (
TradeOffer.objects.select_related('initiated_by')
.prefetch_related(
'trade_offer_have_cards__card',
'trade_offer_want_cards__card',
Prefetch(
'acceptances',
queryset=TradeAcceptance.objects.select_related('accepted_by', 'requested_card', 'offered_card')
)
)
.order_by("-updated_at")
.annotate(
is_active=Case(
When(
manually_closed=False,
total_have_quantity__gt=F('total_have_accepted'),
total_want_quantity__gt=F('total_want_accepted'),
then=Value(True)
),
default=Value(False),
output_field=BooleanField()
)
)
)
if show_closed:
queryset = queryset.filter(is_active=False)
else:
queryset = queryset.filter(is_active=True)
offers_page = request.GET.get("offers_page")
offers_paginator = Paginator(queryset, 10)
context["all_trade_offers_paginated"] = offers_paginator.get_page(offers_page)
return context
class TradeOfferMyListView(LoginRequiredMixin, ListView):
model = TradeOffer # Fallback model; our context data holds separate filtered querysets. model = TradeOffer # Fallback model; our context data holds separate filtered querysets.
template_name = "trades/trade_offer_list.html" template_name = "trades/trade_offer_my_list.html"
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and not request.user.friend_codes.exists(): if request.user.is_authenticated and not request.user.friend_codes.exists():