Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9002d79
fix(mobile): improve auth page mobile styling with proper margins and…
JacksonR64 Jun 19, 2025
f309030
fix(calendar): improve add to calendar card responsive design and layout
JacksonR64 Jun 19, 2025
9376854
feat(calendar): move disconnect to user dropdown and improve UX
JacksonR64 Jun 19, 2025
daf5645
feat(nav): add admin/staff role badges to navigation bar
JacksonR64 Jun 19, 2025
cc02d83
fix(refund): correct price display showing amounts 100x larger
JacksonR64 Jun 19, 2025
da3da8a
feat(nav): restrict Create Event to staff/admin and reorder navigation
JacksonR64 Jun 19, 2025
7017712
feat(nav): implement optimistic UI for auth loading state
JacksonR64 Jun 19, 2025
1e5c95b
feat(cards): improve event card description consistency and layout
JacksonR64 Jun 19, 2025
5f60538
fix(auth): improve authentication session handling and resolve redire…
JacksonR64 Jun 19, 2025
075265d
fix(typescript): resolve boolean type assignment in middleware
JacksonR64 Jun 19, 2025
2122c6b
fix(e2e): resolve CI pipeline failures for E2E and smoke tests
JacksonR64 Jun 19, 2025
e7dc982
fix(mobile): disable zoom and horizontal scrolling for better UX
JacksonR64 Jun 20, 2025
4603c05
feat(events): add Free and Soon badges with improved color scheme
JacksonR64 Jun 20, 2025
61cf4b6
fix(ui): improve dark mode compatibility and navigation layout
JacksonR64 Jun 20, 2025
84fb84b
refactor(events): improve event detail layout and reduce redundancy
JacksonR64 Jun 20, 2025
1564510
feat(homepage): implement past events toggle functionality
JacksonR64 Jun 20, 2025
d6877c4
feat(forms): enhance event creation form layout and usability
JacksonR64 Jun 20, 2025
7c091f9
chore: remove unused favicon and add cursor ignore file
JacksonR64 Jun 20, 2025
80e5b5a
fix(ui): standardize logo size across navigation and footer
JacksonR64 Jun 20, 2025
fa4e59c
Merge branch 'main' into feat/past-events-toggle
JacksonR64 Jun 20, 2025
0a885f9
fix(lint): remove unused imports and variables in EventForm
JacksonR64 Jun 20, 2025
601360e
fix(syntax): resolve JSX parsing error in EventForm component
JacksonR64 Jun 20, 2025
7262300
fix(accessibility): resolve lighthouse accessibility issues to improv…
JacksonR64 Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
Binary file removed app/favicon.ico
Binary file not shown.
2 changes: 2 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -159,6 +160,7 @@ body {
html {
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
overflow-x: hidden;
}

/* Improve tap highlighting */
Expand Down
10 changes: 9 additions & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,22 @@ async function getEventsData(): Promise<EventData[]> {
// 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 (
<div className="min-h-screen bg-background">
<HomePageClient
featuredEvents={featuredEvents}
nonFeaturedEvents={nonFeaturedEvents}
upcomingEvents={upcomingEvents}
pastEvents={pastEvents}
/>
</div>
);
Expand Down
26 changes: 22 additions & 4 deletions app/staff/events/create/StaffEventCreateClient.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -16,9 +20,23 @@ export default function StaffEventCreateClient() {
}

return (
<EventForm
onSuccess={handleSuccess}
onCancel={handleCancel}
/>
<>
<div className="mb-4 flex justify-end">
<Button
type="button"
variant="outline"
onClick={() => setShowPreview(!showPreview)}
className="flex items-center gap-2"
>
{showPreview ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
{showPreview ? 'Hide Preview' : 'Show Preview'}
</Button>
</div>
<EventForm
onSuccess={handleSuccess}
onCancel={handleCancel}
showPreview={showPreview}
/>
</>
)
}
8 changes: 5 additions & 3 deletions app/staff/events/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export default async function StaffEventCreatePage() {
return (
<div className="min-h-screen bg-background">
<div className="max-w-4xl mx-auto py-8 px-4">
<div className="mb-8">
<h1 className="text-3xl font-bold text-foreground">Create New Event</h1>
<p className="mt-2 text-muted-foreground">Create and manage your event details</p>
<div className="mb-6 flex items-start justify-between">
<div>
<h1 className="text-3xl font-bold text-foreground">Create New Event</h1>
<p className="mt-2 text-muted-foreground">Create and manage your event details</p>
</div>
</div>
<StaffEventCreateClient />
</div>
Expand Down
4 changes: 2 additions & 2 deletions components/dashboard/UserDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,8 @@ export default function UserDashboard({ user }: UserDashboardProps) {
<div className="max-w-4xl mx-auto p-6">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 mb-2">My Dashboard</h1>
<p className="text-gray-600">
<h1 className="text-3xl font-bold text-foreground mb-2">My Dashboard</h1>
<p className="text-muted-foreground">
Welcome back! Here are your tickets, orders, and event RSVPs.
</p>
</div>
Expand Down
96 changes: 78 additions & 18 deletions components/events/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ interface CardComponentProps {
isUpcoming: boolean;
hasPrice: boolean;
lowestPrice: number;
isSoon: boolean;
}

// Safe Image component with error handling
Expand Down Expand Up @@ -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,
Expand All @@ -138,7 +145,8 @@ export function EventCard({
spotsRemaining,
isUpcoming,
hasPrice,
lowestPrice
lowestPrice,
isSoon
};

// Render based on style
Expand All @@ -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<CardComponentProps>) {
return (
<Card
size={size}
Expand Down Expand Up @@ -192,13 +200,23 @@ function DefaultCard({ event, size, featured, showImage, className, onClick, spo
{event.title}
</CardTitle>
<div className="flex gap-2">
{!event.is_paid && isUpcoming && (
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">
Free
</span>
)}
{event.is_paid && (
<span className="text-xs bg-secondary text-secondary-foreground px-2 py-1 rounded-full">
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full">
{hasPrice ? formatPrice(lowestPrice) : 'Paid'}
</span>
)}
{isSoon && (
<span className="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded-full">
Soon
</span>
)}
{!isUpcoming && (
<span className="text-xs bg-muted text-muted-foreground px-2 py-1 rounded-full">
<span className="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded-full">
Past
</span>
)}
Expand Down Expand Up @@ -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<CardComponentProps>) {
return (
<Card
variant="outlined"
Expand Down Expand Up @@ -278,13 +296,23 @@ function PreviewListCard({ event, className, onClick, isUpcoming, hasPrice, lowe
{event.title}
</h3>
<div className="flex gap-1 flex-shrink-0">
{!event.is_paid && isUpcoming && (
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">
Free
</span>
)}
{event.is_paid && (
<span className="text-xs bg-secondary text-secondary-foreground px-2 py-1 rounded-full">
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full">
{hasPrice ? formatPrice(lowestPrice) : 'Paid'}
</span>
)}
{isSoon && (
<span className="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded-full">
Soon
</span>
)}
{!isUpcoming && (
<span className="text-xs bg-muted text-muted-foreground px-2 py-1 rounded-full">
<span className="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded-full">
Past
</span>
)}
Expand Down Expand Up @@ -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<CardComponentProps>) {
return (
<Card
variant="default"
Expand Down Expand Up @@ -350,13 +378,23 @@ function FullListCard({ event, className, onClick, spotsRemaining, isUpcoming, h
{event.title}
</CardTitle>
<div className="flex gap-2">
{!event.is_paid && isUpcoming && (
<span className="text-sm bg-green-100 text-green-800 px-3 py-1 rounded-full font-medium">
Free Event
</span>
)}
{event.is_paid && (
<span className="text-sm bg-secondary text-secondary-foreground px-3 py-1 rounded-full font-medium">
<span className="text-sm bg-blue-100 text-blue-800 px-3 py-1 rounded-full font-medium">
{hasPrice ? formatPrice(lowestPrice) : 'Paid Event'}
</span>
)}
{isSoon && (
<span className="text-sm bg-orange-100 text-orange-800 px-3 py-1 rounded-full font-medium">
Soon
</span>
)}
{!isUpcoming && (
<span className="text-sm bg-muted text-muted-foreground px-3 py-1 rounded-full">
<span className="text-sm bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full">
Past Event
</span>
)}
Expand Down Expand Up @@ -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<CardComponentProps>) {
return (
<Card
size="sm"
Expand All @@ -455,11 +493,21 @@ function CompactCard({ event, className, onClick, hasPrice, lowestPrice }: CardC
</div>
</div>
<div className="flex items-center gap-2 ml-3">
{!event.is_paid && isUpcoming && (
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">
Free
</span>
)}
{event.is_paid && (
<span className="text-xs bg-secondary text-secondary-foreground px-2 py-1 rounded">
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded">
{hasPrice ? formatPrice(lowestPrice) : 'Paid'}
</span>
)}
{isSoon && (
<span className="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded">
Soon
</span>
)}
<ExternalLink className="w-3 h-3 text-muted-foreground group-hover:text-foreground" />
</div>
</div>
Expand All @@ -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<CardComponentProps>) {
const eventDate = new Date(event.start_time);
const day = eventDate.getDate();
const month = eventDate.toLocaleDateString('en-US', { month: 'short' });
Expand All @@ -492,11 +540,23 @@ function TimelineCard({ event, className, onClick, hasPrice, lowestPrice }: Card
<h3 className="font-semibold text-base text-foreground group-hover:text-blue-600 transition-colors line-clamp-2 min-h-[3rem] leading-relaxed">
{event.title}
</h3>
{event.is_paid && (
<span className="text-xs bg-secondary text-secondary-foreground px-2 py-1 rounded-full ml-2">
{hasPrice ? formatPrice(lowestPrice) : 'Paid'}
</span>
)}
<div className="flex gap-1 ml-2">
{!event.is_paid && isUpcoming && (
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">
Free
</span>
)}
{event.is_paid && (
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full">
{hasPrice ? formatPrice(lowestPrice) : 'Paid'}
</span>
)}
{isSoon && (
<span className="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded-full">
Soon
</span>
)}
</div>
</div>

<p className="text-sm text-gray-600 mb-2 line-clamp-2 min-h-[2.5rem] leading-relaxed">
Expand Down
Loading
Loading