from __future__ import annotations from collections.abc import Callable import discord from discord import app_commands from core import economy import strings as S def register_economy_support_commands( tree: app_commands.CommandTree, parse_amount: Callable[[str, int], tuple[int | None, str | None]], coin: Callable[[int], str], cancel_reminder_task: Callable[[int, str], None], ) -> None: class FundModal(discord.ui.Modal): summa = discord.ui.TextInput( label=S.REQUEST_UI["modal_label"], min_length=1, max_length=10, ) def __init__(self, view: "RequestView"): super().__init__(title=S.REQUEST_UI["modal_title"]) self._view = view self.summa.placeholder = f"1 - {view.remaining}" async def on_submit(self, interaction: discord.Interaction): amount, err = parse_amount(self.summa.value, 0) if err or amount is None: await interaction.response.send_message(S.ERR["invalid_amount"], ephemeral=True) return if amount <= 0 or amount > self._view.remaining: await interaction.response.send_message( S.ERR["fund_range"].format(max=self._view.remaining), ephemeral=True ) return res = await economy.do_give(interaction.user.id, self._view.requester.id, amount) if not res["ok"]: data = await economy.get_user(interaction.user.id) await interaction.response.send_message( S.ERR["broke"].format(bal=coin(data["balance"])), ephemeral=True ) return self._view.remaining -= amount funded_line = S.REQUEST_UI["funded_line"].format( name=interaction.user.display_name, amount=coin(amount), ) if self._view.remaining <= 0: self._view.fund_btn.disabled = True self._view.fund_btn.label = S.REQUEST_UI["btn_funded"] self._view.fund_btn.style = discord.ButtonStyle.secondary self._view.stop() funded_line += S.REQUEST_UI["funded_full"] else: self._view.fund_btn.label = S.REQUEST_UI["btn_fund_remaining"].format( remaining=self._view.remaining ) funded_line += S.REQUEST_UI["funded_partial"].format( remaining=coin(self._view.remaining) ) await interaction.response.send_message(funded_line) if self._view.message: await self._view.message.edit(view=self._view) class RequestView(discord.ui.View): def __init__(self, requester: discord.Member, amount: int, target: discord.Member | None): super().__init__(timeout=300) self.requester = requester self.remaining = amount self.target = target self.message: discord.Message | None = None self.fund_btn = discord.ui.Button( label=S.REQUEST_UI["btn_fund"], style=discord.ButtonStyle.success, ) self.fund_btn.callback = self._fund self.add_item(self.fund_btn) async def _fund(self, interaction: discord.Interaction): if interaction.user.id == self.requester.id: await interaction.response.send_message(S.ERR["request_self_fund"], ephemeral=True) return if self.target and interaction.user.id != self.target.id: await interaction.response.send_message( S.ERR["request_targeted"].format(name=self.target.display_name), ephemeral=True, ) return await interaction.response.send_modal(FundModal(self)) async def on_timeout(self): for item in self.children: item.disabled = True max_request = 1_000_000 @tree.command(name="request", description=S.CMD["request"]) @app_commands.describe( summa=S.OPT["request_summa"], põhjus=S.OPT["request_põhjus"], sihtmärk=S.OPT["request_sihtmärk"], ) async def cmd_request( interaction: discord.Interaction, summa: str, põhjus: str, sihtmärk: discord.Member | None = None, ): summa_int, err = parse_amount(summa, 0) if err or summa_int is None: await interaction.response.send_message(err or S.ERR["invalid_amount"], ephemeral=True) return if summa_int <= 0: await interaction.response.send_message(S.ERR["positive_amount"], ephemeral=True) return if summa_int > max_request: await interaction.response.send_message( S.ERR["fund_range"].format(max=coin(max_request)), ephemeral=True, ) return summa = summa_int if sihtmärk and sihtmärk.id == interaction.user.id: await interaction.response.send_message(S.ERR["request_self"], ephemeral=True) return if sihtmärk and sihtmärk.bot: await interaction.response.send_message(S.ERR["request_bot"], ephemeral=True) return audience = ( S.REQUEST_UI["audience_targeted"].format(name=sihtmärk.display_name) if sihtmärk else S.REQUEST_UI["audience_all"] ) embed = discord.Embed( title=S.TITLE["request"], description=S.REQUEST_UI["desc"].format( requester=interaction.user.display_name, amount=coin(summa), reason=põhjus, audience=audience, ), color=0xF4C430, ) embed.set_footer(text=S.REQUEST_UI["footer"]) view = RequestView(interaction.user, summa, sihtmärk) await interaction.response.send_message(embed=embed, view=view) view.message = await interaction.original_response() class RemindersSelect(discord.ui.Select): def __init__(self, user_id: int, current: list[str]): self.user_id = user_id options = [ discord.SelectOption( label=label, description=desc, value=cmd, default=cmd in current, ) for cmd, label, desc in S.REMINDER_OPTS ] super().__init__( placeholder=S.REMINDERS_UI["select_placeholder"], options=options, min_values=0, max_values=len(S.REMINDER_OPTS), ) async def callback(self, interaction: discord.Interaction): if interaction.user.id != self.user_id: await interaction.response.send_message(S.ERR["not_your_menu"], ephemeral=True) return await economy.do_set_reminders(self.user_id, self.values) enabled = set(self.values) for cmd in [opt[0] for opt in S.REMINDER_OPTS]: if cmd not in enabled: cancel_reminder_task(self.user_id, cmd) if self.values: names = " ".join(f"`/{v}`" for v in self.values) msg = S.REMINDERS_UI["saved_on"].format(names=names) else: msg = S.REMINDERS_UI["saved_off"] await interaction.response.send_message(msg, ephemeral=True) class RemindersView(discord.ui.View): def __init__(self, user_id: int, current: list[str]): super().__init__(timeout=60) self.add_item(RemindersSelect(user_id, current)) @tree.command(name="reminders", description=S.CMD["reminders"]) async def cmd_reminders(interaction: discord.Interaction): user_data = await economy.get_user(interaction.user.id) current = user_data.get("reminders", []) if current: status = " ".join(f"`/{c}`" for c in current) desc = S.REMINDERS_UI["desc_active"].format(status=status) else: desc = S.REMINDERS_UI["desc_none"] embed = discord.Embed( title=S.TITLE["reminders"], description=desc, color=0x5865F2, ) embed.set_footer(text=S.REMINDERS_UI["footer"]) await interaction.response.send_message( embed=embed, view=RemindersView(interaction.user.id, current), ephemeral=True, )