fix card_multiselect filtering and quantity controls

This commit is contained in:
badblocks 2025-03-13 15:48:26 -07:00
parent 6e4c6040bd
commit b97ddde71c
52 changed files with 1689 additions and 2268 deletions

View file

@ -0,0 +1,9 @@
{% if messages %}
<div class="flex flex-col gap-2">
{% for message in messages %}
<div class="alert alert-{{ message.tags }} bg-base-100 mb-4">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}

View file

@ -7,7 +7,7 @@
{% block content %}
<div class="container mx-auto max-w-md mt-6 text-center">
<h1 class="text-3xl font-bold mb-6">{% trans "Account Inactive" %}</h1>
<p class="text-gray-700">
<p>
{% trans "This account is inactive." %}
</p>
</div>

View file

@ -15,7 +15,7 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.code.id_for_label }}" class="block font-medium text-gray-700">{% trans "Verification Code" %}</label>
<label for="{{ form.code.id_for_label }}" class="block font-medium>{% trans "Verification Code" %}</label>
{{ form.code }}
{{ form.code.errors }}
</div>

View file

@ -19,7 +19,7 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.code.id_for_label }}" class="block font-medium text-gray-700">{% trans "Sign-In Code" %}</label>
<label for="{{ form.code.id_for_label }}" class="block font-medium>{% trans "Sign-In Code" %}</label>
{{ form.code }}
{{ form.code.errors }}
</div>

View file

@ -15,7 +15,7 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.code.id_for_label }}" class="block font-medium text-gray-700">{% trans "Reset Code" %}</label>
<label for="{{ form.code.id_for_label }}" class="block font-medium>{% trans "Reset Code" %}</label>
{{ form.code }}
{{ form.code.errors }}
</div>

View file

@ -15,7 +15,7 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.code.id_for_label }}" class="block font-medium text-gray-700">{% trans "Verification Code" %}</label>
<label for="{{ form.code.id_for_label }}" class="block font-medium>{% trans "Verification Code" %}</label>
{{ form.code }}
{{ form.code.errors }}
</div>

View file

@ -8,7 +8,7 @@
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Email Addresses" %}</h1>
{% if emailaddresses %}
<p class="text-gray-700 mb-4">
<p class="mb-4">
{% trans "The following email addresses are associated with your account:" %}
</p>
{% url 'account_email' as email_url %}
@ -46,7 +46,7 @@
<form method="post" action="{{ action_url }}" class="space-y-4">
{% csrf_token %}
<div>
<label for="{{ form.email.id_for_label }}" class="block font-medium text-gray-700">{{ form.email.label }}</label>
<label for="{{ form.email.id_for_label }}" class="block font-medium>{{ form.email.label }}</label>
{{ form.email }}
{{ form.email.errors }}
</div>

View file

@ -15,13 +15,13 @@
{% csrf_token %}
{% if current_emailaddress %}
<div>
<label for="current_email" class="block font-medium text-gray-700">{% trans "Current email" %}:</label>
<label for="current_email" class="block font-medium>{% trans "Current email" %}:</label>
<input id="current_email" type="email" value="{{ current_emailaddress.email }}" disabled class="input input-bordered w-full">
</div>
{% endif %}
{% if new_emailaddress %}
<div>
<label for="new_email" class="block font-medium text-gray-700">
<label for="new_email" class="block font-medium>
{% if not current_emailaddress %}
{% trans "Current email" %}:
{% else %}
@ -41,7 +41,7 @@
</div>
{% endif %}
<div>
<label for="{{ form.email.id_for_label }}" class="block font-medium text-gray-700">{% trans "Change to" %}:</label>
<label for="{{ form.email.id_for_label }}" class="block font-medium>{% trans "Change to" %}:</label>
{{ form.email }}
{{ form.email.errors }}
</div>

View file

