Fix create trade offer flow and other related bugs

This commit is contained in:
badblocks 2025-03-26 11:38:02 -07:00
parent f3a1366269
commit 65ca344582
40 changed files with 867 additions and 278 deletions

View file

@ -1,9 +1,9 @@
{% if messages %}
<div class="flex flex-col gap-2">
{% for message in messages %}
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% else %}alert-info{% endif %} mb-4 flex justify-between items-center">
<div class="alert {% if message.tags %}alert-{{ message.tags }} text-(--color-{{ message.tags }}-content){% else %}alert-info text-(--color-info-content){% endif %} font-semibold mb-4 flex justify-between items-center">
<span>{{ message }}</span>
<button class="btn btn-xs btn-circle" onclick="this.parentElement.remove();" aria-label="Dismiss"></button>
<button class="btn btn-xs btn-circle border-none bg-black/20" onclick="this.parentElement.remove();" aria-label="Dismiss"></button>
</div>
{% endfor %}
</div>

View file

@ -8,15 +8,19 @@
<h1 class="text-3xl font-semibold text-center mb-6">{% trans "Profile" %}</h1>
<div class="card card-border bg-base-100 shadow-lg w-4/5 mx-auto">
<div class="card-body">
<div class="mx-auto mb-4">{{ user.email|gravatar:100 }}</div>
<div class="hovercard-preview">
<iframe src="https://gravatar.com/{{ user.email|gravatar_hash }}.card" width="100%" height="344px" style="border:0; margin:0; padding:0;" onload="resizeIframe(this)"></iframe>
</div>
<p class="text-center">All profile information is managed through Gravatar.</p>
<p class="text-center mt-4">
<a href="https://gravatar.com/profile/" target="_blank" rel="noopener noreferrer" class="btn btn-secondary">
<div class="text-center mt-4 flex flex-col gap-4 mx-auto">
<a href="https://gravatar.com/profile/" target="_blank" rel="noopener noreferrer" class="btn btn-primary">
Edit Profile on Gravatar
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" />
</svg>
</a></p>
</a>
<a href="{% url 'settings' %}" class="btn btn-secondary">Back to Settings</a>
</div>
<div class="divider"></div>
<h2 class="text-lg font-semibold pt-0">What is Gravatar?</h2>
<p class="mb-4">Gravatar (Globally Recognized Avatar) is a free service that links your email address to a profile picture and, optionally, a profile. Many websites, including this one, use Gravatar to display your avatar and profile automatically.</p>
@ -24,6 +28,9 @@
<h2 class="text-lg font-semibold">How does it work?</h2>
<p class="mb-4">If you've set up a Gravatar, your profile picture will appear here whenever you use your email on supported sites. When someone hovers over or clicks on your avatar, your Gravatar profile will also appear if you have one. If you don't have a Gravatar yet, you'll see a default image instead.</p>
<h2 class="text-lg font-semibold">Is it safe? What about privacy?</h2>
<p class="mb-4">Gravatar is completely optional, opt-in, and prioritizes your security and privacy. Your email is never shared and only a hashed version is sent to Gravatar, protecting your identity while ensuring that your email address is not exposed to bots or scrapers. Your personal data remains secure, and you maintain full control over your public profile.</p>
<h2 class="text-lg font-semibold">Want to update or add a Gravatar?</h2>
<p class="mb-4">Go to Gravatar.com to set up or change your avatar or profile. Your updates will appear here once saved!</p>
</div>

View file

