feat(config): enhance development experience with strict linting and types

- Update ESLint configuration with strict React/TypeScript rules
- Enhance TypeScript configuration with stricter checks
- Add comprehensive type definitions and exports
- Update App.tsx with new routing and layout integration
- Create showcase pages for component development
- Improve package.json with proper dependencies

Configuration ensures code quality and developer productivity with
zero-tolerance for type errors and consistent code standards.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-16 12:44:54 -06:00
parent 48b9b680e3
commit edb83ff6b5
9 changed files with 874 additions and 249 deletions

View File

@@ -1,24 +1,130 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { ProtectedRoute, AdminRoute } from './components/auth/ProtectedRoute';
import { AppErrorBoundary } from './components/errors/AppErrorBoundary';
import { GlassShowcase } from './components/GlassShowcase';
import { AppLayout } from './components/layout/AppLayout';
import { RouteSuspense } from './components/loading/RouteSuspense';
import { ThemeDocumentation } from './components/ThemeDocumentation';
import { AuthProvider } from './contexts/AuthContext';
import { DashboardPage } from './pages/DashboardPage';
import {
ErrorPage,
NotFoundPage,
UnauthorizedPage,
ServerErrorPage,
NetworkErrorPage
} from './pages/ErrorPage';
import { EventsPage } from './pages/EventsPage';
import { HomePage } from './pages/HomePage';
import { LoginPage } from './pages/LoginPage';
function App() {
function App(): JSX.Element {
return (
<Router>
<div className='bg-premium-dark min-h-screen'>
<Routes>
<Route path='/' element={<HomePage />} />
<Route path='/dashboard' element={<DashboardPage />} />
<Route path='/events' element={<EventsPage />} />
<AppErrorBoundary>
<AuthProvider>
<Router>
<RouteSuspense
skeletonType="page"
loadingText="Loading application..."
timeout={15000}
>
<Routes>
{/* Public routes without authentication */}
<Route path='/login' element={<LoginPage />} />
<Route path='/home' element={<HomePage />} />
<Route path='/showcase' element={<GlassShowcase />} />
<Route path='/docs' element={<ThemeDocumentation />} />
{/* Protected routes with layout */}
<Route path='/' element={
<ProtectedRoute>
<AppLayout title="Dashboard" subtitle="Overview of your events and performance">
<DashboardPage />
</AppLayout>
</ProtectedRoute>
} />
<Route path='/dashboard' element={
<ProtectedRoute>
<AppLayout title="Dashboard" subtitle="Overview of your events and performance">
<DashboardPage />
</AppLayout>
</ProtectedRoute>
} />
<Route path='/events' element={
<ProtectedRoute permissions={['events:read']}>
<AppLayout title="Events" subtitle="Manage your upcoming events">
<EventsPage />
</AppLayout>
</ProtectedRoute>
} />
<Route path='/tickets' element={
<ProtectedRoute permissions={['tickets:read']}>
<AppLayout title="Tickets" subtitle="Track ticket sales and manage inventory">
<div className="text-slate-900 dark:text-slate-100">
<h2 className="text-xl font-semibold mb-4">Tickets Management</h2>
<p>Ticket management functionality coming soon...</p>
</div>
</AppLayout>
</ProtectedRoute>
} />
<Route path='/customers' element={
<ProtectedRoute permissions={['customers:read']}>
<AppLayout title="Customers" subtitle="View and manage customer information">
<div className="text-slate-900 dark:text-slate-100">
<h2 className="text-xl font-semibold mb-4">Customer Management</h2>
<p>Customer management functionality coming soon...</p>
</div>
</AppLayout>
</ProtectedRoute>
} />
<Route path='/analytics' element={
<ProtectedRoute permissions={['analytics:read']}>
<AppLayout title="Analytics" subtitle="View detailed performance metrics">
<div className="text-slate-900 dark:text-slate-100">
<h2 className="text-xl font-semibold mb-4">Analytics Dashboard</h2>
<p>Analytics dashboard coming soon...</p>
</div>
</AppLayout>
</ProtectedRoute>
} />
<Route path='/settings' element={
<ProtectedRoute>
<AppLayout title="Settings" subtitle="Configure your account and preferences">
<div className="text-slate-900 dark:text-slate-100">
<h2 className="text-xl font-semibold mb-4">Account Settings</h2>
<p>Settings page coming soon...</p>
</div>
</AppLayout>
</ProtectedRoute>
} />
{/* Admin routes */}
<Route path='/admin/*' element={
<AdminRoute>
<AppLayout title="Admin" subtitle="Platform administration">
<div className="text-slate-900 dark:text-slate-100">
<h2 className="text-xl font-semibold mb-4">Admin Panel</h2>
<p>Admin functionality coming soon...</p>
</div>
</AppLayout>
</AdminRoute>
} />
{/* Error routes */}
<Route path='/unauthorized' element={<UnauthorizedPage />} />
<Route path='/error/network' element={<NetworkErrorPage />} />
<Route path='/error/server' element={<ServerErrorPage />} />
<Route path='/error/timeout' element={<NetworkErrorPage />} />
<Route path='/error' element={<ErrorPage />} />
{/* 404 catch-all route - must be last */}
<Route path='*' element={<NotFoundPage />} />
</Routes>
</div>
</Router>
</RouteSuspense>
</Router>
</AuthProvider>
</AppErrorBoundary>
);
}

View File

@@ -0,0 +1,265 @@
import { useState } from 'react';
import {
Button,
Input,
Select,
Card,
CardHeader,
CardBody,
CardFooter,
Badge,
Alert,
type SelectOption
} from './ui';
export function UIShowcase() {
const [inputValue, setInputValue] = useState('');
const [selectValue, setSelectValue] = useState('');
const [showAlert, setShowAlert] = useState(true);
const selectOptions: SelectOption[] = [
{ value: 'option1', label: 'First Option' },
{ value: 'option2', label: 'Second Option' },
{ value: 'option3', label: 'Third Option' },
{ value: 'option4', label: 'Disabled Option', disabled: true },
];
return (
<div className="min-h-screen bg-background-primary p-6">
<div className="max-w-6xl mx-auto space-y-8">
{/* Header */}
<div className="text-center space-y-4">
<h1 className="text-4xl font-bold text-text-primary">UI Component Showcase</h1>
<p className="text-text-secondary">
Premium glassmorphism UI components using design tokens
</p>
</div>
{/* Alerts */}
{showAlert && (
<Alert
variant="info"
title="Component Showcase"
dismissible
onDismiss={() => setShowAlert(false)}
>
This showcase demonstrates all the UI primitive components with glassmorphism styling.
</Alert>
)}
{/* Buttons */}
<Card>
<CardHeader>
<h2 className="text-xl font-semibold text-text-primary">Buttons</h2>
</CardHeader>
<CardBody>
<div className="space-y-6">
{/* Button Variants */}
<div>
<h3 className="text-sm font-medium text-text-secondary mb-3">Variants</h3>
<div className="flex flex-wrap gap-3">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="gold">Gold</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Danger</Button>
</div>
</div>
{/* Button Sizes */}
<div>
<h3 className="text-sm font-medium text-text-secondary mb-3">Sizes</h3>
<div className="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
</div>
{/* Button States */}
<div>
<h3 className="text-sm font-medium text-text-secondary mb-3">States</h3>
<div className="flex flex-wrap gap-3">
<Button loading>Loading</Button>
<Button disabled>Disabled</Button>
<Button
iconLeft={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
}
>
With Icon
</Button>
</div>
</div>
</div>
</CardBody>
</Card>
{/* Form Inputs */}
<Card>
<CardHeader>
<h2 className="text-xl font-semibold text-text-primary">Form Inputs</h2>
</CardHeader>
<CardBody>
<div className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Input
label="Email Address"
placeholder="Enter your email"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
helperText="We'll never share your email"
/>
<Input
label="Password"
type="password"
placeholder="Enter password"
iconLeft={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
}
/>
</div>
<Input
label="Error Example"
placeholder="This field has an error"
error="This field is required"
/>
<Select
label="Select an Option"
options={selectOptions}
value={selectValue}
onChange={(value) => setSelectValue(value as string)}
placeholder="Choose an option..."
helperText="Select from the available options"
/>
</div>
</CardBody>
</Card>
{/* Badges */}
<Card>
<CardHeader>
<h2 className="text-xl font-semibold text-text-primary">Badges</h2>
</CardHeader>
<CardBody>
<div className="space-y-6">
<div>
<h3 className="text-sm font-medium text-text-secondary mb-3">Variants</h3>
<div className="flex flex-wrap gap-3">
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="error">Error</Badge>
<Badge variant="info">Info</Badge>
<Badge variant="neutral">Neutral</Badge>
<Badge variant="gold">Gold</Badge>
</div>
</div>
<div>
<h3 className="text-sm font-medium text-text-secondary mb-3">With Dots</h3>
<div className="flex flex-wrap gap-3">
<Badge variant="success" dot>Online</Badge>
<Badge variant="warning" dot>Pending</Badge>
<Badge variant="error" dot>Offline</Badge>
</div>
</div>
<div>
<h3 className="text-sm font-medium text-text-secondary mb-3">Removable</h3>
<div className="flex flex-wrap gap-3">
<Badge variant="info" removable onRemove={() => { /* removed */ }}>
Removable Badge
</Badge>
</div>
</div>
</div>
</CardBody>
</Card>
{/* Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<Card variant="default">
<CardHeader>
<h3 className="text-lg font-medium text-text-primary">Default Card</h3>
</CardHeader>
<CardBody>
<p className="text-text-secondary">
This is a default card with glassmorphism styling.
</p>
</CardBody>
<CardFooter>
<Button size="sm">Action</Button>
</CardFooter>
</Card>
<Card variant="elevated" elevation="lg">
<CardHeader>
<h3 className="text-lg font-medium text-text-primary">Elevated Card</h3>
</CardHeader>
<CardBody>
<p className="text-text-secondary">
This card has higher elevation with enhanced shadows.
</p>
</CardBody>
</Card>
<Card
clickable
onClick={() => { /* card clicked */ }}
className="cursor-pointer"
>
<CardBody>
<h3 className="text-lg font-medium text-text-primary mb-2">Clickable Card</h3>
<p className="text-text-secondary">
This card is clickable and will trigger an action.
</p>
</CardBody>
</Card>
</div>
{/* Alerts */}
<Card>
<CardHeader>
<h2 className="text-xl font-semibold text-text-primary">Alerts</h2>
</CardHeader>
<CardBody>
<div className="space-y-4">
<Alert variant="success" title="Success!">
Your action was completed successfully.
</Alert>
<Alert variant="warning" title="Warning">
Please review your information before proceeding.
</Alert>
<Alert variant="error" title="Error">
There was an error processing your request.
</Alert>
<Alert
variant="info"
title="Information"
actions={
<div className="flex gap-2">
<Button size="sm" variant="ghost">Dismiss</Button>
<Button size="sm">Learn More</Button>
</div>
}
>
Here&apos;s some important information you should know.
</Alert>
</div>
</CardBody>
</Card>
</div>
</div>
);
}