@ -10,7 +10,7 @@
{% if confirmation %}
{% user_display confirmation.email_address.user as user_display %}
{% if can_confirm %}
<p class="text-gray-700 mb-4">
<p class="mb-4">
{% blocktrans with confirmation.email_address.email as email %}
Please confirm that <a class="text-primary underline" href="mailto:{{ email }}">{{ email }}</a> is an email address for user {{ user_display }}.
{% endblocktrans %}
@ -22,13 +22,13 @@
<button type="submit" class="btn btn-primary w-full">{% trans "Confirm" %}</button>
</form>
{% else %}
<p class="text-gray-700">
<p>
{% blocktrans %}Unable to confirm {{ confirmation.email_address.email }} because it is already confirmed by a different account.{% endblocktrans %}
</p>
{% endif %}
{% else %}
{% url 'account_email' as email_url %}
<p class="text-gray-700">
<p>
{% blocktrans %}This email confirmation link expired or is invalid. Please <a class="text-primary underline" href="{{ email_url }}">issue a new email confirmation request</a>.{% endblocktrans %}
</p>
{% endif %}

View file

@ -10,12 +10,12 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.login.id_for_label }}" class="block font-medium text-gray-700">{{ form.login.label }}</label>
<label for="{{ form.login.id_for_label }}" class="block font-medium">{{ form.login.label }}</label>
{{ form.login }}
{{ form.login.errors }}
</div>
<div>
<label for="{{ form.password.id_for_label }}" class="block font-medium text-gray-700">{{ form.password.label }}</label>
<label for="{{ form.password.id_for_label }}" class="block font-medium">{{ form.password.label }}</label>
{{ form.password }}
{{ form.password.errors }}
</div>

View file

@ -11,7 +11,7 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.email.id_for_label }}" class="block font-medium text-gray-700">{{ form.email.label }}</label>
<label for="{{ form.email.id_for_label }}" class="block font-medium>{{ form.email.label }}</label>
{{ form.email|add_class:"input input-bordered w-full" }}
{{ form.email.errors }}
</div>

View file

@ -5,14 +5,14 @@
{% block content %}
<div class="container mx-auto max-w-md mt-6">
<p class="text-gray-700 mb-4">{% trans "Enter your password:" %}</p>
<p class="mb-4">{% trans "Enter your password:" %}</p>
{% url 'account_reauthenticate' as action_url %}
<form method="post" action="{{ action_url }}" class="space-y-4">
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<div>
<label for="{{ field.id_for_label }}" class="block font-medium text-gray-700">{{ field.label }}</label>
<label for="{{ field.id_for_label }}" class="block font-medium>{{ field.label }}</label>
{{ field }}
{{ field.errors }}
</div>

View file

@ -7,7 +7,7 @@
{% block content %}
<div class="container mx-auto max-w-md mt-6">
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Send me a sign-in code" %}</h1>
<p class="text-gray-700 mb-4 text-center">
<p class="mb-4 text-center">
{% trans "You will receive a special code for a password-free sign-in." %}
</p>
{% url 'account_request_login_code' as login_url %}
@ -16,7 +16,7 @@
{{ form.non_field_errors }}
{% for field in form %}
<div>
<label for="{{ field.id_for_label }}" class="block font-medium text-gray-700">{{ field.label }}</label>
<label for="{{ field.id_for_label }}" class="block font-medium>{{ field.label }}</label>
{{ field }}
{{ field.errors }}
</div>

View file