@ -1,19 +1,31 @@
{% extends 'base.html' %}
{% load i18n %}
{% load i18n crispy_forms_tags %}
{% block head_title %}{% trans "Settings" %}{% endblock %}
{% block content %}
<div class="container mx-auto">
<div class="container mx-auto space-y-8">
<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-6 w-full mx-auto p-6">
<a href="{% url 'profile' %}" class="btn btn-secondary">
{% trans "Profile" %}
</a>
<a href="{% url 'list_friend_codes' %}" class="btn btn-primary">
{% trans "Friend Codes" %}
</a>
<!-- Account Navigation Section -->
<div class="card card-border bg-base-100 shadow-lg w-4/5 mx-auto p-6">
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="w-full btn btn-success mt-4">
{% trans "Save Settings" %}
</button>
</form>
<div class="divider my-4"></div>
<div class="flex flex-col gap-4">
<div class="flex flex-row gap-4">
<a href="{% url 'profile' %}" class="btn btn-secondary w-20 grow-1">
{% trans "Profile" %}
</a>
<a href="{% url 'list_friend_codes' %}" class="btn btn-primary w-20 grow-1">
{% trans "Friend Codes" %}
</a>
</div>
<a href="{% url 'account_logout' %}" class="btn btn-warning">
{% trans "Sign Out" %}
</a>

View file

