Skip to content

Commit 8c586a8

Browse files
Phase 5 - Implement theme management and suggested prompts
- Added `ThemeProvider` and `useTheme` hook for managing light, dark, and system themes. - Integrated `ThemeToggle` component in `ChatHeader` for user theme selection. - Updated styles across components to utilize CSS variables for theming. - Introduced `SuggestedPrompts` component to provide quick question suggestions in the chat. - Enhanced `AIChat` to display suggested prompts for improved user interaction. - Refactored `AIChat.scss` and other stylesheets to support new theme variables. - Created `ShareModal` for sharing chat responses via link or email.
1 parent 9fa0607 commit 8c586a8

File tree

17 files changed

+772
-28
lines changed

17 files changed

+772
-28
lines changed

frontend/src/App.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import ScrollProvider from 'common/providers/ScrollProvider';
1616
import { AIChatProvider } from 'common/providers/AIChatProvider';
1717
import Toasts from 'common/components/Toast/Toasts';
1818
import AppRouter from 'common/components/Router/AppRouter';
19+
import ThemeProvider from 'pages/Chat/context/ThemeContext';
1920

21+
import 'pages/Chat/styles/theme-variables.scss';
2022
import './theme/main.css';
2123

2224
setupIonicReact({
@@ -59,11 +61,13 @@ const App = (): JSX.Element => {
5961
<AxiosProvider>
6062
<ToastProvider>
6163
<ScrollProvider>
62-
<AIChatProvider>
63-
<AppRouter />
64-
<Toasts />
65-
<ReactQueryDevtools initialIsOpen={false} buttonPosition="bottom-left" />
66-
</AIChatProvider>
64+
<ThemeProvider>
65+
<AIChatProvider>
66+
<AppRouter />
67+
<Toasts />
68+
<ReactQueryDevtools initialIsOpen={false} buttonPosition="bottom-left" />
69+
</AIChatProvider>
70+
</ThemeProvider>
6771
</ScrollProvider>
6872
</ToastProvider>
6973
</AxiosProvider>

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
flex-direction: column;
44
width: 100%;
55
height: 100%;
6-
background-color: #ffffff;
6+
background-color: var(--chat-bg-color);
77
border-radius: 1.25rem 1.25rem 0 0;
8-
box-shadow: 0 -0.25rem 1rem rgba(0, 0, 0, 0.1);
8+
box-shadow: 0 -0.25rem 1rem var(--chat-shadow-color);
99
overflow: hidden;
1010
transition: height 0.3s ease-in-out;
1111
position: relative;
@@ -20,6 +20,7 @@
2020
flex: 1;
2121
overflow-y: auto;
2222
padding: 1rem;
23+
--background: var(--chat-bg-color);
2324
}
2425

2526
&__messages {
@@ -31,17 +32,16 @@
3132

3233
&__empty-state {
3334
display: flex;
35+
flex-direction: column;
3436
align-items: center;
3537
justify-content: center;
36-
height: 100%;
37-
text-align: center;
38-
color: #666;
39-
padding: 2rem;
38+
padding: 1.5rem;
4039

4140
p {
4241
font-size: 1rem;
43-
max-width: 20rem;
44-
margin: 0 auto;
42+
color: var(--chat-secondary-text);
43+
text-align: center;
44+
margin-bottom: 1.5rem;
4545
}
4646
}
4747

@@ -81,12 +81,12 @@
8181
justify-content: center;
8282
margin: 1rem 0;
8383
padding: 0.75rem 1rem;
84-
background-color: rgba(255, 0, 0, 0.1);
84+
background-color: var(--chat-error-bg);
8585
border-radius: 0.5rem;
86-
border-left: 0.25rem solid #f44336;
86+
border-left: 0.25rem solid var(--chat-error-border);
8787

8888
p {
89-
color: #d32f2f;
89+
color: var(--chat-error-text);
9090
margin: 0;
9191
font-size: 0.875rem;
9292
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ChatHeader from '../ChatHeader/ChatHeader';
44
import ChatInput from '../ChatInput/ChatInput';
55
import ChatMessage from '../ChatMessage/ChatMessage';
66
import TypingIndicator from '../ChatMessage/TypingIndicator';
7+
import SuggestedPrompts from '../SuggestedPrompts/SuggestedPrompts';
78
import { useChatContext } from '../../hooks/useChatContext';
89
import { ChatSessionStatus } from 'common/models/chat';
910
import './AIChat.scss';
@@ -33,6 +34,11 @@ const AIChat: React.FC<AIChatProps> = ({
3334
await sendMessage(text);
3435
};
3536

37+
// Handle suggested prompt selection
38+
const handleSelectPrompt = (prompt: string) => {
39+
handleSendMessage(prompt);
40+
};
41+
3642
// Scroll to bottom when messages change or when typing
3743
useEffect(() => {
3844
if (contentRef.current) {
@@ -53,6 +59,7 @@ const AIChat: React.FC<AIChatProps> = ({
5359
{messages.length === 0 ? (
5460
<div className="ai-chat__empty-state">
5561
<p>Ask me anything about your medical reports or health questions.</p>
62+
<SuggestedPrompts onSelectPrompt={handleSelectPrompt} />
5663
</div>
5764
) : (
5865
messages.map(message => (

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.chat-header {
22
&__toolbar {
3-
--background: #f7f7f7;
3+
--background: var(--chat-header-bg);
44
--border-color: transparent;
55
padding: 0.75rem 1rem;
66
display: flex;
@@ -11,7 +11,7 @@
1111
&__title {
1212
font-size: 1.125rem;
1313
font-weight: 600;
14-
color: #333;
14+
color: var(--chat-text-color);
1515
}
1616

1717
&__actions {
@@ -41,19 +41,32 @@
4141
}
4242

4343
&--clear {
44-
color: #ff6b6b;
44+
color: var(--chat-icon-danger);
4545
}
4646

4747
&--expand {
48-
color: #4765ff;
48+
color: var(--chat-icon-primary);
4949
}
5050

5151
&--close {
52-
color: #888;
52+
color: var(--chat-icon-secondary);
5353
}
5454
}
5555

5656
&__icon {
5757
font-size: 1.25rem;
5858
}
59+
}
60+
61+
// Dark theme adjustments
62+
.dark-theme .chat-header {
63+
&__button {
64+
&:hover {
65+
background-color: rgba(255, 255, 255, 0.1);
66+
}
67+
68+
&:active {
69+
background-color: rgba(255, 255, 255, 0.15);
70+
}
71+
}
5972
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
22
import { IonHeader, IonIcon, IonToolbar, IonAlert } from '@ionic/react';
33
import { close, expandOutline, contractOutline, trashOutline } from 'ionicons/icons';
44
import { useChatContext } from '../../hooks/useChatContext';
5+
import ThemeToggle from '../ThemeToggle/ThemeToggle';
56
import './ChatHeader.scss';
67

78
interface ChatHeaderProps {
@@ -37,6 +38,7 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
3738
AI Assistant
3839
</div>
3940
<div className="chat-header__actions">
41+
<ThemeToggle />
4042
<button
4143
className="chat-header__button chat-header__button--clear"
4244
onClick={handleClearClick}

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
}
2121

2222
.chat-message__bubble {
23-
background-color: #4765ff;
24-
color: white;
23+
background-color: var(--chat-user-bubble-bg);
24+
color: var(--chat-user-bubble-color);
2525
border-radius: 1.25rem 0 1.25rem 1.25rem;
2626

2727
.chat-message__time {
@@ -34,25 +34,26 @@
3434
align-items: flex-start;
3535

3636
.chat-message__bubble {
37-
background-color: #f0f0f0;
38-
color: #333;
37+
background-color: var(--chat-ai-bubble-bg);
38+
color: var(--chat-ai-bubble-color);
3939
border-radius: 0 1.25rem 1.25rem 1.25rem;
40+
border: 1px solid var(--chat-ai-bubble-border);
4041
}
4142
}
4243

4344
&__avatar {
4445
width: 2rem;
4546
height: 2rem;
4647
border-radius: 50%;
47-
background-color: #4765ff;
48+
background-color: var(--chat-icon-primary);
4849
display: flex;
4950
align-items: center;
5051
justify-content: center;
5152
flex-shrink: 0;
5253
}
5354

5455
&__avatar-icon {
55-
color: white;
56+
color: var(--chat-user-bubble-color);
5657
font-size: 0.875rem;
5758
font-weight: 600;
5859
}
@@ -103,7 +104,7 @@
103104

104105
&__time {
105106
font-size: 0.75rem;
106-
color: #999;
107+
color: var(--chat-secondary-text);
107108
margin-top: 0.25rem;
108109
text-align: right;
109110
opacity: 0;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { format } from 'date-fns';
33
import ReactMarkdown from 'react-markdown';
44
import rehypeSanitize from 'rehype-sanitize';
55
import { ChatMessage as ChatMessageType } from 'common/models/chat';
6+
import MessageActions from './MessageActions';
67
import './ChatMessage.scss';
78

89
interface ChatMessageProps {
@@ -53,6 +54,8 @@ const ChatMessage: React.FC<ChatMessageProps> = ({ message }) => {
5354
<div className={`chat-message__time ${showTime ? 'chat-message__time--visible' : ''}`}>
5455
{formattedTime}
5556
</div>
57+
58+
{isAI && <MessageActions text={text} />}
5659
</div>
5760
</div>
5861
</div>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
.message-actions {
2+
display: flex;
3+
align-items: center;
4+
justify-content: space-between;
5+
margin-top: 0.5rem;
6+
opacity: 0;
7+
transition: opacity 0.2s ease;
8+
9+
&__button {
10+
background: transparent;
11+
border: none;
12+
display: flex;
13+
align-items: center;
14+
justify-content: center;
15+
width: 2rem;
16+
height: 2rem;
17+
border-radius: 50%;
18+
padding: 0;
19+
cursor: pointer;
20+
color: #777;
21+
transition: all 0.2s ease;
22+
23+
&:hover {
24+
background-color: rgba(0, 0, 0, 0.05);
25+
color: #444;
26+
}
27+
28+
&--active {
29+
color: #4765ff;
30+
}
31+
32+
&--positive {
33+
color: #2ecc71;
34+
}
35+
36+
&--negative {
37+
color: #e74c3c;
38+
}
39+
}
40+
41+
&__feedback {
42+
display: flex;
43+
gap: 0.25rem;
44+
}
45+
}
46+
47+
// Make actions visible when the message bubble is hovered
48+
.chat-message__bubble:hover .message-actions {
49+
opacity: 1;
50+
}

0 commit comments

Comments
 (0)