@ -10,27 +10,27 @@
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<label for="{{ form.username.id_for_label }}" class="block font-medium text-gray-700">{{ form.username.label }}</label>
<label for="{{ form.username.id_for_label }}" class="block font-medium">{{ form.username.label }}</label>
{{ form.username }}
{{ form.username.errors }}
</div>
<div>
<label for="{{ form.email.id_for_label }}" class="block font-medium text-gray-700">{{ form.email.label }}</label>
<label for="{{ form.email.id_for_label }}" class="block font-medium">{{ form.email.label }}</label>
{{ form.email }}
{{ form.email.errors }}
</div>
<div>
<label for="{{ form.password1.id_for_label }}" class="block font-medium text-gray-700">{{ form.password1.label }}</label>
<label for="{{ form.password1.id_for_label }}" class="block font-medium">{{ form.password1.label }}</label>
{{ form.password1 }}
{{ form.password1.errors }}
</div>
<div>
<label for="{{ form.password2.id_for_label }}" class="block font-medium text-gray-700">{{ form.password2.label }}</label>
<label for="{{ form.password2.id_for_label }}" class="block font-medium">{{ form.password2.label }}</label>
{{ form.password2 }}
{{ form.password2.errors }}
</div>
<div>
<label for="{{ form.friend_code.id_for_label }}" class="block font-medium text-gray-700">{{ form.friend_code.label }}</label>
<label for="{{ form.friend_code.id_for_label }}" class="block font-medium">{{ form.friend_code.label }}</label>
{{ form.friend_code }}
{{ form.friend_code.errors }}
</div>

View file

@ -6,7 +6,7 @@
{% block content %}
<div class="container mx-auto max-w-md mt-6">
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Passkey Sign Up" %}</h1>
<p class="text-gray-700 mb-4 text-center">
<p class="mb-4 text-center">
{% blocktranslate %}
Already have an account? Then please <a href="{{ login_url }}" class="text-primary underline">{% trans "sign in" %}</a>.
{% endblocktranslate %}
@ -17,7 +17,7 @@
{{ form.non_field_errors }}
{% for field in form %}
<div>
<label for="{{ field.id_for_label }}" class="block font-medium text-gray-700">{{ field.label }}</label>
<label for="{{ field.id_for_label }}" class="block font-medium>{{ field.label }}</label>
{{ field }}
{{ field.errors }}
</div>

View file

@ -7,7 +7,7 @@
{% block content %}
<div class="container mx-auto max-w-md mt-6 text-center">
<h1 class="text-3xl font-bold mb-6">{% trans "Sign Up Closed" %}</h1>
<p class="text-gray-700">
<p>
{% trans "We are sorry, but the sign up is currently closed." %}
</p>
</div>

View file

@ -7,7 +7,7 @@
{% block content %}
<div class="container mx-auto max-w-md mt-6">
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Verify Your Email Address" %}</h1>
<p class="text-gray-700">
<p>
{% blocktrans %}
We have sent an email to you for verification. Follow the link provided to finalize the signup process. If you do not see the verification email in your main inbox, check your spam folder. Please contact us if you do not receive the verification email within a few minutes.
{% endblocktrans %}

View file

@ -8,17 +8,17 @@
<div class="container mx-auto max-w-md mt-6">
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Verify Your Email Address" %}</h1>
{% url 'account_email' as email_url %}
<p class="text-gray-700 mb-4">
<p class="mb-4">
{% blocktrans %}
This part of the site requires us to verify that you are who you claim to be. For this purpose, we require that you verify ownership of your email address.
{% endblocktrans %}
</p>
<p class="text-gray-700 mb-4">
<p class="mb-4">
{% blocktrans %}
We have sent an email to you for verification. Please click on the link inside that email. If you do not see the verification email in your main inbox, check your spam folder. Otherwise contact us if you do not receive it within a few minutes.
{% endblocktrans %}
</p>
<p class="text-gray-700">
<p>
{% blocktrans %}
<strong>Note:</strong> you can still <a class="text-primary underline" href="{{ email_url }}">change your email address</a>.
{% endblocktrans %}

View file