@ -46,11 +46,13 @@
<!-- Import the hovercards library -->
<script src="https://unpkg.com/@gravatar-com/hovercards@0.10.8"></script>
<script src="{% static 'js/base.js' %}"></script>
{% block css %}{% endblock %}
{% block javascript_head %}{% endblock %}
</head>
<div class="min-h-screen bg-base-200">
<body class="min-h-screen bg-base-200" id="body">
<!-- Header and Navigation -->
<div class="navbar bg-base-100 shadow-sm">
<div class="navbar-start">
@ -76,7 +78,7 @@
<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>
<span aria-hidden="false" class="sr-only">PKMN Trade Club</span>
</a>
</div>
<div class="navbar-center hidden md:flex">
@ -114,13 +116,8 @@
tabindex="0"
class="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-32 p-2 shadow">
<li>
<a class="flex items-center justify-between" href="{% url 'profile' %}">
Profile
</a>
</li>
<li>
<a class="justify-between" href="{% url 'list_friend_codes' %}">
Friend Codes
<a class="justify-between" href="{% url 'settings' %}">
Settings
</a>
</li>
<li><a href="{% url 'account_logout' %}">Sign Out</a></li>
@ -143,7 +140,7 @@
<!-- Footer -->
<footer class="bg-base-200 text-base-content p-4">
<div class="container mx-auto text-center">
<div class="container mx-auto text-center text-sm">
<p>&copy; {% now "Y" %} PKMNTrade.Club. All rights reserved.</p>
</div>
</footer>
@ -181,7 +178,7 @@
document.addEventListener('DOMContentLoaded', function() {
if (typeof Gravatar !== 'undefined' && typeof Gravatar.Hovercards !== 'undefined') {
const hovercards = new Gravatar.Hovercards({
myHash: '{{ user.email|gravatar_hash }}'
myHash: '{{ user.email|gravatar_hash }}',
});
hovercards.attach( document.body, { ignoreSelector: 'img[src*="gravatar.com/avatar/"].ignore' } );
}
@ -197,7 +194,7 @@
// 'Internal Server Error.': 'Erreur interne du serveur.',
// }
</script>
<script defer src="{% static 'js/base.js' %}"></script>
{% block javascript %}{% endblock %}
</body>

View file

@ -0,0 +1,35 @@
{% load trade_offer_tags %}
{% if trade_offers %}
<div class="flex flex-col">
{% for offer in trade_offers %}
<div class="mb-4">
{% render_trade_offer offer %}
</div>
{% endfor %}
</div>
{% if is_paginated %}
<div class="flex justify-between items-center mt-4">
{% if page_obj.has_previous %}
<button type="button" class="btn btn-sm"
@click="$dispatch('change-page-{{ side }}', { page: {{ page_obj.previous_page_number }} })">
Previous
</button>
{% else %}
<span></span>
{% endif %}
{% if paginator.num_pages > 1 %}
<span class="text-sm">Page {{ page_obj.number }} of {{ paginator.num_pages }}</span>
{% endif %}
{% if page_obj.has_next %}
<button type="button" class="btn btn-sm"
@click="$dispatch('change-page-{{ side }}', { page: {{ page_obj.next_page_number }} })">
Next
</button>
{% else %}
<span></span>
{% endif %}
</div>
{% endif %}
{% else %}
<p class="text-gray-500">No trade offers found.</p>
{% endif %}

View file

@ -0,0 +1,27 @@
{% load trade_offer_tags %}
{% if trade_offers %}
<div class="grid grid-cols-1 gap-4">
{% for offer in trade_offers %}
<div class="mb-4">
{% render_trade_offer offer %}
</div>
{% endfor %}
</div>
<div class="flex justify-between items-center mt-4">
{% if trade_offers.has_previous %}
<button type="button" class="btn btn-sm" @click="$dispatch('change-page', { page: {{ trade_offers.previous_page_number }} })">Previous</button>
{% else %}
<span></span>
{% endif %}
{% if trade_offers.paginator.num_pages > 1 %}
<span class="text-sm">Page {{ trade_offers.number }} of {{ trade_offers.paginator.num_pages }}</span>
{% endif %}
{% if trade_offers.has_next %}
<button type="button" class="btn btn-sm" @click="$dispatch('change-page', { page: {{ trade_offers.next_page_number }} })">Next</button>
{% else %}
<span></span>
{% endif %}
</div>
{% else %}
<p class="text-gray-500">No trade offers found.</p>
{% endif %}

View file

@ -0,0 +1,91 @@
{% extends "base.html" %}
{% load static card_badge %}
{% block content %}
<div class="container mx-auto p-4">
<!-- Card header with badge and details -->
<div class="flex items-center mb-6">
<div class="ml-4">
<h1 class="text-3xl font-bold">{{card.name}}</h1>
<h2 class="text-lg text-gray-500">{{ card.cardset }} #{{ card.cardnum }} &bull; {{ card.rarity_icon }}</h2>
</div>
</div>
<!-- Trade Offers sections -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- Trade Offers: Have -->
<div x-data="{
order: 'newest',
page: 1,
loadOffers() {
document.activeElement.blur();
fetch(`{% url 'cards:card_trade_offer_have_list' card.pk %}?order=` + this.order + '&page=' + this.page)
.then(response => response.text())
.then(html => { this.$refs.offerList.innerHTML = html; });
}
}"
x-init="loadOffers()"
x-on:change-page-have.window="page = $event.detail.page; loadOffers()"
class="p-4">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-semibold">Have this Card ({{ trade_offer_have_count }})</h2>
<!-- DaisyUI dropdown replacing the select -->
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn m-1" x-text="order === 'newest' ? 'Newest 🞃' : 'Oldest 🞃'"></div>
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-1 w-26 p-2 shadow-sm">
<li>
<a href="#" @click.prevent="order = 'newest'; page = 1; loadOffers()">
Newest
</a>
</li>
<li>
<a href="#" @click.prevent="order = 'oldest'; page = 1; loadOffers()">
Oldest
</a>
</li>
</ul>
</div>
</div>
<div x-ref="offerList">
</div>
</div>
<!-- Trade Offers: Want -->
<div x-data="{
order: 'newest',
page: 1,
loadOffers() {
fetch(`{% url 'cards:card_trade_offer_want_list' card.pk %}?order=` + this.order + '&page=' + this.page)
.then(response => response.text())
.then(html => { this.$refs.offerList.innerHTML = html; });
}
}"
x-init="loadOffers()"
x-on:change-page.window="page = $event.detail.page; loadOffers()"
class="p-4">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-semibold">Want this Card ({{ trade_offer_want_count }})</h2>
<!-- DaisyUI dropdown replacing the select -->
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn m-1" x-text="order === 'newest' ? 'Newest 🞃' : 'Oldest 🞃'"></div>
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-1 w-26 p-2 shadow-sm">
<li>
<a href="#" @click.prevent="order = 'newest'; page = 1; loadOffers()">
Newest
</a>
</li>
<li>
<a href="#" @click.prevent="order = 'oldest'; page = 1; loadOffers()">
Oldest
</a>
</li>
</ul>
</div>
</div>
<div x-ref="offerList">
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -35,7 +35,8 @@
<p>You do not have any friend codes added yet.</p>
{% endif %}
<div class="mt-4">
<div class="mt-4 flex flex-row justify-between">
<a href="{% url 'settings' %}" class="btn btn-secondary">Back to Settings</a>
<a href="{% url 'add_friend_code' %}" class="btn btn-primary">Add a New Friend Code</a>
</div>
</div>

