# Views Directory The views directory contains Discord UI components for Discord Bot v2.0, providing consistent visual interfaces and interactive elements. This includes embeds, modals, buttons, select menus, and other Discord UI components. ## Architecture ### Component-Based UI Design Views in Discord Bot v2.0 follow these principles: - **Consistent styling** via centralized templates - **Reusable components** for common UI patterns - **Error handling** with graceful degradation - **User interaction tracking** and validation - **Accessibility** with proper labeling and feedback ### Base Components All view components inherit from Discord.py base classes with enhanced functionality: - **BaseView** - Enhanced discord.ui.View with logging and user validation - **BaseModal** - Enhanced discord.ui.Modal with error handling - **EmbedTemplate** - Centralized embed creation with consistent styling ## View Components ### Base View System (`base.py`) #### BaseView Class Foundation for all interactive views: ```python class BaseView(discord.ui.View): def __init__(self, timeout=180.0, user_id=None): super().__init__(timeout=timeout) self.user_id = user_id self.logger = get_contextual_logger(f'{__name__}.BaseView') async def interaction_check(self, interaction) -> bool: """Validate user permissions for interaction.""" async def on_timeout(self) -> None: """Handle view timeout gracefully.""" async def on_error(self, interaction, error, item) -> None: """Handle view errors with user feedback.""" ``` #### ConfirmationView Class Standard Yes/No confirmation dialogs: ```python confirmation = ConfirmationView( user_id=interaction.user.id, confirm_callback=handle_confirm, cancel_callback=handle_cancel ) await interaction.followup.send("Confirm action?", view=confirmation) ``` #### PaginationView Class Multi-page navigation for large datasets: ```python pages = [embed1, embed2, embed3] pagination = PaginationView( pages=pages, user_id=interaction.user.id, show_page_numbers=True ) await interaction.followup.send(embed=pagination.get_current_embed(), view=pagination) ``` ### Embed Templates (`embeds.py`) #### EmbedTemplate Class Centralized embed creation with consistent styling: ```python # Success embed embed = EmbedTemplate.success( title="Operation Completed", description="Your request was processed successfully." ) # Error embed embed = EmbedTemplate.error( title="Operation Failed", description="Please check your input and try again." ) # Warning embed embed = EmbedTemplate.warning( title="Careful!", description="This action cannot be undone." ) # Info embed embed = EmbedTemplate.info( title="Information", description="Here's what you need to know." ) ``` #### EmbedColors Dataclass Consistent color scheme across all embeds: ```python @dataclass(frozen=True) class EmbedColors: PRIMARY: int = 0xa6ce39 # SBA green SUCCESS: int = 0x28a745 # Green WARNING: int = 0xffc107 # Yellow ERROR: int = 0xdc3545 # Red INFO: int = 0x17a2b8 # Blue SECONDARY: int = 0x6c757d # Gray ``` ### Modal Forms (`modals.py`) #### BaseModal Class Foundation for interactive forms: ```python class BaseModal(discord.ui.Modal): def __init__(self, title: str, timeout=300.0): super().__init__(title=title, timeout=timeout) self.logger = get_contextual_logger(f'{__name__}.BaseModal') self.result = None async def on_submit(self, interaction): """Handle form submission.""" async def on_error(self, interaction, error): """Handle form errors.""" ``` #### Usage Pattern ```python class CustomCommandModal(BaseModal): def __init__(self): super().__init__(title="Create Custom Command") name = discord.ui.TextInput( label="Command Name", placeholder="Enter command name...", required=True, max_length=50 ) response = discord.ui.TextInput( label="Response", placeholder="Enter command response...", style=discord.TextStyle.paragraph, required=True, max_length=2000 ) async def on_submit(self, interaction): # Process form data command_data = { "name": self.name.value, "response": self.response.value } # Handle creation logic ``` ### Common UI Elements (`common.py`) #### Shared Components - **Loading indicators** for async operations - **Status messages** for operation feedback - **Navigation elements** for multi-step processes - **Validation displays** for form errors ### Specialized Views #### Custom Commands (`custom_commands.py`) Views specific to custom command management: - Command creation forms - Command listing with actions - Bulk management interfaces #### Transaction Management (`transaction_embed.py`) Views for player transaction interfaces: - Transaction builder with interactive controls - Comprehensive validation and sWAR display - Pre-existing transaction context - Approval/submission workflows ## Styling Guidelines ### Embed Consistency All embeds should use EmbedTemplate methods: ```python # ✅ Consistent styling embed = EmbedTemplate.success("Player Added", "Player successfully added to roster") # ❌ Inconsistent styling embed = discord.Embed(title="Player Added", color=0x00ff00) ``` ### Color Usage Use the standard color palette: - **PRIMARY (SBA Green)** - Default for neutral information - **SUCCESS (Green)** - Successful operations - **ERROR (Red)** - Errors and failures - **WARNING (Yellow)** - Warnings and cautions - **INFO (Blue)** - General information - **SECONDARY (Gray)** - Less important information ### User Feedback Provide clear feedback for all user interactions: ```python # Loading state embed = EmbedTemplate.info("Processing", "Please wait while we process your request...") # Success state embed = EmbedTemplate.success("Complete", "Your request has been processed successfully.") # Error state with helpful information embed = EmbedTemplate.error( "Request Failed", "The player name was not found. Please check your spelling and try again." ) ``` ## Interactive Components ### Button Patterns #### Action Buttons ```python @discord.ui.button(label="Confirm", style=discord.ButtonStyle.success, emoji="✅") async def confirm_button(self, interaction, button): self.increment_interaction_count() # Handle confirmation await interaction.response.edit_message(content="Confirmed!", view=None) ``` #### Navigation Buttons ```python @discord.ui.button(emoji="◀️", style=discord.ButtonStyle.primary) async def previous_page(self, interaction, button): self.current_page = max(0, self.current_page - 1) await interaction.response.edit_message(embed=self.get_current_embed(), view=self) ``` ### Select Menu Patterns #### Option Selection ```python @discord.ui.select(placeholder="Choose an option...") async def select_option(self, interaction, select): selected_value = select.values[0] # Handle selection await interaction.response.send_message(f"You selected: {selected_value}") ``` #### Dynamic Options ```python class PlayerSelectMenu(discord.ui.Select): def __init__(self, players: List[Player]): options = [ discord.SelectOption( label=player.name, value=str(player.id), description=f"{player.position} - {player.team.abbrev}" ) for player in players[:25] # Discord limit ] super().__init__(placeholder="Select a player...", options=options) ``` ## Error Handling ### View Error Handling All views implement comprehensive error handling: ```python async def on_error(self, interaction, error, item): """Handle view errors gracefully.""" self.logger.error("View error", error=error, item_type=type(item).__name__) try: embed = EmbedTemplate.error( "Interaction Error", "Something went wrong. Please try again." ) if not interaction.response.is_done(): await interaction.response.send_message(embed=embed, ephemeral=True) else: await interaction.followup.send(embed=embed, ephemeral=True) except Exception as e: self.logger.error("Failed to send error message", error=e) ``` ### User Input Validation Forms validate user input before processing: ```python async def on_submit(self, interaction): # Validate input if len(self.name.value) < 2: embed = EmbedTemplate.error( "Invalid Input", "Command name must be at least 2 characters long." ) await interaction.response.send_message(embed=embed, ephemeral=True) return # Process valid input await self.create_command(interaction) ``` ## Accessibility Features ### User-Friendly Labels - **Clear button labels** with descriptive text - **Helpful placeholders** in form fields - **Descriptive error messages** with actionable guidance - **Consistent emoji usage** for visual recognition ### Permission Validation Views respect user permissions and provide appropriate feedback: ```python async def interaction_check(self, interaction) -> bool: """Check if user can interact with this view.""" if self.user_id and interaction.user.id != self.user_id: await interaction.response.send_message( "❌ You cannot interact with this menu.", ephemeral=True ) return False return True ``` ## Performance Considerations ### View Lifecycle Management - **Timeout handling** prevents orphaned views - **Resource cleanup** in view destructors - **Interaction tracking** for usage analytics - **Memory management** for large datasets ### Efficient Updates ```python # ✅ Efficient - Only update what changed await interaction.response.edit_message(embed=new_embed, view=self) # ❌ Inefficient - Sends new message await interaction.response.send_message(embed=new_embed, view=new_view) ``` ## Testing Strategies ### View Testing ```python @pytest.mark.asyncio async def test_confirmation_view(): view = ConfirmationView(user_id=123) # Mock interaction interaction = Mock() interaction.user.id = 123 # Test button click await view.confirm_button.callback(interaction) assert view.result is True ``` ### Modal Testing ```python @pytest.mark.asyncio async def test_custom_command_modal(): modal = CustomCommandModal() # Set form values modal.name.value = "test" modal.response.value = "Test response" # Mock interaction interaction = Mock() # Test form submission await modal.on_submit(interaction) # Verify processing assert modal.result is not None ``` ## Development Guidelines ### Creating New Views 1. **Inherit from base classes** for consistency 2. **Use EmbedTemplate** for all embed creation 3. **Implement proper error handling** in all interactions 4. **Add user permission checks** where appropriate 5. **Include comprehensive logging** with context 6. **Follow timeout patterns** to prevent resource leaks ### View Composition - **Keep views focused** on single responsibilities - **Use composition** over complex inheritance - **Separate business logic** from UI logic - **Make views testable** with dependency injection ### UI Guidelines - **Follow Discord design patterns** for familiarity - **Use consistent colors** from EmbedColors - **Provide clear user feedback** for all actions - **Handle edge cases** gracefully - **Consider mobile users** in layout design ## Transaction Embed Enhancements (January 2025) ### Enhanced Display Features The transaction embed now provides comprehensive information for better decision-making: #### New Embed Sections ```python async def create_transaction_embed(builder: TransactionBuilder) -> discord.Embed: """ Creates enhanced transaction embed with sWAR and pre-existing transaction context. """ # Existing sections... # NEW: Team Cost (sWAR) Display swar_status = f"{validation.major_league_swar_status}\n{validation.minor_league_swar_status}" embed.add_field(name="Team sWAR", value=swar_status, inline=False) # NEW: Pre-existing Transaction Context (when applicable) if validation.pre_existing_transactions_note: embed.add_field( name="📋 Transaction Context", value=validation.pre_existing_transactions_note, inline=False ) ``` ### Enhanced Information Display #### sWAR Tracking - **Major League sWAR**: Projected team cost for ML roster - **Minor League sWAR**: Projected team cost for MiL roster - **Formatted Display**: Uses 📊 emoji with 1 decimal precision #### Pre-existing Transaction Context Dynamic context display based on scheduled moves: ```python # Example displays: "ℹ️ **Pre-existing Moves**: 3 scheduled moves (+3.7 sWAR)" "ℹ️ **Pre-existing Moves**: 2 scheduled moves (-2.5 sWAR)" "ℹ️ **Pre-existing Moves**: 1 scheduled moves (no sWAR impact)" # No display when no pre-existing moves (clean interface) ``` ### Complete Embed Structure The enhanced transaction embed now includes: 1. **Current Moves** - List of moves in transaction builder 2. **Roster Status** - Legal/illegal roster counts with limits 3. **Team Cost (sWAR)** - sWAR for both rosters 4. **Transaction Context** - Pre-existing moves impact (conditional) 5. **Errors/Suggestions** - Validation feedback and recommendations ### Usage Examples #### Basic Transaction Display ```python # Standard transaction without pre-existing moves builder = get_transaction_builder(user_id, team) embed = await create_transaction_embed(builder) # Shows: moves, roster status, sWAR, errors/suggestions ``` #### Enhanced Context Display ```python # Transaction with pre-existing moves context validation = await builder.validate_transaction(next_week=current_week + 1) embed = await create_transaction_embed(builder) # Shows: all above + pre-existing transaction impact ``` ### User Experience Improvements - **Complete Context**: Users see full impact including scheduled moves - **Visual Clarity**: Consistent emoji usage and formatting - **Conditional Display**: Context only shown when relevant - **Decision Support**: sWAR projections help strategic planning ### Implementation Notes - **Backwards Compatible**: Existing embed functionality preserved - **Conditional Sections**: Pre-existing context only appears when applicable - **Performance**: Validation data cached to avoid repeated calculations - **Accessibility**: Clear visual hierarchy with emojis and formatting --- **Next Steps for AI Agents:** 1. Review existing view implementations for patterns 2. Understand the Discord UI component system 3. Follow the EmbedTemplate system for consistent styling 4. Implement proper error handling and user validation 5. Test interactive components thoroughly 6. Consider accessibility and user experience in design 7. Leverage enhanced transaction context for better user guidance