""" Interactive CLI interface for NimbusFlow. """ import sys from pathlib import Path from typing import TYPE_CHECKING if TYPE_CHECKING: from .base import NimbusFlowCLI from .commands import ( cmd_members_list, cmd_members_show, cmd_schedules_list, cmd_schedules_show, cmd_schedules_accept, cmd_schedules_decline, cmd_services_list, ) def load_ascii_art() -> str: """Load ASCII art from file.""" ascii_file = Path(__file__).parent / "ascii.txt" if ascii_file.exists(): with open(ascii_file, 'r', encoding='utf-8') as f: content = f.read() # Use only the cloud portion (middle section) for better display lines = content.strip().split('\n') if len(lines) > 30: # Take a smaller portion of the cloud art start = len(lines) // 3 end = start + 15 return '\n'.join(lines[start:end]) return content return "šŸŽµ NimbusFlow šŸŽµ" # Fallback if file doesn't exist def display_welcome(): """Display welcome screen with ASCII art.""" print("\033[2J\033[H") # Clear screen and move cursor to top # Display the cloud ASCII art ascii_art = load_ascii_art() print(ascii_art) print() # Add the NimbusFlow branding welcome_text = """ ╔═══════════════════════════════════════════════════════════════════════════════╗ ā•‘ ā•‘ ā•‘ ā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā•‘ ā•‘ ā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•‘ ā•‘ ā–ˆā–ˆā•”ā–ˆā–ˆā•— ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā•— ā–ˆā–ˆā•‘ ā•‘ ā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā•—ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā•‘ ā•‘ ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā•šā•ā• ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā•šā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā•”ā• ā•‘ ā•‘ ā•šā•ā• ā•šā•ā•ā•ā•ā•šā•ā•ā•šā•ā• ā•šā•ā•ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•šā•ā•ā• ā•‘ ā•‘ ā•‘ ā•‘ šŸŽµ Choir Scheduling System šŸŽµ ā•‘ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā• """ print(welcome_text) print() def display_main_menu(): """Display the main menu options.""" print("šŸŽÆ " + "="*60) print(" MAIN MENU - What would you like to manage?") print("šŸŽÆ " + "="*60) print() print(" 1ļøāƒ£ šŸ‘„ Members - Manage choir members") print(" 2ļøāƒ£ šŸ“… Schedules - View and manage schedules") print(" 3ļøāƒ£ šŸŽ¼ Services - Manage services and events") print(" 4ļøāƒ£ āŒ Exit - Close NimbusFlow CLI") print() def display_members_menu(): """Display members submenu.""" print("\nšŸ‘„ " + "="*50) print(" MEMBERS MENU") print("šŸ‘„ " + "="*50) print() print(" 1ļøāƒ£ šŸ“‹ List all members") print(" 2ļøāƒ£ āœ… List active members only") print(" 3ļøāƒ£ šŸŽµ List by classification") print(" 4ļøāƒ£ šŸ‘¤ Show member details") print(" 5ļøāƒ£ šŸ”™ Back to main menu") print() def display_schedules_menu(): """Display schedules submenu.""" print("\nšŸ“… " + "="*50) print(" SCHEDULES MENU") print("šŸ“… " + "="*50) print() print(" 1ļøāƒ£ šŸ“‹ List all schedules") print(" 2ļøāƒ£ ā³ List pending schedules") print(" 3ļøāƒ£ āœ… List accepted schedules") print(" 4ļøāƒ£ āŒ List declined schedules") print(" 5ļøāƒ£ šŸ‘¤ Show schedule details") print(" 6ļøāƒ£ ✨ Accept a schedule (interactive)") print(" 7ļøāƒ£ 🚫 Decline a schedule (interactive)") print(" 8ļøāƒ£ šŸ”™ Back to main menu") print() def display_services_menu(): """Display services submenu.""" print("\nšŸŽ¼ " + "="*50) print(" SERVICES MENU") print("šŸŽ¼ " + "="*50) print() print(" 1ļøāƒ£ šŸ“‹ List all services") print(" 2ļøāƒ£ šŸ”® List upcoming services") print(" 3ļøāƒ£ šŸ“… List services by date") print(" 4ļøāƒ£ šŸ”™ Back to main menu") print() def get_user_choice(max_options: int) -> int: """Get user menu choice with validation.""" while True: try: choice = input(f"šŸŽÆ Enter your choice (1-{max_options}): ").strip() if not choice: continue choice_int = int(choice) if 1 <= choice_int <= max_options: return choice_int else: print(f"āŒ Please enter a number between 1 and {max_options}") except ValueError: print("āŒ Please enter a valid number") except (KeyboardInterrupt, EOFError): print("\nšŸ›‘ Goodbye!") sys.exit(0) def get_text_input(prompt: str, required: bool = True) -> str: """Get text input from user.""" while True: try: value = input(f"šŸ“ {prompt}: ").strip() if value or not required: return value print("āŒ This field is required") except (KeyboardInterrupt, EOFError): print("\nšŸ›‘ Operation cancelled") return "" def get_date_input(prompt: str = "Enter date (YYYY-MM-DD)") -> str: """Get date input from user.""" while True: try: date_str = input(f"šŸ“… {prompt}: ").strip() if not date_str: print("āŒ Date is required") continue # Basic date format validation if len(date_str) == 10 and date_str.count('-') == 2: parts = date_str.split('-') if len(parts[0]) == 4 and len(parts[1]) == 2 and len(parts[2]) == 2: return date_str print("āŒ Please use format YYYY-MM-DD (e.g., 2025-09-07)") except (KeyboardInterrupt, EOFError): print("\nšŸ›‘ Operation cancelled") return "" class MockArgs: """Mock args object for interactive commands.""" def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) def handle_members_menu(cli: "NimbusFlowCLI"): """Handle members menu interactions.""" while True: display_members_menu() choice = get_user_choice(5) if choice == 1: # List all members print("\nšŸ” Listing all members...") cmd_members_list(cli, MockArgs(active=False, classification=None)) input("\nāøļø Press Enter to continue...") elif choice == 2: # List active members print("\nšŸ” Listing active members...") cmd_members_list(cli, MockArgs(active=True, classification=None)) input("\nāøļø Press Enter to continue...") elif choice == 3: # List by classification classification = get_text_input("Enter classification (Soprano, Alto / Mezzo, Tenor, Baritone)", True) if classification: print(f"\nšŸ” Listing {classification} members...") cmd_members_list(cli, MockArgs(active=False, classification=classification)) input("\nāøļø Press Enter to continue...") elif choice == 4: # Show member details member_id = get_text_input("Enter member ID", True) if member_id.isdigit(): print(f"\nšŸ” Showing details for member {member_id}...") cmd_members_show(cli, MockArgs(member_id=int(member_id))) else: print("āŒ Invalid member ID") input("\nāøļø Press Enter to continue...") elif choice == 5: # Back to main menu break def handle_schedules_menu(cli: "NimbusFlowCLI"): """Handle schedules menu interactions.""" while True: display_schedules_menu() choice = get_user_choice(8) if choice == 1: # List all schedules print("\nšŸ” Listing all schedules...") cmd_schedules_list(cli, MockArgs(service_id=None, status=None)) input("\nāøļø Press Enter to continue...") elif choice == 2: # List pending schedules print("\nšŸ” Listing pending schedules...") cmd_schedules_list(cli, MockArgs(service_id=None, status="pending")) input("\nāøļø Press Enter to continue...") elif choice == 3: # List accepted schedules print("\nšŸ” Listing accepted schedules...") cmd_schedules_list(cli, MockArgs(service_id=None, status="accepted")) input("\nāøļø Press Enter to continue...") elif choice == 4: # List declined schedules print("\nšŸ” Listing declined schedules...") cmd_schedules_list(cli, MockArgs(service_id=None, status="declined")) input("\nāøļø Press Enter to continue...") elif choice == 5: # Show schedule details schedule_id = get_text_input("Enter schedule ID", True) if schedule_id.isdigit(): print(f"\nšŸ” Showing details for schedule {schedule_id}...") cmd_schedules_show(cli, MockArgs(schedule_id=int(schedule_id))) else: print("āŒ Invalid schedule ID") input("\nāøļø Press Enter to continue...") elif choice == 6: # Accept schedule date = get_date_input("Enter date for interactive accept") if date: print(f"\n✨ Starting interactive accept for {date}...") cmd_schedules_accept(cli, MockArgs(date=date, schedule_id=None)) input("\nāøļø Press Enter to continue...") elif choice == 7: # Decline schedule date = get_date_input("Enter date for interactive decline") if date: reason = get_text_input("Enter decline reason (optional)", False) print(f"\n🚫 Starting interactive decline for {date}...") cmd_schedules_decline(cli, MockArgs(date=date, schedule_id=None, reason=reason)) input("\nāøļø Press Enter to continue...") elif choice == 8: # Back to main menu break def handle_services_menu(cli: "NimbusFlowCLI"): """Handle services menu interactions.""" while True: display_services_menu() choice = get_user_choice(4) if choice == 1: # List all services print("\nšŸ” Listing all services...") cmd_services_list(cli, MockArgs(date=None, upcoming=False, limit=None)) input("\nāøļø Press Enter to continue...") elif choice == 2: # List upcoming services print("\nšŸ” Listing upcoming services...") cmd_services_list(cli, MockArgs(date=None, upcoming=True, limit=20)) input("\nāøļø Press Enter to continue...") elif choice == 3: # List by date date = get_date_input("Enter date to filter services") if date: print(f"\nšŸ” Listing services for {date}...") cmd_services_list(cli, MockArgs(date=date, upcoming=False, limit=None)) input("\nāøļø Press Enter to continue...") elif choice == 4: # Back to main menu break def run_interactive_mode(cli: "NimbusFlowCLI"): """Run the main interactive CLI mode.""" display_welcome() print("šŸŽ‰ Welcome to the NimbusFlow Interactive CLI!") print(" Navigate through menus to manage your choir scheduling system.") print() input("āøļø Press Enter to continue...") while True: print("\033[2J\033[H") # Clear screen display_main_menu() choice = get_user_choice(4) if choice == 1: # Members handle_members_menu(cli) elif choice == 2: # Schedules handle_schedules_menu(cli) elif choice == 3: # Services handle_services_menu(cli) elif choice == 4: # Exit print("\nšŸŽµ Thank you for using NimbusFlow!") print(" Have a wonderful day! 🌟") break