restore quantity display on expanded card_badges and add limits to all trade offer creation (currently 20 unique cards per side, 20 max quantity per card), fixes #3 and fixes #17
This commit is contained in:
parent
1cdeaa9bba
commit
b5db5af185
4 changed files with 49 additions and 10 deletions
|
|
@ -17,7 +17,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% render_trade_offer dummy_trade_offer True %}
|
{% render_trade_offer dummy_trade_offer %}
|
||||||
|
|
||||||
<div class="flex justify-between mt-4">
|
<div class="flex justify-between mt-4">
|
||||||
<button type="submit" name="edit" class="btn btn-secondary">Edit</button>
|
<button type="submit" name="edit" class="btn btn-secondary">Edit</button>
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,22 @@
|
||||||
<div class="flex flex-row items-center h-[32px] p-1.5 w-40 text-white shadow-lg" style="{{ style }}">
|
<div class="flex flex-row items-center h-[32px] p-1.5 w-40 text-white shadow-lg" style="{{ style }}">
|
||||||
<div class="grow"><div class="truncate text-ellipsis font-semibold leading-tight text-sm marquee-calc max-w-24">{{ name }}</div></div>
|
<div class="grow"><div class="truncate text-ellipsis font-semibold leading-tight text-sm marquee-calc max-w-24">{{ name }}</div></div>
|
||||||
<div class="grow-0 shrink-0 text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
|
<div class="grow-0 shrink-0 text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
|
||||||
{% if quantity != None %}<div class="grow-0 shrink-0 relative w-fit ps-1">
|
{% if quantity != None %}
|
||||||
<div class="card-quantity-badge relative bg-gray-600 text-white text-sm font-semibold rounded-full text-center size-max px-1.5">{{ quantity }}</div></div>{% endif %}
|
<div class="grow-0 shrink-0 relative w-fit ps-1">
|
||||||
|
<div class="card-quantity-badge relative bg-gray-600 text-white text-sm font-semibold rounded-full text-center size-max px-1.5">{{ quantity }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="relative block m-1">
|
<div class="relative block m-1">
|
||||||
<div class="grid grid-rows-2 grid-cols-4 h-[52px] p-1.5 w-40 text-white shadow-lg" style="{{ style }}">
|
<div class="grid grid-rows-2 grid-cols-4 h-[52px] p-1.5 w-40 text-white shadow-lg" style="{{ style }}">
|
||||||
<div class="row-start-1 col-start-1 col-span-4 self-start leading-tight truncate text-ellipsis"><span class="font-semibold text-sm marquee-calc">{{ name }}</span></div>
|
<div class="row-start-1 col-start-1 {% if quantity != None %}col-span-3{% else %}col-span-4{% endif %} self-start leading-tight truncate text-ellipsis"><span class="font-semibold text-sm marquee-calc">{{ name }}</span></div>
|
||||||
|
{% if quantity != None %}
|
||||||
|
<div class="row-start-1 col-start-4 col-span-1 self-start ms-auto leading-tight relative w-fit ps-1">
|
||||||
|
<div class="card-quantity-badge relative bg-gray-600 text-white text-sm font-semibold rounded-full text-center size-max px-1.5">{{ quantity }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="row-start-2 col-start-1 col-span-3 truncate self-end text-xs text-transparent">{{ rarity }}</div>
|
<div class="row-start-2 col-start-1 col-span-3 truncate self-end text-xs text-transparent">{{ rarity }}</div>
|
||||||
<div class="row-start-2 col-start-4 col-span-1 self-end text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
|
<div class="row-start-2 col-start-4 col-span-1 self-end text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,16 @@ class TradeOfferCreateForm(ModelForm):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise forms.ValidationError(f"Invalid quantity provided in {item}")
|
raise forms.ValidationError(f"Invalid quantity provided in {item}")
|
||||||
parsed[card_id] = parsed.get(card_id, 0) + quantity
|
parsed[card_id] = parsed.get(card_id, 0) + quantity
|
||||||
|
# Validate that each have card does not exceed the max quantity of 20.
|
||||||
|
for card_id, quantity in parsed.items():
|
||||||
|
if quantity > 20:
|
||||||
|
card = Card.objects.get(pk=card_id)
|
||||||
|
raise forms.ValidationError(
|
||||||
|
f"Maximum allowed quantity for each have card is 20. Card {card} has {quantity}."
|
||||||
|
)
|
||||||
|
# Ensure no more than 20 unique have cards are selected.
|
||||||
|
if len(parsed) > 20:
|
||||||
|
raise forms.ValidationError("You can only select a maximum of 20 unique have cards.")
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
def clean_want_cards(self):
|
def clean_want_cards(self):
|
||||||
|
|
@ -156,6 +166,17 @@ class TradeOfferCreateForm(ModelForm):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise forms.ValidationError(f"Invalid quantity provided in {item}")
|
raise forms.ValidationError(f"Invalid quantity provided in {item}")
|
||||||
parsed[card_id] = parsed.get(card_id, 0) + quantity
|
parsed[card_id] = parsed.get(card_id, 0) + quantity
|
||||||
|
# Validate that each want card does not exceed the max quantity of 20.
|
||||||
|
for card_id, quantity in parsed.items():
|
||||||
|
if quantity > 20:
|
||||||
|
# look up card name
|
||||||
|
card = Card.objects.get(pk=card_id)
|
||||||
|
raise forms.ValidationError(
|
||||||
|
f"Maximum allowed quantity for each want card is 20. Card {card} has {quantity}."
|
||||||
|
)
|
||||||
|
# Ensure no more than 20 unique want cards are selected.
|
||||||
|
if len(parsed) > 20:
|
||||||
|
raise forms.ValidationError("You can only select a maximum of 20 unique want cards.")
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
|
|
|
||||||
|
|
@ -610,7 +610,7 @@ class TradeOfferCreateConfirmView(LoginRequiredMixin, View):
|
||||||
}
|
}
|
||||||
return render(request, "trades/trade_offer_create.html", context)
|
return render(request, "trades/trade_offer_create.html", context)
|
||||||
messages.success(request, "Trade offer created successfully!")
|
messages.success(request, "Trade offer created successfully!")
|
||||||
return HttpResponseRedirect(reverse_lazy("trade_offer_list"))
|
return HttpResponseRedirect(reverse_lazy("trade_offer_detail", kwargs={"pk": trade_offer.pk}))
|
||||||
else:
|
else:
|
||||||
# When the form is not valid, update its initial data as well:
|
# When the form is not valid, update its initial data as well:
|
||||||
form.initial = {
|
form.initial = {
|
||||||
|
|
@ -641,14 +641,24 @@ class TradeOfferCreateConfirmView(LoginRequiredMixin, View):
|
||||||
return HttpResponseRedirect(url_with_params)
|
return HttpResponseRedirect(url_with_params)
|
||||||
|
|
||||||
def _preview_offer(self, request):
|
def _preview_offer(self, request):
|
||||||
"""
|
|
||||||
Processes the preview action (existing logic remains unchanged).
|
|
||||||
"""
|
|
||||||
form = TradeOfferCreateForm(request.POST)
|
form = TradeOfferCreateForm(request.POST)
|
||||||
form.fields["initiated_by"].queryset = request.user.friend_codes.all()
|
form.fields["initiated_by"].queryset = request.user.friend_codes.all()
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
# Re-render the creation template with errors.
|
# Set initial values required by the template.
|
||||||
return render(request, "trades/trade_offer_create.html", {"form": form})
|
form.initial = {
|
||||||
|
"have_cards": request.POST.getlist("have_cards"),
|
||||||
|
"want_cards": request.POST.getlist("want_cards"),
|
||||||
|
"initiated_by": request.POST.get("initiated_by"),
|
||||||
|
}
|
||||||
|
from cards.models import Card
|
||||||
|
context = {
|
||||||
|
"form": form,
|
||||||
|
"friend_codes": request.user.friend_codes.all(),
|
||||||
|
"selected_friend_code": request.user.default_friend_code or request.user.friend_codes.first(),
|
||||||
|
"cards": Card.objects.all().order_by("name", "rarity_level"),
|
||||||
|
}
|
||||||
|
return render(request, "trades/trade_offer_create.html", context)
|
||||||
|
|
||||||
|
|
||||||
# Parse the card selections for "have" and "want" cards.
|
# Parse the card selections for "have" and "want" cards.
|
||||||
have_selections = self._parse_card_selections("have_cards")
|
have_selections = self._parse_card_selections("have_cards")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue