From 26a87d0d00dd246b4be432d4d44324aee8e039fb Mon Sep 17 00:00:00 2001 From: dzinesco Date: Sat, 12 Jul 2025 18:21:40 -0600 Subject: [PATCH] feat: Complete platform enhancement with multi-tenant architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major additions: - Territory manager system with application workflow - Custom pricing and page builder with Craft.js - Enhanced Stripe Connect onboarding - CodeReadr QR scanning integration - Kiosk mode for venue sales - Super admin dashboard and analytics - MCP integration for AI-powered operations Infrastructure improvements: - Centralized API client and routing system - Enhanced authentication with organization context - Comprehensive theme management system - Advanced event management with custom tabs - Performance monitoring and accessibility features Database schema updates: - Territory management tables - Custom pages and pricing structures - Kiosk PIN system - Enhanced organization profiles - CodeReadr integration tables 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CLAUDE.md | 40 +- MCP_SETUP.md | 167 ++ POLISH_PLAN.md | 165 ++ astro.config.mjs | 1 + claude_desktop_config.json | 17 + eslint-output.json | 1 + package-lock.json | 1912 ++++++++++++- package.json | 21 +- promote-to-admin.js | 60 + setup-schema.js | 18 +- setup-super-admins.js | 2 +- src/components/AccountStatusBanner.tsx | 199 ++ src/components/AgeVerification.astro | 58 +- src/components/Calendar.tsx | 74 +- src/components/ChatWidget.tsx | 4 +- src/components/ComparisonSection.astro | 112 +- src/components/CustomPageRenderer.tsx | 175 ++ src/components/CustomPricingManager.tsx | 500 ++++ src/components/EventHeader.astro | 272 +- src/components/EventManagement.tsx | 246 +- src/components/ImageUploadCropper.tsx | 46 +- src/components/Navigation.astro | 362 ++- src/components/PageBuilder.tsx | 303 ++ src/components/ProtectedRoute.astro | 166 +- src/components/PublicHeader.astro | 63 +- src/components/QuickStats.astro | 239 +- src/components/QuickTicketPurchase.tsx | 152 +- src/components/StripeEmbeddedOnboarding.tsx | 373 +++ src/components/SuperAdminDashboard.tsx | 268 ++ src/components/TemplateManager.tsx | 336 +++ src/components/ThemeToggle.tsx | 89 + src/components/TicketCheckout.tsx | 418 ++- src/components/WhatsHotEvents.tsx | 84 +- src/components/admin/AnalyticsTab.tsx | 210 ++ src/components/admin/EventsTab.tsx | 291 ++ src/components/admin/ManagementTab.tsx | 400 +++ src/components/admin/OrganizersTab.tsx | 241 ++ src/components/admin/RevenueTab.tsx | 266 ++ .../admin/SuperAdminTabNavigation.tsx | 61 + .../craft/components/ButtonBlock.tsx | 142 + .../craft/components/EventDetails.tsx | 105 + .../craft/components/HeroSection.tsx | 139 + .../craft/components/ImageBlock.tsx | 178 ++ .../craft/components/SpacerBlock.tsx | 65 + src/components/craft/components/TextBlock.tsx | 137 + .../craft/components/TicketSection.tsx | 100 + .../craft/components/TwoColumnLayout.tsx | 107 + src/components/craft/components/index.ts | 9 + src/components/manage/AddonsTab.tsx | 21 +- src/components/manage/AttendeesTab.tsx | 59 +- src/components/manage/CustomPageTab.tsx | 589 ++++ src/components/manage/DiscountTab.tsx | 34 +- src/components/manage/EventSettingsTab.tsx | 71 + src/components/manage/MarketingTab.tsx | 757 ++++- src/components/manage/OrdersTab.tsx | 62 +- src/components/manage/PresaleTab.tsx | 26 +- src/components/manage/PrintedTab.tsx | 60 +- src/components/manage/PromotionsTab.tsx | 56 +- src/components/manage/SettingsTab.tsx | 10 +- src/components/manage/TabNavigation.tsx | 42 +- src/components/manage/TicketingAccessTab.tsx | 58 + src/components/manage/TicketsTab.tsx | 383 +-- src/components/manage/VenueTab.tsx | 48 +- src/components/modals/EmbedCodeModal.tsx | 23 +- src/components/modals/TicketPreviewModal.tsx | 272 ++ src/components/tables/AttendeesTable.tsx | 15 +- src/components/tables/OrdersTable.tsx | 99 +- src/layouts/Layout.astro | 67 +- src/layouts/LoginLayout.astro | 62 +- src/layouts/SecureLayout.astro | 52 +- src/lib/accessibility.ts | 2 +- src/lib/addons.ts | 18 +- src/lib/admin-api-router.ts | 607 ++++ src/lib/ai.ts | 6 +- src/lib/api-client.ts | 389 +++ src/lib/api-router.ts | 290 ++ src/lib/auth.ts | 26 +- src/lib/backup.ts | 30 +- src/lib/canvas-image-generator.ts | 2 +- src/lib/codereadr-api.ts | 321 +++ src/lib/email.ts | 351 ++- src/lib/event-management.ts | 79 +- src/lib/eventScraper.ts | 19 +- src/lib/firebaseEventScraper.ts | 62 +- src/lib/geolocation.ts | 16 +- src/lib/marketing-kit-enhanced.ts | 745 +++++ src/lib/marketing-kit-service.ts | 2 +- src/lib/marketing-kit.ts | 77 +- src/lib/performance.js | 125 + src/lib/performance.ts | 14 +- src/lib/qr-generator.ts | 2 +- src/lib/qr.ts | 4 +- src/lib/sales-analytics.ts | 73 +- src/lib/scanner-lock.ts | 2 +- src/lib/seating-management.ts | 24 +- src/lib/sentry.ts | 7 +- src/lib/simple-auth.ts | 126 + src/lib/stripe-account-switching.ts | 242 ++ src/lib/stripe.ts | 68 +- src/lib/supabase-admin.ts | 26 + src/lib/supabase-ssr.ts | 61 + src/lib/supabase.ts | 20 +- src/lib/super-admin-auth.ts | 17 + src/lib/super-admin-types.ts | 151 + src/lib/territory-manager-api.ts | 511 ++++ src/lib/territory-manager-auth.ts | 288 ++ src/lib/territory-manager-router.ts | 561 ++++ src/lib/territory-manager-types.ts | 351 +++ src/lib/theme.ts | 60 + src/lib/ticket-management.ts | 72 +- src/middleware.ts | 40 +- src/pages/[customSlug].astro | 99 + src/pages/admin/dashboard.astro | 938 +++---- src/pages/admin/index.astro | 111 +- src/pages/admin/pending-approvals.astro | 440 +++ src/pages/admin/super-dashboard.astro | 2458 ++++++----------- .../territory-manager/applications.astro | 435 +++ src/pages/api/admin/approve-organization.ts | 149 + src/pages/api/admin/check-super-admin.ts | 32 + src/pages/api/admin/events.ts | 18 +- src/pages/api/admin/reject-organization.ts | 153 + src/pages/api/admin/scraper.ts | 7 +- src/pages/api/admin/setup-super-admin.ts | 4 +- src/pages/api/admin/subscriptions.ts | 18 +- src/pages/api/admin/super-analytics.ts | 154 +- .../admin/territory-manager/applications.ts | 90 + .../applications/[id]/approve.ts | 98 + .../applications/[id]/reject.ts | 99 + src/pages/api/admin/tickets.ts | 22 +- src/pages/api/analytics/track.ts | 3 +- src/pages/api/auth/login.ts | 65 + src/pages/api/auth/logout.ts | 10 + src/pages/api/auth/session.ts | 36 + src/pages/api/chat.ts | 13 +- src/pages/api/checkin-barcode.ts | 2 +- src/pages/api/codereadr/scan.ts | 201 ++ src/pages/api/codereadr/setup-guide.ts | 181 ++ src/pages/api/codereadr/setup.ts | 168 ++ src/pages/api/codereadr/sync.ts | 215 ++ src/pages/api/codereadr/webhook.ts | 192 ++ src/pages/api/cron/update-popularity.ts | 11 +- src/pages/api/custom-pages/[id].ts | 247 ++ src/pages/api/custom-pages/index.ts | 258 ++ .../api/custom-pricing/overrides/[id].ts | 41 + .../api/custom-pricing/overrides/index.ts | 125 + .../api/custom-pricing/profile/[userId].ts | 144 + .../api/emails/send-admin-notification.ts | 87 + .../api/emails/send-application-received.ts | 81 + .../api/emails/send-approval-notification.ts | 98 + src/pages/api/events/[id]/marketing-kit.ts | 208 +- .../api/events/[id]/marketing-kit/download.ts | 2 +- src/pages/api/events/nearby.ts | 2 +- src/pages/api/events/trending.ts | 2 +- src/pages/api/gdpr/user-data.ts | 10 +- .../inventory/availability/[ticketTypeId].ts | 5 +- src/pages/api/inventory/purchase-attempt.ts | 5 +- src/pages/api/inventory/release.ts | 31 +- src/pages/api/inventory/reserve.ts | 20 +- src/pages/api/kiosk/create-payment-intent.ts | 122 + src/pages/api/kiosk/generate-pin.ts | 140 + src/pages/api/kiosk/process-payment.ts | 160 ++ src/pages/api/kiosk/purchase.ts | 214 ++ src/pages/api/kiosk/send-pin-email.ts | 123 + src/pages/api/kiosk/verify-pin.ts | 109 + src/pages/api/location/preferences.ts | 4 +- src/pages/api/organizations/process-signup.ts | 251 ++ src/pages/api/organizations/update-profile.ts | 166 ++ src/pages/api/presale/validate.ts | 2 +- src/pages/api/printed-tickets.ts | 19 +- src/pages/api/printed-tickets/[eventId].ts | 8 +- src/pages/api/refunds/process.ts | 5 +- src/pages/api/scanner-lock/disable.ts | 4 +- src/pages/api/scanner-lock/setup.ts | 4 +- src/pages/api/scanner-lock/verify.ts | 2 +- src/pages/api/send-pin-email.ts | 4 +- src/pages/api/send-reminder-emails.ts | 10 +- src/pages/api/stripe/account-status.ts | 216 ++ .../api/stripe/create-embedded-account.ts | 301 ++ src/pages/api/stripe/onboarding-url.ts | 281 ++ src/pages/api/templates/[id].ts | 135 + src/pages/api/templates/index.ts | 111 + src/pages/api/territory-manager/apply.ts | 162 ++ src/pages/api/territory-manager/dashboard.ts | 97 + .../notifications/mark-all-read.ts | 40 + .../api/territory-manager/referral-link.ts | 35 + src/pages/api/tickets/preview.ts | 3 +- src/pages/api/upload-event-image.ts | 22 +- src/pages/api/webhooks/stripe.ts | 154 +- src/pages/auth-test.astro | 80 + src/pages/calendar-enhanced.astro | 28 + src/pages/calendar.astro | 398 ++- src/pages/custom-pricing.astro | 43 + src/pages/dashboard.astro | 607 ++-- src/pages/docs/[...slug].astro | 29 - .../docs/getting-started/account-setup.astro | 270 -- .../docs/getting-started/introduction.astro | 151 - src/pages/docs/index.astro | 291 -- src/pages/e/[slug].astro | 59 +- src/pages/embed-code/[slug].astro | 54 +- src/pages/embed.astro | 58 +- src/pages/embed/[slug].astro | 37 +- src/pages/events/[id]/manage.astro | 31 +- src/pages/events/new.astro | 42 +- src/pages/inventory-pools.astro | 23 +- src/pages/kiosk/[slug].astro | 916 ++++++ src/pages/login.astro | 299 +- src/pages/onboarding/organization.astro | 385 +++ src/pages/onboarding/stripe.astro | 314 +++ src/pages/scan.astro | 190 +- src/pages/templates.astro | 33 + src/pages/territory-manager/apply.astro | 323 +++ src/pages/territory-manager/apply/form.astro | 519 ++++ src/pages/territory-manager/dashboard.astro | 469 ++++ .../leads/DEVELOPMENT_GUIDE.md | 169 ++ src/pages/territory-manager/leads/index.astro | 162 ++ src/pages/territory-manager/leads/new.astro | 172 ++ src/pages/territory-manager/territories.astro | 219 ++ src/pages/venues.astro | 95 +- src/styles/glassmorphism.css | 1031 ++++++- styleGuide/microcopy-client.md | 106 + styleGuide/microcopy-crispygoat.md | 119 + styleGuide/uistyleguide.md | 93 + styleGuide/visualAudit.ts | 0 .../011_add_super_admin_support.sql | 125 + .../20250109_add_sample_territories.sql | 579 ++++ .../20250109_codereadr_integration.sql | 186 ++ .../migrations/20250109_kiosk_pin_system.sql | 46 + .../migrations/20250109_onboarding_system.sql | 321 +++ .../20250109_territory_manager_schema.sql | 297 ++ .../20250110_custom_sales_pages.sql | 192 ++ tailwind.config.js | 67 + test-auth.js | 73 + 232 files changed, 33175 insertions(+), 5365 deletions(-) create mode 100644 MCP_SETUP.md create mode 100644 POLISH_PLAN.md create mode 100644 claude_desktop_config.json create mode 100644 eslint-output.json create mode 100644 promote-to-admin.js create mode 100644 src/components/AccountStatusBanner.tsx create mode 100644 src/components/CustomPageRenderer.tsx create mode 100644 src/components/CustomPricingManager.tsx create mode 100644 src/components/PageBuilder.tsx create mode 100644 src/components/StripeEmbeddedOnboarding.tsx create mode 100644 src/components/SuperAdminDashboard.tsx create mode 100644 src/components/TemplateManager.tsx create mode 100644 src/components/ThemeToggle.tsx create mode 100644 src/components/admin/AnalyticsTab.tsx create mode 100644 src/components/admin/EventsTab.tsx create mode 100644 src/components/admin/ManagementTab.tsx create mode 100644 src/components/admin/OrganizersTab.tsx create mode 100644 src/components/admin/RevenueTab.tsx create mode 100644 src/components/admin/SuperAdminTabNavigation.tsx create mode 100644 src/components/craft/components/ButtonBlock.tsx create mode 100644 src/components/craft/components/EventDetails.tsx create mode 100644 src/components/craft/components/HeroSection.tsx create mode 100644 src/components/craft/components/ImageBlock.tsx create mode 100644 src/components/craft/components/SpacerBlock.tsx create mode 100644 src/components/craft/components/TextBlock.tsx create mode 100644 src/components/craft/components/TicketSection.tsx create mode 100644 src/components/craft/components/TwoColumnLayout.tsx create mode 100644 src/components/craft/components/index.ts create mode 100644 src/components/manage/CustomPageTab.tsx create mode 100644 src/components/manage/EventSettingsTab.tsx create mode 100644 src/components/manage/TicketingAccessTab.tsx create mode 100644 src/components/modals/TicketPreviewModal.tsx create mode 100644 src/lib/admin-api-router.ts create mode 100644 src/lib/api-client.ts create mode 100644 src/lib/api-router.ts create mode 100644 src/lib/codereadr-api.ts create mode 100644 src/lib/marketing-kit-enhanced.ts create mode 100644 src/lib/performance.js create mode 100644 src/lib/simple-auth.ts create mode 100644 src/lib/stripe-account-switching.ts create mode 100644 src/lib/supabase-admin.ts create mode 100644 src/lib/supabase-ssr.ts create mode 100644 src/lib/super-admin-auth.ts create mode 100644 src/lib/super-admin-types.ts create mode 100644 src/lib/territory-manager-api.ts create mode 100644 src/lib/territory-manager-auth.ts create mode 100644 src/lib/territory-manager-router.ts create mode 100644 src/lib/territory-manager-types.ts create mode 100644 src/lib/theme.ts create mode 100644 src/pages/[customSlug].astro create mode 100644 src/pages/admin/pending-approvals.astro create mode 100644 src/pages/admin/territory-manager/applications.astro create mode 100644 src/pages/api/admin/approve-organization.ts create mode 100644 src/pages/api/admin/check-super-admin.ts create mode 100644 src/pages/api/admin/reject-organization.ts create mode 100644 src/pages/api/admin/territory-manager/applications.ts create mode 100644 src/pages/api/admin/territory-manager/applications/[id]/approve.ts create mode 100644 src/pages/api/admin/territory-manager/applications/[id]/reject.ts create mode 100644 src/pages/api/auth/login.ts create mode 100644 src/pages/api/auth/logout.ts create mode 100644 src/pages/api/auth/session.ts create mode 100644 src/pages/api/codereadr/scan.ts create mode 100644 src/pages/api/codereadr/setup-guide.ts create mode 100644 src/pages/api/codereadr/setup.ts create mode 100644 src/pages/api/codereadr/sync.ts create mode 100644 src/pages/api/codereadr/webhook.ts create mode 100644 src/pages/api/custom-pages/[id].ts create mode 100644 src/pages/api/custom-pages/index.ts create mode 100644 src/pages/api/custom-pricing/overrides/[id].ts create mode 100644 src/pages/api/custom-pricing/overrides/index.ts create mode 100644 src/pages/api/custom-pricing/profile/[userId].ts create mode 100644 src/pages/api/emails/send-admin-notification.ts create mode 100644 src/pages/api/emails/send-application-received.ts create mode 100644 src/pages/api/emails/send-approval-notification.ts create mode 100644 src/pages/api/kiosk/create-payment-intent.ts create mode 100644 src/pages/api/kiosk/generate-pin.ts create mode 100644 src/pages/api/kiosk/process-payment.ts create mode 100644 src/pages/api/kiosk/purchase.ts create mode 100644 src/pages/api/kiosk/send-pin-email.ts create mode 100644 src/pages/api/kiosk/verify-pin.ts create mode 100644 src/pages/api/organizations/process-signup.ts create mode 100644 src/pages/api/organizations/update-profile.ts create mode 100644 src/pages/api/stripe/account-status.ts create mode 100644 src/pages/api/stripe/create-embedded-account.ts create mode 100644 src/pages/api/stripe/onboarding-url.ts create mode 100644 src/pages/api/templates/[id].ts create mode 100644 src/pages/api/templates/index.ts create mode 100644 src/pages/api/territory-manager/apply.ts create mode 100644 src/pages/api/territory-manager/dashboard.ts create mode 100644 src/pages/api/territory-manager/notifications/mark-all-read.ts create mode 100644 src/pages/api/territory-manager/referral-link.ts create mode 100644 src/pages/auth-test.astro create mode 100644 src/pages/custom-pricing.astro delete mode 100644 src/pages/docs/[...slug].astro delete mode 100644 src/pages/docs/getting-started/account-setup.astro delete mode 100644 src/pages/docs/getting-started/introduction.astro delete mode 100644 src/pages/docs/index.astro create mode 100644 src/pages/kiosk/[slug].astro create mode 100644 src/pages/onboarding/organization.astro create mode 100644 src/pages/onboarding/stripe.astro create mode 100644 src/pages/templates.astro create mode 100644 src/pages/territory-manager/apply.astro create mode 100644 src/pages/territory-manager/apply/form.astro create mode 100644 src/pages/territory-manager/dashboard.astro create mode 100644 src/pages/territory-manager/leads/DEVELOPMENT_GUIDE.md create mode 100644 src/pages/territory-manager/leads/index.astro create mode 100644 src/pages/territory-manager/leads/new.astro create mode 100644 src/pages/territory-manager/territories.astro create mode 100644 styleGuide/microcopy-client.md create mode 100644 styleGuide/microcopy-crispygoat.md create mode 100644 styleGuide/uistyleguide.md create mode 100644 styleGuide/visualAudit.ts create mode 100644 supabase/migrations/011_add_super_admin_support.sql create mode 100644 supabase/migrations/20250109_add_sample_territories.sql create mode 100644 supabase/migrations/20250109_codereadr_integration.sql create mode 100644 supabase/migrations/20250109_kiosk_pin_system.sql create mode 100644 supabase/migrations/20250109_onboarding_system.sql create mode 100644 supabase/migrations/20250109_territory_manager_schema.sql create mode 100644 supabase/migrations/20250110_custom_sales_pages.sql create mode 100644 tailwind.config.js create mode 100644 test-auth.js diff --git a/CLAUDE.md b/CLAUDE.md index dfe0e88..15f6e7b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,6 +22,10 @@ npm run preview # Preview production build locally # Database node setup-schema.js # Initialize database schema (run once) + +# Stripe MCP (Model Context Protocol) +npm run mcp:stripe # Start Stripe MCP server for AI integration +npm run mcp:stripe:debug # Start MCP server with debugging interface ``` ## Tech Stack @@ -82,6 +86,14 @@ node setup-schema.js # Initialize database schema (run once) - **Platform Fees**: Automatically split from each transaction - **Webhooks**: Payment confirmation and dispute handling - **Environment**: Uses publishable/secret key pairs +- **MCP Server**: AI-powered Stripe operations through Model Context Protocol + +### Stripe MCP (Model Context Protocol) +- **Purpose**: AI-powered interactions with Stripe API and knowledge base +- **Tools**: Customer management, payment processing, subscriptions, refunds +- **Configuration**: See `MCP_SETUP.md` for detailed setup instructions +- **Commands**: `npm run mcp:stripe` (production) or `npm run mcp:stripe:debug` (development) +- **Integration**: Works with Claude Desktop and other AI agents ### Design System - **Theme**: Glassmorphism with dark gradients (see DESIGN_SYSTEM.md) @@ -134,9 +146,35 @@ src/ - **Form State**: Native form handling with progressive enhancement - **Auth State**: Supabase auth context with organization data +### API System +- **Centralized API Client**: `/src/lib/api-client.ts` - Main client with authentication +- **API Router**: `/src/lib/api-router.ts` - Browser-friendly wrapper for common operations +- **Authentication**: Automatic session management and organization context +- **Error Handling**: Consistent error responses with user-friendly messages +- **Usage**: Use `import { api } from '../lib/api-router'` in components + +#### API System Usage Examples: +```typescript +// In Astro components (client-side scripts) +const { api } = await import('../lib/api-router'); + +// Load event stats +const stats = await api.loadEventStats(eventId); + +// Load event details +const event = await api.loadEventDetails(eventId); + +// Load complete event page data +const { event, stats, error } = await api.loadEventPage(eventId); + +// Format currency and dates +const formattedPrice = api.formatCurrency(priceInCents); +const formattedDate = api.formatDate(dateString); +``` + ### API Design - **RESTful**: Standard HTTP methods with proper status codes -- **Authentication**: Supabase JWT validation on all protected routes +- **Authentication**: Automatic Supabase JWT validation on all API calls - **Error Handling**: Consistent error responses with user-friendly messages - **Rate Limiting**: Built-in protection against abuse diff --git a/MCP_SETUP.md b/MCP_SETUP.md new file mode 100644 index 0000000..fea77e4 --- /dev/null +++ b/MCP_SETUP.md @@ -0,0 +1,167 @@ +# Stripe MCP (Model Context Protocol) Setup + +This project includes Stripe MCP integration for AI-powered Stripe operations through Claude Code and other AI agents. + +## What is Stripe MCP? + +The Stripe Model Context Protocol (MCP) defines a set of tools that AI agents can use to: +- Interact with the Stripe API +- Search Stripe's knowledge base and documentation +- Automate payment processing tasks +- Manage customers, products, and subscriptions +- Handle refunds and disputes + +## Quick Start + +### 1. Environment Setup + +Ensure your `.env` file contains your Stripe secret key: +```bash +STRIPE_SECRET_KEY=sk_test_... # or sk_live_... for production +``` + +### 2. Run Stripe MCP Server + +```bash +# Start the MCP server with all available tools +npm run mcp:stripe + +# Or with debugging interface +npm run mcp:stripe:debug +``` + +### 3. Claude Desktop Configuration + +Copy the provided `claude_desktop_config.json` to your Claude Desktop configuration directory: + +**macOS:** +```bash +cp claude_desktop_config.json ~/Library/Application\ Support/Claude/claude_desktop_config.json +``` + +**Windows:** +```bash +copy claude_desktop_config.json %APPDATA%\Claude\claude_desktop_config.json +``` + +**Linux:** +```bash +cp claude_desktop_config.json ~/.config/claude/claude_desktop_config.json +``` + +Then update the configuration with your actual Stripe secret key. + +## Available MCP Tools + +The Stripe MCP server provides these tool categories: + +### Customer Management +- `customers.create` - Create new customers +- `customers.read` - Retrieve customer information +- `customers.update` - Update customer details +- `customers.delete` - Delete customers + +### Payment Processing +- `payment_intents.create` - Create payment intents +- `payment_intents.confirm` - Confirm payments +- `payment_intents.cancel` - Cancel payments +- `charges.capture` - Capture authorized charges + +### Product & Pricing +- `products.create` - Create products +- `products.read` - Retrieve product information +- `prices.create` - Create pricing tiers +- `prices.read` - Retrieve pricing information + +### Subscription Management +- `subscriptions.create` - Create subscriptions +- `subscriptions.read` - Retrieve subscription details +- `subscriptions.update` - Update subscriptions +- `subscriptions.cancel` - Cancel subscriptions + +### Financial Operations +- `refunds.create` - Process refunds +- `refunds.read` - Retrieve refund information +- `disputes.read` - Review disputes +- `payouts.read` - Check payout status + +## Custom Tool Selection + +To use specific tools only: +```bash +npx @stripe/mcp --tools=customers.create,customers.read,products.create --api-key=$STRIPE_SECRET_KEY +``` + +## Stripe Connect Account + +For Stripe Connect operations: +```bash +npx @stripe/mcp --tools=all --api-key=$STRIPE_SECRET_KEY --stripe-account=CONNECTED_ACCOUNT_ID +``` + +## Integration with BCT Platform + +The MCP integration enhances the Black Canyon Tickets platform by enabling: + +1. **AI-Powered Customer Support**: Automatically handle customer inquiries about payments and refunds +2. **Intelligent Analytics**: Generate insights from payment and subscription data +3. **Automated Dispute Resolution**: Handle disputes with AI assistance +4. **Smart Subscription Management**: Optimize subscription plans based on usage patterns +5. **Enhanced Event Management**: AI-assisted pricing and capacity optimization + +## Security Considerations + +- Never commit your actual Stripe secret keys to version control +- Use test keys during development +- Ensure proper environment variable configuration +- The MCP server respects all Stripe API security measures +- All operations are logged and auditable + +## Debugging + +Use the MCP Inspector for debugging: +```bash +npm run mcp:stripe:debug +``` + +This opens a web interface showing: +- Available tools and their schemas +- Real-time request/response logs +- Error messages and stack traces +- Performance metrics + +## Troubleshooting + +### Common Issues + +1. **"Could not connect to MCP server"** + - Verify your Stripe secret key is correct + - Check that the environment variable is properly set + - Ensure npx can access @stripe/mcp package + +2. **"Tool not found"** + - Verify the tool name matches exactly + - Check if you're using the correct tool subset + - Ensure the MCP server started successfully + +3. **"API key invalid"** + - Confirm you're using the correct environment (test vs live) + - Verify the API key has necessary permissions + - Check for typos in the environment variable + +### Logs + +MCP server logs are available in the Claude Desktop application logs. Check: +- macOS: `~/Library/Logs/Claude/` +- Windows: `%LOCALAPPDATA%\Claude\logs\` +- Linux: `~/.local/share/claude/logs/` + +## Next Steps + +1. Configure Claude Desktop with your Stripe credentials +2. Test the MCP integration with simple customer operations +3. Explore AI-powered payment analytics +4. Implement automated customer support workflows +5. Integrate with the BCT platform's existing Stripe Connect setup + +For more information, see the [Stripe MCP Documentation](https://docs.stripe.com/building-with-llms). \ No newline at end of file diff --git a/POLISH_PLAN.md b/POLISH_PLAN.md new file mode 100644 index 0000000..a7c357a --- /dev/null +++ b/POLISH_PLAN.md @@ -0,0 +1,165 @@ +# 🚀 Black Canyon Tickets - "WOW Factor" Production Polish Plan + +## Mission: Create a website that impresses ANYONE who uses it + +This plan focuses on transforming your solid foundation into a jaw-dropping, premium experience that makes users think "this company is clearly successful and professional." + +--- + +## Phase 1: Immediate Visual Impact (High Priority) + +### 1.1 Create Master Tracking Document +- [x] Create `POLISH_PLAN.md` in root directory +- [x] Set up checkbox tracking system for all tasks +- [ ] Document before/after comparisons + +### 1.2 Premium Color System Enhancement +- [x] Add strategic white/light content areas for important sections +- [x] Introduce emerald green for success metrics and positive actions +- [x] Add gold/amber accents for premium features and CTAs +- [x] Include sophisticated grays for better visual hierarchy +- [x] Use red strategically for alerts and critical actions +- [x] Keep purple as primary but not overwhelming + +### 1.3 Navigation Excellence +- [x] Create professional user dropdown with avatar +- [x] Add smooth micro-animations to all interactive elements +- [ ] Implement breadcrumb navigation for complex sections +- [ ] Add notification badges for admin users +- [x] Polish mobile menu with smooth slide transitions + +--- + +## Phase 2: Dashboard That Screams "Premium" (High Priority) + +### 2.1 Stats Cards with Maximum Impact +- [x] Add count-up animations that make numbers feel alive +- [x] Implement skeleton loading states for professional feel +- [x] Add trend indicators with animated arrows +- [ ] Include sparkline mini-charts for visual appeal +- [x] Add hover effects that feel expensive (subtle shadows, transforms) + +### 2.2 Event Cards Redesign +- [ ] Create card layouts that rival top SaaS platforms +- [ ] Add status badges with smooth color transitions +- [ ] Include progress indicators for event completion +- [ ] Add quick action buttons with premium styling +- [ ] Implement smooth loading states between views + +### 2.3 Calendar Interface Enhancement +- [ ] Make calendar interactions feel native and smooth +- [ ] Add subtle animations for date transitions +- [ ] Include event preview popups on hover +- [ ] Add drag-and-drop capabilities where appropriate + +--- + +## Phase 3: Component Excellence (Medium Priority) + +### 3.1 Form & Input Polish +- [ ] Create floating label inputs that feel premium +- [ ] Add real-time validation with smooth feedback +- [ ] Include loading states for all form submissions +- [ ] Add success animations for completed actions +- [ ] Implement smart error handling with helpful messages + +### 3.2 Event Management Interface +- [ ] Polish all 12 tabs for consistency and premium feel +- [ ] Add smooth tab transitions with content fade-ins +- [ ] Include context-sensitive help tooltips +- [ ] Add bulk action capabilities with smooth animations +- [ ] Implement auto-save indicators for peace of mind + +### 3.3 Interactive Elements +- [ ] Create button states that feel responsive and premium +- [ ] Add loading spinners that match the brand aesthetic +- [ ] Include hover effects on all clickable elements +- [ ] Add keyboard shortcuts for power users +- [ ] Implement toast notifications with slide-in animations + +--- + +## Phase 4: Features That Impress (Medium Priority) + +### 4.1 Real-time Capabilities +- [ ] Add live updates for ticket sales and attendance +- [ ] Include real-time notifications for important events +- [ ] Show typing indicators where appropriate +- [ ] Add live collaboration features for team members + +### 4.2 Advanced Analytics Display +- [ ] Create beautiful charts and graphs for revenue +- [ ] Add animated data transitions +- [ ] Include export capabilities with professional formatting +- [ ] Add trend analysis and insights + +### 4.3 Mobile Experience Excellence +- [ ] Ensure all interactions feel native on mobile +- [ ] Add touch gestures for common actions +- [ ] Include haptic feedback simulation where possible +- [ ] Make mobile experience feel like a premium app + +--- + +## Phase 5: Production Polish (Lower Priority) + +### 5.1 Performance That Impresses +- [ ] Optimize all animations for 60fps smoothness +- [ ] Add intelligent loading states that reduce perceived wait time +- [ ] Implement progressive image loading +- [ ] Add smooth page transitions + +### 5.2 Error Handling Excellence +- [ ] Create error pages that don't break the premium feel +- [ ] Add helpful error messages with suggested actions +- [ ] Include contact options for users who need help +- [ ] Add retry mechanisms with smooth animations + +### 5.3 Accessibility Without Compromise +- [ ] Ensure all premium features work with screen readers +- [ ] Add keyboard navigation that feels natural +- [ ] Include high contrast mode that still looks premium +- [ ] Add focus indicators that match the design aesthetic + +--- + +## Success Metrics: "Impressive" Checklist + +- [ ] **First Impression Test**: New users say "wow" within 5 seconds +- [ ] **Smooth Factor**: All interactions feel buttery smooth +- [ ] **Professional Credibility**: Users trust this is a serious business +- [ ] **Mobile Excellence**: Mobile experience rivals native apps +- [ ] **Speed Perception**: Loading feels instant, even when it's not +- [ ] **Visual Hierarchy**: Users intuitively know where to look +- [ ] **Error Recovery**: Even errors feel polished and helpful + +--- + +## Timeline for Maximum Impact +- **Phase 1 (Foundation)**: 8-10 hours - Creates immediate wow factor +- **Phase 2 (Dashboard)**: 10-12 hours - Makes core experience impressive +- **Phase 3 (Components)**: 8-10 hours - Ensures consistency throughout +- **Phase 4 (Features)**: 6-8 hours - Adds impressive functionality +- **Phase 5 (Polish)**: 4-6 hours - Final touches for perfection + +**Total: 36-46 hours for a website that impresses everyone** + +--- + +## Progress Notes + +**Started:** [Date] +**Phase 1 Begin:** [Date] +**Phase 1 Complete:** [Date] +**Phase 2 Begin:** [Date] +**Phase 2 Complete:** [Date] +**Phase 3 Begin:** [Date] +**Phase 3 Complete:** [Date] +**Phase 4 Begin:** [Date] +**Phase 4 Complete:** [Date] +**Phase 5 Begin:** [Date] +**Phase 5 Complete:** [Date] + +**Final Deployment:** [Date] + +This plan will transform your platform into something that makes users think "this company is clearly successful and professional" - the kind of platform that commands premium pricing and builds instant credibility. \ No newline at end of file diff --git a/astro.config.mjs b/astro.config.mjs index 853d994..3e5ed0f 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -8,6 +8,7 @@ import sentry from '@sentry/astro'; // https://astro.build/config export default defineConfig({ + output: 'server', integrations: [ react(), sentry({ diff --git a/claude_desktop_config.json b/claude_desktop_config.json new file mode 100644 index 0000000..209d15a --- /dev/null +++ b/claude_desktop_config.json @@ -0,0 +1,17 @@ +{ + "mcpServers": { + "stripe": { + "command": "npx", + "args": [ + "-y", + "@stripe/mcp", + "--tools=all", + "--api-key", + "STRIPE_SECRET_KEY" + ], + "env": { + "STRIPE_SECRET_KEY": "YOUR_STRIPE_SECRET_KEY_HERE" + } + } + } +} \ No newline at end of file diff --git a/eslint-output.json b/eslint-output.json new file mode 100644 index 0000000..511a7e7 --- /dev/null +++ b/eslint-output.json @@ -0,0 +1 @@ +[{"filePath":"/home/tyler/apps/bct-whitelabel/docs/astro.config.mjs","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/setup-schema.mjs","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/AccountStatusBanner.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/Calendar.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/ChatWidget.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/CustomPageRenderer.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/CustomPricingManager.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/EventManagement.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'_err' is defined but never used.","line":125,"column":16,"nodeType":null,"messageId":"unusedVar","endLine":125,"endColumn":20}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useState, useEffect } from 'react';\nimport TabNavigation from './manage/TabNavigation';\nimport TicketingAccessTab from './manage/TicketingAccessTab';\nimport OrdersTab from './manage/OrdersTab';\nimport AttendeesTab from './manage/AttendeesTab';\nimport EventSettingsTab from './manage/EventSettingsTab';\nimport CustomPageTab from './manage/CustomPageTab';\nimport { api } from '../lib/api-router.js';\nimport type { EventData } from '../lib/event-management.js';\n\ninterface EventManagementProps {\n eventId: string;\n organizationId?: string;\n eventSlug?: string;\n}\n\nexport default function EventManagement({ eventId, _organizationId, eventSlug }: EventManagementProps) {\n const [activeTab, setActiveTab] = useState('ticketing');\n const [eventData, setEventData] = useState(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(null);\n const [_user, setUser] = useState(null);\n const [userOrganizationId, setUserOrganizationId] = useState(null);\n const [actualEventSlug, setActualEventSlug] = useState(eventSlug || null);\n\n const tabs = [\n {\n id: 'ticketing',\n name: 'Ticketing & Access',\n icon: (\n \n \n \n ),\n component: TicketingAccessTab\n },\n {\n id: 'custom-pages',\n name: 'Custom Pages',\n icon: (\n \n \n \n ),\n component: CustomPageTab\n },\n {\n id: 'sales',\n name: 'Sales',\n icon: (\n \n \n \n ),\n component: OrdersTab\n },\n {\n id: 'attendees',\n name: 'Attendees',\n icon: (\n \n \n \n ),\n component: AttendeesTab\n },\n {\n id: 'settings',\n name: 'Event Settings',\n icon: (\n \n \n \n \n ),\n component: EventSettingsTab\n }\n ];\n\n useEffect(() => {\n // Check authentication and load data\n const initializeComponent = async () => {\n try {\n setLoading(true);\n setError(null);\n \n // Check authentication status\n const authStatus = await api.checkAuth();\n \n if (!authStatus.authenticated) {\n // Give a bit more time for auth to load on page refresh\n // Auth check failed, retrying in 1 second...\n setTimeout(async () => {\n const retryAuthStatus = await api.checkAuth();\n if (!retryAuthStatus.authenticated) {\n // Still not authenticated, redirect to login\n // Auth retry failed, redirecting to login\n window.location.href = '/login';\n return;\n }\n // Retry loading with successful auth\n // Auth retry succeeded, reinitializing component\n initializeComponent();\n }, 1000);\n return;\n }\n \n setUser(authStatus.user);\n \n if (!authStatus.organizationId) {\n setError('User not associated with any organization');\n return;\n }\n \n setUserOrganizationId(authStatus.organizationId);\n \n // Load event data using centralized API\n const data = await api.loadEventData(eventId);\n if (data) {\n setEventData(data);\n setActualEventSlug(data.slug);\n } else {\n setError(`Event not found or access denied. Event ID: ${eventId}`);\n }\n } catch (_err) {\n setError('Failed to load event data. Please try again.');\n } finally {\n setLoading(false);\n }\n };\n\n initializeComponent();\n }, [eventId]);\n\n // Loading state\n if (loading) {\n return (\n
\n
\n
\n

Loading event data...

\n
\n
\n );\n }\n\n // Error state\n if (error) {\n return (\n
\n
\n
\n \n \n \n
\n

Error Loading Event

\n

{error}

\n window.location.reload()}\n className=\"px-4 py-2 border rounded-lg text-sm transition-colors backdrop-blur-lg\"\n style={{\n background: 'var(--ui-bg-elevated)',\n borderColor: 'var(--ui-border-primary)',\n color: 'var(--ui-text-primary)'\n }}\n onMouseEnter={(e) => e.target.style.background = 'var(--ui-bg-secondary)'}\n onMouseLeave={(e) => e.target.style.background = 'var(--ui-bg-elevated)'}\n >\n Try Again\n \n
\n
\n );\n }\n\n return (\n \n );\n}","usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/ImageUploadCropper.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/LocationInput.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/PageBuilder.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/QuickTicketPurchase.tsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/StripeEmbeddedOnboarding.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'currentStep' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":68,"column":10,"nodeType":null,"messageId":"unusedVar","endLine":68,"endColumn":21},{"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":70,"column":40,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":70,"endColumn":43,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1952,1955],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1952,1955],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":107,"column":33,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":107,"endColumn":36,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3218,3221],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3218,3221],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'e' is defined but never used. Allowed unused args must match /^_/u.","line":118,"column":35,"nodeType":null,"messageId":"unusedVar","endLine":118,"endColumn":36},{"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":118,"column":38,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":118,"endColumn":41,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3539,3542],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3539,3542],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'index' is defined but never used. Allowed unused args must match /^_/u.","line":276,"column":33,"nodeType":null,"messageId":"unusedVar","endLine":276,"endColumn":38}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useState, useRef } from 'react';\nimport { loadConnectAndInitialize } from '@stripe/connect-js';\n\ninterface StripeEmbeddedOnboardingProps {\n accountId: string;\n clientSecret: string;\n onComplete?: () => void;\n onError?: (error: Error) => void;\n}\n\ninterface OnboardingStep {\n id: number;\n title: string;\n icon: string;\n status: 'completed' | 'current' | 'pending';\n description: string;\n securityNote: string;\n estimatedTime: string;\n}\n\nconst onboardingSteps: OnboardingStep[] = [\n {\n id: 1,\n title: \"Business Information\",\n icon: \"🏢\",\n status: \"current\",\n description: \"Basic details about your organization\",\n securityNote: \"All information is encrypted in transit and at rest\",\n estimatedTime: \"2-3 minutes\"\n },\n {\n id: 2,\n title: \"Identity Verification\",\n icon: \"🔐\",\n status: \"pending\",\n description: \"Secure verification required by financial regulations\",\n securityNote: \"Documents are processed by Stripe's secure systems\",\n estimatedTime: \"5-10 minutes\"\n },\n {\n id: 3,\n title: \"Bank Account Setup\",\n icon: \"🏦\",\n status: \"pending\",\n description: \"Connect your bank account for automated payouts\",\n securityNote: \"Bank details are never stored on our servers\",\n estimatedTime: \"2-3 minutes\"\n },\n {\n id: 4,\n title: \"Final Review\",\n icon: \"✅\",\n status: \"pending\",\n description: \"Review and complete your secure account setup\",\n securityNote: \"Your account will be activated immediately\",\n estimatedTime: \"1-2 minutes\"\n }\n];\n\nconst StripeEmbeddedOnboarding: React.FC = ({\n accountId,\n clientSecret,\n onComplete,\n onError\n}) => {\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(null);\n const [currentStep, setCurrentStep] = useState(1);\n const [steps, setSteps] = useState(onboardingSteps);\n const stripeConnectInstance = useRef(null);\n const containerRef = useRef(null);\n\n useEffect(() => {\n const initializeStripe = async () => {\n try {\n setLoading(true);\n \n // Initialize Stripe Connect\n const publishableKey = import.meta.env.PUBLIC_STRIPE_PUBLISHABLE_KEY;\n if (!publishableKey) {\n throw new Error('Stripe publishable key not configured');\n }\n\n stripeConnectInstance.current = loadConnectAndInitialize({\n publishableKey,\n clientSecret,\n appearance: {\n variables: {\n colorPrimary: '#1f2937',\n colorBackground: '#ffffff',\n colorText: '#1f2937',\n colorDanger: '#ef4444',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n spacingUnit: '4px',\n borderRadius: '8px',\n fontSizeBase: '14px',\n fontWeightNormal: '400',\n fontWeightBold: '600'\n }\n }\n });\n\n // Create and mount the onboarding component\n const component = stripeConnectInstance.current.create('account-onboarding');\n \n // Set up event listeners before mounting\n component.setOnExit((e: any) => {\n\n if (e.reason === 'account_onboarding_completed') {\n updateStepStatus(4, 'completed');\n onComplete?.();\n } else if (e.reason === 'account_onboarding_closed') {\n // User closed the onboarding flow\n\n }\n });\n\n component.setOnLoadError((e: any) => {\n\n onError?.(new Error('Failed to load onboarding component'));\n });\n\n // Mount the component\n if (containerRef.current) {\n containerRef.current.appendChild(component);\n }\n\n setLoading(false);\n } catch (error) {\n // Stripe initialization error\n const errorMessage = error instanceof Error ? error.message : 'Failed to initialize Stripe Connect';\n setError(errorMessage);\n onError?.(error as Error);\n setLoading(false);\n }\n };\n\n if (accountId && clientSecret) {\n initializeStripe();\n }\n\n return () => {\n // Cleanup if needed\n if (stripeConnectInstance.current) {\n stripeConnectInstance.current = null;\n }\n };\n }, [accountId, clientSecret, onComplete, onError]);\n\n const updateStepStatus = (stepId: number, status: 'completed' | 'current' | 'pending') => {\n setSteps(prev => prev.map(step => \n step.id === stepId ? { ...step, status } : step\n ));\n setCurrentStep(stepId);\n };\n\n const getStepStatusColor = (status: string) => {\n switch (status) {\n case 'completed':\n return 'bg-green-100 border-green-500 text-green-700';\n case 'current':\n return 'bg-blue-100 border-blue-500 text-blue-700';\n case 'pending':\n return 'bg-gray-100 border-gray-300 text-gray-500';\n default:\n return 'bg-gray-100 border-gray-300 text-gray-500';\n }\n };\n\n const getStepIcon = (status: string) => {\n switch (status) {\n case 'completed':\n return (\n \n \n \n );\n case 'current':\n return (\n
\n
\n
\n );\n default:\n return
;\n }\n };\n\n if (error) {\n return (\n
\n
\n
\n
\n
\n \n \n \n
\n

Setup Error

\n

{error}

\n
\n \n \n Return to Dashboard\n \n
\n
\n
\n
\n
\n );\n }\n\n if (loading) {\n return (\n
\n
\n
\n
\n
\n

Initializing Secure Setup

\n

Preparing your encrypted onboarding experience...

\n
\n
\n
\n
\n );\n }\n\n return (\n
\n {/* Security Header */}\n
\n
\n
\n
\n
\n BCT\n
\n

Secure Account Setup

\n
\n
\n \n \n \n \n 256-bit SSL\n \n \n Powered by Stripe\n
\n
\n
\n
\n\n
\n {/* Progress Steps */}\n
\n
\n
\n

Account Setup Progress

\n

Complete each step to activate your payment processing account

\n
\n \n
\n {steps.map((step, index) => (\n
\n
\n {getStepIcon(step.status)}\n
\n
\n
\n

{step.title}

\n {step.estimatedTime}\n
\n

{step.description}

\n
\n \n \n \n {step.securityNote}\n
\n
\n
\n ))}\n
\n
\n
\n\n {/* Main Onboarding Container */}\n
\n
\n
\n \n \n \n Secure Connection\n \n Stripe Connect\n \n PCI DSS Compliant\n
\n
\n \n
\n
\n

Payment Account Setup

\n

\n Complete your secure payment processing setup to start accepting payments. \n All information is encrypted and processed by Stripe's bank-level security infrastructure.\n

\n
\n\n {/* Trust Indicators */}\n
\n
\n
\n \n \n \n Bank-level Security\n
\n
\n \n \n \n PCI DSS Level 1\n
\n
\n \n \n \n Trusted by Millions\n
\n
\n
\n\n {/* Stripe Embedded Component Container */}\n
\n
\n
\n\n {/* Security Footer */}\n
\n
\n

\n 🔒 Your data is protected by industry-leading security measures\n

\n

\n Questions? Contact our support team at{' '}\n \n support@blackcanyontickets.com\n \n

\n
\n
\n
\n
\n
\n
\n );\n};\n\nexport default StripeEmbeddedOnboarding;","usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/SuperAdminDashboard.tsx","messages":[{"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":31,"column":36,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":31,"endColumn":39,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[1158,1161],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[1158,1161],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'err' is defined but never used.","line":107,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":107,"endColumn":17},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":122,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":122,"endColumn":19},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":145,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":145,"endColumn":19},{"ruleId":"no-empty","severity":1,"message":"Empty block statement.","line":145,"column":21,"nodeType":"BlockStatement","messageId":"unexpected","endLine":147,"endColumn":6,"suggestions":[{"messageId":"suggestComment","data":{"type":"block"},"fix":{"range":[5693,5699],"text":" /* empty */ "},"desc":"Add comment inside empty block statement."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useState, useEffect } from 'react';\nimport SuperAdminTabNavigation from './admin/SuperAdminTabNavigation';\nimport AnalyticsTab from './admin/AnalyticsTab';\nimport RevenueTab from './admin/RevenueTab';\nimport EventsTab from './admin/EventsTab';\nimport OrganizersTab from './admin/OrganizersTab';\nimport ManagementTab from './admin/ManagementTab';\nimport { makeAuthenticatedRequest } from '../lib/api-client';\n\ninterface SuperAdminDashboardProps {\n // No props needed for now - keeping interface for future expansion\n readonly _placeholder?: never;\n}\n\ninterface PlatformMetrics {\n totalRevenue: number;\n totalFees: number;\n activeOrganizers: number;\n totalTickets: number;\n revenueChange: number;\n feesChange: number;\n organizersChange: number;\n ticketsChange: number;\n}\n\nexport default function SuperAdminDashboard(_props: SuperAdminDashboardProps) {\n const [activeTab, setActiveTab] = useState('analytics');\n const [platformMetrics, setPlatformMetrics] = useState(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(null);\n const [user, setUser] = useState(null);\n\n const tabs = [\n {\n id: 'analytics',\n name: 'Analytics',\n icon: (\n \n \n \n ),\n component: AnalyticsTab\n },\n {\n id: 'revenue',\n name: 'Revenue & Performance',\n icon: (\n \n \n \n ),\n component: RevenueTab\n },\n {\n id: 'events',\n name: 'Events & Tickets',\n icon: (\n \n \n \n ),\n component: EventsTab\n },\n {\n id: 'organizers',\n name: 'Organizers',\n icon: (\n \n \n \n ),\n component: OrganizersTab\n },\n {\n id: 'management',\n name: 'Management',\n icon: (\n \n \n \n \n ),\n component: ManagementTab\n }\n ];\n\n useEffect(() => {\n initializeComponent();\n }, []);\n\n const initializeComponent = async () => {\n try {\n setLoading(true);\n setError(null);\n \n // Check super admin authentication\n const authResult = await checkSuperAdminAuth();\n if (!authResult) {\n window.location.href = '/login';\n return;\n }\n \n setUser(authResult.user);\n \n // Load platform metrics\n await loadPlatformMetrics();\n } catch (err) {\n\n setError('Failed to load dashboard data. Please try again.');\n } finally {\n setLoading(false);\n }\n };\n\n const checkSuperAdminAuth = async () => {\n try {\n const result = await makeAuthenticatedRequest('/api/admin/check-super-admin');\n if (result.success && result.data.isSuperAdmin) {\n return result.data;\n }\n return null;\n } catch (error) {\n\n return null;\n }\n };\n\n const loadPlatformMetrics = async () => {\n try {\n const result = await makeAuthenticatedRequest('/api/admin/super-analytics?metric=platform_overview');\n \n if (result.success) {\n const data = result.data.summary;\n setPlatformMetrics({\n totalRevenue: data.totalRevenue || 0,\n totalFees: data.totalPlatformFees || 0,\n activeOrganizers: data.activeOrganizers || 0,\n totalTickets: data.totalTickets || 0,\n revenueChange: data.revenueGrowth || 0,\n feesChange: data.feesGrowth || 0,\n organizersChange: data.organizersThisMonth || 0,\n ticketsChange: data.ticketsThisMonth || 0\n });\n }\n } catch (error) {\n\n }\n };\n\n // Loading state\n if (loading) {\n return (\n
\n
\n
\n

Loading super admin dashboard...

\n
\n
\n );\n }\n\n // Error state\n if (error) {\n return (\n
\n
\n
\n \n \n \n
\n

Error Loading Dashboard

\n

{error}

\n window.location.reload()}\n className=\"px-4 py-2 bg-white/10 hover:bg-white/20 border border-white/20 rounded-lg text-white text-sm transition-colors\"\n >\n Try Again\n \n
\n
\n );\n }\n\n return (\n
\n {/* Page Header */}\n
\n

Business Intelligence

\n

Platform-wide analytics and performance insights

\n
\n\n {/* Key Metrics Dashboard */}\n {platformMetrics && (\n
\n
\n
\n
\n \n \n \n
\n
\n

Platform Revenue

\n

${platformMetrics.totalRevenue.toLocaleString()}

\n

+{platformMetrics.revenueChange}% vs last month

\n
\n
\n
\n\n
\n
\n
\n \n \n \n
\n
\n

Platform Fees

\n

${platformMetrics.totalFees.toLocaleString()}

\n

+{platformMetrics.feesChange}% vs last month

\n
\n
\n
\n\n
\n
\n
\n \n \n \n
\n
\n

Active Organizers

\n

{platformMetrics.activeOrganizers}

\n

+{platformMetrics.organizersChange} this month

\n
\n
\n
\n\n
\n
\n
\n \n \n \n
\n
\n

Tickets Sold

\n

{platformMetrics.totalTickets}

\n

+{platformMetrics.ticketsChange} this month

\n
\n
\n
\n
\n )}\n\n \n
\n );\n}","usedDeprecatedRules":[]},{"filePath":"/home/tyler/apps/bct-whitelabel/src/components/TemplateManager.tsx","messages":[{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":42,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":42,"endColumn":19},{"ruleId":"no-empty","severity":1,"message":"Empty block statement.","line":42,"column":21,"nodeType":"BlockStatement","messageId":"unexpected","endLine":44,"endColumn":6,"suggestions":[{"messageId":"suggestComment","data":{"type":"block"},"fix":{"range":[1225,1231],"text":" /* empty */ "},"desc":"Add comment inside empty block statement."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":72,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":72,"endColumn":19},{"ruleId":"no-empty","severity":1,"message":"Empty block statement.","line":72,"column":21,"nodeType":"BlockStatement","messageId":"unexpected","endLine":74,"endColumn":6,"suggestions":[{"messageId":"suggestComment","data":{"type":"block"},"fix":{"range":[2012,2018],"text":" /* empty */ "},"desc":"Add comment inside empty block statement."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":93,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":93,"endColumn":19},{"ruleId":"no-empty","severity":1,"message":"Empty block statement.","line":93,"column":21,"nodeType":"BlockStatement","messageId":"unexpected","endLine":95,"endColumn":6,"suggestions":[{"messageId":"suggestComment","data":{"type":"block"},"fix":{"range":[2523,2529],"text":" /* empty */ "},"desc":"Add comment inside empty block statement."}]},{"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":98,"column":47,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":98,"endColumn":50,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[2583,2586],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[2583,2586],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":115,"column":14,"nodeType":null,"messageId":"unusedVar","endLine":115,"endColumn":19},{"ruleId":"no-empty","severity":1,"message":"Empty block statement.","line":115,"column":21,"nodeType":"BlockStatement","messageId":"unexpected","endLine":117,"endColumn":6,"suggestions":[{"messageId":"suggestComment","data":{"type":"block"},"fix":{"range":[3054,3060],"text":" /* empty */ "},"desc":"Add comment inside empty block statement."}]},{"ruleId":"@typescript-eslint/no-unused-vars","severity":1,"message":"'pageData' is defined but never used. Allowed unused args must match /^_/u.","line":120,"column":34,"nodeType":null,"messageId":"unusedVar","endLine":120,"endColumn":42},{"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":120,"column":44,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":120,"endColumn":47,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[3111,3114],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[3111,3114],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useState, useEffect } from 'react';\nimport PageBuilder from './PageBuilder';\n\ninterface Template {\n id: string;\n name: string;\n description: string;\n preview_image_url?: string;\n created_at: string;\n updated_at: string;\n is_active: boolean;\n}\n\ninterface TemplateManagerProps {\n organizationId: string;\n onTemplateSelect?: (template: Template) => void;\n}\n\nconst TemplateManager: React.FC = ({\n organizationId,\n onTemplateSelect\n}) => {\n const [templates, setTemplates] = useState([]);\n const [loading, setLoading] = useState(true);\n const [showBuilder, setShowBuilder] = useState(false);\n const [selectedTemplate, setSelectedTemplate] = useState