feat: add GPS tracking with Traccar integration

- 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>
This commit is contained in:
2026-02-03 18:13:17 +01:00
parent 3814d175ff
commit 5ded039793
91 changed files with 4403 additions and 68 deletions

View File

@@ -0,0 +1,326 @@
/**
* 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 │
* └────────────────────────────────────────────────────────────┘
*/