From ecf3511fcf384169d020b1229b92aa489dcb5d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Hells=C3=A9n?= Date: Mon, 8 Sep 2025 00:55:12 +0200 Subject: [PATCH] Show the drop benefits under game details --- templates/base.html | 6 +++- templates/twitch/game_detail.html | 56 +++++++++++++++++++++++++++++++ twitch/views.py | 20 ++++++++++- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/templates/base.html b/templates/base.html index c6137e3..7a3c9e4 100644 --- a/templates/base.html +++ b/templates/base.html @@ -47,7 +47,11 @@ th, td { padding: 8px; text-align: left; vertical-align: middle; } th {background-color: Canvas; color: CanvasText; font-weight: bold; } tr:nth-child(even) { background-color: color-mix(in srgb, Canvas 95%, CanvasText 5%); } - td img { display: block; height: 160px; width: 160px; object-fit: cover; border-radius: 4px; } + td > img { display: block; height: 160px; width: 160px; object-fit: cover; border-radius: 4px; } + + .campaign-benefits { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 8px; } + .benefit-item { display: inline-flex; align-items: center; padding: 2px 6px; background-color: color-mix(in srgb, Canvas 90%, CanvasText 10%); border-radius: 4px; font-size: 0.9em; } + .benefit-item img { width: 24px !important; height: 24px !important; display: inline-block !important; margin-right: 4px; border-radius: 2px; } @media (prefers-color-scheme: dark) { .highlight { background: #0d1117; color: #E6EDF3; } diff --git a/templates/twitch/game_detail.html b/templates/twitch/game_detail.html index 6a2c8aa..bc07e9a 100644 --- a/templates/twitch/game_detail.html +++ b/templates/twitch/game_detail.html @@ -53,6 +53,25 @@ {{ campaign.clean_name }} + {% if campaign.time_based_drops.all %} +
+ {% comment %}Show unique benefits sorted alphabetically{% endcomment %} + {% for benefit in campaign.sorted_benefits %} + + {% if benefit.image_asset_url %} + {{ benefit.name }} + {% endif %} + {{ benefit.name }} + + {% endfor %} +
+ {% endif %} Ends in {{ campaign.end_at|timeuntil }} @@ -70,6 +89,24 @@ {{ campaign.clean_name }} + {% if campaign.time_based_drops.all %} +
+ {% for benefit in campaign.sorted_benefits %} + + {% if benefit.image_asset_url %} + {{ benefit.name }} + {% endif %} + {{ benefit.name }} + + {% endfor %} +
+ {% endif %} Starts in {{ campaign.start_at|timeuntil }} @@ -87,6 +124,25 @@ {{ campaign.clean_name }} + {% if campaign.time_based_drops.all %} +
+ {% comment %}Show unique benefits sorted alphabetically{% endcomment %} + {% for benefit in campaign.sorted_benefits %} + + {% if benefit.image_asset_url %} + {{ benefit.name }} + {% endif %} + {{ benefit.name }} + + {% endfor %} +
+ {% endif %} {{ campaign.end_at|timesince }} ago diff --git a/twitch/views.py b/twitch/views.py index 09a5ed0..14abb08 100644 --- a/twitch/views.py +++ b/twitch/views.py @@ -438,7 +438,16 @@ class GameDetailView(DetailView): subscription = NotificationSubscription.objects.filter(user=user, game=game).first() now: datetime.datetime = timezone.now() - all_campaigns: QuerySet[DropCampaign, DropCampaign] = DropCampaign.objects.filter(game=game).select_related("game__owner").order_by("-end_at") + all_campaigns: QuerySet[DropCampaign, DropCampaign] = ( + DropCampaign.objects.filter(game=game) + .select_related("game__owner") + .prefetch_related( + Prefetch( + "time_based_drops", queryset=TimeBasedDrop.objects.prefetch_related(Prefetch("benefits", queryset=DropBenefit.objects.order_by("name"))) + ) + ) + .order_by("-end_at") + ) active_campaigns: list[DropCampaign] = [ campaign @@ -453,6 +462,15 @@ class GameDetailView(DetailView): expired_campaigns: list[DropCampaign] = [campaign for campaign in all_campaigns if campaign.end_at is not None and campaign.end_at < now] + # Add unique sorted benefits to each campaign object + for campaign in all_campaigns: + benefits_dict = {} # Use dict to track unique benefits by ID + for drop in campaign.time_based_drops.all(): # type: ignore[attr-defined] + for benefit in drop.benefits.all(): + benefits_dict[benefit.id] = benefit + # Sort benefits by name and attach to campaign + campaign.sorted_benefits = sorted(benefits_dict.values(), key=lambda b: b.name) # type: ignore[attr-defined] + serialized_game = serialize( "json", [game],