progress on conversion to tailwind

This commit is contained in:
badblocks 2025-03-06 21:28:36 -08:00
parent 6a872124c6
commit 6e2843c60e
110 changed files with 4997 additions and 1691 deletions

View file

@ -0,0 +1,27 @@
{% comment %}
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.
- 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 %}
{% endwith %}

View file

@ -0,0 +1,58 @@
{% load trade_offer_tags %}
{% comment %}
This snippet renders a grid of trade offer cards along with pagination controls,
using the trade_offer templatetag (i.e. {% render_trade_offer offer %}).
It expects a context variable:
- offers: an iterable or a paginated page of TradeOffer objects.
{% endcomment %}
<div class="flex flex-row gap-4 flex-wrap justify-center items-start">
{% for offer in offers %}
<div class="flex flex-none">
<a href="{% url 'trade_offer_detail' pk=offer.pk %}" class="no-underline">
{% render_trade_offer offer %}
</a>
</div>
{% empty %}
<div>No trade offers available.</div>
{% endfor %}
</div>
{% if offers.has_other_pages %}
<nav aria-label="Trade offers pagination" class="mt-6">
<ul class="flex justify-center space-x-2">
{% if offers.has_previous %}
<li>
<a class="btn btn-outline ajax-page-link" data-page="{{ offers.previous_page_number }}" href="#">
Previous
</a>
</li>
{% else %}
<li>
<span class="btn btn-outline btn-disabled">Previous</span>
</li>
{% endif %}
{% for num in offers.paginator.page_range %}
<li>
<a class="btn btn-outline ajax-page-link {% if offers.number == num %}btn-active{% endif %}" data-page="{{ num }}" href="#">
{{ num }}
</a>
</li>
{% endfor %}
{% if offers.has_next %}
<li>
<a class="btn btn-outline ajax-page-link" data-page="{{ offers.next_page_number }}" href="#">
Next
</a>
</li>
{% else %}
<li>
<span class="btn btn-outline btn-disabled">Next</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}

View file

