- Add GPS module with Traccar client service for device management - Add driver enrollment flow with QR code generation - Add real-time location tracking on driver profiles - Add GPS settings configuration in admin tools - Add Auth0 OpenID Connect setup script for Traccar - Add deployment configs for production server - Update nginx configs for SSL on GPS port 5055 - Add timezone setting support - Various UI improvements and bug fixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
327 lines
12 KiB
TypeScript
327 lines
12 KiB
TypeScript
/**
|
|
* EXAMPLE: How to Use VIP Schedule PDF Generation
|
|
*
|
|
* This file demonstrates the complete flow of generating a VIP schedule PDF.
|
|
* This is a reference example - the actual implementation is in:
|
|
* - src/components/VIPSchedulePDF.tsx (PDF component)
|
|
* - src/pages/VIPSchedule.tsx (integration)
|
|
*/
|
|
|
|
import { pdf } from '@react-pdf/renderer';
|
|
import { VIPSchedulePDF } from '@/components/VIPSchedulePDF';
|
|
|
|
// Example VIP data
|
|
const exampleVIP = {
|
|
id: '123',
|
|
name: 'John Doe',
|
|
organization: 'Example Corporation',
|
|
department: 'OFFICE_OF_DEVELOPMENT',
|
|
arrivalMode: 'FLIGHT',
|
|
expectedArrival: '2026-02-03T09:00:00Z',
|
|
airportPickup: true,
|
|
venueTransport: true,
|
|
notes: 'VIP prefers electric vehicles. Dietary restriction: vegetarian.',
|
|
flights: [
|
|
{
|
|
id: 'f1',
|
|
flightNumber: 'AA123',
|
|
departureAirport: 'JFK',
|
|
arrivalAirport: 'LAX',
|
|
scheduledDeparture: '2026-02-03T07:00:00Z',
|
|
scheduledArrival: '2026-02-03T10:00:00Z',
|
|
status: 'On Time',
|
|
},
|
|
],
|
|
};
|
|
|
|
// Example schedule events
|
|
const exampleEvents = [
|
|
{
|
|
id: 'e1',
|
|
title: 'Airport Pickup',
|
|
type: 'TRANSPORT',
|
|
status: 'SCHEDULED',
|
|
startTime: '2026-02-03T10:00:00Z',
|
|
endTime: '2026-02-03T11:00:00Z',
|
|
pickupLocation: 'LAX Terminal 4',
|
|
dropoffLocation: 'Hotel Grand Plaza',
|
|
description: 'Pick up from arrival gate',
|
|
driver: {
|
|
id: 'd1',
|
|
name: 'Mike Johnson',
|
|
},
|
|
vehicle: {
|
|
id: 'v1',
|
|
name: 'Tesla Model S',
|
|
type: 'SEDAN',
|
|
seatCapacity: 4,
|
|
},
|
|
},
|
|
{
|
|
id: 'e2',
|
|
title: 'Welcome Lunch',
|
|
type: 'MEAL',
|
|
status: 'SCHEDULED',
|
|
startTime: '2026-02-03T12:00:00Z',
|
|
endTime: '2026-02-03T13:30:00Z',
|
|
location: 'Restaurant Chez Pierre',
|
|
description: 'Lunch with board members',
|
|
driver: null,
|
|
vehicle: null,
|
|
},
|
|
{
|
|
id: 'e3',
|
|
title: 'Board Meeting',
|
|
type: 'MEETING',
|
|
status: 'SCHEDULED',
|
|
startTime: '2026-02-03T14:00:00Z',
|
|
endTime: '2026-02-03T17:00:00Z',
|
|
location: 'Conference Room A, 5th Floor',
|
|
description: 'Q1 strategy discussion',
|
|
driver: null,
|
|
vehicle: null,
|
|
},
|
|
{
|
|
id: 'e4',
|
|
title: 'Airport Return',
|
|
type: 'TRANSPORT',
|
|
status: 'SCHEDULED',
|
|
startTime: '2026-02-04T15:00:00Z',
|
|
endTime: '2026-02-04T16:00:00Z',
|
|
pickupLocation: 'Hotel Grand Plaza',
|
|
dropoffLocation: 'LAX Terminal 4',
|
|
description: 'Departure for flight home',
|
|
driver: {
|
|
id: 'd1',
|
|
name: 'Mike Johnson',
|
|
},
|
|
vehicle: {
|
|
id: 'v1',
|
|
name: 'Tesla Model S',
|
|
type: 'SEDAN',
|
|
seatCapacity: 4,
|
|
},
|
|
},
|
|
];
|
|
|
|
/**
|
|
* EXAMPLE 1: Basic PDF Generation
|
|
*/
|
|
export async function generateBasicPDF() {
|
|
const blob = await pdf(
|
|
<VIPSchedulePDF vip={exampleVIP} events={exampleEvents} />
|
|
).toBlob();
|
|
|
|
// Create download link
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = `${exampleVIP.name.replace(/\s+/g, '_')}_Schedule.pdf`;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
/**
|
|
* EXAMPLE 2: PDF Generation with Custom Contact Info
|
|
*/
|
|
export async function generateCustomContactPDF() {
|
|
const blob = await pdf(
|
|
<VIPSchedulePDF
|
|
vip={exampleVIP}
|
|
events={exampleEvents}
|
|
contactEmail="custom-coordinator@example.com"
|
|
contactPhone="(555) 987-6543"
|
|
appUrl="https://my-vip-app.com"
|
|
/>
|
|
).toBlob();
|
|
|
|
// Download
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = 'VIP_Schedule.pdf';
|
|
link.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
/**
|
|
* EXAMPLE 3: PDF Generation with Environment Variables
|
|
*/
|
|
export async function generateEnvConfigPDF() {
|
|
const blob = await pdf(
|
|
<VIPSchedulePDF
|
|
vip={exampleVIP}
|
|
events={exampleEvents}
|
|
contactEmail={import.meta.env.VITE_CONTACT_EMAIL || 'coordinator@example.com'}
|
|
contactPhone={import.meta.env.VITE_CONTACT_PHONE || '(555) 123-4567'}
|
|
appUrl={window.location.origin}
|
|
/>
|
|
).toBlob();
|
|
|
|
// Download with timestamp
|
|
const date = new Date().toISOString().split('T')[0];
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = `${exampleVIP.name.replace(/\s+/g, '_')}_Schedule_${date}.pdf`;
|
|
link.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
/**
|
|
* EXAMPLE 4: PDF Generation with Error Handling
|
|
*/
|
|
export async function generatePDFWithErrorHandling() {
|
|
try {
|
|
console.log('[PDF] Starting generation...');
|
|
|
|
const blob = await pdf(
|
|
<VIPSchedulePDF
|
|
vip={exampleVIP}
|
|
events={exampleEvents}
|
|
contactEmail={import.meta.env.VITE_CONTACT_EMAIL}
|
|
contactPhone={import.meta.env.VITE_CONTACT_PHONE}
|
|
appUrl={window.location.origin}
|
|
/>
|
|
).toBlob();
|
|
|
|
console.log('[PDF] Generation successful, size:', blob.size, 'bytes');
|
|
|
|
// Create download
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = `${exampleVIP.name.replace(/\s+/g, '_')}_Schedule.pdf`;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
|
|
// Clean up
|
|
URL.revokeObjectURL(url);
|
|
|
|
console.log('[PDF] Download complete');
|
|
return true;
|
|
} catch (error) {
|
|
console.error('[PDF] Generation failed:', error);
|
|
alert('Failed to generate PDF. Please try again.');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* EXAMPLE 5: React Component Integration
|
|
*/
|
|
export function VIPScheduleExampleComponent() {
|
|
const handleExportPDF = async () => {
|
|
try {
|
|
const blob = await pdf(
|
|
<VIPSchedulePDF
|
|
vip={exampleVIP}
|
|
events={exampleEvents}
|
|
contactEmail={import.meta.env.VITE_CONTACT_EMAIL}
|
|
contactPhone={import.meta.env.VITE_CONTACT_PHONE}
|
|
appUrl={window.location.origin}
|
|
/>
|
|
).toBlob();
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = `${exampleVIP.name.replace(/\s+/g, '_')}_Schedule.pdf`;
|
|
link.click();
|
|
URL.revokeObjectURL(url);
|
|
} catch (error) {
|
|
console.error('[PDF] Export failed:', error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<button
|
|
onClick={handleExportPDF}
|
|
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
|
|
>
|
|
Export PDF
|
|
</button>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* EXAMPLE 6: Preview PDF in New Tab (instead of download)
|
|
*/
|
|
export async function previewPDFInNewTab() {
|
|
const blob = await pdf(
|
|
<VIPSchedulePDF vip={exampleVIP} events={exampleEvents} />
|
|
).toBlob();
|
|
|
|
// Open in new tab instead of downloading
|
|
const url = URL.createObjectURL(blob);
|
|
window.open(url, '_blank');
|
|
|
|
// Clean up after a delay (user should have opened it by then)
|
|
setTimeout(() => URL.revokeObjectURL(url), 10000);
|
|
}
|
|
|
|
/**
|
|
* Expected PDF Output Structure:
|
|
*
|
|
* ┌────────────────────────────────────────────────────────────┐
|
|
* │ HEADER │
|
|
* │ ┌──────────────────────────────────────────────────────┐ │
|
|
* │ │ John Doe │ │
|
|
* │ │ Example Corporation │ │
|
|
* │ │ OFFICE OF DEVELOPMENT • VIP Schedule & Itinerary │ │
|
|
* │ │ │ │
|
|
* │ │ ⚠️ DOCUMENT GENERATED AT: │ │
|
|
* │ │ Saturday, February 1, 2026, 2:00 PM EST │ │
|
|
* │ │ This is a snapshot. For latest: https://app.com │ │
|
|
* │ └──────────────────────────────────────────────────────┘ │
|
|
* │ │
|
|
* │ VIP INFORMATION │
|
|
* │ ┌──────────────────────────────────────────────────────┐ │
|
|
* │ │ Arrival Mode: FLIGHT Expected: Feb 3, 9:00 AM │ │
|
|
* │ │ Airport Pickup: Yes Venue Transport: Yes │ │
|
|
* │ └──────────────────────────────────────────────────────┘ │
|
|
* │ │
|
|
* │ FLIGHT INFORMATION │
|
|
* │ ┌──────────────────────────────────────────────────────┐ │
|
|
* │ │ Flight AA123 │ │
|
|
* │ │ JFK → LAX │ │
|
|
* │ │ Arrives: Feb 3, 10:00 AM │ │
|
|
* │ │ Status: On Time │ │
|
|
* │ └──────────────────────────────────────────────────────┘ │
|
|
* │ │
|
|
* │ SPECIAL NOTES │
|
|
* │ ┌──────────────────────────────────────────────────────┐ │
|
|
* │ │ VIP prefers electric vehicles. Dietary: vegetarian │ │
|
|
* │ └──────────────────────────────────────────────────────┘ │
|
|
* │ │
|
|
* │ SCHEDULE & ITINERARY │
|
|
* │ │
|
|
* │ Monday, February 3, 2026 │
|
|
* │ ┌──────────────────────────────────────────────────────┐ │
|
|
* │ │ 10:00 AM - 11:00 AM [TRANSPORT] │ │
|
|
* │ │ Airport Pickup │ │
|
|
* │ │ 📍 LAX Terminal 4 → Hotel Grand Plaza │ │
|
|
* │ │ 👤 Driver: Mike Johnson │ │
|
|
* │ │ 🚗 Tesla Model S (SEDAN) │ │
|
|
* │ │ [SCHEDULED] │ │
|
|
* │ └──────────────────────────────────────────────────────┘ │
|
|
* │ │
|
|
* │ ┌──────────────────────────────────────────────────────┐ │
|
|
* │ │ 12:00 PM - 1:30 PM [MEAL] │ │
|
|
* │ │ Welcome Lunch │ │
|
|
* │ │ 📍 Restaurant Chez Pierre │ │
|
|
* │ │ [SCHEDULED] │ │
|
|
* │ └──────────────────────────────────────────────────────┘ │
|
|
* │ │
|
|
* │ ... more events ... │
|
|
* │ │
|
|
* ├────────────────────────────────────────────────────────────┤
|
|
* │ FOOTER │
|
|
* │ For Questions: coordinator@vip-board.com │
|
|
* │ Phone: (555) 123-4567 Page 1 of 2 │
|
|
* └────────────────────────────────────────────────────────────┘
|
|
*/
|