bounty board feature buyers to see bounty boards seller profile page (like have theme chooser) Have the game and set name be filters. Add cards to vault manually update card inventory add to have the autocomplete for the card - store analytics, clicks, views, link to store (url/QR code) bulk item inventory creation -- Make the banner feature flag driven so I can have a beta site setup like the primary site don't use primary key values in urls - update to use uuid4 values site analytics. tianji is being sent item potent on the mtg and lorcana populate scripts Card item images for specific listings check that when you buy a card it is in the vault Buys should be able to search on store inventories More pie charts for the seller! post bounty board is slow to load seller reviews/ratings - show a historgram - need a way for someone to rate Report a seller feature for buyer to report Make sure the stlying is consistent based on the theme choosen smart minimum order quantity and shipping amounts (defined by the store itself) put virtual packs behind a feature flag like bounty board proxy service feature flag Terms of Service new description for TCGKof store SSN, ITIN, and EIN optomize for SEO
165 lines
9.7 KiB
HTML
165 lines
9.7 KiB
HTML
{% extends 'base/layout.html' %}
|
|
{% load static %}
|
|
|
|
{% block content %}
|
|
<div class="browse-container" style="display: grid; grid-template-columns: 250px 1fr; gap: 2rem;">
|
|
<!-- Sidebar Filters -->
|
|
<aside class="browse-sidebar"
|
|
style="background: var(--card-bg); padding: 1.5rem; border-radius: 0.5rem; border: 1px solid var(--border-color); height: fit-content;">
|
|
<h3 style="margin-top: 0;">Filter Bounties</h3>
|
|
<form method="get">
|
|
<div style="margin-bottom: 1rem;">
|
|
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Game</label>
|
|
<select name="game"
|
|
style="width: 100%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);"
|
|
onchange="this.form.submit()">
|
|
<option value="">All Games</option>
|
|
{% for game in games %}
|
|
<option value="{{ game.slug }}" {% if current_game == game.slug %}selected{% endif %}>
|
|
{{game.name}}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
{% if current_game %}
|
|
<div style="margin-bottom: 1rem;">
|
|
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Set</label>
|
|
<select name="set"
|
|
style="width: 100%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
|
<option value="">All Sets</option>
|
|
{% for set in sets %}
|
|
<option value="{{ set.id }}" {% if request.GET.set|add:"0" == set.id %}selected{% endif %}>{{ set.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div style="margin-bottom: 1rem; position: relative;">
|
|
<label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Search</label>
|
|
<input type="text" name="q" id="search-input" value="{{ search_query|default:'' }}" placeholder="Card or Bounty title..." autocomplete="off"
|
|
style="width: 90%; padding: 0.5rem; border-radius: 0.25rem; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color);">
|
|
<ul id="suggestions-list" style="display: none; position: absolute; top: 100%; left: 0; width: 90%; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 0.25rem; z-index: 1000; list-style: none; padding: 0; margin: 0; max-height: 200px; overflow-y: auto;">
|
|
</ul>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
const searchInput = document.getElementById('search-input');
|
|
const suggestionsList = document.getElementById('suggestions-list');
|
|
let debounceTimer;
|
|
|
|
if (searchInput) {
|
|
searchInput.addEventListener('input', function() {
|
|
const query = this.value;
|
|
clearTimeout(debounceTimer);
|
|
if (query.length < 2) {
|
|
suggestionsList.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
debounceTimer = setTimeout(() => {
|
|
fetch(`/api/bounty-autocomplete/?q=${encodeURIComponent(query)}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
suggestionsList.innerHTML = '';
|
|
if (data.results.length > 0) {
|
|
data.results.forEach(name => {
|
|
const li = document.createElement('li');
|
|
li.textContent = name;
|
|
li.style.padding = '0.5rem';
|
|
li.style.cursor = 'pointer';
|
|
li.style.borderBottom = '1px solid var(--border-color)';
|
|
|
|
li.addEventListener('mouseenter', () => {
|
|
li.style.background = 'var(--card-bg)';
|
|
});
|
|
li.addEventListener('mouseleave', () => {
|
|
li.style.background = 'transparent';
|
|
});
|
|
|
|
li.addEventListener('click', () => {
|
|
searchInput.value = name;
|
|
suggestionsList.style.display = 'none';
|
|
searchInput.form.submit();
|
|
});
|
|
suggestionsList.appendChild(li);
|
|
});
|
|
suggestionsList.style.display = 'block';
|
|
} else {
|
|
suggestionsList.style.display = 'none';
|
|
}
|
|
});
|
|
}, 300);
|
|
});
|
|
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target !== searchInput && e.target !== suggestionsList) {
|
|
suggestionsList.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<button type="submit" class="btn" style="width: 100%;">Apply Filters</button>
|
|
<a href="{% url 'store:bounty_list' %}"
|
|
style="display: block; text-align: center; margin-top: 1rem; color: #94a3b8; font-size: 0.875rem; text-decoration: none;">Clear
|
|
Filters</a>
|
|
</form>
|
|
</aside>
|
|
|
|
<!-- Bounty Grid -->
|
|
<div>
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
|
<h2 style="margin: 0;">Bounty Board</h2>
|
|
{% if user.seller_profile %}
|
|
<a href="{% url 'store:bounty_create' %}" class="btn btn-outline" style="padding: 0.5rem 1rem; font-size: 0.875rem;">Post a Bounty</a>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="card-grid">
|
|
{% for bounty in bounties %}
|
|
<div class="tcg-card">
|
|
<a href="{% url 'store:bounty_detail' bounty.uuid %}" style="text-decoration: none; color: inherit;">
|
|
<div style="aspect-ratio: 2.5/3.5; background: #000; position: relative;">
|
|
{% if bounty.card.image_url %}
|
|
<img src="{{ bounty.card.image_url }}" alt="{{ bounty.card.name }}"
|
|
style="width: 100%; height: 100%; object-fit: cover;">
|
|
{% else %}
|
|
<div
|
|
style="display: flex; align-items: center; justify-content: center; height: 100%; color: #64748b; background: #334155; padding: 1rem; text-align: center;">
|
|
{{ bounty.title|default:"No Image" }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="tcg-card-body">
|
|
<h4
|
|
style="margin: 0 0 0.5rem; font-size: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
|
{% if bounty.card %}{{ bounty.card.name }}{% else %}{{ bounty.title }}{% endif %}
|
|
</h4>
|
|
<div
|
|
style="display: flex; justify-content: space-between; align-items: center; font-size: 0.875rem; color: #94a3b8;">
|
|
<span>{% if bounty.card %}{{ bounty.card.set.code|default:bounty.card.set.game.name }}{% else %}Wanted{% endif %}</span>
|
|
<span style="color: #10b981;">Offering ${{ bounty.target_price }}</span>
|
|
</div>
|
|
<div
|
|
style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center;">
|
|
<span style="font-size: 0.75rem; color: #94a3b8;">{{ bounty.offers.count }} Offers</span>
|
|
|
|
<span class="btn" style="padding: 0.25rem 0.5rem; font-size: 0.75rem;">View Bounty</span>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
{% empty %}
|
|
<div style="grid-column: 1 / -1; text-align: center; padding: 3rem; background: var(--card-bg); border-radius: 0.5rem; border: 1px solid var(--border-color);">
|
|
<p style="color: #94a3b8; font-size: 1.1rem; margin-bottom: 1rem;">No active bounties found matching your criteria.</p>
|
|
<a href="{% url 'store:bounty_list' %}" class="btn btn-outline">Clear Filters</a>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|