fix card_multiselect filtering and quantity controls
This commit is contained in:
parent
6e4c6040bd
commit
b97ddde71c
52 changed files with 1689 additions and 2268 deletions
|
|
@ -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 %}
|
||||
|
|
@ -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 %}
|
||||
|
|
@ -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 %}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue