feat: Complete platform enhancement with multi-tenant architecture

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 <noreply@anthropic.com>
This commit is contained in:
2025-07-12 18:21:40 -06:00
parent a02d64a86c
commit 26a87d0d00
232 changed files with 33175 additions and 5365 deletions

View File

@@ -1,6 +1,17 @@
---
import Layout from '../layouts/Layout.astro';
import Navigation from '../components/Navigation.astro';
import { verifyAuth } from '../lib/auth';
// Enable server-side rendering for auth checks
export const prerender = false;
// Disable server-side auth check temporarily to fix redirect loop
// We'll handle auth check on the client side in the script section
// const auth = await verifyAuth(Astro.request);
// if (!auth) {
// return Astro.redirect('/login');
// }
---
<Layout title="Dashboard - Black Canyon Tickets">
@@ -39,30 +50,74 @@ import Navigation from '../components/Navigation.astro';
transform: translateY(-2px);
}
.glass-effect {
background: rgba(255, 255, 255, 0.9);
/* Dark mode glass effects */
[data-theme="dark"] .glass-effect {
background: rgba(15, 23, 42, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.1);
}
[data-theme="dark"] .glass-card {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
[data-theme="dark"] .glass-card-content {
background: rgba(15, 23, 42, 0.9);
backdrop-filter: blur(5px);
padding: 1rem;
border-radius: 0.75rem;
}
/* Light mode solid effects - No glassmorphism */
[data-theme="light"] .glass-effect,
[data-theme="light"] .glass-card {
background: white !important;
backdrop-filter: none !important;
border: none !important;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
border-radius: 1rem !important;
}
[data-theme="light"] .glass-card-content {
background: transparent !important;
backdrop-filter: none !important;
padding: 0;
}
[data-theme="light"] .glass-card:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05) !important;
transform: translateY(-1px);
}
/* Remove all blur and transparency in light mode */
[data-theme="light"] * {
backdrop-filter: none !important;
}
[data-theme="light"] .event-card {
background: white !important;
border: 1px solid rgba(0, 0, 0, 0.1) !important;
}
.bg-grid-pattern {
background-image:
linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
linear-gradient(var(--grid-pattern) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-pattern) 1px, transparent 1px);
background-size: 20px 20px;
}
</style>
<div class="min-h-screen bg-gradient-to-br from-indigo-900 via-purple-900 to-slate-900">
<div class="min-h-screen" data-theme-background>
<!-- Animated background elements -->
<div class="fixed inset-0 overflow-hidden pointer-events-none">
<div class="absolute -top-40 -right-40 w-80 h-80 bg-gradient-to-br from-purple-600/20 to-pink-600/20 rounded-full blur-3xl animate-pulse"></div>
<div class="absolute -bottom-40 -left-40 w-80 h-80 bg-gradient-to-br from-blue-600/20 to-cyan-600/20 rounded-full blur-3xl animate-pulse"></div>
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-gradient-to-br from-indigo-600/10 to-purple-600/10 rounded-full blur-3xl animate-pulse"></div>
<div class="absolute -top-40 -right-40 w-80 h-80 rounded-full blur-3xl animate-pulse" style="background: var(--bg-orb-1);"></div>
<div class="absolute -bottom-40 -left-40 w-80 h-80 rounded-full blur-3xl animate-pulse" style="background: var(--bg-orb-2);"></div>
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-96 h-96 rounded-full blur-3xl animate-pulse" style="background: var(--bg-orb-3);"></div>
</div>
<!-- Grid pattern overlay -->
<div class="absolute inset-0 bg-grid-pattern opacity-5"></div>
<!-- Grid pattern is now integrated into bg-static-pattern -->
<Navigation title="Dashboard" />
@@ -72,13 +127,15 @@ import Navigation from '../components/Navigation.astro';
<div class="mb-12 animate-slideIn">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-6">
<div>
<h1 class="text-4xl md:text-5xl font-light text-white tracking-wide">Dashboard</h1>
<p class="text-white/80 mt-2 text-lg font-light">Manage your events and track performance</p>
<h1 class="text-4xl md:text-5xl font-light tracking-wide" style="color: var(--glass-text-primary);">Dashboard</h1>
<p class="mt-2 text-lg font-light" style="color: var(--glass-text-secondary);">Manage your events and track performance</p>
</div>
<div class="flex flex-wrap gap-4">
<button
id="toggle-view-btn"
class="bg-white/10 backdrop-blur-lg border border-white/20 hover:bg-white/20 text-white px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg shadow-black/10 flex items-center gap-2 hover:shadow-xl hover:scale-105"
type="button"
class="glass-card px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg flex items-center gap-2 hover:shadow-xl hover:scale-105"
style="color: var(--glass-text-primary);"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
@@ -86,8 +143,9 @@ import Navigation from '../components/Navigation.astro';
<span id="view-text">Calendar View</span>
</button>
<a
href="/settings/fees"
class="bg-white/10 backdrop-blur-lg border border-white/20 hover:bg-white/20 text-white px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg shadow-black/10 flex items-center gap-2 hover:shadow-xl hover:scale-105"
href="/calendar"
class="glass-card px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg flex items-center gap-2 hover:shadow-xl hover:scale-105 hover:opacity-80"
style="color: var(--glass-text-primary);"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
@@ -95,9 +153,20 @@ import Navigation from '../components/Navigation.astro';
</svg>
Fee Settings
</a>
<a
href="/onboarding/stripe"
class="btn-premium-gold px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg flex items-center gap-2 hover:shadow-xl hover:scale-105"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
</svg>
Stripe Setup
</a>
<a
href="/events/new"
class="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg shadow-blue-500/30 flex items-center gap-2 hover:shadow-xl hover:scale-105"
class="px-6 py-3 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg flex items-center gap-2 hover:shadow-xl hover:scale-105"
style="background: var(--glass-text-accent); color: white;"
data-light-shadow
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
@@ -120,43 +189,50 @@ import Navigation from '../components/Navigation.astro';
<!-- List View -->
<div id="list-view">
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg overflow-hidden">
<div class="px-8 py-6 border-b border-white/20 bg-gradient-to-r from-white/10 to-white/5">
<h3 class="text-xl font-light text-white tracking-wide">Your Events</h3>
</div>
<div class="p-8">
<div id="events-container" class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
<!-- Events will be loaded here -->
<div class="glass-card rounded-2xl shadow-lg overflow-hidden">
<div class="glass-card-content">
<div class="px-8 py-6 border-b" style="border-color: var(--glass-border);">
<h3 class="text-xl font-light tracking-wide" style="color: var(--glass-text-primary);">Your Events</h3>
</div>
<div class="p-8">
<div id="events-container" class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
<!-- Events will be loaded here -->
</div>
</div>
</div>
</div>
</div>
<div id="loading" class="text-center py-16">
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg p-12 max-w-md mx-auto">
<div class="animate-spin rounded-full h-12 w-12 border-2 border-blue-400 border-t-transparent mx-auto mb-6"></div>
<p class="text-white/80 font-light text-lg">Loading your events...</p>
<div class="glass-card rounded-2xl shadow-lg p-12 max-w-md mx-auto">
<div class="glass-card-content">
<div class="animate-spin rounded-full h-12 w-12 border-2 border-t-transparent mx-auto mb-6" style="border-color: var(--glass-text-accent); border-top-color: transparent;"></div>
<p class="font-light text-lg" style="color: var(--glass-text-secondary);">Loading your events...</p>
</div>
</div>
</div>
<div id="no-events" class="text-center py-16 hidden">
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg p-16 max-w-lg mx-auto">
<div class="w-20 h-20 bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-2xl flex items-center justify-center mx-auto mb-6">
<svg class="h-10 w-10 text-white/60" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<div class="glass-card rounded-2xl shadow-lg p-16 max-w-lg mx-auto">
<div class="glass-card-content">
<div class="w-20 h-20 rounded-2xl flex items-center justify-center mx-auto mb-6" style="background: var(--glass-text-accent); opacity: 0.2;">
<svg class="h-10 w-10" style="color: var(--glass-text-accent);" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</div>
<h3 class="text-xl font-light mb-3 tracking-wide" style="color: var(--glass-text-primary);">No events yet</h3>
<p class="mb-8 text-lg font-light leading-relaxed" style="color: var(--glass-text-secondary);">Get started by creating your first event and start selling tickets.</p>
<a
href="/events/new"
class="inline-flex items-center gap-2 px-6 py-3 text-white font-medium rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl hover:scale-105"
style="background: var(--glass-text-accent); box-shadow: 0 4px 15px rgba(139, 92, 246, 0.3);"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
Create Your First Event
</a>
</div>
<h3 class="text-xl font-light text-white mb-3 tracking-wide">No events yet</h3>
<p class="text-white/80 mb-8 text-lg font-light leading-relaxed">Get started by creating your first event and start selling tickets.</p>
<a
href="/events/new"
class="inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-medium rounded-xl transition-all duration-200 shadow-lg shadow-blue-500/30 hover:shadow-xl hover:scale-105"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
Create Your First Event
</a>
</div>
</div>
</div>
@@ -164,6 +240,56 @@ import Navigation from '../components/Navigation.astro';
</div>
</Layout>
<script>
// Theme persistence and initialization
function initializeTheme() {
// Get saved theme or use system preference, fallback to 'dark'
const savedTheme = localStorage.getItem('theme') ||
(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') ||
'dark';
document.documentElement.setAttribute('data-theme', savedTheme);
document.documentElement.classList.remove('light', 'dark');
document.documentElement.classList.add(savedTheme);
// Store the theme for consistency
localStorage.setItem('theme', savedTheme);
window.__INITIAL_THEME__ = savedTheme;
updateBackground();
}
// Theme-aware background handling
function updateBackground() {
const theme = document.documentElement.getAttribute('data-theme') || 'dark';
const bgElement = document.querySelector('[data-theme-background]');
if (bgElement) {
if (theme === 'light') {
// Light mode gets solid clean background
bgElement.style.background = '#f8fafc';
} else {
// Dark mode gets rich dark background with gradient - use CSS variable
bgElement.style.background = 'var(--bg-gradient)';
}
}
}
// Listen for theme changes from other components
window.addEventListener('themeChanged', (e) => {
const newTheme = e.detail?.theme || document.documentElement.getAttribute('data-theme');
if (newTheme) {
localStorage.setItem('theme', newTheme);
updateBackground();
}
});
// Initialize immediately
initializeTheme();
// Also initialize on DOM ready as fallback
document.addEventListener('DOMContentLoaded', initializeTheme);
</script>
<script>
import { supabase } from '../lib/supabase';
@@ -180,11 +306,58 @@ import Navigation from '../components/Navigation.astro';
let currentView = 'list';
let allEvents = [];
// Check authentication (simplified since Navigation component handles user display)
// Handle Stripe onboarding completion from URL parameters
function handleOnboardingSuccess() {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('stripe_onboarding') === 'completed') {
// Show success notification
showSuccessNotification('Payment processing setup completed successfully! You can now start accepting payments for your events.');
// Clean up URL
const newUrl = window.location.pathname;
window.history.replaceState({}, document.title, newUrl);
}
}
// Show success notification
function showSuccessNotification(message) {
// Create notification element
const notification = document.createElement('div');
notification.innerHTML = `
<div class="fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg z-50 max-w-md" style="background: var(--success-color); color: white;">
<div class="flex items-start space-x-3">
<svg class="w-6 h-6 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<div>
<h4 class="font-semibold mb-1">Success!</h4>
<p class="text-sm">${message}</p>
</div>
<button onclick="this.closest('div').parentElement.remove()" class="ml-4 text-green-200 hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
`;
document.body.appendChild(notification.firstElementChild);
// Auto-remove after 8 seconds
setTimeout(() => {
const element = notification.firstElementChild;
if (element && element.parentNode) {
element.remove();
}
}, 8000);
}
// Check authentication and redirect immediately if no session
async function checkAuth() {
const { data: { session } } = await supabase.auth.getSession();
if (!session) {
window.location.href = '/';
// No session found, redirecting to login
window.location.href = '/login';
return null;
}
return session;
@@ -195,6 +368,13 @@ import Navigation from '../components/Navigation.astro';
try {
// Check if user has organization_id or is admin
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
// User is null, redirecting to login
window.location.href = '/login';
return;
}
const { data: userProfile, error: userError } = await supabase
.from('users')
.select('organization_id, role')
@@ -202,23 +382,22 @@ import Navigation from '../components/Navigation.astro';
.single();
if (userError) {
console.error('Error loading user profile:', userError);
console.error('User ID:', user?.id);
// Error loading user profile
loading.innerHTML = `
<div class="bg-red-50 border border-red-200 rounded-xl p-6 max-w-md mx-auto">
<p class="text-red-600 font-medium">Error loading user profile</p>
<p class="text-red-500 text-sm mt-2">${userError.message || userError}</p>
<div class="rounded-xl p-6 max-w-md mx-auto" style="background: var(--error-bg); border: 1px solid var(--error-border);">
<p class="font-medium" style="color: var(--error-color);">Error loading user profile</p>
<p class="text-sm mt-2" style="color: var(--error-color); opacity: 0.8;">${userError.message || userError}</p>
</div>
`;
return;
}
console.log('User profile loaded:', userProfile);
// User profile loaded successfully
// Check if user is admin or has organization_id
const isAdmin = userProfile?.role === 'admin';
if (!isAdmin && !userProfile?.organization_id) {
console.log('User has no organization_id and is not admin, showing no events');
// User has no organization_id and is not admin, showing no events
loading.classList.add('hidden');
noEvents.classList.remove('hidden');
return;
@@ -236,11 +415,11 @@ import Navigation from '../components/Navigation.astro';
const { data: events, error } = await query.order('created_at', { ascending: false });
if (error) {
console.error('Error loading events from database:', error);
// Error loading events from database
throw error;
}
console.log('Successfully loaded events:', events?.length || 0, 'events');
// Successfully loaded events
allEvents = events || [];
loading.classList.add('hidden');
@@ -255,11 +434,11 @@ import Navigation from '../components/Navigation.astro';
renderCalendarView();
}
} catch (error) {
console.error('Error loading events:', error);
// Error loading events
loading.innerHTML = `
<div class="bg-red-50 border border-red-200 rounded-xl p-6 max-w-md mx-auto">
<p class="text-red-600 font-medium">Error loading events</p>
<p class="text-red-500 text-sm mt-2">${error.message || error}</p>
<div class="rounded-xl p-6 max-w-md mx-auto" style="background: var(--error-bg); border: 1px solid var(--error-border);">
<p class="font-medium" style="color: var(--error-color);">Error loading events</p>
<p class="text-sm mt-2" style="color: var(--error-color); opacity: 0.8;">${error.message || error}</p>
</div>
`;
}
@@ -272,44 +451,74 @@ import Navigation from '../components/Navigation.astro';
const pastEvents = totalEvents - upcomingEvents;
statsCards.innerHTML = `
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg p-8 hover:shadow-xl hover:-translate-y-1 hover:scale-105 transition-all duration-200 ease-out cursor-pointer group">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-white/80 uppercase tracking-wider">Total Events</p>
<p class="text-3xl font-light text-white mt-2 group-hover:text-blue-400 transition-colors">${totalEvents}</p>
</div>
<div class="w-14 h-14 bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-lg transition-all duration-200 ease-out">
<svg class="w-7 h-7 text-blue-400 group-hover:text-blue-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<div class="glass-card rounded-2xl shadow-lg p-8 premium-hover cursor-pointer group">
<div class="glass-card-content">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold uppercase tracking-wider" style="color: var(--glass-text-secondary);">Total Events</p>
<p class="text-3xl font-light mt-2 transition-colors animate-countUp" style="color: var(--glass-text-primary);">${totalEvents}</p>
<div class="flex items-center mt-1">
<span class="text-xs flex items-center" style="color: var(--glass-text-tertiary);">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
All time
</span>
</div>
</div>
<div class="w-16 h-16 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl group-hover:scale-110 transition-all duration-300" style="background: var(--glass-text-accent); opacity: 0.15;">
<svg class="w-8 h-8" style="color: white;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</div>
</div>
</div>
</div>
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg p-8 hover:shadow-xl hover:-translate-y-1 hover:scale-105 transition-all duration-200 ease-out cursor-pointer group">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-white/80 uppercase tracking-wider">Upcoming Events</p>
<p class="text-3xl font-light text-white mt-2 group-hover:text-emerald-400 transition-colors">${upcomingEvents}</p>
</div>
<div class="w-14 h-14 bg-gradient-to-br from-emerald-500/20 to-teal-500/20 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-lg transition-all duration-200 ease-out">
<svg class="w-7 h-7 text-emerald-400 group-hover:text-emerald-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div class="glass-card rounded-2xl shadow-lg p-8 premium-hover cursor-pointer group" style="--card-accent: var(--success-color);">
<div class="glass-card-content">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold uppercase tracking-wider" style="color: var(--success-color);">Upcoming Events</p>
<p class="text-3xl font-light mt-2 transition-colors animate-countUp" style="color: var(--success-color);">${upcomingEvents}</p>
<div class="flex items-center mt-1">
<span class="text-xs flex items-center" style="color: var(--success-color); opacity: 0.8;">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
</svg>
Ready to launch
</span>
</div>
</div>
<div class="w-16 h-16 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl group-hover:scale-110 transition-all duration-300" style="background: var(--success-color); opacity: 0.15;">
<svg class="w-8 h-8" style="color: white;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
</div>
</div>
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg p-8 hover:shadow-xl hover:-translate-y-1 hover:scale-105 transition-all duration-200 ease-out cursor-pointer group">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-white/80 uppercase tracking-wider">Past Events</p>
<p class="text-3xl font-light text-white mt-2 group-hover:text-slate-400 transition-colors">${pastEvents}</p>
</div>
<div class="w-14 h-14 bg-gradient-to-br from-slate-500/20 to-gray-500/20 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-lg transition-all duration-200 ease-out">
<svg class="w-7 h-7 text-slate-400 group-hover:text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div class="glass-card rounded-2xl shadow-lg p-8 premium-hover cursor-pointer group" style="--card-accent: var(--premium-gold);">
<div class="glass-card-content">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold uppercase tracking-wider" style="color: var(--premium-gold);">Past Events</p>
<p class="text-3xl font-light mt-2 transition-colors animate-countUp" style="color: var(--premium-gold);">${pastEvents}</p>
<div class="flex items-center mt-1">
<span class="text-xs flex items-center" style="color: var(--premium-gold); opacity: 0.8;">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Completed
</span>
</div>
</div>
<div class="w-16 h-16 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl group-hover:scale-110 transition-all duration-300" style="background: var(--premium-gold); opacity: 0.15;">
<svg class="w-8 h-8" style="color: white;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
</div>
</div>
@@ -334,59 +543,63 @@ import Navigation from '../components/Navigation.astro';
const animationDelay = index * 0.1;
return `
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg hover:shadow-xl hover:-translate-y-1 hover:scale-105 transition-all duration-200 ease-out overflow-hidden group">
<div class="p-8">
<div class="flex items-start justify-between mb-6">
<div class="flex-1">
<h3 class="text-xl font-light text-white mb-3 tracking-wide group-hover:text-white/90 transition-colors duration-200">${event.title}</h3>
<div class="flex items-center text-sm text-white/80 mb-3 group-hover:text-white/90 transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
${event.venue}
<div class="glass-card event-card rounded-2xl shadow-lg overflow-hidden group hover:shadow-lg hover:translate-y-px transition-all duration-200">
<div class="glass-card-content">
<div class="p-8">
<div class="flex items-start justify-between mb-6">
<div class="flex-1">
<h3 class="text-xl font-light mb-4 tracking-wide" style="color: var(--glass-text-primary);">${event.title}</h3>
<div class="flex items-center text-sm mb-3" style="color: var(--glass-text-secondary);">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
${event.venue}
</div>
<div class="flex items-center text-sm mb-6" style="color: var(--glass-text-secondary);">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
${formattedDate} at ${formattedTime}
</div>
</div>
<div class="flex items-center text-sm text-white/80 group-hover:text-white/90 transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
${formattedDate} at ${formattedTime}
<div class="flex items-start ml-4">
<span class="px-3 py-1 text-xs font-semibold rounded-full transition-all duration-200 ease-out" style="${isUpcoming ? 'background: var(--success-bg); color: var(--success-color); border: 1px solid var(--success-border);' : 'background: var(--glass-bg); color: var(--glass-text-tertiary); border: 1px solid var(--glass-border);'}">
${isUpcoming ? 'Upcoming' : 'Past'}
</span>
</div>
</div>
<div class="flex items-center">
<span class="px-3 py-1 text-xs font-semibold rounded-full ${isUpcoming ? 'bg-gradient-to-r from-emerald-500/20 to-teal-500/20 text-emerald-400' : 'bg-gradient-to-r from-slate-500/20 to-gray-500/20 text-slate-400'} transition-all duration-200 ease-out">
${isUpcoming ? 'Upcoming' : 'Past'}
</span>
</div>
</div>
${event.description ? `<p class="text-sm text-white/70 mb-6 leading-relaxed group-hover:text-white/80 transition-colors">${event.description}</p>` : ''}
<div class="flex items-center justify-between pt-6 border-t border-white/20">
<div class="flex space-x-3">
<a
href="/events/${event.id}/manage"
class="inline-flex items-center gap-2 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg shadow-blue-500/25 hover:shadow-lg hover:-translate-y-0.5 hover:scale-105"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Manage
</a>
<a
href="/e/${event.slug}"
class="inline-flex items-center gap-2 border border-white/20 hover:bg-white/10 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg shadow-black/10 hover:shadow-lg hover:-translate-y-0.5 hover:scale-105"
target="_blank"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
Preview
</a>
</div>
<div class="text-xs text-white/60 font-medium">
Created ${new Date(event.created_at).toLocaleDateString()}
${event.description ? `<p class="text-sm mb-6 leading-relaxed group-hover:opacity-80 transition-colors" style="color: var(--glass-text-tertiary);">${event.description}</p>` : ''}
<div class="flex items-center justify-between pt-6 border-t" style="border-color: var(--glass-border);">
<div class="flex space-x-3">
<a
href="/events/${event.id}/manage"
class="inline-flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg hover:shadow-lg hover:-translate-y-0.5 hover:scale-105"
style="background: var(--glass-text-accent); color: white;"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Manage
</a>
<a
href="/e/${event.slug}"
class="glass-card inline-flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium transition-all duration-200 shadow-lg hover:shadow-lg hover:-translate-y-0.5 hover:scale-105"
style="color: var(--glass-text-primary);"
target="_blank"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
Preview
</a>
</div>
<div class="text-xs font-medium" style="color: var(--glass-text-tertiary);">
Created ${new Date(event.created_at).toLocaleDateString()}
</div>
</div>
</div>
</div>
@@ -412,37 +625,38 @@ import Navigation from '../components/Navigation.astro';
const firstDay = new Date(year, month, 1).getDay();
let html = `
<div class="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-lg overflow-hidden">
<!-- Calendar Header -->
<div class="px-8 py-6 bg-gradient-to-r from-white/10 to-white/5 border-b border-white/20 backdrop-blur-sm">
<div class="flex items-center justify-between">
<h3 class="text-2xl font-light text-white tracking-wide">${monthNames[month]} ${year}</h3>
<div class="flex gap-3">
<button onclick="navigateMonth(-1)" class="p-3 hover:bg-white/10 rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl hover:scale-105">
<svg class="w-5 h-5 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
<button onclick="navigateMonth(1)" class="p-3 hover:bg-white/10 rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl hover:scale-105">
<svg class="w-5 h-5 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
<div class="glass-card rounded-2xl shadow-lg overflow-hidden">
<div class="glass-card-content">
<!-- Calendar Header -->
<div class="px-8 py-6 border-b" style="border-color: var(--glass-border);">
<div class="flex items-center justify-between">
<h3 class="text-2xl font-light tracking-wide" style="color: var(--glass-text-primary);">${monthNames[month]} ${year}</h3>
<div class="flex gap-3">
<button onclick="navigateMonth(-1)" class="glass-card p-3 rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl hover:scale-105" style="color: var(--glass-text-secondary);">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
<button onclick="navigateMonth(1)" class="glass-card p-3 rounded-xl transition-all duration-200 shadow-lg hover:shadow-xl hover:scale-105" style="color: var(--glass-text-secondary);">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- Calendar Body -->
<div class="p-4 sm:p-6">
<!-- Day Headers -->
<div class="grid grid-cols-7 gap-1 mb-4">
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Sun</div>
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Mon</div>
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Tue</div>
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Wed</div>
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Thu</div>
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Fri</div>
<div class="text-center text-xs sm:text-sm font-semibold text-white/80 py-2">Sat</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Sun</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Mon</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Tue</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Wed</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Thu</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Fri</div>
<div class="text-center text-xs sm:text-sm font-semibold py-2" style="color: var(--glass-text-secondary);">Sat</div>
</div>
<!-- Calendar Grid -->
@@ -467,23 +681,25 @@ import Navigation from '../components/Navigation.astro';
const hasEvents = dayEvents.length > 0;
html += `
<div class="aspect-square border rounded-lg p-1 sm:p-2 hover:bg-white/10 transition-colors cursor-pointer ${
isToday ? 'bg-blue-500/20 border-blue-400 ring-2 ring-blue-400/20' :
hasEvents ? 'border-white/30 bg-white/5' : 'border-white/20'
<div class="aspect-square rounded-lg p-1 sm:p-2 transition-colors cursor-pointer ${
isToday ? 'ring-2' : ''
}" style="${
isToday ? 'background: rgba(96, 165, 250, 0.2); border: 1px solid rgb(96, 165, 250); ring-color: rgba(96, 165, 250, 0.3); color: rgb(96, 165, 250);' :
hasEvents ? 'border: 1px solid var(--glass-border); background: var(--glass-bg);' : 'border: 1px solid var(--glass-border);'
}" onclick="showDayEvents(${year}, ${month}, ${day})">
<div class="h-full flex flex-col">
<div class="text-xs sm:text-sm font-semibold mb-1 ${
isToday ? 'text-blue-400' : 'text-white'
}">${day}</div>
<div class="text-xs sm:text-sm font-semibold mb-1" style="color: ${
isToday ? 'rgb(96, 165, 250)' : 'var(--glass-text-primary)'
};">${day}</div>
<!-- Mobile: Show event dots -->
<div class="flex-1 sm:hidden">
${dayEvents.length > 0 ? `
<div class="flex flex-wrap gap-0.5">
${dayEvents.slice(0, 3).map(() => `
<div class="w-1.5 h-1.5 bg-blue-400 rounded-full"></div>
<div class="w-1.5 h-1.5 rounded-full" style="background: var(--glass-text-accent);"></div>
`).join('')}
${dayEvents.length > 3 ? '<div class="text-xs text-white/60">+</div>' : ''}
${dayEvents.length > 3 ? '<div class="text-xs" style="color: var(--glass-text-tertiary);">+</div>' : ''}
</div>
` : ''}
</div>
@@ -491,12 +707,13 @@ import Navigation from '../components/Navigation.astro';
<!-- Desktop: Show event titles -->
<div class="hidden sm:block flex-1 space-y-1 overflow-hidden">
${dayEvents.slice(0, 2).map(event => `
<div class="text-xs bg-blue-500/20 text-blue-400 rounded px-1.5 py-0.5 truncate font-medium"
<div class="text-xs rounded px-1.5 py-0.5 truncate font-medium"
style="background: var(--glass-bg-button); color: var(--glass-text-accent);"
title="${event.title} at ${event.venue}">
${event.title}
</div>
`).join('')}
${dayEvents.length > 2 ? `<div class="text-xs text-white/60 font-medium">+${dayEvents.length - 2} more</div>` : ''}
${dayEvents.length > 2 ? `<div class="text-xs font-medium" style="color: var(--glass-text-tertiary);">+${dayEvents.length - 2} more</div>` : ''}
</div>
</div>
</div>
@@ -508,18 +725,23 @@ import Navigation from '../components/Navigation.astro';
</div>
</div>
<!-- Mobile Event List (shows when day is clicked) -->
<div id="mobile-day-events" class="hidden sm:hidden mt-4 bg-white/10 backdrop-blur-xl border border-white/20 rounded-xl shadow-lg p-4">
<div class="flex items-center justify-between mb-3">
<h4 id="selected-day-title" class="font-semibold text-white"></h4>
<button onclick="hideMobileDayEvents()" class="p-1 hover:bg-white/10 rounded">
<svg class="w-4 h-4 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div id="selected-day-events" class="space-y-2">
<!-- Events will be populated here -->
</div>
<!-- Mobile Event List (shows when day is clicked) -->
<div id="mobile-day-events" class="hidden sm:hidden mt-4 glass-card rounded-xl shadow-lg p-4">
<div class="glass-card-content">
<div class="flex items-center justify-between mb-3">
<h4 id="selected-day-title" class="font-semibold" style="color: var(--glass-text-primary);"></h4>
<button onclick="hideMobileDayEvents()" class="glass-card p-1 rounded" style="color: var(--glass-text-secondary);">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div id="selected-day-events" class="space-y-2">
<!-- Events will be populated here -->
</div>
</div>
</div>
`;
@@ -565,12 +787,16 @@ import Navigation from '../components/Navigation.astro';
selectedDayTitle.textContent = `${monthNames[month]} ${day}, ${year}`;
selectedDayEventsContainer.innerHTML = dayEvents.map(event => `
<div class="flex items-start gap-3 p-3 bg-white/10 backdrop-blur-lg rounded-lg">
<div class="w-2 h-2 bg-blue-400 rounded-full mt-2 flex-shrink-0"></div>
<div class="flex-1 min-w-0">
<h5 class="font-medium text-white text-sm">${event.title}</h5>
<p class="text-xs text-white/80 mt-1">${event.venue}</p>
<p class="text-xs text-white/60 mt-1">${new Date(event.start_time).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</p>
<div class="glass-card flex items-start gap-3 p-3 rounded-lg">
<div class="glass-card-content">
<div class="flex items-start gap-3">
<div class="w-2 h-2 rounded-full mt-2 flex-shrink-0" style="background: var(--glass-text-accent);"></div>
<div class="flex-1 min-w-0">
<h5 class="font-medium text-sm" style="color: var(--glass-text-primary);">${event.title}</h5>
<p class="text-xs mt-1" style="color: var(--glass-text-secondary);">${event.venue}</p>
<p class="text-xs mt-1" style="color: var(--glass-text-tertiary);">${new Date(event.start_time).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</p>
</div>
</div>
</div>
</div>
`).join('');
@@ -602,6 +828,9 @@ import Navigation from '../components/Navigation.astro';
toggleViewBtn.addEventListener('click', toggleView);
// Initialize
// Handle onboarding success on page load
handleOnboardingSuccess();
checkAuth().then(session => {
if (session) {
loadEvents();