diff --git a/.cursorignore b/.cursorignore new file mode 100644 index 0000000..6f9f00f --- /dev/null +++ b/.cursorignore @@ -0,0 +1 @@ +# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv) diff --git a/app/favicon.ico b/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/app/favicon.ico and /dev/null differ diff --git a/app/globals.css b/app/globals.css index 7b94767..9cca00f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -108,6 +108,7 @@ body { background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb)); + overflow-x: hidden; } /* Custom scrollbar for better UX */ @@ -159,6 +160,7 @@ body { html { scroll-behavior: smooth; -webkit-overflow-scrolling: touch; + overflow-x: hidden; } /* Improve tap highlighting */ diff --git a/app/page.tsx b/app/page.tsx index 7074e19..b778e7b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -75,14 +75,22 @@ async function getEventsData(): Promise { // Main Page Component - Server Component that renders the full page export default async function HomePage() { const events = await getEventsData(); + const now = new Date(); + + // Separate events by featured status and time const featuredEvents = events.filter(event => event.featured); const nonFeaturedEvents = events.filter(event => !event.featured); + + // Separate non-featured events into upcoming and past + const upcomingEvents = nonFeaturedEvents.filter(event => new Date(event.start_time) >= now); + const pastEvents = nonFeaturedEvents.filter(event => new Date(event.start_time) < now); return (
); diff --git a/app/staff/events/create/StaffEventCreateClient.tsx b/app/staff/events/create/StaffEventCreateClient.tsx index 537696b..60f090f 100644 --- a/app/staff/events/create/StaffEventCreateClient.tsx +++ b/app/staff/events/create/StaffEventCreateClient.tsx @@ -1,10 +1,14 @@ 'use client' +import { useState } from 'react' import { useRouter } from 'next/navigation' +import { Button } from '@/components/ui/button' +import { Eye, EyeOff } from 'lucide-react' import EventForm from '@/components/events/EventForm' export default function StaffEventCreateClient() { const router = useRouter() + const [showPreview, setShowPreview] = useState(false) const handleSuccess = () => { // Redirect to the staff dashboard after successful creation @@ -16,9 +20,23 @@ export default function StaffEventCreateClient() { } return ( - + <> +
+ +
+ + ) } \ No newline at end of file diff --git a/app/staff/events/create/page.tsx b/app/staff/events/create/page.tsx index cdb4ea4..0979177 100644 --- a/app/staff/events/create/page.tsx +++ b/app/staff/events/create/page.tsx @@ -25,9 +25,11 @@ export default async function StaffEventCreatePage() { return (
-
-

Create New Event

-

Create and manage your event details

+
+
+

Create New Event

+

Create and manage your event details

+
diff --git a/components/dashboard/UserDashboard.tsx b/components/dashboard/UserDashboard.tsx index 3b94794..c3faa80 100644 --- a/components/dashboard/UserDashboard.tsx +++ b/components/dashboard/UserDashboard.tsx @@ -390,8 +390,8 @@ export default function UserDashboard({ user }: UserDashboardProps) {
{/* Header */}
-

My Dashboard

-

+

My Dashboard

+

Welcome back! Here are your tickets, orders, and event RSVPs.

diff --git a/components/events/EventCard.tsx b/components/events/EventCard.tsx index c5332ae..e204c19 100644 --- a/components/events/EventCard.tsx +++ b/components/events/EventCard.tsx @@ -62,6 +62,7 @@ interface CardComponentProps { isUpcoming: boolean; hasPrice: boolean; lowestPrice: number; + isSoon: boolean; } // Safe Image component with error handling @@ -127,6 +128,12 @@ export function EventCard({ const isUpcoming = new Date(event.start_time) > new Date(); const hasPrice = Boolean(event.is_paid && event.ticket_types && event.ticket_types.length > 0); const lowestPrice = hasPrice ? Math.min(...event.ticket_types!.map(t => t.price)) : 0; + + // Check if event is soon (within 7 days) + const eventDate = new Date(event.start_time); + const today = new Date(); + const daysDifference = Math.ceil((eventDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)); + const isSoon = isUpcoming && daysDifference <= 7 && daysDifference >= 0; const commonProps: CardComponentProps = { event, @@ -138,7 +145,8 @@ export function EventCard({ spotsRemaining, isUpcoming, hasPrice, - lowestPrice + lowestPrice, + isSoon }; // Render based on style @@ -157,7 +165,7 @@ export function EventCard({ } // Default Card Style (same as current homepage implementation) -function DefaultCard({ event, size, featured, showImage, className, onClick, spotsRemaining, isUpcoming, hasPrice, lowestPrice }: CardComponentProps) { +function DefaultCard({ event, size, featured, showImage, className, onClick, spotsRemaining, isUpcoming, hasPrice, lowestPrice, isSoon }: Readonly) { return (
+ {!event.is_paid && isUpcoming && ( + + Free + + )} {event.is_paid && ( - + {hasPrice ? formatPrice(lowestPrice) : 'Paid'} )} + {isSoon && ( + + Soon + + )} {!isUpcoming && ( - + Past )} @@ -250,7 +268,7 @@ function DefaultCard({ event, size, featured, showImage, className, onClick, spo } // Preview List Style - Compact horizontal layout for list views -function PreviewListCard({ event, className, onClick, isUpcoming, hasPrice, lowestPrice }: CardComponentProps) { +function PreviewListCard({ event, className, onClick, isUpcoming, hasPrice, lowestPrice, isSoon }: Readonly) { return (
+ {!event.is_paid && isUpcoming && ( + + Free + + )} {event.is_paid && ( - + {hasPrice ? formatPrice(lowestPrice) : 'Paid'} )} + {isSoon && ( + + Soon + + )} {!isUpcoming && ( - + Past )} @@ -316,7 +344,7 @@ function PreviewListCard({ event, className, onClick, isUpcoming, hasPrice, lowe } // Full List Style - Detailed view with all information -function FullListCard({ event, className, onClick, spotsRemaining, isUpcoming, hasPrice, lowestPrice }: CardComponentProps) { +function FullListCard({ event, className, onClick, spotsRemaining, isUpcoming, hasPrice, lowestPrice, isSoon }: Readonly) { return (
+ {!event.is_paid && isUpcoming && ( + + Free Event + + )} {event.is_paid && ( - + {hasPrice ? formatPrice(lowestPrice) : 'Paid Event'} )} + {isSoon && ( + + Soon + + )} {!isUpcoming && ( - + Past Event )} @@ -433,7 +471,7 @@ function FullListCard({ event, className, onClick, spotsRemaining, isUpcoming, h } // Compact Card Style - Minimal information for dense layouts -function CompactCard({ event, className, onClick, hasPrice, lowestPrice }: CardComponentProps) { +function CompactCard({ event, className, onClick, hasPrice, lowestPrice, isUpcoming, isSoon }: Readonly) { return (
+ {!event.is_paid && isUpcoming && ( + + Free + + )} {event.is_paid && ( - + {hasPrice ? formatPrice(lowestPrice) : 'Paid'} )} + {isSoon && ( + + Soon + + )}
@@ -468,7 +516,7 @@ function CompactCard({ event, className, onClick, hasPrice, lowestPrice }: CardC } // Timeline Card Style - Vertical timeline layout -function TimelineCard({ event, className, onClick, hasPrice, lowestPrice }: CardComponentProps) { +function TimelineCard({ event, className, onClick, hasPrice, lowestPrice, isUpcoming, isSoon }: Readonly) { const eventDate = new Date(event.start_time); const day = eventDate.getDate(); const month = eventDate.toLocaleDateString('en-US', { month: 'short' }); @@ -492,11 +540,23 @@ function TimelineCard({ event, className, onClick, hasPrice, lowestPrice }: Card

{event.title}

- {event.is_paid && ( - - {hasPrice ? formatPrice(lowestPrice) : 'Paid'} - - )} +
+ {!event.is_paid && isUpcoming && ( + + Free + + )} + {event.is_paid && ( + + {hasPrice ? formatPrice(lowestPrice) : 'Paid'} + + )} + {isSoon && ( + + Soon + + )} +

diff --git a/components/events/EventDetailClient.tsx b/components/events/EventDetailClient.tsx index 2efec88..95236d0 100644 --- a/components/events/EventDetailClient.tsx +++ b/components/events/EventDetailClient.tsx @@ -213,83 +213,74 @@ export function EventDetailClient({ event }: EventDetailClientProps) {

{/* Registration/Ticket Section */} {event.is_paid && ticketTypes.length > 0 ? ( - - -

Get Tickets

- - {checkoutStep === 'tickets' ? ( -
-
- -
+ checkoutStep === 'tickets' ? ( +
+
+ +
- {getTotalTickets() > 0 && ( -
-
- Total: - {formatPrice(getTotalPrice())} -
- + {getTotalTickets() > 0 && ( + + +
+ Total: + {formatPrice(getTotalPrice())}
- )} -
- ) : ( -
- - -
- { - console.log('Payment successful:', paymentIntentId) - // Handle success - could redirect or show success message - setCheckoutStep('tickets') - }} - onCancel={() => { - setCheckoutStep('tickets') - }} - /> -
-
+ + + )} - - - ) : ( - - -

RSVP

-
- + ) : ( +
+ + +
+ { + console.log('Payment successful:', paymentIntentId) + // Handle success - could redirect or show success message + setCheckoutStep('tickets') + }} + onCancel={() => { + setCheckoutStep('tickets') + }} />
- - +
+ ) + ) : ( +
+ +
)} {/* Event Stats */} diff --git a/components/events/EventForm.tsx b/components/events/EventForm.tsx index de843d7..c79d7eb 100644 --- a/components/events/EventForm.tsx +++ b/components/events/EventForm.tsx @@ -25,9 +25,7 @@ import { AlertCircle, Save, X, - Plus, - Eye, - EyeOff + Plus } from 'lucide-react' import { cn } from '@/lib/utils' @@ -60,6 +58,7 @@ interface EventFormProps { isEdit?: boolean onSuccess?: (eventId: string) => void onCancel?: () => void + showPreview?: boolean } const CATEGORIES = [ @@ -114,7 +113,6 @@ export default function EventForm({ eventId, isEdit = false, onSuccess, onCancel const [error, setError] = useState(null) const [validationErrors, setValidationErrors] = useState>({}) const [tagInput, setTagInput] = useState('') - const [showPreview, setShowPreview] = useState(false) // Load event data for editing const loadEventData = useCallback(async () => { @@ -384,30 +382,7 @@ export default function EventForm({ eventId, isEdit = false, onSuccess, onCancel } return ( -
- {/* Header */} -
-
-

- {isEdit ? 'Edit Event' : 'Create New Event'} -

-

- {isEdit ? 'Update your event details below' : 'Fill in the details below to create your event'} -

-
- -
- -
-
+
{error && ( @@ -416,7 +391,7 @@ export default function EventForm({ eventId, isEdit = false, onSuccess, onCancel )} -
+ {/* Basic Information */} @@ -425,27 +400,28 @@ export default function EventForm({ eventId, isEdit = false, onSuccess, onCancel Basic Information - -
+ +
- + handleInputChange('title', e.target.value)} - placeholder="Enter a compelling event title" + placeholder="Summer Food Truck Festival" className={cn(validationErrors.title && 'border-red-500')} /> {validationErrors.title && (

{validationErrors.title}

)} -
-

+

+

+ Keep it concise and engaging

60 ? "text-orange-600 font-medium" : "text-gray-400" + formData.title.length > 60 ? "text-orange-600 font-medium" : "text-muted-foreground" )}> {formData.title.length}/60

@@ -458,24 +434,24 @@ export default function EventForm({ eventId, isEdit = false, onSuccess, onCancel
- + handleInputChange('slug', e.target.value)} - placeholder="event-url-slug" + placeholder="summer-food-truck-festival" className={cn(validationErrors.slug && 'border-red-500')} /> {validationErrors.slug && (

{validationErrors.slug}

)} -

+

This will be part of your event URL

- + handleInputChange('short_description', e.target.value)} - placeholder="Brief one-line description (optional)" + placeholder="Local food trucks with diverse cuisines and live music" />
-

+

+ This appears in event listings and search results

- +