View File

@@ -1,5 +1,8 @@
import { motion } from 'framer-motion';
import { BarChart3, DollarSign, Users, Calendar } from 'lucide-react';
import { BarChart3, DollarSign, Users, Calendar, Plus } from 'lucide-react';
import { Button } from '../components/ui/Button';
import { Card, CardBody } from '../components/ui/Card';
export function DashboardPage() {
const stats = [
@@ -7,110 +10,148 @@ export function DashboardPage() {
label: 'Total Revenue',
value: '$12,450',
icon: DollarSign,
color: 'text-green-400',
change: '+12%',
changeType: 'positive' as const,
},
{
label: 'Tickets Sold',
value: '1,234',
icon: Users,
color: 'text-blue-400',
change: '+8%',
changeType: 'positive' as const,
},
{
label: 'Active Events',
value: '8',
icon: Calendar,
color: 'text-purple-400',
change: '+2',
changeType: 'positive' as const,
},
{
label: 'Growth Rate',
value: '+23%',
icon: BarChart3,
color: 'text-indigo-400',
change: '+5%',
changeType: 'positive' as const,
},
];
return (
<div className='min-h-screen p-8'>
<div className='mx-auto max-w-7xl'>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className='mb-8'
>
<h1 className='mb-2 text-4xl font-bold text-white'>Dashboard</h1>
<p className='text-white/70'>
Overview of your events and performance
</p>
</motion.div>
const recentEvents = [
{ name: 'Summer Gala', status: 'Active', attendees: 150 },
{ name: 'Wedding Reception', status: 'Active', attendees: 80 },
{ name: 'Corporate Event', status: 'Draft', attendees: 0 },
];
<div className='mb-8 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4'>
{stats.map((stat, index) => (
return (
<div className="space-y-8">
{/* Stats grid */}
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4">
{stats.map((stat, index) => {
const Icon = stat.icon;
return (
<motion.div
key={stat.label}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: index * 0.1 }}
className='glass rounded-2xl p-6'
>
<div className='mb-2 flex items-center justify-between'>
<stat.icon className={`h-8 w-8 ${stat.color}`} />
<span className={`text-2xl font-bold ${stat.color}`}>
{stat.value}
</span>
</div>
<p className='text-sm text-white/70'>{stat.label}</p>
</motion.div>
))}
</div>
<div className='grid grid-cols-1 gap-6 lg:grid-cols-2'>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
className='glass rounded-2xl p-6'
>
<h2 className='mb-4 text-2xl font-semibold text-white'>
Recent Events
</h2>
<div className='space-y-4'>
{['Summer Gala', 'Wedding Reception', 'Corporate Event'].map(
event => (
<div
key={event}
className='flex items-center justify-between rounded-lg bg-white/5 p-4'
>
<span className='text-white'>{event}</span>
<span className='text-white/70'>Active</span>
<Card className="h-full">
<CardBody className="p-6">
<div className="flex items-center justify-between mb-4">
<div className="p-2 bg-gold-100 dark:bg-gold-900/20 rounded-lg">
<Icon className="h-6 w-6 text-gold-600 dark:text-gold-400" />
</div>
<span className="text-sm font-medium text-green-600 dark:text-green-400">
{stat.change}
</span>
</div>
)
)}
</div>
</motion.div>
<div className="space-y-1">
<p className="text-2xl font-bold text-slate-900 dark:text-slate-100">
{stat.value}
</p>
<p className="text-sm text-slate-600 dark:text-slate-400">
{stat.label}
</p>
</div>
</CardBody>
</Card>
</motion.div>
);
})}
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.6 }}
className='glass rounded-2xl p-6'
>
<h2 className='mb-4 text-2xl font-semibold text-white'>
Quick Actions
</h2>
<div className='space-y-3'>
<button className='w-full rounded-lg bg-gradient-to-r from-blue-500 to-purple-600 p-3 font-semibold text-white transition-all duration-200 hover:from-blue-600 hover:to-purple-700'>
Create New Event
</button>
<button className='glass w-full rounded-lg p-3 font-semibold text-white transition-all duration-200 hover:bg-white/20'>
View Analytics
</button>
<button className='glass w-full rounded-lg p-3 font-semibold text-white transition-all duration-200 hover:bg-white/20'>
Manage Attendees
</button>
</div>
</motion.div>
</div>
{/* Main content grid */}
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
{/* Recent Events */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
>
<Card>
<CardBody className="p-6">
<h2 className="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-6">
Recent Events
</h2>
<div className="space-y-4">
{recentEvents.map((event) => (
<div
key={event.name}
className="flex items-center justify-between p-4 rounded-lg
bg-slate-50 dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700"
>
<div className="flex-1">
<p className="font-medium text-slate-900 dark:text-slate-100">
{event.name}
</p>
<p className="text-sm text-slate-600 dark:text-slate-400">
{event.attendees} attendees
</p>
</div>
<div className="flex items-center space-x-3">
<span className={`px-2 py-1 text-xs font-medium rounded-full ${
event.status === 'Active'
? 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400'
: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400'
}`}>
{event.status}
</span>
</div>
</div>
))}
</div>
</CardBody>
</Card>
</motion.div>
{/* Quick Actions */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.6 }}
>
<Card>
<CardBody className="p-6">
<h2 className="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-6">
Quick Actions
</h2>
<div className="space-y-4">
<Button variant="primary" size="lg" className="w-full justify-center">
<Plus className="h-5 w-5 mr-2" />
Create New Event
</Button>
<Button variant="secondary" size="lg" className="w-full justify-center">
<BarChart3 className="h-5 w-5 mr-2" />
View Analytics
</Button>
<Button variant="ghost" size="lg" className="w-full justify-center">
<Users className="h-5 w-5 mr-2" />
Manage Attendees
</Button>
</div>
</CardBody>
</Card>
</motion.div>
</div>
</div>
);