@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% block title %}Accept Trade Offer{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-xl mt-6">
<h2 class="text-2xl font-bold">Accept Trade Offer</h2>
<form method="post" novalidate>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit Acceptance</button>
</form>
{% if form.errors %}
<div class="alert alert-error mt-4">
<strong>Please correct the errors below:</strong>
<ul>
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="mt-6">
<a href="{% url 'trade_offer_detail' pk=trade_offer.pk %}" class="btn btn-secondary">Back to Offer Details</a>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% block title %}Update Trade Acceptance{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-xl mt-6">
<h2 class="text-2xl font-bold">Update Trade Acceptance</h2>
<form method="post" novalidate>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Update</button>
</form>
{% if form.errors %}
<div class="alert alert-error mt-4">
<strong>Please correct the errors below:</strong>
<ul>
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="mt-6">
<a href="{% url 'trade_offer_detail' pk=object.trade_offer.pk %}" class="btn btn-secondary">Back to Offer Details</a>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,77 @@
{% extends 'base.html' %}
{% load card_multiselect %}
{% block title %}Create Trade Offer{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-xl mt-6">
<h2 class="text-2xl font-bold mb-4">Create a Trade Offer</h2>
<form method="post" novalidate class="space-y-4">
{% csrf_token %}
{# Use the DRY friend code selector fragment #}
{% 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" %}
<!-- Grid layout for 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 %}
</div>
<div class="form-control">
{% card_multiselect "want_cards" "Want:" "Select one or more cards..." available_cards form.initial.want_cards %}
</div>
</div>
<button type="submit" class="btn btn-primary w-full">Submit</button>
</form>
{% if form.errors %}
<div class="alert alert-error mt-4">
<strong>Please correct the errors below:</strong>
<ul class="mt-2">
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</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>
`);
},
};
},
});
// Style the Choices control as needed
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

@ -0,0 +1,47 @@
{% extends 'base.html' %}
{% block title %}Delete or Close Trade Offer{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-md mt-6">
<h2 class="text-2xl font-bold mb-4">
{% if action == 'delete' %}
Delete Trade Offer
{% elif action == 'close' %}
Close Trade Offer
{% else %}
Delete/Close Trade Offer
{% endif %}
</h2>
{% 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.
{% elif action == 'close' %}
Are you sure you want to close this trade offer? It will remain in the system as closed.
{% else %}
This trade offer cannot be deleted or closed because there are active acceptances.
{% endif %}
</p>
<form method="post" class="space-x-4">
{% csrf_token %}
{% if action %}
{% if action == 'delete' %}
<button type="submit" class="btn btn-error">Confirm Delete</button>
{% elif action == 'close' %}
<button type="submit" class="btn btn-warning">Confirm Close Trade Offer</button>
{% endif %}
{% else %}
<button type="submit" class="btn btn-error" disabled>Cannot Delete/Close Trade Offer</button>
{% endif %}
<a href="{% url 'trade_offer_list' %}" class="btn btn-secondary">Cancel</a>
</form>
</div>
{% endblock content %}

View file

@ -0,0 +1,64 @@
{% extends 'base.html' %}
{% block title %}Trade Offer Detail{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-2xl mt-6">
<h2 class="text-2xl font-bold">Trade Offer Details</h2>
<div class="card bg-base-100 shadow-lg p-4">
<p>
<strong>Hash:</strong> {{ object.hash }}<br>
<strong>Initiated By:</strong> {{ object.initiated_by }}<br>
<strong>Cards You Have (Offer):</strong>
{% for through in object.trade_offer_have_cards.all %}
{{ through.card.name }} x{{ through.quantity }}{% if not forloop.last %}, {% endif %}
{% endfor %}<br>
<strong>Cards You Want:</strong>
{% for through in object.trade_offer_want_cards.all %}
{{ through.card.name }} x{{ through.quantity }}{% if not forloop.last %}, {% endif %}
{% endfor %}<br>
<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>
<strong>Status:</strong> {% if object.is_closed %}Closed{% else %}Open{% endif %}
</p>
</div>
<h3 class="text-xl font-semibold mt-6">Acceptances</h3>
{% if acceptances %}
<ul class="space-y-2">
{% for acceptance in acceptances %}
<li class="card p-4">
<p>
<strong>Accepted By:</strong> {{ acceptance.accepted_by }}<br>
<strong>Requested Card:</strong> {{ acceptance.requested_card.name }}<br>
<strong>Offered Card:</strong> {{ acceptance.offered_card.name }}<br>
<strong>State:</strong> {{ acceptance.get_state_display }}
</p>
<a href="{% url 'trade_acceptance_update' acceptance.pk %}" class="btn btn-sm">Update</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No acceptances yet.</p>
{% endif %}
{% if acceptance_form %}
<h3 class="text-xl font-semibold mt-6">Accept This Offer</h3>
<div class="card p-4">
<form method="post" action="{% url 'trade_acceptance_create' offer_pk=object.pk %}">
{% csrf_token %}
{{ acceptance_form.as_p }}
<button type="submit" class="btn btn-primary">Submit Acceptance</button>
</form>
</div>
{% endif %}
<div class="mt-6">
<!-- Show delete/close button for the initiator -->
{% if is_initiator %}
<a href="{{ delete_close_url }}" class="btn btn-danger">Delete/Close Trade Offer</a>
{% endif %}
<a href="{% url 'trade_offer_list' %}" class="btn btn-secondary">Back to Trade Offers</a>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,94 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}Trade Offer & Acceptance List{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-4xl mt-6">
<!-- Filter Form: Friend Code Selector + Toggle for Completed view -->
<div class="flex justify-end mb-4">
<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 Completed</span>
<input type="checkbox" name="show_completed" value="true" class="toggle toggle-primary" {% if show_completed %}checked{% endif %}>
</label>
<button type="submit" class="btn btn-primary">Apply</button>
</form>
</div>
<!-- Section 1: My Trade Offers -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">My Trade Offers</h2>
{% if my_trade_offers_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=my_trade_offers_paginated %}
<div class="flex justify-between items-center mt-4">
{% if my_trade_offers_paginated.has_previous %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'offers_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}offers_page={{ my_trade_offers_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ my_trade_offers_paginated.number }} of {{ my_trade_offers_paginated.paginator.num_pages }}</span>
{% if my_trade_offers_paginated.has_next %}
<a href="?{% for key, value in request.GET.items %}{% if key != 'offers_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}offers_page={{ my_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>
<!-- Section 2: Trade Acceptances Waiting For Your Response -->
<section class="mb-12">
<h2 class="text-2xl font-bold mb-4">Trade Acceptances 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>No pending acceptances at this time.</p>
{% endif %}
</section>
<!-- Section 3: Other Trade Acceptances -->
<section>
<h2 class="text-2xl font-bold mb-4">Other Trade Acceptances</h2>
{% if other_trade_acceptances_paginated.object_list %}
{% include "trades/_trade_offer_list.html" with offers=other_trade_acceptances_paginated %}
<div class="flex justify-between items-center mt-4">
{% if other_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_trade_acceptances_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
{% else %}
<span></span>
{% endif %}
<span>Page {{ other_trade_acceptances_paginated.number }} of {{ other_trade_acceptances_paginated.paginator.num_pages }}</span>
{% if other_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_trade_acceptances_paginated.next_page_number }}" class="btn btn-sm">Next</a>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p>No other acceptances 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

@ -0,0 +1,89 @@
{% extends 'base.html' %}
{% block title %}Trade Offer Details & Update{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-2xl mt-6 space-y-6">
<h2 class="text-2xl font-bold">Trade Offer Details</h2>
<!-- Offer Details Card -->
<div class="card bg-base-100 shadow-lg">
<div class="card-body">
<p class="text-gray-700">
<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 %}
<strong>Initiated By:</strong> {{ object.initiated_by }}<br>
<strong>Accepted By:</strong>
{% if object.accepted_by %}
{{ object.accepted_by }}
{% else %}
Not yet accepted
{% endif %}<br>
{% endif %}
<strong>Cards You Have:</strong>
{% for card in object.have_cards.all %}
{{ card.name }}{% if not forloop.last %}, {% endif %}
{% endfor %}<br>
<strong>Cards You Want:</strong>
{% for card in object.want_cards.all %}
{{ card.name }}{% if not forloop.last %}, {% endif %}
{% endfor %}<br>
<strong>Current State:</strong> {{ object.get_state_display }}
</p>
</div>
</div>
{% if form.fields %}
<!-- Form Card -->
<div class="card bg-base-100 shadow-lg">
<div class="card-body">
<div class="mb-4 font-semibold text-lg">
{% if action == "accept" %}
Accept Trade Offer
{% else %}
Update Trade Offer
{% endif %}
</div>
<form method="post" novalidate class="space-y-4">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn {% if action == 'accept' %}btn-success{% else %}btn-primary{% endif %}">
{% if action == "accept" %}
Accept Trade Offer
{% else %}
Submit
{% endif %}
</button>
</form>
</div>
</div>
{% else %}
<div class="alert alert-info">
You are not authorized to perform any status changes on this trade offer.
</div>
{% endif %}
{% if form and form.errors %}
<div class="alert alert-error">
<strong>Please correct the errors below:</strong>
<ul class="mt-2">
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="flex space-x-4">
<a href="{% url 'trade_offer_list' %}" class="btn btn-secondary">Back to Trade Offers</a>
{% if can_delete %}
<a href="{% url 'trade_offer_delete' object.pk %}" class="btn btn-error">Delete Trade Offer</a>
{% endif %}
</div>
</div>
{% endblock content %}