Spaces:
Sleeping
Sleeping
| import React, { useEffect } from 'react'; | |
| import { Send, User, Bot } from 'lucide-react'; | |
| import InsuCompassLogo from '../../assets/InsuCompass_Logo.png'; | |
| import ReactMarkdown from 'react-markdown'; | |
| import { useChatInterface } from './useChatInterface'; | |
| import { Plan, UserProfile } from '../../interface'; | |
| const PlanCard: React.FC<{ plan: Plan }> = ({ plan }) => ( | |
| <div className="bg-white border border-gray-200 rounded-2xl shadow-sm p-6 hover:shadow-lg transition"> | |
| <h3 className="text-xl font-semibold text-gray-900">{plan.plan_name}</h3> | |
| <p className="text-sm text-gray-600 mb-2">{plan.plan_type}</p> | |
| <p className="text-sm italic text-gray-700 mb-4">{plan.reasoning}</p> | |
| <p className="text-sm font-medium text-gray-800 mb-2"> | |
| Estimated Premium: {plan.estimated_premium} | |
| </p> | |
| <ul className="list-disc list-inside space-y-1 text-sm text-gray-700"> | |
| {plan.key_features.map((feat, i) => ( | |
| <li key={i}>{feat}</li> | |
| ))} | |
| </ul> | |
| </div> | |
| ); | |
| interface ChatInterfaceScreenProps { | |
| userProfile: UserProfile; | |
| } | |
| const ChatInterfaceScreen: React.FC<ChatInterfaceScreenProps> = ({ userProfile }) => { | |
| const { | |
| chatHistory, | |
| isLoading, | |
| currentMessage, | |
| setCurrentMessage, | |
| handleSendMessage, | |
| showPlanRecs, | |
| chatEndRef, | |
| sendChatMessage | |
| } = useChatInterface(userProfile); | |
| useEffect(() => { | |
| if (chatHistory.length === 0) { | |
| sendChatMessage('START_PROFILE_BUILDING', userProfile); | |
| } | |
| }, [userProfile]) | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-indigo-50 flex flex-col"> | |
| {/* Header */} | |
| <div className="fixed top-0 left-0 w-full bg-white shadow-sm border-b z-50"> | |
| <div className="max-w-10xl mx-auto px-6 py-4"> | |
| <div className="flex items-center space-x-3"> | |
| <img src={InsuCompassLogo} alt="InsuCompass Logo" className="h-12 w-auto" /> | |
| <div> | |
| <h1 className="text-2xl font-bold text-gray-900">InsuCompass</h1> | |
| <p className="text-sm text-gray-600">Chat with your AI insurance advisor</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Chat Messages */} | |
| <div className="flex-1 overflow-y-auto pt-20"> | |
| <div className="max-w-4xl mx-auto px-6 py-8"> | |
| <div className="space-y-6"> | |
| {chatHistory.map((message, index) => ( | |
| <div | |
| key={index} | |
| className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`} | |
| > | |
| <div className={`flex items-start space-x-3 max-w-3xl ${message.role === 'user' ? 'flex-row-reverse space-x-reverse' : ''}`}> | |
| {/* Avatar */} | |
| <div className={`w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0 ${ | |
| message.role === 'user' | |
| ? 'bg-blue-500 text-white' | |
| : 'bg-gradient-to-r from-purple-500 to-pink-500 text-white' | |
| }`}> | |
| {message.role === 'user' ? ( | |
| <User className="w-5 h-5" /> | |
| ) : ( | |
| <Bot className="w-5 h-5" /> | |
| )} | |
| </div> | |
| {/* Message Bubble */} | |
| <div className={`px-6 py-4 rounded-2xl shadow-sm ${ | |
| message.role === 'user' | |
| ? 'bg-blue-500 text-white rounded-tr-sm' | |
| : 'bg-white text-gray-900 rounded-tl-sm border border-gray-200' | |
| }`}> | |
| <div className="text-sm font-medium mb-1 opacity-75"> | |
| {message.role === 'user' ? 'You' : 'InsuCompass AI'} | |
| </div> | |
| <ReactMarkdown className="prose prose-sm max-w-none prose-table:border prose-table:border-gray-300 prose-th:bg-gray-100 prose-th:p-2 prose-td:p-2 prose-td:border prose-td:border-gray-300"> | |
| {message.content} | |
| </ReactMarkdown> | |
| {showPlanRecs && message.plans?.length && ( | |
| <> | |
| <h2 className="text-2xl font-bold text-gray-900">Recommended Plans for You</h2> | |
| <div className="grid md:grid-cols-2 gap-6"> | |
| {message.plans?.map((plan, idx) => ( | |
| <PlanCard key={idx} plan={plan} /> | |
| ))} | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| {/* Loading indicator */} | |
| {isLoading && ( | |
| <div className="flex justify-start"> | |
| <div className="flex items-start space-x-3"> | |
| <div className="w-10 h-10 rounded-full bg-gradient-to-r from-purple-500 to-pink-500 text-white flex items-center justify-center"> | |
| <Bot className="w-5 h-5" /> | |
| </div> | |
| <div className="bg-white px-6 py-4 rounded-2xl rounded-tl-sm border border-gray-200"> | |
| <div className="flex space-x-2"> | |
| <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div> | |
| <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div> | |
| <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| <div ref={chatEndRef} /> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Message Input */} | |
| <div className="bg-white border-t border-gray-200 p-4"> | |
| <div className="max-w-4xl mx-auto"> | |
| <div className="flex items-center space-x-4"> | |
| <div className="flex-1 relative"> | |
| <input | |
| type="text" | |
| value={currentMessage} | |
| onChange={(e) => setCurrentMessage(e.target.value)} | |
| onKeyDown={(e) => e.key === 'Enter' && handleSendMessage()} | |
| placeholder="Type your message..." | |
| className="w-full px-4 py-3 pr-12 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors" | |
| disabled={isLoading} | |
| /> | |
| <button | |
| onClick={handleSendMessage} | |
| disabled={isLoading || !currentMessage.trim()} | |
| className="absolute right-2 top-1/2 transform -translate-y-1/2 p-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" | |
| > | |
| <Send className="w-4 h-4" /> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default ChatInterfaceScreen; |