feat: Add Event Summary Page functionality
- Add event-summary page to required_pages array in main plugin file - Update render_event_summary() method to handle event ID from URL - Update template_include filter to load custom event summary template - Update dashboard event links to point to new event summary page - Create comprehensive event summary template with statistics and attendee info - Add E2E tests for Event Summary Page - Add documentation for Event Summary functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e59c2e5ccc
commit
1a563f3133
6 changed files with 732 additions and 5 deletions
171
wordpress-dev/tests/e2e/event-summary.spec.ts
Normal file
171
wordpress-dev/tests/e2e/event-summary.spec.ts
Normal file
|
|
@ -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.*/);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -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
|
||||||
|
|
@ -59,6 +59,10 @@ function hvac_ce_create_required_pages() {
|
||||||
'title' => 'Trainer Profile',
|
'title' => 'Trainer Profile',
|
||||||
'content' => '<!-- wp:shortcode -->[hvac_trainer_profile]<!-- /wp:shortcode -->',
|
'content' => '<!-- wp:shortcode -->[hvac_trainer_profile]<!-- /wp:shortcode -->',
|
||||||
],
|
],
|
||||||
|
'event-summary' => [ // Add event summary page
|
||||||
|
'title' => 'Event Summary',
|
||||||
|
'content' => '<!-- wp:shortcode -->[hvac_event_summary]<!-- /wp:shortcode -->',
|
||||||
|
],
|
||||||
// REMOVED: 'submit-event' page creation. Will link to default TEC CE page.
|
// REMOVED: 'submit-event' page creation. Will link to default TEC CE page.
|
||||||
// 'submit-event' => [
|
// 'submit-event' => [
|
||||||
// 'title' => 'Submit Event',
|
// 'title' => 'Submit Event',
|
||||||
|
|
|
||||||
|
|
@ -241,8 +241,34 @@ class HVAC_Community_Events {
|
||||||
* Render event summary content
|
* Render event summary content
|
||||||
*/
|
*/
|
||||||
public function render_event_summary() {
|
public function render_event_summary() {
|
||||||
// This can be used to display custom event summary content
|
// Check if user is logged in
|
||||||
return '<div class="hvac-event-summary">Event Summary Content Here</div>';
|
if (!is_user_logged_in()) {
|
||||||
|
return '<p>Please log in to view the event summary.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get event ID from URL parameter
|
||||||
|
$event_id = isset($_GET['event_id']) ? absint($_GET['event_id']) : 0;
|
||||||
|
|
||||||
|
if ($event_id <= 0) {
|
||||||
|
return '<div class="hvac-error">No event ID provided. Please access this page from your dashboard.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 '<div class="hvac-error">Event not found or invalid.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 '<div class="hvac-error">You do not have permission to view this event summary.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the event summary template
|
||||||
|
ob_start();
|
||||||
|
include HVAC_CE_PLUGIN_DIR . 'templates/event-summary/template-event-summary.php';
|
||||||
|
return ob_get_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -295,6 +321,14 @@ class HVAC_Community_Events {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
// Check for single event view (temporary)
|
||||||
if ( is_singular( 'tribe_events' ) ) {
|
if ( is_singular( 'tribe_events' ) ) {
|
||||||
$custom_template = HVAC_CE_PLUGIN_DIR . 'templates/single-tribe_events.php';
|
$custom_template = HVAC_CE_PLUGIN_DIR . 'templates/single-tribe_events.php';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,413 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Template Name: HVAC Event Summary
|
||||||
|
*
|
||||||
|
* This template handles the display of the HVAC Event Summary page.
|
||||||
|
* It shows detailed information about a specific event, including ticket sales,
|
||||||
|
* attendee information, and revenue tracking.
|
||||||
|
*
|
||||||
|
* @package HVAC Community Events
|
||||||
|
* @subpackage Templates
|
||||||
|
* @author HVAC Community Events
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the event ID from the URL parameter
|
||||||
|
$event_id = isset( $_GET['event_id'] ) ? absint( $_GET['event_id'] ) : 0;
|
||||||
|
|
||||||
|
// Ensure the data class is available
|
||||||
|
if ( ! class_exists( 'HVAC_Event_Summary_Data' ) ) {
|
||||||
|
// Attempt to include it if not loaded
|
||||||
|
$class_path = plugin_dir_path( __FILE__ ) . '../includes/community/class-event-summary-data.php';
|
||||||
|
if ( file_exists( $class_path ) ) {
|
||||||
|
require_once $class_path;
|
||||||
|
} else {
|
||||||
|
// Handle error: Class not found, cannot display summary
|
||||||
|
echo "<p>Error: Event Summary data handler not found.</p>";
|
||||||
|
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();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="primary" class="content-area primary ast-container">
|
||||||
|
<main id="main" class="site-main">
|
||||||
|
|
||||||
|
<!-- Event Summary Header & Navigation -->
|
||||||
|
<div class="hvac-dashboard-header">
|
||||||
|
<h1 class="entry-title"><?php echo esc_html( $event_details['title'] ); ?> - Summary</h1>
|
||||||
|
<div class="hvac-dashboard-nav">
|
||||||
|
<a href="<?php echo esc_url( home_url( '/hvac-dashboard/' ) ); ?>" class="ast-button ast-button-primary">Dashboard</a>
|
||||||
|
<?php
|
||||||
|
// Edit event link (if user has permission)
|
||||||
|
if ( current_user_can( 'edit_post', $event_id ) ) {
|
||||||
|
$edit_url = add_query_arg( 'event_id', $event_id, home_url( '/manage-event/' ) );
|
||||||
|
echo '<a href="' . esc_url( $edit_url ) . '" class="ast-button ast-button-primary">Edit Event</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// View public event page
|
||||||
|
echo '<a href="' . esc_url( $event_details['permalink'] ) . '" class="ast-button ast-button-secondary" target="_blank">View Public Page</a>';
|
||||||
|
|
||||||
|
// 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 '<a href="' . esc_url( $email_url ) . '" class="ast-button ast-button-secondary">Email Attendees</a>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Event Overview Section -->
|
||||||
|
<section class="hvac-event-summary-section">
|
||||||
|
<h2>Event Overview</h2>
|
||||||
|
<div class="hvac-event-summary-content">
|
||||||
|
<!-- Event Details -->
|
||||||
|
<div class="hvac-event-details">
|
||||||
|
<table class="hvac-details-table">
|
||||||
|
<tr>
|
||||||
|
<th>Date & Time:</th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
if ( function_exists( 'tribe_get_start_date' ) && function_exists( 'tribe_get_end_date' ) ) {
|
||||||
|
echo esc_html( tribe_get_start_date( $event_id, false ) );
|
||||||
|
if ( ! $event_details['is_all_day'] ) {
|
||||||
|
echo ' @ ' . esc_html( tribe_get_start_date( $event_id, false, 'g:i a' ) );
|
||||||
|
}
|
||||||
|
// Show end date/time if different from start date
|
||||||
|
$start_date = tribe_get_start_date( $event_id, false, 'Y-m-d' );
|
||||||
|
$end_date = tribe_get_end_date( $event_id, false, 'Y-m-d' );
|
||||||
|
if ( $start_date !== $end_date ) {
|
||||||
|
echo ' - ' . esc_html( tribe_get_end_date( $event_id, false ) );
|
||||||
|
if ( ! $event_details['is_all_day'] ) {
|
||||||
|
echo ' @ ' . esc_html( tribe_get_end_date( $event_id, false, 'g:i a' ) );
|
||||||
|
}
|
||||||
|
} elseif ( ! $event_details['is_all_day'] ) {
|
||||||
|
echo ' - ' . esc_html( tribe_get_end_date( $event_id, false, 'g:i a' ) );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo esc_html( $event_details['start_date'] ?? 'N/A' );
|
||||||
|
echo ' - ';
|
||||||
|
echo esc_html( $event_details['end_date'] ?? 'N/A' );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Status:</th>
|
||||||
|
<td><?php echo esc_html( ucfirst( get_post_status( $event_id ) ) ); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Cost:</th>
|
||||||
|
<td><?php echo esc_html( $event_details['cost'] ?? 'N/A' ); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php if ( $venue_details && ! empty( $venue_details['name'] ) ) : ?>
|
||||||
|
<tr>
|
||||||
|
<th>Venue:</th>
|
||||||
|
<td>
|
||||||
|
<?php echo esc_html( $venue_details['name'] ); ?>
|
||||||
|
<?php if ( ! empty( $venue_details['address'] ) ) : ?>
|
||||||
|
<div class="hvac-detail-subtext"><?php echo esc_html( $venue_details['address'] ); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ( $organizer_details && ! empty( $organizer_details['name'] ) ) : ?>
|
||||||
|
<tr>
|
||||||
|
<th>Organizer:</th>
|
||||||
|
<td>
|
||||||
|
<?php echo esc_html( $organizer_details['name'] ); ?>
|
||||||
|
<?php if ( ! empty( $organizer_details['email'] ) ) : ?>
|
||||||
|
<div class="hvac-detail-subtext"><?php echo esc_html( $organizer_details['email'] ); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Event Statistics Section -->
|
||||||
|
<section class="hvac-event-summary-section">
|
||||||
|
<h2>Event Statistics</h2>
|
||||||
|
<div class="hvac-stats-row">
|
||||||
|
<!-- Total Tickets Stat Card -->
|
||||||
|
<div class="hvac-stat-col">
|
||||||
|
<div class="hvac-stat-card">
|
||||||
|
<h3>Total Tickets</h3>
|
||||||
|
<p class="metric-value"><?php echo esc_html( $total_tickets ); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Total Revenue Stat Card -->
|
||||||
|
<div class="hvac-stat-col">
|
||||||
|
<div class="hvac-stat-card">
|
||||||
|
<h3>Total Revenue</h3>
|
||||||
|
<p class="metric-value">$<?php echo esc_html( number_format( $total_revenue, 2 ) ); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Ticket Types / Distribution -->
|
||||||
|
<?php foreach ( $ticket_types as $type => $data ) : ?>
|
||||||
|
<div class="hvac-stat-col">
|
||||||
|
<div class="hvac-stat-card">
|
||||||
|
<h3><?php echo esc_html( $type ); ?></h3>
|
||||||
|
<p class="metric-value"><?php echo esc_html( $data['count'] ); ?></p>
|
||||||
|
<small>$<?php echo esc_html( number_format( $data['revenue'], 2 ) ); ?></small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Ticket Sales / Attendees Section -->
|
||||||
|
<section class="hvac-event-summary-section">
|
||||||
|
<h2>Ticket Sales & Attendees</h2>
|
||||||
|
<?php if ( ! empty( $transactions ) ) : ?>
|
||||||
|
<div class="hvac-event-summary-content">
|
||||||
|
<table class="hvac-transactions-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Attendee</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Ticket Type</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Order ID</th>
|
||||||
|
<th>Checked In</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ( $transactions as $txn ) : ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo esc_html( $txn['purchaser_name'] ?? 'N/A' ); ?></td>
|
||||||
|
<td><?php echo esc_html( $txn['purchaser_email'] ?? 'N/A' ); ?></td>
|
||||||
|
<td><?php echo esc_html( $txn['ticket_type_name'] ?? 'N/A' ); ?></td>
|
||||||
|
<td>$<?php echo esc_html( number_format( $txn['price'] ?? 0, 2 ) ); ?></td>
|
||||||
|
<td><?php echo esc_html( $txn['order_id'] ?? 'N/A' ); ?></td>
|
||||||
|
<td><?php echo $txn['checked_in'] ? 'Yes' : 'No'; ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<p>No ticket sales or attendees found for this event.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Event Description Section -->
|
||||||
|
<section class="hvac-event-summary-section">
|
||||||
|
<h2>Event Description</h2>
|
||||||
|
<div class="hvac-event-summary-content">
|
||||||
|
<div class="hvac-event-description">
|
||||||
|
<?php echo wp_kses_post( $event_details['description'] ); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Include CSS for the Event Summary page -->
|
||||||
|
<style>
|
||||||
|
/* Event Summary Specific Styles */
|
||||||
|
.hvac-event-summary-section {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-event-summary-section h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-event-summary-content {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Details Table */
|
||||||
|
.hvac-details-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-details-table th,
|
||||||
|
.hvac-details-table td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-details-table th {
|
||||||
|
width: 150px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-detail-subtext {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transactions Table */
|
||||||
|
.hvac-transactions-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-transactions-table th,
|
||||||
|
.hvac-transactions-table td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-transactions-table th {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-transactions-table tr:nth-child(even) {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-transactions-table tr:hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stats Row (reused from dashboard) */
|
||||||
|
.hvac-stats-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: -10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-stat-col {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 160px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-stat-card {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
padding: 15px;
|
||||||
|
background: #fff;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-stat-card h3 {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-stat-card .metric-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #E9AF28;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-stat-card small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 5px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.hvac-dashboard-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-dashboard-nav {
|
||||||
|
margin-top: 15px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-dashboard-nav a {
|
||||||
|
margin: 5px 5px 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-details-table th {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hvac-transactions-table {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
get_footer();
|
||||||
|
?>
|
||||||
|
|
@ -186,11 +186,14 @@ get_header(); // Use theme's header
|
||||||
<?php
|
<?php
|
||||||
// Link to the new page containing the TEC CE submission form shortcode
|
// Link to the new page containing the TEC CE submission form shortcode
|
||||||
$edit_url = add_query_arg( 'event_id', $event['id'], home_url( '/manage-event/' ) );
|
$edit_url = add_query_arg( 'event_id', $event['id'], home_url( '/manage-event/' ) );
|
||||||
// Link to the standard WP single event view (handled by our custom template)
|
// Link to the custom event summary page
|
||||||
$summary_url = get_permalink( $event['id'] );
|
$summary_url = add_query_arg( 'event_id', $event['id'], home_url( '/event-summary/' ) );
|
||||||
|
// Link to the standard WP single event view
|
||||||
|
$view_url = get_permalink( $event['id'] );
|
||||||
?>
|
?>
|
||||||
<a href="<?php echo esc_url( $edit_url ); ?>">Edit</a> |
|
<a href="<?php echo esc_url( $edit_url ); ?>">Edit</a> |
|
||||||
<a href="<?php echo esc_url( $summary_url ); ?>">Summary</a>
|
<a href="<?php echo esc_url( $summary_url ); ?>">Summary</a> |
|
||||||
|
<a href="<?php echo esc_url( $view_url ); ?>" target="_blank">View</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue