![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/src/components/ |
import React, { useState, useEffect } from 'react';
import { Calendar, MessageSquare, Users, Clock, MapPin, Bell, FileText, Phone, Video, ArrowRight, CheckCircle, AlertTriangle, Brain, Zap } from 'lucide-react';
interface CalendarEvent {
id: string;
title: string;
date: string;
time: string;
type: 'court_hearing' | 'client_meeting' | 'detention_visit' | 'team_meeting';
location: string;
participants: string[];
chatRoomId?: string;
status: 'scheduled' | 'confirmed' | 'completed';
priority: 'low' | 'medium' | 'high' | 'critical';
}
interface ChatRoom {
id: string;
name: string;
description: string;
participantCount: number;
lastMessage?: string;
unreadCount: number;
}
interface AIInsight {
type: 'scheduling' | 'communication' | 'efficiency';
message: string;
action: string;
}
const CalendarChatIntegration: React.FC = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
const [events, setEvents] = useState<CalendarEvent[]>([]);
const [detentionChatRooms, setDetentionChatRooms] = useState<ChatRoom[]>([]);
const [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(null);
const [showChatIntegration, setShowChatIntegration] = useState(false);
const [aiInsights, setAiInsights] = useState<AIInsight[]>([]);
useEffect(() => {
loadCalendarEvents();
loadDetentionChatRooms();
loadAIInsights();
}, []);
const loadCalendarEvents = () => {
const sampleEvents: CalendarEvent[] = [
{
id: 'evt_001',
title: 'Bordeaux Detention Center Visit',
date: '2025-03-10',
time: '14:00',
type: 'detention_visit',
location: 'Bordeaux Detention Center, Montreal',
participants: ['Client: Marie Dubois', 'Lawyer: Audrey Labrecque'],
chatRoomId: 'bordeaux_montreal',
status: 'scheduled',
priority: 'high'
},
{
id: 'evt_002',
title: 'Class Action Case Strategy Meeting',
date: '2025-03-10',
time: '10:00',
type: 'team_meeting',
location: 'Office Conference Room A',
participants: ['Justin Wee', 'Danny Perez', 'Audrey Labrecque', 'Marie-Christine Vachon'],
chatRoomId: 'team_strategy',
status: 'confirmed',
priority: 'critical'
},
{
id: 'evt_003',
title: 'Quebec Superior Court Hearing',
date: '2025-03-12',
time: '09:30',
type: 'court_hearing',
location: 'Palais de Justice de Montréal, Room 2.09',
participants: ['Justin Wee', 'Opposing Counsel'],
status: 'scheduled',
priority: 'critical'
},
{
id: 'evt_004',
title: 'Family Consultation - Rivière-des-Prairies',
date: '2025-03-11',
time: '15:30',
type: 'client_meeting',
location: 'Rivière-des-Prairies Detention Center',
participants: ['Family Member: Jean Tremblay', 'Lawyer: David Frappier'],
chatRoomId: 'riviere_des_prairies_montreal',
status: 'scheduled',
priority: 'medium'
}
];
setEvents(sampleEvents);
};
const loadDetentionChatRooms = () => {
const quebecDetentionRooms: ChatRoom[] = [
{
id: 'bordeaux_montreal',
name: 'Bordeaux (Montréal)',
description: 'Établissement de détention de Bordeaux - Montréal',
participantCount: 8,
lastMessage: 'Nouvelle visite programmée pour demain',
unreadCount: 3
},
{
id: 'riviere_des_prairies_montreal',
name: 'Rivière-des-Prairies (Montréal)',
description: 'Centre de détention Rivière-des-Prairies',
participantCount: 5,
lastMessage: 'Documents médicaux requis',
unreadCount: 1
},
{
id: 'leclerc_laval',
name: 'Leclerc (Laval)',
description: 'Institut Leclerc - Établissement fédéral',
participantCount: 6,
lastMessage: 'Transfert prévu la semaine prochaine',
unreadCount: 0
},
{
id: 'orsainville_quebec',
name: 'Orsainville (Québec)',
description: 'Établissement de détention de Québec',
participantCount: 4,
lastMessage: 'Rendez-vous médical confirmé',
unreadCount: 2
},
{
id: 'maison_tanguay_femmes',
name: 'Maison Tanguay (Femmes)',
description: 'Établissement pour femmes - Montréal',
participantCount: 3,
lastMessage: 'Visite familiale autorisée',
unreadCount: 0
},
{
id: 'sherbrooke',
name: 'Sherbrooke',
description: 'Établissement de détention de Sherbrooke',
participantCount: 2,
lastMessage: 'Nouvelle demande de libération conditionnelle',
unreadCount: 1
}
];
setDetentionChatRooms(quebecDetentionRooms);
};
const loadAIInsights = () => {
const insights: AIInsight[] = [
{
type: 'scheduling',
message: 'Optimal time for Bordeaux visits: Tuesday-Thursday 2-4 PM (87% success rate)',
action: 'Reschedule upcoming visits to recommended time slots'
},
{
type: 'communication',
message: '23 unread messages across detention center chats may contain urgent requests',
action: 'Review and prioritize detention center communications'
},
{
type: 'efficiency',
message: 'Calendar-chat integration saved 18.5 hours this month vs manual coordination',
action: 'Continue using integrated workflow for all detention visits'
}
];
setAiInsights(insights);
};
const handleEventClick = (event: CalendarEvent) => {
setSelectedEvent(event);
setShowChatIntegration(true);
};
const handleJoinChat = (chatRoomId: string) => {
// This would integrate with the existing GroupChat component
window.open(`/chat?room=${chatRoomId}`, '_blank');
};
const typeColors = {
court_hearing: 'bg-red-100 text-red-800 border-red-200',
client_meeting: 'bg-blue-100 text-blue-800 border-blue-200',
detention_visit: 'bg-purple-100 text-purple-800 border-purple-200',
team_meeting: 'bg-green-100 text-green-800 border-green-200'
};
const priorityColors = {
low: 'bg-gray-100 text-gray-800',
medium: 'bg-yellow-100 text-yellow-800',
high: 'bg-orange-100 text-orange-800',
critical: 'bg-red-100 text-red-800'
};
const statusIcons = {
scheduled: Clock,
confirmed: CheckCircle,
completed: CheckCircle
};
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-purple-50 to-indigo-50 p-6">
{/* Header */}
<div className="mb-8">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold bg-gradient-to-r from-purple-600 to-blue-600 bg-clip-text text-transparent">
📅💬 Calendar-Chat Integration Demo
</h1>
<p className="text-gray-600 mt-2">
Revolutionary integration between calendar events and Quebec detention center chat rooms
</p>
</div>
<div className="flex items-center space-x-4">
<div className="bg-white rounded-lg p-3 shadow-md">
<div className="text-sm font-medium text-gray-600">Quebec Detention Centers</div>
<div className="text-2xl font-bold text-purple-600">56 Active</div>
</div>
<div className="bg-white rounded-lg p-3 shadow-md">
<div className="text-sm font-medium text-gray-600">Total Participants</div>
<div className="text-2xl font-bold text-green-600">28</div>
</div>
</div>
</div>
</div>
{/* AI Insights */}
<div className="mb-8 bg-white rounded-xl shadow-lg border border-gray-100 p-6">
<h2 className="text-xl font-bold text-gray-900 mb-4 flex items-center">
<Brain className="h-5 w-5 mr-2 text-purple-600" />
AI-Powered Insights
</h2>
<div className="grid grid-cols-3 gap-4">
{aiInsights.map((insight, index) => (
<div key={index} className="p-4 bg-gradient-to-r from-purple-50 to-blue-50 rounded-lg border border-purple-200">
<div className="flex items-center space-x-2 mb-2">
<Zap className="h-4 w-4 text-purple-600" />
<span className="text-sm font-semibold text-purple-700 uppercase">{insight.type}</span>
</div>
<p className="text-sm text-gray-700 mb-3">{insight.message}</p>
<button className="text-xs bg-purple-600 text-white px-3 py-1 rounded-full hover:bg-purple-700 transition-colors">
{insight.action}
</button>
</div>
))}
</div>
</div>
<div className="grid grid-cols-3 gap-8">
{/* Calendar Events */}
<div className="col-span-2">
<div className="bg-white rounded-xl shadow-lg border border-gray-100 p-6">
<h2 className="text-xl font-bold text-gray-900 mb-6 flex items-center">
<Calendar className="h-5 w-5 mr-2" />
Upcoming Legal Events
</h2>
<div className="space-y-4">
{events.map((event) => {
const StatusIcon = statusIcons[event.status];
return (
<div
key={event.id}
onClick={() => handleEventClick(event)}
className="p-4 border border-gray-200 rounded-lg hover:shadow-md hover:border-purple-300 transition-all cursor-pointer"
>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center space-x-3">
<h3 className="font-semibold text-gray-900">{event.title}</h3>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${typeColors[event.type]}`}>
{event.type.replace('_', ' ').toUpperCase()}
</span>
</div>
<div className="flex items-center space-x-2">
<span className={`px-2 py-1 rounded-full text-xs font-medium ${priorityColors[event.priority]}`}>
{event.priority.toUpperCase()}
</span>
<StatusIcon className="h-4 w-4 text-green-600" />
</div>
</div>
<div className="grid grid-cols-2 gap-4 text-sm text-gray-600">
<div className="flex items-center space-x-2">
<Clock className="h-4 w-4" />
<span>{event.date} at {event.time}</span>
</div>
<div className="flex items-center space-x-2">
<MapPin className="h-4 w-4" />
<span>{event.location}</span>
</div>
</div>
<div className="mt-3 flex items-center justify-between">
<div className="flex items-center space-x-2 text-sm text-gray-600">
<Users className="h-4 w-4" />
<span>{event.participants.length} participants</span>
</div>
<div className="flex items-center space-x-2">
{event.chatRoomId && (
<button className="flex items-center space-x-1 px-3 py-1 bg-purple-100 text-purple-700 rounded-full text-xs font-medium hover:bg-purple-200 transition-colors">
<MessageSquare className="h-3 w-3" />
<span>Chat Room</span>
</button>
)}
<button className="flex items-center space-x-1 px-3 py-1 bg-blue-100 text-blue-700 rounded-full text-xs font-medium hover:bg-blue-200 transition-colors">
<span>View Details</span>
<ArrowRight className="h-3 w-3" />
</button>
</div>
</div>
</div>
);
})}
</div>
</div>
</div>
{/* Quebec Detention Center Chat Rooms */}
<div>
<div className="bg-white rounded-xl shadow-lg border border-gray-100 p-6">
<h2 className="text-xl font-bold text-gray-900 mb-6 flex items-center">
<MessageSquare className="h-5 w-5 mr-2" />
Quebec Detention Centers
</h2>
<div className="space-y-3">
{detentionChatRooms.map((room) => (
<div key={room.id} className="p-3 border border-gray-200 rounded-lg hover:shadow-md transition-all">
<div className="flex items-center justify-between mb-2">
<h3 className="font-semibold text-gray-900 text-sm">{room.name}</h3>
{room.unreadCount > 0 && (
<span className="bg-red-500 text-white text-xs px-2 py-1 rounded-full">
{room.unreadCount}
</span>
)}
</div>
<p className="text-xs text-gray-600 mb-2">{room.description}</p>
{room.lastMessage && (
<p className="text-xs text-gray-500 italic mb-2">"{room.lastMessage}"</p>
)}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2 text-xs text-gray-600">
<Users className="h-3 w-3" />
<span>{room.participantCount} participants</span>
</div>
<button
onClick={() => handleJoinChat(room.id)}
className="flex items-center space-x-1 px-2 py-1 bg-purple-600 text-white rounded text-xs hover:bg-purple-700 transition-colors"
>
<MessageSquare className="h-3 w-3" />
<span>Join</span>
</button>
</div>
</div>
))}
</div>
<div className="mt-6 p-4 bg-gradient-to-r from-green-50 to-blue-50 rounded-lg border border-green-200">
<h4 className="font-semibold text-green-700 mb-2">🏆 Competitive Advantage</h4>
<ul className="text-xs text-green-600 space-y-1">
<li>✅ 56 Quebec detention centers integrated</li>
<li>✅ Real-time bilingual chat support</li>
<li>✅ Calendar-chat synchronization</li>
<li>✅ AI-powered scheduling optimization</li>
<li>❌ Clio: No detention center integration</li>
<li>❌ MyCase: No Quebec specialization</li>
<li>❌ LegalZoom: No practice management</li>
</ul>
</div>
</div>
</div>
</div>
{/* Event Detail Modal */}
{showChatIntegration && selectedEvent && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div className="p-6 border-b border-gray-200">
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold text-gray-900">{selectedEvent.title}</h2>
<button
onClick={() => setShowChatIntegration(false)}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
✕
</button>
</div>
</div>
<div className="p-6">
<div className="grid grid-cols-2 gap-6 mb-6">
<div>
<h3 className="font-semibold text-gray-900 mb-3">Event Details</h3>
<div className="space-y-2 text-sm">
<div className="flex items-center space-x-2">
<Clock className="h-4 w-4 text-gray-500" />
<span>{selectedEvent.date} at {selectedEvent.time}</span>
</div>
<div className="flex items-center space-x-2">
<MapPin className="h-4 w-4 text-gray-500" />
<span>{selectedEvent.location}</span>
</div>
<div className="flex items-center space-x-2">
<Users className="h-4 w-4 text-gray-500" />
<span>{selectedEvent.participants.join(', ')}</span>
</div>
</div>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-3">Chat Integration</h3>
{selectedEvent.chatRoomId ? (
<div className="space-y-3">
<p className="text-sm text-gray-600">
This event is linked to the Quebec detention center chat room
</p>
<button
onClick={() => handleJoinChat(selectedEvent.chatRoomId!)}
className="flex items-center space-x-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
>
<MessageSquare className="h-4 w-4" />
<span>Join Chat Room</span>
</button>
</div>
) : (
<p className="text-sm text-gray-500">No chat room linked to this event</p>
)}
</div>
</div>
<div className="border-t pt-6">
<h3 className="font-semibold text-gray-900 mb-3">Quick Actions</h3>
<div className="flex items-center space-x-3">
<button className="flex items-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
<Video className="h-4 w-4" />
<span>Start Video Call</span>
</button>
<button className="flex items-center space-x-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors">
<Phone className="h-4 w-4" />
<span>Voice Call</span>
</button>
<button className="flex items-center space-x-2 px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors">
<FileText className="h-4 w-4" />
<span>Generate Documents</span>
</button>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default CalendarChatIntegration;