View File

@@ -1,5 +1,9 @@
import { motion } from 'framer-motion';
import { Calendar, MapPin, Users, Clock } from 'lucide-react';
import { Calendar, MapPin, Users, Clock, Plus, Edit, Eye } from 'lucide-react';
import { Badge } from '../components/ui/Badge';
import { Button } from '../components/ui/Button';
import { Card, CardBody } from '../components/ui/Card';
export function EventsPage() {
const events = [
@@ -10,7 +14,7 @@ export function EventsPage() {
time: '7:00 PM',
location: 'Grand Ballroom',
attendees: 150,
status: 'active',
status: 'active' as const,
},
{
id: 2,
@@ -19,7 +23,7 @@ export function EventsPage() {
time: '5:30 PM',
location: 'Garden Pavilion',
attendees: 200,
status: 'active',
status: 'active' as const,
},
{
id: 3,
@@ -28,85 +32,94 @@ export function EventsPage() {
time: '6:00 PM',
location: 'Conference Center',
attendees: 80,
status: 'draft',
status: 'draft' as const,
},
];
return (
<div className='min-h-screen p-8'>
<div className='mx-auto max-w-7xl'>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className='mb-8 flex items-center justify-between'
>
<div>
<h1 className='mb-2 text-4xl font-bold text-white'>Events</h1>
<p className='text-white/70'>
Manage your events and track performance
</p>
</div>
<button className='transform rounded-lg bg-gradient-to-r from-blue-500 to-purple-600 px-6 py-3 font-semibold text-white transition-all duration-200 hover:scale-105 hover:from-blue-600 hover:to-purple-700'>
Create Event
</button>
</motion.div>
<div className='grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3'>
{events.map((event, index) => (
<motion.div
key={event.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: index * 0.1 }}
className='glass cursor-pointer rounded-2xl p-6 transition-all duration-200 hover:bg-white/15'
>
<div className='mb-4 flex items-start justify-between'>
<h3 className='text-xl font-semibold text-white'>
{event.title}
</h3>
<span
className={`rounded-full px-3 py-1 text-xs font-medium ${
event.status === 'active'
? 'bg-green-500/20 text-green-400'
: 'bg-yellow-500/20 text-yellow-400'
}`}
>
{event.status}
</span>
</div>
<div className='mb-6 space-y-3'>
<div className='flex items-center text-white/70'>
<Calendar className='mr-2 h-4 w-4' />
<span>{event.date}</span>
</div>
<div className='flex items-center text-white/70'>
<Clock className='mr-2 h-4 w-4' />
<span>{event.time}</span>
</div>
<div className='flex items-center text-white/70'>
<MapPin className='mr-2 h-4 w-4' />
<span>{event.location}</span>
</div>
<div className='flex items-center text-white/70'>
<Users className='mr-2 h-4 w-4' />
<span>{event.attendees} attendees</span>
</div>
</div>
<div className='flex space-x-2'>
<button className='flex-1 rounded-lg bg-white/10 px-4 py-2 font-medium text-white transition-all duration-200 hover:bg-white/20'>
Edit
</button>
<button className='flex-1 rounded-lg bg-blue-500/20 px-4 py-2 font-medium text-blue-400 transition-all duration-200 hover:bg-blue-500/30'>
View
</button>
</div>
</motion.div>
))}
</div>
<div className="space-y-8">
{/* Action bar */}
<div className="flex justify-end">
<Button variant="primary" size="lg">
<Plus className="h-5 w-5 mr-2" />
Create Event
</Button>
</div>
{/* Events grid */}
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{events.map((event, index) => (
<motion.div
key={event.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: index * 0.1 }}
>
<Card className="h-full cursor-pointer hover:shadow-lg transition-shadow duration-200">
<CardBody className="p-6">
<div className="flex items-start justify-between mb-4">
<h3 className="text-xl font-semibold text-slate-900 dark:text-slate-100 line-clamp-2">
{event.title}
</h3>
<Badge
variant={event.status === 'active' ? 'success' : 'warning'}
className="ml-2 flex-shrink-0"
>
{event.status}
</Badge>
</div>
<div className="space-y-3 mb-6">
<div className="flex items-center text-slate-600 dark:text-slate-400">
<Calendar className="mr-3 h-4 w-4 flex-shrink-0" />
<span className="text-sm">{event.date}</span>
</div>
<div className="flex items-center text-slate-600 dark:text-slate-400">
<Clock className="mr-3 h-4 w-4 flex-shrink-0" />
<span className="text-sm">{event.time}</span>
</div>
<div className="flex items-center text-slate-600 dark:text-slate-400">
<MapPin className="mr-3 h-4 w-4 flex-shrink-0" />
<span className="text-sm">{event.location}</span>
</div>
<div className="flex items-center text-slate-600 dark:text-slate-400">
<Users className="mr-3 h-4 w-4 flex-shrink-0" />
<span className="text-sm">{event.attendees} attendees</span>
</div>
</div>
<div className="flex space-x-2">
<Button variant="ghost" size="sm" className="flex-1">
<Edit className="h-4 w-4 mr-1" />
Edit
</Button>
<Button variant="secondary" size="sm" className="flex-1">
<Eye className="h-4 w-4 mr-1" />
View
</Button>
</div>
</CardBody>
</Card>
</motion.div>
))}
</div>
{/* Empty state when no events */}
{events.length === 0 && (
<div className="text-center py-12">
<Calendar className="h-12 w-12 mx-auto text-slate-400 mb-4" />
<h3 className="text-lg font-medium text-slate-900 dark:text-slate-100 mb-2">
No events yet
</h3>
<p className="text-slate-600 dark:text-slate-400 mb-6">
Get started by creating your first event
</p>
<Button variant="primary">
<Plus className="h-5 w-5 mr-2" />
Create Your First Event
</Button>
</div>
)}
</div>
);
}

