feat: comprehensive update with Signal, Copilot, themes, and PDF features

## Signal Messaging Integration
- Added SignalService for sending messages to drivers via Signal
- SignalMessage model for tracking message history
- Driver chat modal for real-time messaging
- Send schedule via Signal (ICS + PDF attachments)

## AI Copilot
- Natural language interface for VIP Coordinator
- Capabilities: create VIPs, schedule events, assign drivers
- Help and guidance for users
- Floating copilot button in UI

## Theme System
- Dark/light/system theme support
- Color scheme selection (blue, green, purple, orange, red)
- ThemeContext for global state
- AppearanceMenu in header

## PDF Schedule Export
- VIPSchedulePDF component for schedule generation
- PDF settings (header, footer, branding)
- Preview PDF in browser
- Settings stored in database

## Database Migrations
- add_signal_messages: SignalMessage model
- add_pdf_settings: Settings model for PDF config
- add_reminder_tracking: lastReminderSent for events
- make_driver_phone_optional: phone field nullable

## Event Management
- Event status service for automated updates
- IN_PROGRESS/COMPLETED status tracking
- Reminder tracking for notifications

## UI/UX Improvements
- Driver schedule modal
- Improved My Schedule page
- Better error handling and loading states
- Responsive design improvements

## Other Changes
- AGENT_TEAM.md documentation
- Seed data improvements
- Ability factory updates
- Driver profile page

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-01 19:30:41 +01:00
parent 2d842ed294
commit 3b0b1205df
84 changed files with 12330 additions and 2103 deletions

View File

@@ -56,14 +56,14 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between p-6 border-b">
<h2 className="text-2xl font-bold text-gray-900">
<div className="bg-card rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between p-6 border-b border-border">
<h2 className="text-2xl font-bold text-foreground">
{driver ? 'Edit Driver' : 'Add New Driver'}
</h2>
<button
onClick={onCancel}
className="text-gray-400 hover:text-gray-600"
className="text-muted-foreground hover:text-foreground"
>
<X className="h-6 w-6" />
</button>
@@ -72,7 +72,7 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
<form onSubmit={handleSubmit} className="p-6 space-y-4">
{/* Name */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
<label className="block text-sm font-medium text-foreground mb-1">
Full Name *
</label>
<input
@@ -81,13 +81,13 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
required
value={formData.name}
onChange={handleChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
className="w-full px-3 py-2 border border-input rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
/>
</div>
{/* Phone */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
<label className="block text-sm font-medium text-foreground mb-1">
Phone Number *
</label>
<input
@@ -96,20 +96,20 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
required
value={formData.phone}
onChange={handleChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
className="w-full px-3 py-2 border border-input rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
/>
</div>
{/* Department */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
<label className="block text-sm font-medium text-foreground mb-1">
Department
</label>
<select
name="department"
value={formData.department}
onChange={handleChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
className="w-full px-3 py-2 border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary"
>
<option value="">Select Department</option>
<option value="OFFICE_OF_DEVELOPMENT">Office of Development</option>
@@ -119,7 +119,7 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
{/* User ID (optional, for linking driver to user account) */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
<label className="block text-sm font-medium text-foreground mb-1">
User Account ID (Optional)
</label>
<input
@@ -128,9 +128,9 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
value={formData.userId}
onChange={handleChange}
placeholder="Leave blank for standalone driver"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
className="w-full px-3 py-2 border border-input rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary"
/>
<p className="mt-1 text-xs text-gray-500">
<p className="mt-1 text-xs text-muted-foreground">
Link this driver to a user account for login access
</p>
</div>
@@ -147,7 +147,7 @@ export function DriverForm({ driver, onSubmit, onCancel, isSubmitting }: DriverF
<button
type="button"
onClick={onCancel}
className="flex-1 bg-gray-200 text-gray-800 py-2 px-4 rounded-md hover:bg-gray-300"
className="flex-1 bg-muted text-foreground py-2 px-4 rounded-md hover:bg-muted/80"
>
Cancel
</button>