diff --git a/src/models/campaign.py b/src/models/campaign.py index 2c68a9e..5554937 100644 --- a/src/models/campaign.py +++ b/src/models/campaign.py @@ -35,7 +35,6 @@ class DropsCampaign: self.link_url: str = data["accountLinkURL"] # campaign's image actually comes from the game object # we use regex to get rid of the dimensions part (ex. ".../game_id-285x380.jpg") - self.image_url: URLType = remove_dimensions(data["game"]["boxArtURL"]) self.starts_at: datetime = isoparse(data["startAt"]) self.ends_at: datetime = isoparse(data["endAt"]) self._valid: bool = data["status"] != "EXPIRED" diff --git a/src/web/managers/inventory.py b/src/web/managers/inventory.py index 1dd86a2..cbdd546 100644 --- a/src/web/managers/inventory.py +++ b/src/web/managers/inventory.py @@ -41,7 +41,6 @@ class InventoryManager: campaign: The drop campaign to add """ # Get campaign image from cache - image_url = str(campaign.image_url) drops_data = [] for drop in campaign.drops: @@ -74,7 +73,7 @@ class InventoryManager: "id": campaign.id, "name": campaign.name, "game_name": campaign.game.name, - "image_url": image_url, + "game_box_art_url": campaign.game.box_art_url, "campaign_url": campaign.campaign_url, "link_url": campaign.link_url, "starts_at": campaign.starts_at.isoformat(), diff --git a/web/static/app.js b/web/static/app.js index 4fe7e48..c1ed067 100644 --- a/web/static/app.js +++ b/web/static/app.js @@ -811,11 +811,38 @@ function renderInventory() { ? `` : ''; + // Add game icon if available + let gameIconHtml = ''; + if (campaign.game_box_art_url) { + const iconUrl = campaign.game_box_art_url.replace('{width}', '52').replace('{height}', '70'); + gameIconHtml = `${campaign.game_name}`; + } + + // Format campaign timing based on status + let timingHtml = ''; + if (campaign.active && campaign.ends_at) { + const endDate = new Date(campaign.ends_at); + const formattedDate = endDate.toLocaleString(); + const endsLabel = t.gui?.inventory?.ends || 'Ends: {time}'; + timingHtml = `
${endsLabel.replace('{time}', formattedDate)}
`; + } else if (campaign.upcoming && campaign.starts_at) { + const startDate = new Date(campaign.starts_at); + const formattedDate = startDate.toLocaleString(); + const startsLabel = t.gui?.inventory?.starts || 'Starts: {time}'; + timingHtml = `
${startsLabel.replace('{time}', formattedDate)}
`; + } else if (campaign.expired && campaign.ends_at) { + const endDate = new Date(campaign.ends_at); + const formattedDate = endDate.toLocaleString(); + const endsLabel = t.gui?.inventory?.ends || 'Ends: {time}'; + timingHtml = `
${endsLabel.replace('{time}', formattedDate)}
`; + } + const claimedCountText = t.gui?.inventory?.claimed_drops || 'claimed'; card.innerHTML = `
- ${campaign.game_name} + ${gameIconHtml} + ${campaign.game_name} ${linkStatusBadgeHtml}
${campaignNameHtml} @@ -825,6 +852,7 @@ function renderInventory() { ${statusText} ${campaign.claimed_drops} / ${campaign.total_drops} ${claimedCountText}
+ ${timingHtml}
${dropsHtml}
diff --git a/web/static/styles.css b/web/static/styles.css index f575dfc..2db8da1 100644 --- a/web/static/styles.css +++ b/web/static/styles.css @@ -618,10 +618,19 @@ header h1 { } .campaign-game { + display: flex; + align-items: center; + gap: 12px; font-weight: bold; font-size: 16px; } +.campaign-game .game-icon { + width: 52px; + height: 70px; + flex-shrink: 0; +} + .campaign-name { font-size: 14px; color: var(--text-secondary); @@ -712,6 +721,13 @@ header h1 { justify-content: space-between; } +.campaign-timing { + padding: 5px 15px 10px; + font-size: 11px; + color: var(--text-secondary); + font-style: italic; +} + .campaign-drops { padding: 15px; }