View file

@ -12,9 +12,9 @@
<div class="mx-4 grid gap-3 grid-cols-[repeat(auto-fit,minmax(150px,1fr))] justify-items-center">
{% for card in cards %}
{% if mode == "offered" %}
<a href="?offered_cards={{ card.id }}"
<a href="{% url 'cards:card_detail' card.id %}"
{% else %}
<a href="?wanted_cards={{ card.id }}"
<a href="{% url 'cards:card_detail' card.id %}"
{% endif %}
class="flex justify-between items-center text-primary no-underline">
{% card_badge card card.offer_count %}

View file

@ -8,12 +8,12 @@
<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>
<span aria-hidden="false" class="sr-only">Welcome to PKMN Trade Club</span>
</h1>
<!-- Search Form Section -->
<!-- Search/Create Form Section -->
<section id="trade-search" class="mb-8">
<form method="post" action="{% url 'trade_offer_search' %}" class="space-y-4">
<form id="tradeSearchForm" method="post" class="space-y-4">
{% csrf_token %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
@ -23,26 +23,28 @@
{% card_multiselect "want_cards" "I Want:" "Select some cards..." cards want_cards %}
</div>
</div>
{# Pass the user's default friend code as a hidden field for creation #}
<input type="hidden" name="initiated_by" value="{{ request.user.default_friend_code.pk }}">
<div class="flex flex-col md:flex-row gap-4">
<button type="submit" class="btn btn-primary grow">
<button type="submit" name="search" formaction="{% url 'trade_offer_search' %}" class="btn btn-primary grow">
Find a Trade Offer
</button>
<a href="{% url 'trade_offer_create' %}" id="createTradeOfferBtn" class="btn btn-secondary grow">
<button type="submit" name="preview" formaction="{% url 'trade_offer_confirm_create' %}" class="btn btn-secondary grow">
Create Trade Offer
</a>
</button>
</div>
</form>
</section>
<!-- Market Stats Section -->
<!-- Card Stats Section -->
<section aria-labelledby="stats-heading" class="mb-8">
<h2 id="stats-heading" class="text-2xl font-semibold mb-4">Market Stats</h2>
<h2 id="stats-heading" class="text-2xl font-semibold mb-4">Card Stats</h2>
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<!-- Most Offered Cards -->
<div>
<div class="card card-border bg-base-100 shadow-lg">
<div class="card-header text-base-content p-4">
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Offered Cards</h5>
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Offered</h5>
</div>
<div class="card-body my-4 p-0">
{% cache 3600 most_offered_cards %}
@ -55,7 +57,7 @@
<div>
<div class="card card-border bg-base-100 shadow-lg">
<div class="card-header text-base-content p-4">
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Wanted Cards</h5>
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Wanted</h5>
</div>
<div class="card-body my-4 p-0">
{% cache 3600 most_wanted_cards %}
@ -68,7 +70,7 @@
<div class="col-span-2 md:col-span-1">
<div class="card card-border bg-base-100 shadow-lg">
<div class="card-header text-base-content p-4">
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Least Offered Cards</h5>
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Least Offered</h5>
</div>
<div class="card-body my-4 p-0">
{% cache 3600 least_offered_cards %}
@ -160,39 +162,6 @@
{% block javascript %}
<script defer>
document.addEventListener('DOMContentLoaded', function() {
// Updated: JS to carry over selections (including quantities) to the Create Trade Offer page.
const createBtn = document.getElementById('createTradeOfferBtn');
if (createBtn) {
createBtn.addEventListener('click', function(e) {
e.preventDefault();
// Use the standardized field names for both "have_cards" and "want_cards"
const haveSelect = document.querySelector('select[name="have_cards"]');
const wantSelect = document.querySelector('select[name="want_cards"]');
const url = new URL(createBtn.href, window.location.origin);
if (haveSelect) {
// For each selected option, include the quantity from data-quantity (defaulting to "1")
const selectedHave = Array.from(haveSelect.selectedOptions).map(opt => {
const cardId = opt.value;
const quantity = opt.getAttribute('data-quantity') || '1';
return cardId + ':' + quantity;
});
selectedHave.forEach(val => url.searchParams.append('have_cards', val));
}
if (wantSelect) {
const selectedWant = Array.from(wantSelect.selectedOptions).map(opt => {
const cardId = opt.value;
const quantity = opt.getAttribute('data-quantity') || '1';
return cardId + ':' + quantity;
});
selectedWant.forEach(val => url.searchParams.append('want_cards', val));
}
window.location.href = url.href;
});
}
// Minimal JavaScript for toggling Featured Offers tabs
const featuredTabs = document.querySelectorAll('input[name="featured_tabs"]');
const featuredTabContents = document.querySelectorAll('#featured-tab-contents .tab-content');
@ -202,11 +171,7 @@ document.addEventListener('DOMContentLoaded', function() {
if (radio.checked) {
const target = radio.id;
featuredTabContents.forEach(content => {
if (content.getAttribute('data-tab') === target) {
content.style.display = 'block';
} else {
content.style.display = 'none';
}
content.style.display = content.getAttribute('data-tab') === target ? 'block' : 'none';
});
}
});

View file

@ -0,0 +1,37 @@
{% load tailwind_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{# Opening Div and Label first #}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="{% if wrapper_class %}{{ wrapper_class }} {% endif %}{% if field_class %}{{ field_class }}{% else %}mb-3{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="{% if label_class %}{{ label_class }}{% else %}block text-base-content bg-base-100 text-sm font-bold mb-2{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
{# if field has a special template then use this #}
{% if field|is_select %}
<div class="{% if field_class %}{{ field_class }}{% else %}mb-3{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'tailwind/layout/select.html' %}
</div>
{% elif field|is_checkboxselectmultiple %}
<div class="{% if field_class %}{{ field_class }}{% else %}mb-3{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'tailwind/layout/checkboxselectmultiple.html' %}
</div>
{% elif field|is_radioselect %}
<div class="{% if field_class %}{{ field_class }}{% else %}mb-3{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'tailwind/layout/radioselect.html' %}
</div>
{% else %}
{# otherwise use django rendering with additional classes added #}
{% tailwind_field field %}
{% endif %}
{% include 'tailwind/layout/help_text_and_errors.html' %}
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
{% endif %}

View file

@ -0,0 +1,7 @@
{% if field.help_text %}
{% if help_text_inline %}
<p {% if field.id_for_label %}id="{{ field.id_for_label }}_helptext" {% endif %}class="text-base-content bg-base-100">{{ field.help_text|safe }}</p>
{% else %}
<small {% if field.id_for_label %}id="{{ field.id_for_label }}_helptext" {% endif %}class="text-base-content bg-base-100">{{ field.help_text|safe }}</small>
{% endif %}
{% endif %}

View file

@ -1,5 +1,5 @@
{% load trade_offer_tags %}
{% if offered_cards or wanted_cards %}
{% if have_cards or want_cards %}
<hr class="my-8 border-t border-base-300">
<h2 class="text-2xl font-bold mb-4">Results</h2>
{% if search_results %}

View file

@ -0,0 +1,28 @@
{% extends 'base.html' %}
{% load static card_badge trade_offer_tags %}
{% block title %}Confirm Trade Offer{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-xl mt-6">
<h2 class="text-2xl font-bold mb-4">Confirm Trade Offer</h2>
<form method="post">
{% csrf_token %}
{# Re-create hidden inputs from POST data, except the preview button #}
{% for key, values in post_data.lists %}
{% for value in values %}
{% if key != "preview" %}
<input type="hidden" name="{{ key }}" value="{{ value }}">
{% endif %}
{% endfor %}
{% endfor %}
{% render_trade_offer dummy_trade_offer False False True %}
<div class="flex justify-between mt-4">
<button type="submit" name="edit" class="btn btn-secondary">Edit</button>
<button type="submit" name="confirm" class="btn btn-primary">Confirm Trade Offer</button>
</div>
</form>
</div>
{% endblock content %}

View file

@ -6,7 +6,7 @@
{% 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">
<form method="post" action="{% url 'trade_offer_confirm_create' %}" novalidate class="space-y-4">
{% csrf_token %}
{% 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" %}
@ -14,14 +14,18 @@
<!-- 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" "I Have:" "Select some cards..." cards form.initial.have_cards %}
{% with have_values=form.have_cards.value|default:form.initial.have_cards %}
{% card_multiselect "have_cards" "I Have:" "Select some cards..." cards have_values %}
{% endwith %}
</div>
<div class="form-control">
{% card_multiselect "want_cards" "I Want:" "Select some cards..." cards form.initial.want_cards %}
{% with want_values=form.want_cards.value|default:form.initial.want_cards %}
{% card_multiselect "want_cards" "I Want:" "Select some cards..." cards want_values %}
{% endwith %}
</div>
</div>
<button type="submit" class="btn btn-primary w-full">Create Offer</button>
<button type="submit" name="preview" class="btn btn-primary w-full">Preview Trade Offer</button>
</form>
{% if form.errors %}
<div class="alert alert-error mt-4">

View file

@ -8,9 +8,9 @@
<h2 class="text-2xl font-bold">Trade Offer Details</h2>
<div class="flex justify-center mt-10">
{% if screenshot_mode == "true" %}
{% render_trade_offer object True %}
{% render_trade_offer object True show_friend_code %}
{% else %}
{% render_trade_offer object %}
{% render_trade_offer object False False True %}
{% endif %}
</div>
{% if acceptance_form %}
@ -55,7 +55,7 @@
{% if is_initiator %}
<a href="{{ delete_close_url }}" class="btn btn-danger">Delete/Close Trade Offer</a>
{% elif request.user.is_authenticated %}
<button type="submit" class="btn btn-primary">Submit Acceptance</button>
<button type="submit" class="btn btn-primary">Accept Offer</button>
{% endif %}
</form>
</div>

View file

@ -10,21 +10,21 @@
{% csrf_token %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
{% card_multiselect "offered_cards" "Have:" "Select zero or more cards..." cards offered_cards %}
{% card_multiselect "have_cards" "I Have:" "Select zero or more cards..." cards have_cards %}
</div>
<div>
{% card_multiselect "wanted_cards" "Want:" "Select zero or more cards..." cards wanted_cards %}
{% card_multiselect "want_cards" "I Want:" "Select zero or more cards..." cards want_cards %}
</div>
</div>
<div class="flex flex-col md:flex-row gap-4">
<button type="submit" class="btn btn-primary flex-1">Find a Trade Offer</button>
<button type="submit" class="btn btn-primary">Find a Trade Offer</button>
</div>
</form>
</section>
<!-- Search Results Section -->
<section id="search-results" class="mb-8">
{% include "trades/_search_results.html" %}
{% include "trades/_search_results.html" with search_results=search_results %}
</section>
{% endblock content %}