diff --git a/wordpress-dev/tests/e2e/event-summary.spec.ts b/wordpress-dev/tests/e2e/event-summary.spec.ts new file mode 100644 index 00000000..7ef171b4 --- /dev/null +++ b/wordpress-dev/tests/e2e/event-summary.spec.ts @@ -0,0 +1,171 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from './pages/LoginPage'; +import { DashboardPage } from './pages/DashboardPage'; + +test.describe('Event Summary Page', () => { + // Define test variables + const testTrainerUsername = 'test_trainer'; + const testTrainerPassword = 'Test123!'; + + // We'll need to figure out a test event ID during the test + let testEventId: string; + + test.beforeEach(async ({ page }) => { + // Log in before each test + const loginPage = new LoginPage(page); + await loginPage.navigate(); + await loginPage.login(testTrainerUsername, testTrainerPassword); + + // Navigate to dashboard to find an event to use for testing + const dashboardPage = new DashboardPage(page); + await dashboardPage.navigate(); + + // Find the first event in the dashboard and get its ID + // We'll extract the event ID from the "Summary" link's href + const summaryLink = page.locator('.column-actions a:has-text("Summary")').first(); + + // Check if there's at least one event + const linkCount = await summaryLink.count(); + if (linkCount === 0) { + // No events available for testing, we'll need to skip the tests + test.skip(true, 'No events available for testing'); + return; + } + + // Get the href attribute from the summary link + const summaryUrl = await summaryLink.getAttribute('href'); + + // Extract the event ID from the URL + if (summaryUrl) { + const match = summaryUrl.match(/event_id=(\d+)/); + if (match && match[1]) { + testEventId = match[1]; + } else { + test.skip(true, 'Could not extract event ID from summary link'); + } + } else { + test.skip(true, 'Summary link has no href attribute'); + } + }); + + test('should be accessible from dashboard', async ({ page }) => { + // Navigate to dashboard + const dashboardPage = new DashboardPage(page); + await dashboardPage.navigate(); + + // Find and click the first summary link + const summaryLink = page.locator('.column-actions a:has-text("Summary")').first(); + await expect(summaryLink).toBeVisible(); + await summaryLink.click(); + + // Verify we're on the event summary page + await expect(page).toHaveURL(/.*\/event-summary\/.*event_id=.*/); + await expect(page.locator('h1')).toContainText('Summary'); + }); + + test('should display event overview information', async ({ page }) => { + // Navigate directly to the event summary page + await page.goto(`/event-summary/?event_id=${testEventId}`); + + // Check for event overview section + await expect(page.locator('h2:has-text("Event Overview")')).toBeVisible(); + + // Check for basic event details + const detailsTable = page.locator('.hvac-details-table'); + await expect(detailsTable).toBeVisible(); + + // Check for specific fields + const dateRow = detailsTable.locator('tr', { hasText: 'Date & Time' }); + const statusRow = detailsTable.locator('tr', { hasText: 'Status' }); + + await expect(dateRow).toBeVisible(); + await expect(statusRow).toBeVisible(); + }); + + test('should display event statistics', async ({ page }) => { + // Navigate directly to the event summary page + await page.goto(`/event-summary/?event_id=${testEventId}`); + + // Check for statistics section + await expect(page.locator('h2:has-text("Event Statistics")')).toBeVisible(); + + // Check for statistics cards + const statsRow = page.locator('.hvac-stats-row'); + await expect(statsRow).toBeVisible(); + + // Look for specific metric cards + const totalTicketsCard = page.locator('.hvac-stat-card h3:has-text("Total Tickets")'); + const totalRevenueCard = page.locator('.hvac-stat-card h3:has-text("Total Revenue")'); + + await expect(totalTicketsCard).toBeVisible(); + await expect(totalRevenueCard).toBeVisible(); + }); + + test('should display ticket sales and attendees information', async ({ page }) => { + // Navigate directly to the event summary page + await page.goto(`/event-summary/?event_id=${testEventId}`); + + // Check for ticket sales section + await expect(page.locator('h2:has-text("Ticket Sales & Attendees")')).toBeVisible(); + + // The table might not be visible if there are no attendees, so check for either + // the table or the "No ticket sales" message + const attendeesTable = page.locator('.hvac-transactions-table'); + const noAttendeesMessage = page.locator('text=No ticket sales or attendees found'); + + const hasTable = await attendeesTable.count() > 0; + if (hasTable) { + // Check table headers + const attendeeHeader = attendeesTable.locator('th', { hasText: 'Attendee' }); + const emailHeader = attendeesTable.locator('th', { hasText: 'Email' }); + const ticketTypeHeader = attendeesTable.locator('th', { hasText: 'Ticket Type' }); + + await expect(attendeeHeader).toBeVisible(); + await expect(emailHeader).toBeVisible(); + await expect(ticketTypeHeader).toBeVisible(); + } else { + // Check for no attendees message + await expect(noAttendeesMessage).toBeVisible(); + } + }); + + test('should display event description', async ({ page }) => { + // Navigate directly to the event summary page + await page.goto(`/event-summary/?event_id=${testEventId}`); + + // Check for event description section + await expect(page.locator('h2:has-text("Event Description")')).toBeVisible(); + + // Check for description content + const descriptionContainer = page.locator('.hvac-event-description'); + await expect(descriptionContainer).toBeVisible(); + }); + + test('should have working navigation links', async ({ page }) => { + // Navigate directly to the event summary page + await page.goto(`/event-summary/?event_id=${testEventId}`); + + // Check for dashboard navigation link + const dashboardLink = page.locator('a[href*="/hvac-dashboard/"]'); + await expect(dashboardLink).toBeVisible(); + + // Check for edit event link (may not be visible if user doesn't have permission) + const editEventLink = page.locator('a[href*="/manage-event/"]'); + + // Check for view public page link + const viewPublicLink = page.locator('a[href*="/event/"]'); + await expect(viewPublicLink).toBeVisible(); + }); + + test('should redirect to login page when not logged in', async ({ page }) => { + // Log out first + await page.goto('/wp-login.php?action=logout'); + await page.waitForURL(/.*\/community-login.*/); + + // Try to access event summary page directly + await page.goto(`/event-summary/?event_id=${testEventId}`); + + // Should redirect to login page + await expect(page).toHaveURL(/.*\/community-login.*/); + }); +}); \ No newline at end of file diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/docs/event-summary.md b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/docs/event-summary.md new file mode 100644 index 00000000..eed5f340 --- /dev/null +++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/docs/event-summary.md @@ -0,0 +1,102 @@ +# Event Summary Functionality + +## Overview + +The Event Summary page provides trainers with detailed information about their events, including ticket sales, attendee data, and revenue tracking. This page is designed to be a central hub for monitoring event performance and managing attendees. + +## Access & Navigation + +- **Access Path**: The Event Summary page can be accessed from the Trainer Dashboard by clicking the "Summary" link next to any event in the events table. +- **URL Structure**: `/event-summary/?event_id={id}` where `{id}` is the event post ID. +- **Authentication**: Only logged-in users with appropriate permissions (event creators or administrators) can access this page. + +## Page Components + +### 1. Header & Navigation + +The header section contains: +- The event title with "Summary" suffix +- Navigation links to: + - Dashboard + - Edit Event (if user has permission) + - View Public Page (opens in new tab) + - Email Attendees (Phase 2 feature, currently a placeholder) + +### 2. Event Overview + +This section provides basic event information including: +- Date & Time (start and end) +- Event Status (Published, Draft, etc.) +- Cost +- Venue information (if available) +- Organizer details (if available) + +### 3. Event Statistics + +A visual representation of key metrics: +- Total Tickets Sold +- Total Revenue +- Ticket Type Distribution (with count and revenue for each type) + +Statistics are displayed in card format for easy scanning, with the same visual style as the dashboard stats. + +### 4. Ticket Sales & Attendees + +A comprehensive table showing all attendee information: +- Attendee name +- Email address +- Ticket type +- Price paid +- Order ID +- Check-in status + +This table provides a complete overview of all registrations and can be used for attendee management. + +### 5. Event Description + +The full event description is displayed for reference. + +## Technical Implementation + +### Files & Classes + +- **Template**: `templates/template-event-summary.php` +- **Data Handler**: `includes/community/class-event-summary-data.php` +- **Shortcode**: `[hvac_event_summary]` (registered in main plugin class) +- **Styling**: Inline CSS in the template (consistent with dashboard styling) + +### Data Flow + +1. The `render_event_summary()` method in the main plugin class: + - Retrieves the event ID from the URL parameter + - Verifies user permissions + - Includes the event summary template + +2. The template: + - Initializes the `HVAC_Event_Summary_Data` class with the event ID + - Retrieves event details, venue info, organizer info, and transaction data + - Calculates statistics from the transaction data + - Renders the UI with the retrieved data + +3. The `HVAC_Event_Summary_Data` class: + - Provides methods to retrieve all necessary event data + - Integrates with The Events Calendar API for event details + - Integrates with Event Tickets for transaction data + +## Testing + +The Event Summary page is verified by E2E tests in `tests/e2e/event-summary.spec.ts`. The tests cover: +- Page accessibility from the dashboard +- Display of event overview information +- Display of event statistics +- Display of ticket sales and attendees data +- Display of event description +- Proper navigation links +- Authentication requirements + +## Future Enhancements (Planned) + +- **Phase 2**: Integration with the Email Attendees feature +- **Phase 2**: CSV export of attendee data +- **Phase 3**: Enhanced visualization of event statistics +- **Phase 3**: Integration with certificate generation \ No newline at end of file diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/hvac-community-events.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/hvac-community-events.php index 917ecb9d..3de90f76 100644 --- a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/hvac-community-events.php +++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/hvac-community-events.php @@ -59,6 +59,10 @@ function hvac_ce_create_required_pages() { 'title' => 'Trainer Profile', 'content' => '[hvac_trainer_profile]', ], + 'event-summary' => [ // Add event summary page + 'title' => 'Event Summary', + 'content' => '[hvac_event_summary]', + ], // REMOVED: 'submit-event' page creation. Will link to default TEC CE page. // 'submit-event' => [ // 'title' => 'Submit Event', diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/class-hvac-community-events.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/class-hvac-community-events.php index 46404001..27f683b2 100644 --- a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/class-hvac-community-events.php +++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/class-hvac-community-events.php @@ -241,8 +241,34 @@ class HVAC_Community_Events { * Render event summary content */ public function render_event_summary() { - // This can be used to display custom event summary content - return '
Event Summary Content Here
'; + // Check if user is logged in + if (!is_user_logged_in()) { + return '

Please log in to view the event summary.

'; + } + + // Get event ID from URL parameter + $event_id = isset($_GET['event_id']) ? absint($_GET['event_id']) : 0; + + if ($event_id <= 0) { + return '
No event ID provided. Please access this page from your dashboard.
'; + } + + // Check if the event exists and user has permission to view it + $event = get_post($event_id); + if (!$event || get_post_type($event) !== Tribe__Events__Main::POSTTYPE) { + return '
Event not found or invalid.
'; + } + + // Check if the current user has permission to view this event + // For now, we'll check if they're the post author or have edit_posts capability + if ($event->post_author != get_current_user_id() && !current_user_can('edit_posts')) { + return '
You do not have permission to view this event summary.
'; + } + + // Include the event summary template + ob_start(); + include HVAC_CE_PLUGIN_DIR . 'templates/event-summary/template-event-summary.php'; + return ob_get_clean(); } /** @@ -294,6 +320,14 @@ class HVAC_Community_Events { return $custom_template; } } + + // Check for event-summary page + if (is_page('event-summary')) { + $custom_template = HVAC_CE_PLUGIN_DIR . 'templates/template-event-summary.php'; + if (file_exists($custom_template)) { + return $custom_template; + } + } // Check for single event view (temporary) if ( is_singular( 'tribe_events' ) ) { diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-event-summary.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-event-summary.php new file mode 100644 index 00000000..da127e8d --- /dev/null +++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-event-summary.php @@ -0,0 +1,413 @@ +Error: Event Summary data handler not found.

"; + return; + } +} + +// Initialize the event summary data handler +$summary_data_handler = new HVAC_Event_Summary_Data( $event_id ); + +// Check if the event is valid +if ( ! $summary_data_handler->is_valid_event() ) { + // Redirect to dashboard if the event doesn't exist or user doesn't have permission + wp_safe_redirect( home_url( '/hvac-dashboard/' ) ); + exit; +} + +// Fetch all the required event data +$event_details = $summary_data_handler->get_event_details(); +$venue_details = $summary_data_handler->get_event_venue_details(); +$organizer_details = $summary_data_handler->get_event_organizer_details(); +$transactions = $summary_data_handler->get_event_transactions(); + +// Calculate ticket sales summary data +$total_tickets = 0; +$total_revenue = 0; +$ticket_types = array(); + +// Process transactions data +if ( ! empty( $transactions ) ) { + foreach ( $transactions as $txn ) { + $total_tickets++; + if ( isset( $txn['price'] ) ) { + $total_revenue += floatval( $txn['price'] ); + } + + // Count ticket types + $ticket_type = $txn['ticket_type_name'] ?? 'Unknown'; + if ( isset( $ticket_types[$ticket_type] ) ) { + $ticket_types[$ticket_type]['count']++; + if ( isset( $txn['price'] ) ) { + $ticket_types[$ticket_type]['revenue'] += floatval( $txn['price'] ); + } + } else { + $ticket_types[$ticket_type] = array( + 'count' => 1, + 'revenue' => isset( $txn['price'] ) ? floatval( $txn['price'] ) : 0, + ); + } + } +} + +// Start the template +get_header(); +?> + +
+
+ + +
+

- Summary

+
+ Dashboard + Edit Event'; + } + + // View public event page + echo 'View Public Page'; + + // Email attendees link (future feature) + if ( current_user_can( 'edit_post', $event_id ) ) { + // TODO: Link to actual Email Attendees page when implemented (Phase 2) + $email_url = '#'; // Placeholder for now + echo 'Email Attendees'; + } + ?> +
+
+ + +
+

Event Overview

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Date & Time: + +
Status:
Cost:
Venue: + + +
+ +
Organizer: + + +
+ +
+
+
+
+ + +
+

Event Statistics

+
+ +
+
+

Total Tickets

+

+
+
+ + +
+
+

Total Revenue

+

$

+
+
+ + + $data ) : ?> +
+
+

+

+ $ +
+
+ +
+
+ + +
+

Ticket Sales & Attendees

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
AttendeeEmailTicket TypePriceOrder IDChecked In
$
+
+ +

No ticket sales or attendees found for this event.

+ +
+ + +
+

Event Description

+
+
+ +
+
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-hvac-dashboard.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-hvac-dashboard.php index e6b9d681..49a44569 100644 --- a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-hvac-dashboard.php +++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/template-hvac-dashboard.php @@ -186,11 +186,14 @@ get_header(); // Use theme's header Edit | - Summary + Summary | + View