Refactor Shop cog to utilize modern UI components for inventory and purchase interactions. Replace menu-based displays with interactive views for better user experience. Update item redemption process to handle pending items with improved confirmation dialogs. Enhance purchase logic to support quantity selection and stock validation.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-25 23:11:37 -04:00
parent a63232fb2a
commit c9f172c451
2 changed files with 549 additions and 134 deletions

View file

@ -13,7 +13,7 @@ from itertools import zip_longest
from typing import Literal
# Shop
from .menu import ShopMenu
from .ui import ShopView, InventoryView, PurchaseView, UseItemView
from .inventory import Inventory
from .checks import Checks
@ -29,7 +29,7 @@ from redbot.core.errors import BalanceTooHigh
log = logging.getLogger("red.shop")
__version__ = "3.1.13"
__version__ = "3.2.0"
__author__ = "Redjumpman"
@ -114,16 +114,23 @@ class Shop(commands.Cog):
instance = await self.get_instance(ctx, user=ctx.author)
except AttributeError:
return await ctx.send("You can't use this command in DMs when not in global mode.")
if not await instance.Inventory():
return await ctx.send("You don't have any items to display.")
data = await instance.Inventory.all()
menu = Inventory(ctx, list(data.items()))
inventory = await instance.Inventory.all()
if not inventory:
return await ctx.send("Your inventory is empty.")
view = InventoryView(ctx, inventory)
await ctx.send(
f"{ctx.author.mention}'s Inventory",
view=view
)
try:
item = await menu.display()
except RuntimeError:
return
await self.pending_prompt(ctx, instance, data, item)
await view.wait()
if view.value: # An item was selected to use
await self.pending_prompt(ctx, instance, inventory, view.value)
except asyncio.TimeoutError:
await ctx.send("Inventory view timed out.")
async def inv_hook(self, user):
"""Inventory Hook for outside cogs
@ -159,61 +166,79 @@ class Shop(commands.Cog):
@shop.command()
@commands.max_concurrency(1, commands.BucketType.user)
async def buy(self, ctx, *purchase):
"""Shop menu appears with no purchase order.
When no argument is specified for purchase, it will bring up the
shop menu.
Using the purchase argument allows direct purchases from a shop.
The order is "Shop Name" "Item Name" and names with spaces
must include quotes.
Examples
--------
[p]shop buy \"Secret Shop\" oil
"""Opens the shop menu or directly purchases an item.
When no argument is specified, opens an interactive shop menu.
For direct purchase, use: "Shop Name" "Item Name"
Examples:
[p]shop buy "Secret Shop" oil
[p]shop buy Junkyard tire
[p]shop buy \"Holy Temple\" \"Healing Potion\"
[p]shop buy "Holy Temple" "Healing Potion"
"""
try:
instance = await self.get_instance(ctx, settings=True)
except AttributeError:
return await ctx.send("You can't use this command in DMs when not in global mode.")
if not await instance.Shops():
return await ctx.send("No shops have been created yet.")
if await instance.Settings.Closed():
return await ctx.send("The shop system is currently closed.")
shops = await instance.Shops.all()
col = await self.check_availability(ctx, shops)
if not col:
available_shops = await self.check_availability(ctx, shops)
if not available_shops:
return await ctx.send(
"Either no items have been created, you need a higher role, "
"Either no items have been created, you need a higher role, "
"or this command should be used in a server and not DMs."
)
if purchase:
try:
shop, item = purchase
except ValueError:
return await ctx.send("Too many parameters passed. Use help on this command for more information.")
if shop not in shops:
return await ctx.send("Either that shop does not exist, or you don't have access to it.")
else:
style = await instance.Settings.Sorting()
menu = ShopMenu(ctx, shops, sorting=style)
# Create purchase view directly for the specified item
item_data = shops[shop]["Items"].get(item)
if not item_data:
return await ctx.send(f"Item '{item}' not found in shop '{shop}'.")
view = PurchaseView(ctx, shop, item, item_data)
embed = view.build_embed()
await ctx.send(embed=embed, view=view)
try:
shop, item = await menu.display()
except RuntimeError:
return
user_data = await self.get_instance(ctx, user=ctx.author)
sm = ShopManager(ctx, instance, user_data)
try:
await sm.order(shop, item)
except asyncio.TimeoutError:
await ctx.send("Request timed out.")
except ExitProcess:
await ctx.send("Transaction canceled.")
await view.wait()
if view.quantity: # A purchase was initiated
user_data = await self.get_instance(ctx, user=ctx.author)
sm = ShopManager(ctx, instance, user_data)
await sm.order(shop, item, view.quantity)
except asyncio.TimeoutError:
await ctx.send("Purchase menu timed out.")
else:
# Open interactive shop menu
view = ShopView(ctx, shops)
await ctx.send(
f"Welcome to the shop, {ctx.author.mention}!",
view=view
)
try:
await view.wait()
if view.current_shop and view.current_item: # An item was selected
user_data = await self.get_instance(ctx, user=ctx.author)
sm = ShopManager(ctx, instance, user_data)
await sm.order(view.current_shop, view.current_item, view.quantity)
except asyncio.TimeoutError:
await ctx.send("Shop menu timed out.")
@commands.max_concurrency(1, commands.BucketType.user)
@shop.command()
@ -372,18 +397,153 @@ class Shop(commands.Cog):
instance = await self.get_instance(ctx, settings=True)
if not await instance.Pending():
return await ctx.send("There are not any pending items.")
data = await instance.Pending.all()
menu = ShopMenu(ctx, data, mode=1, sorting="name")
try:
user, item, = await menu.display()
except RuntimeError:
return
try:
await self.clear_single_pending(ctx, instance, data, item, user)
except asyncio.TimeoutError:
await ctx.send("Request timed out.")
class PendingView(discord.ui.View):
def __init__(self, cog, data, timeout=60):
super().__init__(timeout=timeout)
self.cog = cog
self.data = data
self.setup_user_select()
def setup_user_select(self):
options = []
for user_id, items in self.data.items():
user = self.cog.bot.get_user(int(user_id))
if user:
desc = f"{len(items)} pending items"
options.append(discord.SelectOption(
label=user.name,
description=desc,
value=user_id
))
if options:
user_select = discord.ui.Select(
placeholder="Select a user",
options=options[:25], # Discord limit
row=0
)
user_select.callback = self.user_selected
self.add_item(user_select)
async def user_selected(self, interaction: discord.Interaction):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
user_id = interaction.data["values"][0]
user_items = self.data[user_id]
# Clear previous item select if it exists
for item in self.children[:]:
if isinstance(item, discord.ui.Select) and item.row == 1:
self.remove_item(item)
# Add item select for this user
options = []
for item_id, item_data in user_items.items():
options.append(discord.SelectOption(
label=item_data["Item"][:25],
description=f"ID: {item_id[:8]}...",
value=f"{user_id}:{item_id}"
))
if options:
item_select = discord.ui.Select(
placeholder="Select an item to process",
options=options[:25],
row=1
)
item_select.callback = self.item_selected
self.add_item(item_select)
await interaction.response.edit_message(view=self)
async def item_selected(self, interaction: discord.Interaction):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
user_id, item_id = interaction.data["values"][0].split(":")
user = self.cog.bot.get_user(int(user_id))
item_data = self.data[user_id][item_id]
# Create confirmation view
confirm_view = PendingConfirmView(self.cog, user, item_id, item_data["Item"])
embed = discord.Embed(
title="Pending Item",
description=f"Process pending item for {user.mention}",
color=discord.Color.blue()
)
embed.add_field(name="Item", value=item_data["Item"])
embed.add_field(name="ID", value=item_id)
embed.add_field(name="Timestamp", value=item_data["Timestamp"])
await interaction.response.edit_message(embed=embed, view=confirm_view)
class PendingConfirmView(discord.ui.View):
def __init__(self, cog, user, item_id, item_name, timeout=60):
super().__init__(timeout=timeout)
self.cog = cog
self.user = user
self.item_id = item_id
self.item_name = item_name
@discord.ui.button(label="Approve", style=discord.ButtonStyle.green)
async def approve(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
async with instance.Pending() as p:
del p[str(self.user.id)][self.item_id]
if not p[str(self.user.id)]:
del p[str(self.user.id)]
await interaction.response.edit_message(
content=f"{self.item_name} was approved for {self.user.name}.",
embed=None,
view=None
)
try:
await self.user.send(f"{ctx.author.name} approved your pending {self.item_name}!")
except discord.HTTPException:
pass
self.stop()
@discord.ui.button(label="Deny", style=discord.ButtonStyle.red)
async def deny(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
async with instance.Pending() as p:
del p[str(self.user.id)][self.item_id]
if not p[str(self.user.id)]:
del p[str(self.user.id)]
await interaction.response.edit_message(
content=f"{self.item_name} was denied for {self.user.name}.",
embed=None,
view=None
)
try:
await self.user.send(f"{ctx.author.name} denied your pending {self.item_name}.")
except discord.HTTPException:
pass
self.stop()
@discord.ui.button(label="Cancel", style=discord.ButtonStyle.grey)
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
await interaction.response.edit_message(content="Action cancelled.", embed=None, view=None)
self.stop()
# Start the pending menu
view = PendingView(self, data)
await ctx.send(
"Select a user to view their pending items:",
view=view
)
@shop.command()
@commands.guild_only()
@ -774,22 +934,90 @@ class Shop(commands.Cog):
await sm.remove(item)
await ctx.send("{} was granted the {} role.".format(ctx.author.mention, role.name))
async def pending_prompt(self, ctx, instance, data, item):
"""Handle item redemption with modern UI."""
e = discord.Embed(color=await ctx.embed_colour())
e.add_field(name=item, value=data[item]["Info"], inline=False)
class RedeemView(discord.ui.View):
def __init__(self, cog, timeout=60):
super().__init__(timeout=timeout)
self.cog = cog
self.value = None
@discord.ui.button(label="Redeem", style=discord.ButtonStyle.green)
async def redeem(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
self.value = True
self.stop()
await interaction.response.defer()
@discord.ui.button(label="Cancel", style=discord.ButtonStyle.red)
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user != ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
self.value = False
self.stop()
await interaction.response.defer()
if data[item]["Type"].lower() == "role":
prompt = f"{ctx.author.mention} Do you wish to redeem {item}? This will grant you the role assigned to this item and it will be removed from your inventory permanently."
else:
prompt = f"{ctx.author.mention} Do you wish to redeem {item}? This will add the item to the pending list for an admin to review and grant. The item will be removed from your inventory while this is processing."
view = RedeemView(self)
msg = await ctx.send(prompt, embed=e, view=view)
try:
await view.wait()
if view.value is None:
await msg.edit(content="Redemption timed out.", view=None)
return
elif not view.value:
await msg.edit(content="Redemption cancelled.", view=None)
return
if data[item]["Type"].lower() == "role":
await self.assign_role(ctx, instance, item, data[item]["Role"])
else:
await self.pending_add(ctx, item)
sm = ShopManager(ctx, instance=None, user_data=instance)
await sm.remove(item)
except Exception as exc:
await msg.edit(content=f"An error occurred: {str(exc)}", view=None)
async def pending_add(self, ctx, item):
"""Add an item to the pending list with modern UI."""
instance = await self.get_instance(ctx, settings=True)
unique_id = str(uuid.uuid4())[:17]
timestamp = ctx.message.created_at.now().strftime("%Y-%m-%d %H:%M:%S")
async with instance.Pending() as p:
if str(ctx.author.id) in p:
p[str(ctx.author.id)][unique_id] = {"Item": item, "Timestamp": timestamp}
else:
p[str(ctx.author.id)] = {unique_id: {"Item": item, "Timestamp": timestamp}}
msg = "{} added {} to your pending list.".format(ctx.author.mention, item)
embed = discord.Embed(
title="Item Pending",
description=f"{ctx.author.mention} added {item} to the pending list.",
color=discord.Color.blue()
)
embed.add_field(name="ID", value=unique_id)
embed.add_field(name="Timestamp", value=timestamp)
if await instance.Settings.Alerts():
alert_role = await instance.Settings.Alert_Role()
role = discord.utils.get(ctx.guild.roles, name=alert_role)
if role:
msg = "{}\n{}".format(role.mention, msg)
await ctx.send(msg)
await ctx.send(role.mention, embed=embed)
else:
await ctx.send(embed=embed)
else:
await ctx.send(embed=embed)
async def change_mode(self, mode):
await self.config.clear_all()
@ -879,40 +1107,6 @@ class Shop(commands.Cog):
"list.".format(name.content)
)
async def pending_prompt(self, ctx, instance, data, item):
e = discord.Embed(color=await ctx.embed_colour())
e.add_field(name=item, value=data[item]["Info"], inline=False)
if data[item]["Type"].lower() == "Role":
await ctx.send(
"{} Do you wish to redeem {}? This will grant you the role assigned to "
"this item and it will be removed from your inventory "
"permanently.".format(ctx.author.mention, item),
embed=e,
)
else:
await ctx.send(
"{} Do you wish to redeem {}? This will add the item to the pending "
"list for an admin to review and grant. The item will be removed from "
"your inventory while this is "
"processing.".format(ctx.author.mention, item),
embed=e,
)
try:
choice = await ctx.bot.wait_for("message", timeout=25, check=Checks(ctx).confirm)
except asyncio.TimeoutError:
return await ctx.send("No Response. Item redemption canceled.")
if choice.content.lower() != "yes":
return await ctx.send("Canceled item redemption.")
if data[item]["Type"].lower() == "role":
return await self.assign_role(ctx, instance, item, data[item]["Role"])
else:
await self.pending_add(ctx, item)
sm = ShopManager(ctx, instance=None, user_data=instance)
await sm.remove(item)
class ShopManager:
def __init__(self, ctx, instance, user_data):
@ -954,7 +1148,8 @@ class ShopManager:
await asyncio.sleep(2) # At least a little buffer to prevent rate limiting
await self.ctx.author.send(chunk)
async def order(self, shop, item):
async def order(self, shop, item, quantity):
"""Process a purchase order with the specified quantity."""
try:
async with self.instance.Shops() as shops:
if shop not in shops:
@ -972,55 +1167,27 @@ class ShopManager:
if stock != "--" and stock <= 0:
return await self.ctx.send(f"Sorry, {item} is out of stock.")
e = discord.Embed(color=await self.ctx.embed_colour())
e.add_field(name=item, value=item_data["Info"], inline=False)
e.add_field(name="Cost", value=f"{cost} {cur}", inline=True)
e.add_field(name="Stock", value="Infinite" if stock == "--" else stock, inline=True)
text = (
f"How many {item} would you like to purchase?\n*If this "
f"is a random item, you can only buy 1 at a time.*"
)
await self.ctx.send(content=text, embed=e)
# Validate quantity for random items
if _type == "random" and quantity != 1:
return await self.ctx.send("You can only buy 1 random item at a time.")
def predicate(m):
if m.author == self.ctx.author and self.ctx.channel == m.channel:
if m.content.isdigit():
if _type == "random":
return int(m.content) == 1
try:
amount = int(m.content)
if stock == "--":
return amount > 0
return 0 < amount <= stock
except (TypeError, ValueError):
return False
elif m.content.lower() in ("exit", "cancel", "e", "x"):
return True
return False
# Check if enough stock
if stock != "--" and quantity > stock:
return await self.ctx.send(f"Not enough stock! Only {stock} available.")
try:
num = await self.ctx.bot.wait_for("message", timeout=25.0, check=predicate)
except asyncio.TimeoutError:
return await self.ctx.send("Purchase timed out.")
if num.content.lower() in ("exit", "cancel", "e", "x"):
raise ExitProcess()
amount = int(num.content)
total_cost = cost * amount
total_cost = cost * quantity
try:
await bank.withdraw_credits(self.ctx.author, total_cost)
except ValueError:
return await self.ctx.send(
f"You cannot afford {amount}x {item} for {total_cost} {cur}. Transaction ended."
f"You cannot afford {quantity}x {item} for {total_cost} {cur}. Transaction ended."
)
# Handle different item types
if _type == "auto":
await self.auto_handler(shop, item, amount)
await self.remove_stock(shop, item, stock, amount)
await self.auto_handler(shop, item, quantity)
await self.remove_stock(shop, item, stock, quantity)
return await self.ctx.send("Message sent.")
if _type == "random":
@ -1035,18 +1202,18 @@ class ShopManager:
f"so {item} cannot be purchased."
)
else:
await self.remove_stock(shop, item, stock, amount)
await self.remove_stock(shop, item, stock, quantity)
item = new_item
async with self.instance.Shops() as shops:
item_data = deepcopy(shops[shop]["Items"][new_item])
stock = item_data["Qty"]
# Update stock and add to inventory
await self.remove_stock(shop, item, stock, amount)
await self.add_to_inventory(item, item_data, amount)
await self.remove_stock(shop, item, stock, quantity)
await self.add_to_inventory(item, item_data, quantity)
await self.ctx.send(
f"{self.ctx.author.mention} purchased {amount}x {item} for {total_cost} {cur}."
f"{self.ctx.author.mention} purchased {quantity}x {item} for {total_cost} {cur}."
)
async def remove_stock(self, shop, item, current_stock, amount):

248
shop/ui.py Normal file
View file

@ -0,0 +1,248 @@
import discord
from discord.ui import View, Select, Button, button
from typing import Optional, List, Dict, Any
from redbot.core.utils.chat_formatting import box, humanize_list
class ShopView(View):
def __init__(self, ctx, shops: Dict[str, Any], timeout: int = 60):
super().__init__(timeout=timeout)
self.ctx = ctx
self.shops = shops
self.current_shop = None
self.current_item = None
self.setup_shop_select()
def setup_shop_select(self):
options = []
for shop_name, shop_data in self.shops.items():
if shop_data["Items"]: # Only show shops with items
options.append(discord.SelectOption(
label=shop_name[:25], # Discord limit
description=f"{len(shop_data['Items'])} items",
value=shop_name
))
if options:
shop_select = Select(
placeholder="Select a shop",
options=options,
row=0
)
shop_select.callback = self.shop_selected
self.add_item(shop_select)
async def shop_selected(self, interaction: discord.Interaction):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
shop_name = interaction.data["values"][0]
self.current_shop = shop_name
# Clear previous item select if it exists
for item in self.children[:]:
if isinstance(item, Select) and item.row == 1:
self.remove_item(item)
# Add new item select
items = self.shops[shop_name]["Items"]
options = []
for item_name, item_data in items.items():
qty = "" if item_data["Qty"] == "--" else item_data["Qty"]
desc = f"Cost: {item_data['Cost']} | Stock: {qty}"
options.append(discord.SelectOption(
label=item_name[:25],
description=desc,
value=item_name
))
if options:
item_select = Select(
placeholder="Select an item",
options=options[:25], # Discord limit
row=1
)
item_select.callback = self.item_selected
self.add_item(item_select)
await interaction.response.edit_message(view=self)
async def item_selected(self, interaction: discord.Interaction):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
item_name = interaction.data["values"][0]
self.current_item = item_name
item_data = self.shops[self.current_shop]["Items"][item_name]
# Create purchase confirmation view
purchase_view = PurchaseView(self.ctx, self.current_shop, item_name, item_data)
embed = purchase_view.build_embed()
await interaction.response.edit_message(embed=embed, view=purchase_view)
class PurchaseView(View):
def __init__(self, ctx, shop: str, item: str, item_data: Dict[str, Any], timeout: int = 60):
super().__init__(timeout=timeout)
self.ctx = ctx
self.shop = shop
self.item = item
self.item_data = item_data
self.quantity = 1
def build_embed(self) -> discord.Embed:
e = discord.Embed(
title=f"Purchase {self.item}",
description=self.item_data["Info"],
color=discord.Color.blue()
)
qty = "Infinite" if self.item_data["Qty"] == "--" else self.item_data["Qty"]
e.add_field(name="Stock", value=qty, inline=True)
e.add_field(name="Cost", value=self.item_data["Cost"], inline=True)
e.add_field(name="Type", value=self.item_data["Type"].title(), inline=True)
if self.item_data["Type"] == "role":
e.add_field(name="Role", value=self.item_data["Role"], inline=True)
return e
@button(label="Buy 1", style=discord.ButtonStyle.green, row=1)
async def buy_one(self, interaction: discord.Interaction, button: Button):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
self.quantity = 1
await self.handle_purchase(interaction)
@button(label="Buy 5", style=discord.ButtonStyle.green, row=1)
async def buy_five(self, interaction: discord.Interaction, button: Button):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
self.quantity = 5
await self.handle_purchase(interaction)
@button(label="Custom Amount", style=discord.ButtonStyle.blurple, row=1)
async def custom_amount(self, interaction: discord.Interaction, button: Button):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
await interaction.response.send_message(
"How many would you like to buy? Type a number:",
ephemeral=True
)
def check(m):
return (
m.author == self.ctx.author
and m.channel == self.ctx.channel
and m.content.isdigit()
)
try:
msg = await self.ctx.bot.wait_for("message", timeout=30.0, check=check)
self.quantity = int(msg.content)
await self.handle_purchase(interaction)
except asyncio.TimeoutError:
await interaction.followup.send("Purchase cancelled - took too long to respond.", ephemeral=True)
@button(label="Cancel", style=discord.ButtonStyle.red, row=1)
async def cancel(self, interaction: discord.Interaction, button: Button):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
await interaction.response.edit_message(content="Purchase cancelled.", embed=None, view=None)
async def handle_purchase(self, interaction: discord.Interaction):
# Validate quantity
if self.item_data["Type"] == "random" and self.quantity != 1:
await interaction.response.send_message(
"You can only buy 1 random item at a time.",
ephemeral=True
)
return
if self.item_data["Qty"] != "--" and self.quantity > self.item_data["Qty"]:
await interaction.response.send_message(
f"Not enough stock! Only {self.item_data['Qty']} available.",
ephemeral=True
)
return
total_cost = self.item_data["Cost"] * self.quantity
# This will be handled by the Shop cog's order method
self.stop()
await interaction.response.edit_message(
content=f"Processing purchase of {self.quantity}x {self.item}...",
embed=None,
view=None
)
class InventoryView(View):
def __init__(self, ctx, inventory: Dict[str, Any], timeout: int = 60):
super().__init__(timeout=timeout)
self.ctx = ctx
self.inventory = inventory
self.setup_inventory_select()
def setup_inventory_select(self):
options = []
for item_name, item_data in self.inventory.items():
desc = f"Quantity: {item_data['Qty']} | Type: {item_data['Type']}"
options.append(discord.SelectOption(
label=item_name[:25],
description=desc,
value=item_name
))
if options:
inv_select = Select(
placeholder="Select an item to view/use",
options=options[:25], # Discord limit
row=0
)
inv_select.callback = self.item_selected
self.add_item(inv_select)
async def item_selected(self, interaction: discord.Interaction):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
item_name = interaction.data["values"][0]
item_data = self.inventory[item_name]
embed = discord.Embed(
title=item_name,
description=item_data["Info"],
color=discord.Color.blue()
)
embed.add_field(name="Quantity", value=item_data["Qty"], inline=True)
embed.add_field(name="Type", value=item_data["Type"].title(), inline=True)
if item_data["Type"] == "role":
use_view = UseItemView(self.ctx, item_name, item_data)
await interaction.response.edit_message(embed=embed, view=use_view)
else:
await interaction.response.edit_message(embed=embed)
class UseItemView(View):
def __init__(self, ctx, item: str, item_data: Dict[str, Any], timeout: int = 60):
super().__init__(timeout=timeout)
self.ctx = ctx
self.item = item
self.item_data = item_data
@button(label="Use Item", style=discord.ButtonStyle.green)
async def use_item(self, interaction: discord.Interaction, button: Button):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
await interaction.response.edit_message(
content=f"Processing use of {self.item}...",
embed=None,
view=None
)
self.stop()
@button(label="Cancel", style=discord.ButtonStyle.red)
async def cancel(self, interaction: discord.Interaction, button: Button):
if interaction.user != self.ctx.author:
return await interaction.response.send_message("This menu is not for you!", ephemeral=True)
await interaction.response.edit_message(content="Cancelled.", embed=None, view=None)
self.stop()