Skip to content

Commit a7b84e9

Browse files
authored
Merge pull request #140 from JacobBaqleh1/jacobbaqleh/feature-suggested-prompts
Feature - add suggested prompts
2 parents aecb916 + 7df2ec0 commit a7b84e9

File tree

4 files changed

+74
-10
lines changed

4 files changed

+74
-10
lines changed

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
1-
import { useState } from "react";
21
import useMessages, { type IMessage } from "../../../hooks/useMessages";
32

43
interface Props {
54
setMessages: React.Dispatch<React.SetStateAction<IMessage[]>>;
65
isLoading: boolean;
76
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
7+
value: string;
88
inputRef: React.RefObject<HTMLInputElement | null>;
9+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
910
}
1011

1112
export default function InputField({
1213
setMessages,
1314
isLoading,
1415
setIsLoading,
1516
inputRef,
17+
value,
18+
onChange,
1619
}: Props) {
17-
const [text, setText] = useState("");
1820
const { addMessage } = useMessages();
1921

2022
const handleSend = async () => {
21-
if (!text.trim()) return;
23+
if (!value.trim()) return;
2224

23-
const userMessage = text;
25+
const userMessage = value;
2426
const userMessageId = Date.now().toString();
2527
const botMessageId = (Date.now() + 1).toString();
2628

27-
setText("");
29+
onChange({ target: { value: "" } } as React.ChangeEvent<HTMLInputElement>);
2830
setIsLoading(true);
2931

3032
// Add user message
@@ -44,7 +46,7 @@ export default function InputField({
4446
]);
4547

4648
try {
47-
const reader = await addMessage(text);
49+
const reader = await addMessage(userMessage);
4850
if (!reader) return;
4951
const decoder = new TextDecoder();
5052
let fullText = "";
@@ -85,11 +87,11 @@ export default function InputField({
8587
<div className="flex gap-2 mt-4 h-11 items-stretch mx-auto max-w-[700px]">
8688
<input
8789
type="text"
88-
value={text}
89-
onChange={(e) => setText(e.target.value)}
90+
value={value}
91+
onChange={onChange}
9092
onKeyDown={(e) => {
9193
if (e.key === "Enter") {
92-
e.preventDefault(); // prevent form submission or newline
94+
e.preventDefault();
9395
handleSend();
9496
}
9597
}}
@@ -101,7 +103,7 @@ export default function InputField({
101103
<button
102104
className="px-6 bg-[#1F584F] hover:bg-[#4F8B82] text-white rounded-md cursor-pointer transition-color duration-300"
103105
onClick={handleSend}
104-
disabled={isLoading || !text.trim()}
106+
disabled={isLoading || !value.trim()}
105107
>
106108
{isLoading ? "..." : "Send"}
107109
</button>

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MessageContent from "./MessageContent";
55
import useSession from "../../../hooks/useSession";
66
import ExportMessagesButton from "./ExportMessagesButton";
77
import CitySelectField from "./CitySelectField";
8+
import SuggestedPrompts from "./SuggestedPrompts";
89

910
interface Props {
1011
messages: IMessage[];
@@ -22,6 +23,7 @@ export default function MessageWindow({
2223
onStatuteClick,
2324
}: Props) {
2425
const [isLoading, setIsLoading] = useState(false);
26+
const [inputValue, setInputValue] = useState("");
2527
const { handleNewSession } = useSession();
2628
const inputRef = useRef<HTMLInputElement | null>(null);
2729
const messagesRef = useRef<HTMLDivElement | null>(null);
@@ -44,6 +46,14 @@ export default function MessageWindow({
4446
}
4547
}, [messages]);
4648

49+
const handlePromptClick = (prompt: string) => {
50+
setInputValue(prompt);
51+
if (inputRef.current) {
52+
inputRef.current.value = prompt;
53+
inputRef.current.focus();
54+
}
55+
};
56+
4757
return (
4858
<>
4959
<div className="flex-1">
@@ -92,11 +102,16 @@ export default function MessageWindow({
92102
<div>
93103
{messages.length > 0 ? (
94104
<>
105+
{messages.length === 1 && inputValue === "" && (
106+
<SuggestedPrompts onPromptClick={handlePromptClick} />
107+
)}
95108
<InputField
96109
setMessages={setMessages}
97110
isLoading={isLoading}
98111
setIsLoading={setIsLoading}
99112
inputRef={inputRef}
113+
value={inputValue}
114+
onChange={(e) => setInputValue(e.target.value)}
100115
/>
101116
<div className="flex justify-center gap-4 mt-4">
102117
<button
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
interface SuggestedPromptsProps {
2+
onPromptClick: (prompt: string) => void;
3+
}
4+
5+
const prompts = [
6+
"Do I qualify for a rental subsidy, such as Section 8/HomeForward?",
7+
"I have a leak in my roof. Help me address this with my landlord.",
8+
"I received an eviction notice for non-payment of rent. What should I do?",
9+
"I received a 'no-cause' eviction notice. How much money is my landlord required to pay me to move out?",
10+
];
11+
12+
export default function SuggestedPrompts({
13+
onPromptClick,
14+
}: SuggestedPromptsProps) {
15+
return (
16+
<div className="items-center m-auto">
17+
<div className="flex flex-col gap-4 fade-in-up items-center">
18+
{prompts.map((prompt, idx) => (
19+
<button
20+
key={idx}
21+
className="inline-flex px-4 border border-[#1f584f] rounded-4xl cursor-pointer py-1 font-medium sm:bg-white hover:bg-[#bac9b2]/50"
22+
onClick={() =>
23+
onPromptClick(Array.isArray(prompt) ? prompt.join(" ") : prompt)
24+
}
25+
type="button"
26+
>
27+
{prompt}
28+
</button>
29+
))}
30+
</div>
31+
</div>
32+
);
33+
}

frontend/src/style.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,17 @@ body {
3939
.message-bubble a {
4040
@apply inline text-blue-600 underline cursor-pointer transition-colors hover:bg-blue-200 rounded;
4141
}
42+
43+
@keyframes fadeInUp {
44+
from {
45+
opacity: 0;
46+
transform: translateY(16px);
47+
}
48+
to {
49+
opacity: 1;
50+
transform: translateY(0);
51+
}
52+
}
53+
.fade-in-up {
54+
animation: fadeInUp 0.5s cubic-bezier(0.22, 1, 0.36, 1);
55+
}

0 commit comments

Comments
 (0)