Spaces:
Sleeping
Sleeping
Upload 5 files
#5
by
AnjanaNAshokan - opened
src/screens/ChatInterfaceScreen/ChatInterfaceScreen.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import React
|
| 2 |
import { Send, User, Bot } from 'lucide-react';
|
| 3 |
import InsuCompassLogo from '../../assets/InsuCompass_Logo.png';
|
| 4 |
import ReactMarkdown from 'react-markdown';
|
|
@@ -26,6 +26,7 @@ interface ChatInterfaceScreenProps {
|
|
| 26 |
}
|
| 27 |
|
| 28 |
const ChatInterfaceScreen: React.FC<ChatInterfaceScreenProps> = ({ userProfile }) => {
|
|
|
|
| 29 |
const {
|
| 30 |
chatHistory,
|
| 31 |
isLoading,
|
|
@@ -34,14 +35,9 @@ const ChatInterfaceScreen: React.FC<ChatInterfaceScreenProps> = ({ userProfile }
|
|
| 34 |
handleSendMessage,
|
| 35 |
showPlanRecs,
|
| 36 |
chatEndRef,
|
| 37 |
-
|
| 38 |
} = useChatInterface(userProfile);
|
| 39 |
|
| 40 |
-
useEffect(() => {
|
| 41 |
-
if (chatHistory.length === 0) {
|
| 42 |
-
sendChatMessage('START_PROFILE_BUILDING', userProfile);
|
| 43 |
-
}
|
| 44 |
-
}, [userProfile])
|
| 45 |
return (
|
| 46 |
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-indigo-50 flex flex-col">
|
| 47 |
{/* Header */}
|
|
@@ -133,6 +129,7 @@ const ChatInterfaceScreen: React.FC<ChatInterfaceScreenProps> = ({ userProfile }
|
|
| 133 |
<div className="flex items-center space-x-4">
|
| 134 |
<div className="flex-1 relative">
|
| 135 |
<input
|
|
|
|
| 136 |
type="text"
|
| 137 |
value={currentMessage}
|
| 138 |
onChange={(e) => setCurrentMessage(e.target.value)}
|
|
|
|
| 1 |
+
import React from 'react';
|
| 2 |
import { Send, User, Bot } from 'lucide-react';
|
| 3 |
import InsuCompassLogo from '../../assets/InsuCompass_Logo.png';
|
| 4 |
import ReactMarkdown from 'react-markdown';
|
|
|
|
| 26 |
}
|
| 27 |
|
| 28 |
const ChatInterfaceScreen: React.FC<ChatInterfaceScreenProps> = ({ userProfile }) => {
|
| 29 |
+
|
| 30 |
const {
|
| 31 |
chatHistory,
|
| 32 |
isLoading,
|
|
|
|
| 35 |
handleSendMessage,
|
| 36 |
showPlanRecs,
|
| 37 |
chatEndRef,
|
| 38 |
+
inputRef
|
| 39 |
} = useChatInterface(userProfile);
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
return (
|
| 42 |
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-indigo-50 flex flex-col">
|
| 43 |
{/* Header */}
|
|
|
|
| 129 |
<div className="flex items-center space-x-4">
|
| 130 |
<div className="flex-1 relative">
|
| 131 |
<input
|
| 132 |
+
ref={inputRef}
|
| 133 |
type="text"
|
| 134 |
value={currentMessage}
|
| 135 |
onChange={(e) => setCurrentMessage(e.target.value)}
|
src/screens/ChatInterfaceScreen/useChatInterface.ts
CHANGED
|
@@ -8,13 +8,37 @@ export function useChatInterface(userProfile: UserProfile, isProfileComplete?: b
|
|
| 8 |
const [currentMessage, setCurrentMessage] = useState('');
|
| 9 |
const [showPlanRecs, setShowPlanRecs] = useState<boolean>(false);
|
| 10 |
const chatEndRef = useRef<HTMLDivElement>(null);
|
|
|
|
| 11 |
// threadId is generated once per chat session and persists for the hook's lifetime
|
| 12 |
const [threadId] = useState(() => crypto.randomUUID());
|
| 13 |
|
| 14 |
useEffect(() => {
|
| 15 |
chatEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
}, [chatHistory]);
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
const sendChatMessage = async (
|
| 19 |
message: string,
|
| 20 |
profileOverride?: UserProfile
|
|
@@ -35,22 +59,16 @@ export function useChatInterface(userProfile: UserProfile, isProfileComplete?: b
|
|
| 35 |
});
|
| 36 |
if (!response.ok) throw new Error('Failed to send message');
|
| 37 |
const data: ApiResponse = await response.json();
|
| 38 |
-
//
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
// role: role.toLowerCase() as 'user' | 'agent',
|
| 43 |
-
// content: contentParts.join(':').trim(),
|
| 44 |
-
// timestamp: Date.now()
|
| 45 |
-
// };
|
| 46 |
-
// });
|
| 47 |
-
let newHistory: ChatMessage[] = [...chatHistory, {
|
| 48 |
role: 'agent',
|
| 49 |
-
content:
|
| 50 |
timestamp: Date.now(),
|
| 51 |
plans: !showPlanRecs && data.plan_recommendations?.recommendations?.length && data.plan_recommendations?.recommendations?.length > 0 ? data.plan_recommendations.recommendations : undefined
|
| 52 |
-
}
|
| 53 |
-
setChatHistory(
|
| 54 |
if (!showPlanRecs && data.plan_recommendations?.recommendations?.length && data.plan_recommendations?.recommendations?.length > 0) {
|
| 55 |
setShowPlanRecs(true);
|
| 56 |
}
|
|
@@ -84,6 +102,7 @@ export function useChatInterface(userProfile: UserProfile, isProfileComplete?: b
|
|
| 84 |
handleSendMessage,
|
| 85 |
showPlanRecs,
|
| 86 |
chatEndRef,
|
|
|
|
| 87 |
sendChatMessage
|
| 88 |
};
|
| 89 |
}
|
|
|
|
| 8 |
const [currentMessage, setCurrentMessage] = useState('');
|
| 9 |
const [showPlanRecs, setShowPlanRecs] = useState<boolean>(false);
|
| 10 |
const chatEndRef = useRef<HTMLDivElement>(null);
|
| 11 |
+
const inputRef = useRef<HTMLInputElement>(null);
|
| 12 |
// threadId is generated once per chat session and persists for the hook's lifetime
|
| 13 |
const [threadId] = useState(() => crypto.randomUUID());
|
| 14 |
|
| 15 |
useEffect(() => {
|
| 16 |
chatEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
| 17 |
+
// Focus input after chatHistory changes (i.e., after response is rendered)
|
| 18 |
+
if (inputRef.current) {
|
| 19 |
+
inputRef.current.focus();
|
| 20 |
+
}
|
| 21 |
}, [chatHistory]);
|
| 22 |
|
| 23 |
+
// Prevent double API call: only send initial chat message once when userProfile is complete
|
| 24 |
+
const hasSentInitialMessage = useRef(false);
|
| 25 |
+
useEffect(() => {
|
| 26 |
+
// TODO: review this logic
|
| 27 |
+
// Check if userProfile is complete before sending initial message
|
| 28 |
+
const isValidProfile = !!userProfile &&
|
| 29 |
+
userProfile?.zip_code?.length && userProfile?.zip_code?.length > 0 &&
|
| 30 |
+
!!userProfile.age && userProfile.age > 0 &&
|
| 31 |
+
!!userProfile.gender && userProfile.gender.length > 0 &&
|
| 32 |
+
!!userProfile.household_size &&
|
| 33 |
+
!!userProfile.income &&
|
| 34 |
+
!!userProfile.employment_status &&
|
| 35 |
+
!!userProfile.citizenship;
|
| 36 |
+
if (isValidProfile && !hasSentInitialMessage.current) {
|
| 37 |
+
sendChatMessage('START_PROFILE_BUILDING', userProfile);
|
| 38 |
+
hasSentInitialMessage.current = true;
|
| 39 |
+
}
|
| 40 |
+
}, [userProfile]);
|
| 41 |
+
|
| 42 |
const sendChatMessage = async (
|
| 43 |
message: string,
|
| 44 |
profileOverride?: UserProfile
|
|
|
|
| 59 |
});
|
| 60 |
if (!response.ok) throw new Error('Failed to send message');
|
| 61 |
const data: ApiResponse = await response.json();
|
| 62 |
+
// Only append the agent's message to the existing chatHistory
|
| 63 |
+
const agentMsgRaw = data.updated_history[data.updated_history.length - 1] || '';
|
| 64 |
+
const agentMsgContent = agentMsgRaw.replace(/^Agent:\s*/, '');
|
| 65 |
+
const agentMessage: ChatMessage = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
role: 'agent',
|
| 67 |
+
content: agentMsgContent,
|
| 68 |
timestamp: Date.now(),
|
| 69 |
plans: !showPlanRecs && data.plan_recommendations?.recommendations?.length && data.plan_recommendations?.recommendations?.length > 0 ? data.plan_recommendations.recommendations : undefined
|
| 70 |
+
};
|
| 71 |
+
setChatHistory(prev => [...prev, agentMessage]);
|
| 72 |
if (!showPlanRecs && data.plan_recommendations?.recommendations?.length && data.plan_recommendations?.recommendations?.length > 0) {
|
| 73 |
setShowPlanRecs(true);
|
| 74 |
}
|
|
|
|
| 102 |
handleSendMessage,
|
| 103 |
showPlanRecs,
|
| 104 |
chatEndRef,
|
| 105 |
+
inputRef,
|
| 106 |
sendChatMessage
|
| 107 |
};
|
| 108 |
}
|