View File

@@ -1,84 +1,180 @@
import { motion } from 'framer-motion';
import { Ticket, Calendar, Users } from 'lucide-react';
import { Link } from 'react-router-dom';
import { ArrowRight, Calendar, Users, BarChart3, Zap } from 'lucide-react';
import { Button } from '../components/ui/Button';
import { Card, CardHeader, CardBody } from '../components/ui/Card';
/**
* HomePage component - Public landing page
*
* Features:
* - Hero section with branding
* - Feature highlights
* - Call-to-action buttons
* - Responsive design with glassmorphism theme
*/
export function HomePage() {
const features = [
{
icon: Calendar,
title: 'Event Management',
description: 'Create and manage events with our intuitive dashboard.',
},
{
icon: Users,
title: 'Customer Insights',
description: 'Track attendees and gain valuable insights about your audience.',
},
{
icon: BarChart3,
title: 'Analytics',
description: 'Monitor ticket sales and revenue with detailed analytics.',
},
{
icon: Zap,
title: 'Fast & Reliable',
description: 'Quick setup and reliable performance for all event sizes.',
},
];
return (
<div className='flex min-h-screen items-center justify-center p-8'>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className='mx-auto max-w-4xl text-center'
>
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
className='mb-6 bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-6xl font-bold text-transparent text-white'
>
Black Canyon Tickets
</motion.h1>
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
{/* Navigation */}
<nav className="border-b border-slate-200 dark:border-slate-700 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center">
<div className="h-8 w-8 bg-gradient-to-br from-gold-400 to-gold-600 rounded-lg
flex items-center justify-center mr-3">
<Calendar className="h-5 w-5 text-white" />
</div>
<span className="text-xl font-bold text-slate-900 dark:text-slate-100">
Black Canyon Tickets
</span>
</div>
<div className="flex items-center space-x-4">
<Link to="/login">
<Button variant="ghost">
Sign In
</Button>
</Link>
<Link to="/login">
<Button>
Get Started
</Button>
</Link>
</div>
</div>
</div>
</nav>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
className='mb-12 text-xl text-white/80'
>
Premium event ticketing platform with beautiful glassmorphism design
</motion.p>
{/* Hero Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-5xl sm:text-6xl font-bold text-slate-900 dark:text-slate-100 mb-6">
Premium Ticketing for{' '}
<span className="bg-gradient-to-r from-gold-400 to-gold-600 bg-clip-text text-transparent">
Upscale Events
</span>
</h1>
<p className="text-xl text-slate-600 dark:text-slate-400 mb-8 max-w-2xl mx-auto">
Black Canyon Tickets is the self-service ticketing platform designed specifically for
high-end venues. Manage dance performances, weddings, galas, and more with elegance.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link to="/login">
<Button size="lg" className="w-full sm:w-auto">
Start Your Free Trial
<ArrowRight className="ml-2 h-5 w-5" />
</Button>
</Link>
<Link to="/showcase">
<Button variant="ghost" size="lg" className="w-full sm:w-auto">
View Demo
</Button>
</Link>
</div>
</div>
</section>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.6 }}
className='mb-12 grid grid-cols-1 gap-8 md:grid-cols-3'
>
<div className='glass rounded-2xl p-6 text-center'>
<Ticket className='mx-auto mb-4 h-12 w-12 text-blue-400' />
<h3 className='mb-2 text-xl font-semibold text-white'>
Premium Tickets
</h3>
<p className='text-white/70'>
Beautiful ticket designs for upscale events
{/* Features Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<h2 className="text-3xl font-bold text-slate-900 dark:text-slate-100 mb-4">
Everything you need to succeed
</h2>
<p className="text-lg text-slate-600 dark:text-slate-400 max-w-2xl mx-auto">
Our platform provides all the tools you need to create, manage, and analyze
your premium events.
</p>
</div>
<div className='glass rounded-2xl p-6 text-center'>
<Calendar className='mx-auto mb-4 h-12 w-12 text-purple-400' />
<h3 className='mb-2 text-xl font-semibold text-white'>
Event Management
</h3>
<p className='text-white/70'>
Comprehensive tools for event organizers
</p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{features.map((feature, index) => (
<Card
key={index}
className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-md border-slate-200/60 dark:border-slate-700/60
hover:bg-white/90 dark:hover:bg-slate-800/90 transition-all duration-200"
>
<CardHeader>
<div className="h-12 w-12 bg-gradient-to-br from-gold-400 to-gold-600 rounded-lg
flex items-center justify-center mb-4">
<feature.icon className="h-6 w-6 text-white" />
</div>
<h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100">
{feature.title}
</h3>
</CardHeader>
<CardBody>
<p className="text-slate-600 dark:text-slate-400">
{feature.description}
</p>
</CardBody>
</Card>
))}
</div>
</div>
</section>
<div className='glass rounded-2xl p-6 text-center'>
<Users className='mx-auto mb-4 h-12 w-12 text-indigo-400' />
<h3 className='mb-2 text-xl font-semibold text-white'>
Guest Experience
</h3>
<p className='text-white/70'>
Seamless check-in and attendee management
</p>
{/* CTA Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto">
<Card className="bg-gradient-to-r from-gold-400 to-gold-600 border-0 text-white">
<CardBody className="p-12 text-center">
<h2 className="text-3xl font-bold mb-4">
Ready to elevate your events?
</h2>
<p className="text-xl mb-8 text-gold-100">
Join the premium venues that trust Black Canyon Tickets for their most important events.
</p>
<Link to="/login">
<Button
size="lg"
className="bg-white text-gold-600 hover:bg-slate-50 border-white hover:border-slate-100"
>
Get Started Today
<ArrowRight className="ml-2 h-5 w-5" />
</Button>
</Link>
</CardBody>
</Card>
</div>
</section>
{/* Footer */}
<footer className="border-t border-slate-200 dark:border-slate-700 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="text-center text-slate-600 dark:text-slate-400">
<p>&copy; 2024 Black Canyon Tickets. All rights reserved.</p>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.8 }}
className='space-x-4'
>
<button className='transform rounded-lg bg-gradient-to-r from-blue-500 to-purple-600 px-8 py-3 font-semibold text-white transition-all duration-200 hover:scale-105 hover:from-blue-600 hover:to-purple-700'>
Get Started
</button>
<button className='glass rounded-lg px-8 py-3 font-semibold text-white transition-all duration-200 hover:bg-white/20'>
Learn More
</button>
</motion.div>
</motion.div>
</div>
</footer>
</div>
);
}
}