Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 10 additions & 48 deletions frontend/src/components/Chat.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import { FiMenu, FiSend } from 'react-icons/fi';
import React, { useCallback, useEffect, useRef, useState } from 'react';

import React, { useCallback, useEffect, useRef, useState } from 'react';
import ReactMarkdown from 'react-markdown';
import TypingIndicator from './TypingIndicator';
import remarkGfm from 'remark-gfm';
import styles from './Chat.module.css';
import type { Message,ChatProps,HandleSendType } from '../../types/DataTypes'
import Header from './sub-components/Header';
import WelcomePromptSuggestions from './sub-components/WelcomePromptSuggestions';
import InputArea from './sub-components/InputArea';

interface Message {
text: string;
sender: 'user' | 'bot';
timestamp: string;
}

interface ChatProps {
onMenuClick: () => void;
resetSignal?: number;
}

const Chat: React.FC<ChatProps> = ({ onMenuClick, resetSignal }) => {
const [messages, setMessages] = useState<Message[]>([]);
Expand All @@ -36,7 +29,7 @@ const Chat: React.FC<ChatProps> = ({ onMenuClick, resetSignal }) => {
const userId = getOrCreateId('apiconf_user_id');
const sessionId = getOrCreateId('apiconf_session_id');

const handleSend = useCallback(async (messageToSend: string) => {
const handleSend:HandleSendType = useCallback(async (messageToSend: string) => {
if (!messageToSend.trim()) return;

// Save the first user message as the preview for the history
Expand Down Expand Up @@ -169,30 +162,12 @@ const Chat: React.FC<ChatProps> = ({ onMenuClick, resetSignal }) => {

return (
<div className={styles.chat}>
<div className={styles.chatHeader}>
<button className={styles.menuButton} onClick={onMenuClick}>
<FiMenu />
</button>
Chat with Ndu
</div>
{/* header */}
<Header onMenuClick={onMenuClick}/>
<div className={styles.content}>
<div className={styles.messages}>
{messages.length === 0 ? (
<div className={styles.welcome}>
<h1>Welcome!</h1>
<p>Your friendly assistant for the API Conference 2025 in Lagos. Ask me about speakers, schedules, and more!</p>
<div className={styles.promptSuggestions}>
<button className={styles.promptButton} onClick={() => handleSend('Who are the main speakers?')}>
Who are the main speakers?
</button>
<button className={styles.promptButton} onClick={() => handleSend('What is the conference schedule?')}>
What is the conference schedule?
</button>
<button className={styles.promptButton} onClick={() => handleSend('How do I get to the venue?')}>
How do I get to the venue?
</button>
</div>
</div>
<WelcomePromptSuggestions handleSend={handleSend}/>
) : (
messages.map((msg, index) => (
<div
Expand Down Expand Up @@ -224,20 +199,7 @@ const Chat: React.FC<ChatProps> = ({ onMenuClick, resetSignal }) => {
<div ref={messagesEndRef} />
</div>
</div>
<div className={styles.inputArea}>
<form onSubmit={handleSubmit} className={styles.inputForm}>
<input
type="text"
className={styles.inputField}
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask something..."
/>
<button type="submit" className={styles.sendButton}>
<FiSend />
</button>
</form>
</div>
<InputArea input={input} setInput={setInput} handleSubmit={handleSubmit}/>
</div>
);
};
Expand Down
14 changes: 2 additions & 12 deletions frontend/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import React, { useEffect, useState } from 'react';
import styles from './Sidebar.module.css';
import { FiPlus, FiX } from 'react-icons/fi';
import type {HistoryItem,SidebarProps} from '../../types/DataTypes'


interface HistoryItem {
sessionId: string;
timestamp: string;
preview: string;
}

interface SidebarProps {
isOpen: boolean;
onClose: () => void;
onNewChat: () => void;
onRestoreSession: (sessionId: string) => void;
activeSessionId: string | null;
}

const Sidebar: React.FC<SidebarProps> = ({ isOpen, onClose, onNewChat, onRestoreSession, activeSessionId }) => {
const [history, setHistory] = useState<HistoryItem[]>([]);
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/components/sub-components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

import styles from '../Chat.module.css';
import { FiMenu} from 'react-icons/fi';
import type { HeaderType} from '../../../types/DataTypes';

const Header = ({onMenuClick}:HeaderType) => {
return (
<div className={styles.chatHeader}>
<button className={styles.menuButton} onClick={onMenuClick}>
<FiMenu />
</button>
Chat with Ndu
</div>
)
}

export default Header
26 changes: 26 additions & 0 deletions frontend/src/components/sub-components/InputArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react'
import type { InputAreaProps } from '../../../types/DataTypes'
import styles from '../Chat.module.css';
import { FiSend } from 'react-icons/fi';


const InputArea: React.FC <InputAreaProps> = ({input,setInput,handleSubmit}) => {
return (
<div className={styles.inputArea}>
<form onSubmit={handleSubmit} className={styles.inputForm}>
<input
type="text"
className={styles.inputField}
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask something..."
/>
<button type="submit" className={styles.sendButton}>
<FiSend />
</button>
</form>
</div>
)
}

export default InputArea
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import styles from '../Chat.module.css';
import type { WelcomePromptSuggestionsProps } from '../../../types/DataTypes';


const WelcomePromptSuggestions = ({handleSend}:WelcomePromptSuggestionsProps) => {

return (
<div className={styles.welcome}>
<h1>Welcome!</h1>
<p>Your friendly assistant for the API Conference 2025 in Lagos. Ask me about speakers, schedules, and more!</p>
<div className={styles.promptSuggestions}>
<button className={styles.promptButton} onClick={() => handleSend('Who are the main speakers?')}>
Who are the main speakers?
</button>
<button className={styles.promptButton} onClick={() => handleSend('What is the conference schedule?')}>
What is the conference schedule?
</button>
<button className={styles.promptButton} onClick={() => handleSend('How do I get to the venue?')}>
How do I get to the venue?
</button>
</div>
</div>
)
}

export default WelcomePromptSuggestions
42 changes: 42 additions & 0 deletions frontend/types/DataTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export interface Message {
text: string;
sender: 'user' | 'bot';
timestamp: string;
}

export interface InputAreaProps {
input: string;
setInput: React.Dispatch<React.SetStateAction<string>>;
handleSubmit: (e: React.FormEvent) => void;
}

export interface HandleSendType {
(messageToSend: string): Promise<void>;
}

export interface WelcomePromptSuggestionsProps {
handleSend: HandleSendType;
}

export interface HeaderType {
onMenuClick: ()=> void
}

export interface ChatProps {
onMenuClick: () => void;
resetSignal?: number;
}

export interface HistoryItem {
sessionId: string;
timestamp: string;
preview: string;
}

export interface SidebarProps {
isOpen: boolean;
onClose: () => void;
onNewChat: () => void;
onRestoreSession: (sessionId: string) => void;
activeSessionId: string | null;
}