Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
60faf2e
EMS-74: Replace hardcoded dashboard stats with real database data and…
Buffden Nov 3, 2025
40d8d50
EMS-74: Add backend pagination, search, and filters for user management
Buffden Nov 3, 2025
c24dc95
EMS-74: Add attendance statistics endpoint excluding admins and speakers
Buffden Nov 3, 2025
5767f3a
EMS-74: Update admin API client with pagination and attendance stats
Buffden Nov 3, 2025
d091c52
EMS-74: Add ref forwarding support to Input component
Buffden Nov 3, 2025
dc9a015
EMS-74: Implement backend pagination and search for user management
Buffden Nov 3, 2025
b2187c6
EMS-74: Add event status distribution endpoint for reports
Buffden Nov 3, 2025
979bc5a
EMS-74: Add top performing events endpoint for reports
Buffden Nov 3, 2025
25404ee
EMS-74: Add user growth trend endpoint for reports
Buffden Nov 3, 2025
d1e848e
EMS-74: Add getReportsData method to admin API client
Buffden Nov 3, 2025
83bfa25
EMS-74: Replace hardcoded data in reports page with real database que…
Buffden Nov 3, 2025
60e964b
EMS-69: Booking Service & Speaker Service Fix
ashwin-athappan Nov 3, 2025
26e3d17
Merge branch 'EMS-74-Implement-Reporting-Analytics' into EMS-69-BE-FE…
ashwin-athappan Nov 3, 2025
1ba1ce9
EMS-69: Speaker Join for Events
ashwin-athappan Nov 3, 2025
dc092a5
EMS-74: Add backend validation for event expiry in speaker attendance…
Buffden Nov 3, 2025
6c61bc1
EMS-74: Add server-side search, filtering, and pagination for speaker…
Buffden Nov 3, 2025
15efca2
EMS-74: Add server-side search and timeframe filtering for events
Buffden Nov 3, 2025
c21fe62
EMS-74: Update frontend API clients for search, filtering, and pagina…
Buffden Nov 3, 2025
d02f9d2
EMS-74: Add event expiry validation in LiveEventAuditorium component
Buffden Nov 3, 2025
b1d0e77
EMS-74: Implement event expiry checks, consistent UI, and remove expi…
Buffden Nov 3, 2025
c11285f
EMS-74: Update speaker components and hooks to use new paginated invi…
Buffden Nov 3, 2025
bfa7f97
EMS-74: Add visual separation between available and past events in ad…
Buffden Nov 3, 2025
01bcae1
EMS-74: Add visual separation between available and past events in sp…
Buffden Nov 3, 2025
782d225
EMS-74: Simplify attendee event cards and remove repetitive elements,…
Buffden Nov 3, 2025
314de50
Merge branch 'EMS-74-Implement-Reporting-Analytics' into EMS-69-BE-FE…
ashwin-athappan Nov 4, 2025
7cdd37d
EMS-69: Added seeding scripts
ashwin-athappan Nov 4, 2025
2fafb5e
EMS-69: User Dashboard Mock Data Replaced with actual Backend Data
ashwin-athappan Nov 4, 2025
fb4a728
EMS-69: Fixed TypeScript errors
ashwin-athappan Nov 4, 2025
2ee8100
EMS-69: Add Back Buttons in Dashboards
ashwin-athappan Nov 4, 2025
584c34c
EMS-69: Email Ticket to user via notification-service
ashwin-athappan Nov 4, 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
!.yarn/releases
!.yarn/versions

