""" Defines widgets for displaying a campaign """ from typing import Optional, TYPE_CHECKING import asyncio import datetime as dt import discord from discord.ui import Modal from discord.ui.select import select, Select, SelectOption from discord.ui.button import button, Button, ButtonStyle from discord.ui.text_input import TextInput, TextStyle from meta import LionBot from meta.errors import UserInputError from meta.config import conf from utils.lib import tabulate, utc_now, MessageArgs, parse_duration from utils.ui import MessageUI from utils.ui.micros import FastModal from ...campaign import RewardCampaign from ...data import EarnedReward from .. import logger from .rewards import RewardList class CampaignDashboard(MessageUI): def __init__(self, bot: LionBot, campaign: RewardCampaign, **kwargs): super().__init__(**kwargs) self.bot = bot self.campaign = campaign # UI state # ------ UI API ----- # ------ UI Components ----- # Button to open rewards list @button(label="Rewards Earned") async def rewards_list_button(self, press: discord.Interaction, pressed: Button): await press.response.defer() widget = RewardList( bot=self.bot, campaign=self.campaign, callerid=self._callerid, ) self._slaves.append(widget) await widget.run(press) await widget.wait() self._slaves.remove(widget) @button(emoji=conf.emojis.cancel) async def quit_button(self, press: discord.Interaction, pressed: Button): """Close the UI and all children.""" await press.response.defer(thinking=False) await self.quit() @button(emoji=conf.emojis.refresh) async def refresh_button(self, press: discord.Interaction, pressed: Button): await press.response.defer() await self.refresh() # ------ UI Flow ----- async def refresh_layout(self): # Nothing to refresh pass async def make_message(self) -> MessageArgs: embed = discord.Embed( title=f"{self.campaign.row.campaign_name} Campaign Dashboard" ) # embed.set_footer with last update # Don't show the webhook url since it contains secrets, just show whether it is set # Hard-coded channel/timer URL for now campaign = self.campaign started_at = ( discord.utils.format_dt(campaign.row.started_at, "F") if campaign.row.started_at else "*Not Started*" ) all_rewards = await campaign.get_rewards() rewards_earned = len(all_rewards) reward_cap = campaign.row.target_rewards if reward_cap is not None: rewards = f"{rewards_earned} out of {reward_cap}" else: rewards = f"{rewards_earned}" description = ( f"Campaign running since {started_at} with {rewards} rewards given." ) table = { "Created at": discord.utils.format_dt(campaign.row.created_at, "F"), "Started at": started_at, "Moderator Role": f"<@&{campaign.row.moderator_role_id}>" if campaign.row.moderator_role_id else "*Not Set*", "Logging webhook": "*Set Up*" if campaign.row.logging_webhook_url else "*Not Set*", "Rewards Earned": str(rewards_earned), "Rewards Cap": str(reward_cap), } if campaign.row.completed_at is not None: table["Finished at"] = discord.utils.format_dt( campaign.row.completed_at, "F" ) prop_table = "\n".join(tabulate(*table.items())) embed.description = f"{description}\n\n{prop_table}" # Brief summary of rewards in columns. 12 per column. Empty titles? rewardrows = [] for reward in all_rewards: name = ( reward.twitch_user_name or str(reward.twitch_user_id) or str(reward.profileid) ) fluffed = reward.fulfilled_at is not None fluffed_emoji = "✅" if fluffed else "🔳" rewardrows.append(f"{fluffed_emoji} {name}") blocks = [ "\n".join(rewardrows[i : i + 12]) for i in range(0, len(rewardrows), 12) ] embed.add_field( name="Rewards Summary", value=blocks[0] if blocks else "No Rewards Earned", inline=True, ) for block in blocks[1:]: embed.add_field( name="--", value=block, ) return MessageArgs(embed=embed) async def reload(self): await self.campaign.row.refresh()