@ -1,4 +1,9 @@
{% load static tailwind_tags gravatar %}
{% url 'home' as home_url %}
{% url 'trade_offer_list' as trade_offer_list_url %}
{% url 'trade_offer_my_list' as trade_offer_my_list_url %}
{% url 'settings' as settings_url %}
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
@ -19,7 +24,7 @@
})();
</script>
<title>{% block title %}Pkmn Trade Club{% endblock title %}</title>
<title>{% block title %}PᴋMɴ Trade Club{% endblock title %}</title>
<link rel="shortcut icon" href="{% static 'images/favicon.ico' %}">
<!-- Choices.js -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js@11.0.6/public/assets/styles/choices.min.css" />
@ -57,12 +62,9 @@
</ul>
</div>
<a class="btn btn-ghost text-xl" href="{% url 'home' %}">
<span aria-hidden="true">
<sup class="inline-block relative left-2">P</sup>
<sub class="inline-block relative">K</sub>
<sup class="inline-block relative -left-2">M</sup>
<sub class="inline-block relative -left-4">N</sub>
<span class="inline-block relative -left-4">Trade Club</span>
<span class="inline leading-none" aria-hidden="true">
<span class="inline-block relative align-text-top">P</span><span class="inline-block relative align-text-bottom">K</span><span class="inline-block relative align-text-top">M</span><span class="inline-block relative align-text-bottom">N</span>
<span class="inline-block relative">Trade Club</span>
</span>
<span aria-hidden="false" class="sr-only">Pokemon Trade Club</span>
</a>
@ -126,6 +128,7 @@
<!-- Main Content -->
<main class="container mx-auto p-4 sm:w-4/5 md:w-full xl:w-256">
{% include '_messages.html' %}
{% block content %}{% endblock %}
</main>
@ -138,19 +141,19 @@
<!-- Dock -->
<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 = '{{ home_url }}'" class="{% if request.path == home_url %}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>
<span class="dock-label">Home</span>
</button>
<button @click="window.location.href = '{% url 'trade_offer_list' %}'" class="{% if '/trades/all/' in request.path %}dock-active{% endif %}">
<button @click="window.location.href = '{{ trade_offer_list_url }}'" class="{% if request.path == trade_offer_list_url %}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.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>
</button>
<button @click="window.location.href = '{% url 'trade_offer_my_list' %}'" class="{% if '/trades/my/' in request.path %}dock-active{% endif %}">
<button @click="window.location.href = '{{ trade_offer_my_list_url }}'" class="{% if request.path == trade_offer_my_list_url %}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>
<span class="dock-label">My Trades</span>
</button>
<button @click="window.location.href = '{% url 'settings' %}'" class="{% if '/settings/' in request.path %}dock-active{% endif %}">
<button @click="window.location.href = '{{ settings_url }}'" class="{% if request.path == settings_url %}dock-active{% endif %}">
{% if user.is_authenticated %}<div tabindex="0" role="button" class="avatar"><div class="w-6 rounded-full">{{ user.email|gravatar:40 }}</div></div>{% else %}<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"><circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></circle><path d="m22,13.25v-2.5l-2.318-.966c-.167-.581-.395-1.135-.682-1.654l.954-2.318-1.768-1.768-2.318.954c-.518-.287-1.073-.515-1.654-.682l-.966-2.318h-2.5l-.966,2.318c-.581.167-1.135.395-1.654.682l-2.318-.954-1.768,1.768.954,2.318c-.287.518-.515,1.073-.682,1.654l-2.318.966v2.5l2.318.966c.167.581.395,1.135.682,1.654l-.954,2.318,1.768,1.768,2.318-.954c.518.287,1.073.515,1.654.682l.966,2.318h2.5l.966-2.318c.581-.167,1.135-.395,1.654-.682l2.318.954,1.768-1.768-.954-2.318c.287-.518.515-1.073.682-1.654l2.318-.966Z" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path></g></svg>{% endif %}
<span class="dock-label">Settings</span>
</button>

View file