# python dependencies
**/.venv
**/*.pyc
# testing
/coverage

Expand Down
137 changes: 135 additions & 2 deletions ems-client/app/dashboard/admin/events/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,28 @@ function EventManagementPage() {
</Card>

{/* Events Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
{filteredEvents.map((event) => (
<div className="space-y-8">
{/* Available Events */}
{filteredEvents.filter(event => {
const now = new Date();
const eventEndDate = new Date(event.bookingEndDate);
return eventEndDate >= now && event.status !== EventStatus.CANCELLED && event.status !== EventStatus.COMPLETED;
}).length > 0 && (
<div>
<h2 className="text-xl font-semibold text-gray-800 dark:text-white mb-4 flex items-center gap-2">
<Calendar className="h-5 w-5 text-blue-600" />
Available Events ({filteredEvents.filter(event => {
const now = new Date();
const eventEndDate = new Date(event.bookingEndDate);
return eventEndDate >= now && event.status !== EventStatus.CANCELLED && event.status !== EventStatus.COMPLETED;
}).length})
</h2>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
{filteredEvents.filter(event => {
const now = new Date();
const eventEndDate = new Date(event.bookingEndDate);
return eventEndDate >= now && event.status !== EventStatus.CANCELLED && event.status !== EventStatus.COMPLETED;
}).map((event) => (
<Card key={event.id} className="border-slate-200 dark:border-slate-700 hover:shadow-lg transition-shadow">
<CardHeader>
<div className="flex items-start justify-between">
Expand Down Expand Up @@ -549,6 +569,119 @@ function EventManagementPage() {
</CardContent>
</Card>
))}
</div>
</div>
)}

{/* Past Events */}
{filteredEvents.filter(event => {
const now = new Date();
const eventEndDate = new Date(event.bookingEndDate);
return eventEndDate < now || event.status === EventStatus.CANCELLED || event.status === EventStatus.COMPLETED;
}).length > 0 && (
<div>
<h2 className="text-xl font-semibold text-gray-800 dark:text-white mb-4 flex items-center gap-2">
<AlertCircle className="h-5 w-5 text-gray-500" />
Past Events ({filteredEvents.filter(event => {
const now = new Date();
const eventEndDate = new Date(event.bookingEndDate);
return eventEndDate < now || event.status === EventStatus.CANCELLED || event.status === EventStatus.COMPLETED;
}).length})
</h2>
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
{filteredEvents.filter(event => {
const now = new Date();
const eventEndDate = new Date(event.bookingEndDate);
return eventEndDate < now || event.status === EventStatus.CANCELLED || event.status === EventStatus.COMPLETED;
}).map((event) => (
<Card key={event.id} className="border-slate-200 dark:border-slate-700 hover:shadow-lg transition-shadow opacity-75">
<CardHeader>
<div className="flex items-start justify-between">
<div className="flex-1">
<CardTitle className="text-lg font-semibold text-slate-900 dark:text-white mb-2">
{event.name}
</CardTitle>
<Button
variant="ghost"
size="sm"
className="mb-2 p-0 h-auto text-blue-600 hover:text-blue-800"
onClick={() => router.push(`/dashboard/admin/events/${event.id}`)}
>
View Details →
</Button>
<Badge className={statusColors[event.status]}>
{event.status.replace('_', ' ')}
</Badge>
</div>
<Button size="sm" variant="ghost">
<MoreHorizontal className="h-4 w-4" />
</Button>
</div>
</CardHeader>

<CardContent>
<p className="text-slate-600 dark:text-slate-400 text-sm mb-4 line-clamp-2">
{event.description}
</p>

{/* Event Details */}
<div className="space-y-3 mb-4">
<div className="flex items-center text-sm text-slate-600 dark:text-slate-400">
<MapPin className="h-4 w-4 mr-2" />
<span>{event.venue.name}</span>
</div>

<div className="flex items-center text-sm text-slate-600 dark:text-slate-400">
<Clock className="h-4 w-4 mr-2" />
<span>
{new Date(event.bookingStartDate).toLocaleDateString()} - {new Date(event.bookingEndDate).toLocaleDateString()}
</span>
</div>

<div className="flex items-center text-sm text-slate-600 dark:text-slate-400">
<Users className="h-4 w-4 mr-2" />
<span>
Capacity: {event.venue.capacity}
</span>
</div>
</div>

{/* Actions */}
<div className="flex flex-wrap gap-2">
<Button
size="sm"
variant="outline"
onClick={() => router.push(`/dashboard/admin/events/${event.id}`)}
>
<Eye className="h-4 w-4 mr-1" />
View
</Button>

<Button
size="sm"
variant="outline"
onClick={() => router.push(`/dashboard/admin/events/modify/${event.id}`)}
>
<Edit className="h-4 w-4 mr-1" />
Edit
</Button>

<Button
size="sm"
variant="destructive"
onClick={() => handleEventAction(event.id, 'delete')}
disabled={actionLoading === event.id}
>
<Trash2 className="h-4 w-4 mr-1" />
Delete
</Button>
</div>
</CardContent>
</Card>
))}
</div>
</div>
)}

{filteredEvents.length === 0 && !loading && (
<div className="col-span-full">
Expand Down
Loading