Skip to content

Commit 1124a81

Browse files
Phase 2 - Add chat context and models for AI Chat feature
- Created new TypeScript models for chat messages, API requests, and responses in `chat.ts`. - Implemented `ChatContext` and `ChatProvider` to manage chat state and interactions. - Updated `AIChat` component to utilize context for message handling and error display. - Enhanced styling for error messages in `AIChat.scss`. - Integrated local storage for message persistence and improved user experience.
1 parent e30edae commit 1124a81

File tree

9 files changed

+518
-44
lines changed

9 files changed

+518
-44
lines changed

frontend/src/common/models/chat.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* Types for the AI Chat feature
3+
*/
4+
5+
/**
6+
* Represents a single chat message in the UI
7+
*/
8+
export interface ChatMessage {
9+
id: string;
10+
text: string;
11+
sender: 'user' | 'ai';
12+
timestamp: Date;
13+
}
14+
15+
/**
16+
* API message format for Bedrock
17+
*/
18+
export interface BedrockMessage {
19+
role: 'user' | 'assistant';
20+
content: string;
21+
}
22+
23+
/**
24+
* Request payload for chat completion
25+
*/
26+
export interface ChatCompletionRequest {
27+
messages: BedrockMessage[];
28+
temperature?: number;
29+
maxTokens?: number;
30+
model?: string;
31+
}
32+
33+
/**
34+
* Response from the chat completion API
35+
*/
36+
export interface ChatCompletionResponse {
37+
message: BedrockMessage;
38+
usage: {
39+
promptTokens: number;
40+
completionTokens: number;
41+
totalTokens: number;
42+
};
43+
model: string;
44+
}
45+
46+
/**
47+
* Status of a chat session
48+
*/
49+
export enum ChatSessionStatus {
50+
IDLE = 'idle',
51+
LOADING = 'loading',
52+
ERROR = 'error'
53+
}
54+
55+
/**
56+
* Chat session configuration
57+
*/
58+
export interface ChatSessionConfig {
59+
maxHistoryLength?: number;
60+
persistHistory?: boolean;
61+
defaultGreeting?: string;
62+
model?: string;
63+
}

frontend/src/pages/Chat/components/AIChat/AIChat.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,23 @@
7474
}
7575
}
7676
}
77+
78+
&__error {
79+
display: flex;
80+
align-items: center;
81+
justify-content: center;
82+
margin: 1rem 0;
83+
padding: 0.75rem 1rem;
84+
background-color: rgba(255, 0, 0, 0.1);
85+
border-radius: 0.5rem;
86+
border-left: 0.25rem solid #f44336;
87+
88+
p {
89+
color: #d32f2f;
90+
margin: 0;
91+
font-size: 0.875rem;
92+
}
93+
}
7794
}
7895

7996
@keyframes bounce {

frontend/src/pages/Chat/components/AIChat/AIChat.tsx

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
1-
import React, { useState } from 'react';
1+
import React, { useRef, useEffect } from 'react';
22
import { IonContent } from '@ionic/react';
33
import ChatHeader from '../ChatHeader/ChatHeader';
44
import ChatInput from '../ChatInput/ChatInput';
55
import ChatMessage from '../ChatMessage/ChatMessage';
6+
import { useChatContext } from '../../hooks/useChatContext';
7+
import { ChatSessionStatus } from 'common/models/chat';
68
import './AIChat.scss';
79

8-
// Mock data structure for a chat message
9-
export interface ChatMessageType {
10-
id: string;
11-
text: string;
12-
sender: 'user' | 'ai';
13-
timestamp: Date;
14-
}
15-
1610
interface AIChatProps {
1711
isExpanded: boolean;
1812
onClose: () => void;
@@ -27,40 +21,23 @@ const AIChat: React.FC<AIChatProps> = ({
2721
onClose,
2822
onToggleExpand
2923
}) => {
30-
const [messages, setMessages] = useState<ChatMessageType[]>([]);
31-
const [isLoading, setIsLoading] = useState(false);
32-
24+
const { state, sendMessage } = useChatContext();
25+
const { messages, status, error } = state;
26+
const contentRef = useRef<HTMLIonContentElement>(null);
27+
const isLoading = status === ChatSessionStatus.LOADING;
28+
3329
// Function to handle sending a new message
34-
const handleSendMessage = (text: string) => {
30+
const handleSendMessage = async (text: string) => {
3531
if (!text.trim()) return;
36-
37-
// Create a new user message
38-
const newUserMessage: ChatMessageType = {
39-
id: Date.now().toString(),
40-
text,
41-
sender: 'user',
42-
timestamp: new Date()
43-
};
44-
45-
// Add the user message to the chat
46-
setMessages(prevMessages => [...prevMessages, newUserMessage]);
47-
48-
// Simulate AI response with loading state
49-
setIsLoading(true);
50-
51-
// Mock AI response after a delay
52-
setTimeout(() => {
53-
const aiResponse: ChatMessageType = {
54-
id: (Date.now() + 1).toString(),
55-
text: `This is a mock response to: "${text}"`,
56-
sender: 'ai',
57-
timestamp: new Date()
58-
};
59-
60-
setMessages(prevMessages => [...prevMessages, aiResponse]);
61-
setIsLoading(false);
62-
}, 1000);
32+
await sendMessage(text);
6333
};
34+
35+
// Scroll to bottom when messages change
36+
useEffect(() => {
37+
if (contentRef.current) {
38+
contentRef.current.scrollToBottom(300);
39+
}
40+
}, [messages]);
6441

6542
return (
6643
<div className={`ai-chat ${isExpanded ? 'ai-chat--expanded' : ''}`}>
@@ -70,7 +47,7 @@ const AIChat: React.FC<AIChatProps> = ({
7047
isExpanded={isExpanded}
7148
/>
7249

73-
<IonContent className="ai-chat__content">
50+
<IonContent className="ai-chat__content" ref={contentRef}>
7451
<div className="ai-chat__messages">
7552
{messages.length === 0 ? (
7653
<div className="ai-chat__empty-state">
@@ -94,6 +71,12 @@ const AIChat: React.FC<AIChatProps> = ({
9471
</div>
9572
</div>
9673
)}
74+
75+
{error && status === ChatSessionStatus.ERROR && (
76+
<div className="ai-chat__error">
77+
<p>{error}</p>
78+
</div>
79+
)}
9780
</div>
9881
</IonContent>
9982

frontend/src/pages/Chat/components/AIChatContainer/AIChatContainer.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useState, useEffect, useRef } from 'react';
22
import AIChat from '../AIChat/AIChat';
3+
import { ChatProvider } from '../../context/ChatContext';
34
import './AIChatContainer.scss';
45

56
/**
@@ -42,7 +43,7 @@ const AIChatContainer: React.FC = () => {
4243
}, [isVisible]);
4344

4445
return (
45-
<>
46+
<ChatProvider>
4647
{/* AI Chat toggle button for bottom nav */}
4748
<div className="ai-chat-container__toggle">
4849
<button
@@ -64,7 +65,7 @@ const AIChatContainer: React.FC = () => {
6465
/>
6566
</div>
6667
)}
67-
</>
68+
</ChatProvider>
6869
);
6970
};
7071

frontend/src/pages/Chat/components/ChatMessage/ChatMessage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import { format } from 'date-fns';
3-
import { ChatMessageType } from '../AIChat/AIChat';
3+
import { ChatMessage as ChatMessageType } from 'common/models/chat';
44
import './ChatMessage.scss';
55

66
interface ChatMessageProps {

0 commit comments

Comments
 (0)