@ -4,31 +4,20 @@
{% block content %}
<div class="container mx-auto max-w-xl mt-6">
{# Display messages if there are any. #}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} mb-4">
{{ message }}
</div>
{% endfor %}
{% endif %}
<h1 class="text-3xl font-bold mb-4">My Friend Codes</h1>
<h1 class="text-3xl font-bold mb-4">My Friend Codes</h1>
{% if friend_codes %}
<ul class="space-y-2">
{% 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-200 dark:bg-green-300 dark:text-base-100{% else %}bg-base-100 dark:bg-base-900 dark:text-white{% endif %} p-4 rounded shadow">
<div>
<span class="font-mono dark:text-base-100">{{ code.friend_code }}</span>
<span class="font-mono">{{ code.friend_code }}</span>
{% if user.default_friend_code and code.id == user.default_friend_code.id %}
<span class="badge badge-success ml-2">Default</span>
{% endif %}
</div>
<div class="flex items-center space-x-2">
{% if user.default_friend_code and code.id == user.default_friend_code.id %}
<button type="button" class="btn btn-secondary btn-sm" disabled>Set as Default</button>
{% else %}
{% if user.default_friend_code and not code.id == user.default_friend_code.id %}
<form method="post" action="{% url 'change_default_friend_code' code.id %}">
{% csrf_token %}
<button type="submit" class="btn btn-secondary btn-sm">Set as Default</button>

View file

@ -3,13 +3,10 @@
{% block content %}
<h1 class="text-center text-4xl font-bold mb-8 pt-4">
<span aria-hidden="true">
<span class="inline-block relative left-2 text-4xl">Welcome to</span>
<sup class="inline-block relative left-4 text-4xl">P</sup>
<sub class="inline-block relative text-4xl">K</sub>
<sup class="inline-block relative -left-2 text-4xl">M</sup>
<sub class="inline-block relative -left-4 text-4xl">N</sub>
<span class="inline-block relative -left-2 text-4xl">Trade Club</span>
<span class="inline leading-none" aria-hidden="true">
<span class="inline-block relative">Welcome to</span>
<span class="inline-block relative align-text-top">P</span><span class="inline-block relative align-text-bottom">K</span><span class="inline-block relative align-text-top">M</span><span class="inline-block relative align-text-bottom">N</span>
<span class="inline-block relative">Trade Club</span>
</span>
<span aria-hidden="false" class="sr-only">Welcome to Pokemon Trade Club</span>
</h1>
@ -20,18 +17,18 @@
{% csrf_token %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
{% card_multiselect "have_cards" "Have:" "Select some cards..." available_cards have_cards %}
{% card_multiselect "have_cards" "I Have:" "Select some cards..." available_cards have_cards %}
</div>
<div>
{% card_multiselect "want_cards" "Want:" "Select some cards..." available_cards want_cards %}
{% card_multiselect "want_cards" "I Want:" "Select some cards..." available_cards want_cards %}
</div>
</div>
<div class="flex flex-col md:flex-row gap-4">
<button type="submit" class="btn btn-primary flex-1">
<button type="submit" class="btn btn-primary grow">
Find a Trade Offer
</button>
{% if user.is_authenticated %}
<a href="{% url 'trade_offer_create' %}" id="createTradeOfferBtn" class="btn btn-secondary flex-1 text-center">
<a href="{% url 'trade_offer_create' %}" id="createTradeOfferBtn" class="btn btn-secondary grow">
Create Trade Offer
</a>
{% endif %}

View file

@ -2,26 +2,30 @@
This fragment renders a friend code selector used for filtering or form submissions.
Expected variables:
- friend_codes: A list or QuerySet of FriendCode objects.
- selected_friend_code: The currently selected FriendCode.
- selected_friend_code (optional): The currently selected FriendCode. If not provided, the user's default friend code is used.
- field_name (optional): The name/id for the input element (default "friend_code").
- label (optional): The label text (default "Friend Code").
{% endcomment %}
{% with field_name=field_name|default:"friend_code" label=label|default:"Friend Code" %}
{% if friend_codes|length > 1 %}
<div class="form-control">
<label for="{{ field_name }}" class="label">
<span class="label-text p-2 rounded">{{ label }}</span>
</label>
<select id="{{ field_name }}" name="{{ field_name }}" class="select select-bordered w-full bg-secondary text-white">
{% for code in friend_codes %}
<option value="{{ code.pk }}" {% if code.pk|stringformat:"s" == selected_friend_code.pk|stringformat:"s" %}selected{% endif %}>
{{ code.friend_code }}
</option>
{% endfor %}
</select>
</div>
{% else %}
<input type="hidden" name="{{ field_name }}" value="{{ friend_codes.0.pk }}">
{% endif %}
{% with field_name=field_name|default:"friend_code" label=label|default:"" %}
{% with effective_friend_code=selected_friend_code|default:request.user.default_friend_code %}
{% if friend_codes|length > 1 %}
<div class="form-control">
{% if label and label != "" %}
<label for="{{ field_name }}" class="label">
<span class="label-text p-2 rounded">{{ label }}</span>
</label>
{% endif %}
<select id="{{ field_name }}" name="{{ field_name }}" class="select select-bordered w-full" @change="$el.form.submit()">
{% for code in friend_codes %}
<option value="{{ code.pk }}" {% if effective_friend_code and code.pk|stringformat:"s" == effective_friend_code.pk|stringformat:"s" %}selected{% endif %}>
{{ code.friend_code }}
</option>
{% endfor %}
</select>
</div>
{% else %}
<input type="hidden" name="{{ field_name }}" value="{{ friend_codes.0.pk }}">
{% endif %}
{% endwith %}
{% endwith %}

View file

@ -5,24 +5,22 @@
{% block content %}
<div class="container mx-auto max-w-4xl mt-6" x-data="{ allExpanded: false }">
<!-- Header-->
<div class="flex justify-between items-center mb-4">
<a href="{% url 'trade_offer_create' %}" class="btn btn-success">Create New Offer</a>
<div>
<form method="get" class="flex items-center space-x-4">
<form method="get" class="flex items-center space-x-4" x-data>
<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 %}>
<span x-text="allExpanded ? 'Collapse All' : 'Expand All'"></span>
<input type="checkbox" name="all_expanded" value="true" class="toggle toggle-primary" @click="allExpanded = !allExpanded; $dispatch('toggle-all', { expanded: allExpanded })">
</label>
<button type="submit" class="btn btn-primary">Apply</button>
<label class="cursor-pointer flex items-center space-x-2">
<span>Only Closed</span>
<input type="checkbox" name="show_closed" value="true" class="toggle toggle-primary" @change="$el.form.submit()" {% if show_closed %}checked{% endif %}>
</label>
<button type="submit" class="btn btn-primary" x-show="false">Apply</button>
</form>
</div>
<div>
<!-- Global toggle button using Alpine only -->
<button type="button"
@click="allExpanded = !allExpanded; $dispatch('toggle-all', { expanded: allExpanded })"
class="btn btn-secondary">
<span x-text="allExpanded ? 'Collapse All' : 'Expand All'"></span>
</button>
</div>
</div>
<!-- Trade Offers -->
<section class="mb-12">
@ -46,9 +44,5 @@
<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

@ -9,20 +9,19 @@
<form method="post" novalidate class="space-y-4">
{% csrf_token %}
{# Use our DRY friend code selector #}
{% include "trades/_friend_code_select.html" with friend_codes=friend_codes selected_friend_code=selected_friend_code field_name=form.initiated_by.html_name label="Initiated by" %}
<!-- Card Selectors: "Have" and "Want" -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="form-control">
{% card_multiselect "have_cards" "Have:" "Select one or more cards..." available_cards form.initial.have_cards %}
{% card_multiselect "have_cards" "I Have:" "Select some cards..." available_cards form.initial.have_cards %}
</div>
<div class="form-control">
{% card_multiselect "want_cards" "Want:" "Select one or more cards..." available_cards form.initial.want_cards %}
{% card_multiselect "want_cards" "I Want:" "Select some cards..." available_cards form.initial.want_cards %}
</div>
</div>
<button type="submit" class="btn btn-primary w-full">Submit</button>
<button type="submit" class="btn btn-primary w-full">Create Offer</button>
</form>
{% if form.errors %}
<div class="alert alert-error mt-4">
@ -40,36 +39,4 @@
</div>
{% endif %}
</div>
<script defer>
document.addEventListener('DOMContentLoaded', () => {
const initiatedBySelect = document.getElementById('{{ form.initiated_by.html_name }}');
if (initiatedBySelect) {
const choicesInstance = new Choices(initiatedBySelect, {
searchEnabled: false,
classNames: {
containerOuter: 'choices',
containerInner: 'choices__inner',
input: 'choices__input',
},
callbackOnCreateTemplates: function(template) {
return {
choice: (classNames, data) => {
return template(`
<div class="${classNames.item} ${classNames.itemChoice} bg-accent text-white"
data-select-text="${this.config.itemSelectText}"
data-choice ${data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'}
data-id="${data.id}" data-value="${data.value}"
${data.groupId > 0 ? 'role="treeitem"' : 'role="option"'}>
${data.label}
</div>
`);
},
};
},
});
choicesInstance.containerOuter.element.classList.add('bg-secondary', 'select', 'select-bordered', 'w-full');
choicesInstance.containerInner.element.classList.add('bg-secondary', 'text-white');
}
});
</script>
{% endblock content %}

View file

@ -15,15 +15,9 @@
</h2>
<p>
<strong>Status:</strong> {% if object.is_active %}Open{% else %}Closed{% endif %}
<strong>Status:</strong> {% if object.is_closed %}Closed{% else %}Open{% endif %}
</p>
{% if messages %}
{% for message in messages %}
<div class="alert {{ message.tags }}">{{ message }}</div>
{% endfor %}
{% endif %}
<p class="mb-4">
{% if action == 'delete' %}
Are you sure you want to delete this trade offer? This will permanently remove the offer.

View file

@ -1,79 +1,78 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}Trade Offer & Acceptance List{% endblock title %}
{% block title %}My Trades{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-4xl mt-6" x-data="{ allExpanded: false }">
<!-- Global Header: Filter Form and Expand All Toggle -->
<div class="flex justify-between items-center mb-4">
<!-- Header -->
<div class="flex justify-between items-start mb-4">
<a href="{% url 'trade_offer_create' %}" class="btn btn-success">Create New Offer</a>
<div>
<form method="get" class="flex items-center space-x-4">
{% include "trades/_friend_code_select.html" with friend_codes=friend_codes selected_friend_code=selected_friend_code field_name="friend_code" label="Filter by Friend Code" %}
<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 %}>
<form method="get" class="flex flex-wrap justify-end space-x-4 gap-2" x-data>
<label class="cursor-pointer flex items-center space-x-2 h-10">
<span x-text="allExpanded ? 'Collapse All' : 'Expand All'"></span>
<input type="checkbox" name="all_expanded" value="true" class="toggle toggle-primary" @click="allExpanded = !allExpanded; $dispatch('toggle-all', { expanded: allExpanded })">
</label>
<button type="submit" class="btn btn-primary">Apply</button>
<label class="cursor-pointer flex items-center space-x-2 h-10">
<span class="font-medium">Only Closed</span>
<input type="checkbox" name="show_closed" value="true" class="toggle toggle-primary" @change="$el.form.submit()" {% if show_closed %}checked{% endif %}>
</label>
{% include "trades/_friend_code_select.html" with friend_codes=friend_codes selected_friend_code=selected_friend_code field_name="friend_code" label="" %}
<button type="submit" class="btn btn-primary" x-show="false">Apply</button>
</form>
</div>
<div>
<!-- Global toggle button using Alpine only -->
<button type="button"
@click="allExpanded = !allExpanded; $dispatch('toggle-all', { expanded: allExpanded })"
class="btn btn-secondary">
<span x-text="allExpanded ? 'Collapse All' : 'Expand All'"></span>
</button>
</div>
</div>
<!-- Section: Waiting for Your Response -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">Waiting for Your Response</h2>
{% if trade_acceptances_waiting_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=trade_acceptances_waiting_paginated %}
<div class="flex justify-between items-center mt-4">
{% if trade_acceptances_waiting_paginated.has_previous %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'waiting_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}waiting_page={{ trade_acceptances_waiting_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ trade_acceptances_waiting_paginated.number }} of {{ trade_acceptances_waiting_paginated.paginator.num_pages }}</span>
{% if trade_acceptances_waiting_paginated.has_next %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'waiting_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}waiting_page={{ trade_acceptances_waiting_paginated.next_page_number }}" class="btn btn-sm">Next</a>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p>None at this time.</p>
{% endif %}
</section>
<!-- Section: Waiting for Trade Partner's Response -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">Waiting for Trade Partner's Response</h2>
{% if other_party_trade_acceptances_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=other_party_trade_acceptances_paginated %}
<div class="flex justify-between items-center mt-4">
{% if other_party_trade_acceptances_paginated.has_previous %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_party_trade_acceptances_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ other_party_trade_acceptances_paginated.number }} of {{ other_party_trade_acceptances_paginated.paginator.num_pages }}</span>
{% if other_party_trade_acceptances_paginated.has_next %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_party_trade_acceptances_paginated.next_page_number }}" class="btn btn-sm">Next</a>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p>None at this time.</p>
{% endif %}
</section>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-8">
<!-- Section: Waiting for Your Response -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">Waiting for Your Response</h2>
{% if trade_acceptances_waiting_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=trade_acceptances_waiting_paginated %}
<div class="flex justify-between items-center mt-4">
{% if trade_acceptances_waiting_paginated.has_previous %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'waiting_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}waiting_page={{ trade_acceptances_waiting_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ trade_acceptances_waiting_paginated.number }} of {{ trade_acceptances_waiting_paginated.paginator.num_pages }}</span>
{% if trade_acceptances_waiting_paginated.has_next %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'waiting_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}waiting_page={{ trade_acceptances_waiting_paginated.next_page_number }}" class="btn btn-sm">Next</a>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p>None at this time.</p>
{% endif %}
</section>
<!-- Section: Waiting for Their Response -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">Waiting for Their Response</h2>
{% if other_party_trade_acceptances_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=other_party_trade_acceptances_paginated %}
<div class="flex justify-between items-center mt-4">
{% if other_party_trade_acceptances_paginated.has_previous %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_party_trade_acceptances_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ other_party_trade_acceptances_paginated.number }} of {{ other_party_trade_acceptances_paginated.paginator.num_pages }}</span>
{% if other_party_trade_acceptances_paginated.has_next %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_party_trade_acceptances_paginated.next_page_number }}" class="btn btn-sm">Next</a>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p>None at this time.</p>
{% endif %}
</section>
</div>
<!-- Section: My Trade Offers -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">My Trade Offers</h2>
@ -96,9 +95,5 @@
<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

@ -8,7 +8,7 @@
<!-- Offer Details Card -->
<div class="card bg-base-100 shadow-lg">
<div class="card-body">
<p class="text-gray-700">
<p>
<strong>Created At:</strong> {{ object.created_at|date:"M d, Y H:i" }}<br>
<strong>Updated At:</strong> {{ object.updated_at|date:"M d, Y H:i" }}<br>
{% if object.initiated_by.user == request.user or object.accepted_by and object.accepted_by.user == request.user %}
@ -28,7 +28,7 @@
{% for card in object.want_cards.all %}
{{ card.name }}{% if not forloop.last %}, {% endif %}
{% endfor %}<br>
<strong>Status:</strong> {% if object.is_active %}Open{% else %}Closed{% endif %}
<strong>Status:</strong> {% if object.is_closed %}Closed{% else %}Open{% endif %}
</p>
</div>
</div>