Skip to content

Commit d52cf46

Browse files
committed
feat(web): Implement messaging functionality in basic page
1 parent 894a23c commit d52cf46

6 files changed

Lines changed: 154 additions & 59 deletions

File tree

web/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"react": "^18.3.1",
2323
"react-dom": "^18.3.1",
2424
"react-router": "^7.0.1",
25+
"react-spinners": "^0.14.1",
2526
"sonner": "^1.7.0",
2627
"tailwind-merge": "^2.5.5",
2728
"tailwindcss-animate": "^1.0.7"

web/src/enums/api.enums.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ export enum TerraformTemplateAPI {
55
EC2 = '/IaC-template/aws/ec2',
66
Docker = '/IaC-template/docker',
77
}
8+
9+
export enum API {
10+
Basic = '/IaC-basic',
11+
}

web/src/index.css

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,26 @@
77
--background: 0 0% 3.9%;
88
--foreground: 0 0% 100%;
99
}
10-
10+
1111
@font-face {
12-
font-family: "figtree";
13-
src: url("/fonts/Figtree-VariableFont_wght.ttf");
12+
font-family: 'figtree';
13+
src: url('/fonts/Figtree-VariableFont_wght.ttf');
1414
font-weight: 100 900;
15-
font-display: "swap";
16-
font-style: "normal";
15+
font-display: 'swap';
16+
font-style: 'normal';
1717
}
1818

1919
body {
20-
@apply bg-background text-foreground font-figtree;
20+
input::-webkit-outer-spin-button,
21+
input::-webkit-inner-spin-button {
22+
-webkit-appearance: none;
23+
margin: 0;
24+
}
25+
26+
input[type='number'] {
27+
-moz-appearance: textfield;
28+
appearance: textfield;
29+
}
30+
@apply bg-background font-figtree text-foreground;
2131
}
2232
}

web/src/pages/basic/basic.tsx

Lines changed: 106 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,143 @@
1-
import { FC } from 'react';
1+
import { FC, useEffect, useRef, useState } from 'react';
22
import { Send } from 'lucide-react';
3+
import { toast } from 'sonner';
4+
import { usePost } from '@/core/react-query';
5+
import { BasicBody, BasicMessage, BasicResponse } from './basic.types';
6+
import { API } from '@/enums/api.enums';
7+
import { BeatLoader } from 'react-spinners';
38

49
const Basic: FC = () => {
10+
const { mutateAsync } = usePost<BasicResponse, BasicBody>(API.Basic, 'basic');
11+
12+
const [minToken, setMinToken] = useState('100');
13+
const [maxToken, setMaxToken] = useState('500');
14+
const [service, setService] = useState('terraform');
15+
const [input, setInput] = useState('');
16+
const [messages, setMessages] = useState<BasicMessage[]>([]);
17+
18+
const messagesRef = useRef<HTMLDivElement>(null);
19+
20+
useEffect(() => {
21+
if (messagesRef.current) {
22+
messagesRef.current.scrollTo({
23+
top: messagesRef.current.scrollHeight,
24+
behavior: 'smooth',
25+
});
26+
}
27+
}, [messages]);
28+
29+
const handleSendMessage = async () => {
30+
try {
31+
setMessages((prev) => [
32+
...prev,
33+
{ role: 'user', content: input },
34+
{ role: 'assistant', content: '', loading: true },
35+
]);
36+
37+
const body: BasicBody = {
38+
max_tokens: parseInt(maxToken),
39+
min_tokens: parseInt(minToken),
40+
service,
41+
input,
42+
};
43+
const {
44+
data: { output },
45+
} = await mutateAsync(body);
46+
setInput('');
47+
setMessages((prev) =>
48+
prev.map((message, index) =>
49+
index === prev.length - 1
50+
? { ...message, content: output, loading: false }
51+
: message,
52+
),
53+
);
54+
} catch (error) {
55+
console.log(error);
56+
setMessages((prev) => prev.slice(0, -1));
57+
toast.error('Something went wrong');
58+
}
59+
};
60+
561
return (
6-
<div className="flex items-center justify-center w-full h-full">
62+
<div className="flex h-full w-full items-center justify-center">
763
<div className="w-full max-w-[768px]">
8-
<div className="w-full p-2 rounded-md">
9-
<div className="flex items-center justify-center w-full h-full gap-3">
10-
<div className="flex flex-col w-full">
64+
<div className="w-full rounded-md p-2">
65+
<div className="flex h-full w-full items-center justify-center gap-3">
66+
<div className="flex w-full flex-col">
1167
<label htmlFor="min_token" className="mb-2">
1268
Min Token
1369
</label>
1470
<input
1571
id="min_token"
16-
className="w-full p-3 rounded-md outline-none"
72+
type="number"
73+
value={minToken}
74+
onChange={(e) => setMinToken(e.target.value)}
75+
className="w-full rounded-md p-3 outline-none"
1776
/>
1877
</div>
19-
<div className="flex flex-col w-full">
78+
<div className="flex w-full flex-col">
2079
<label htmlFor="min_token" className="mb-2">
2180
Max Token
2281
</label>
2382
<input
2483
id="min_token"
25-
className="w-full p-3 rounded-md outline-none"
84+
type="number"
85+
value={maxToken}
86+
onChange={(e) => setMaxToken(e.target.value)}
87+
className="w-full rounded-md p-3 outline-none"
2688
/>
2789
</div>
28-
<div className="flex flex-col w-full">
90+
<div className="flex w-full flex-col">
2991
<label htmlFor="min_token" className="mb-2">
3092
Service
3193
</label>
3294
<input
3395
id="min_token"
34-
className="w-full p-3 rounded-md outline-none"
96+
type="text"
97+
value={service}
98+
onChange={(e) => setService(e.target.value)}
99+
className="w-full rounded-md p-3 outline-none"
35100
/>
36101
</div>
37102
</div>
38103
<div className="mt-4">
39-
<div className="w-full p-3 overflow-y-auto rounded-md scrollbar-corner-transparent scrollbar-thin scrollbar-track-transparent h-96 bg-slate-900">
40-
<div className="max-w-full chat chat-end">
41-
<div className="text-white bg-gray-600 chat-bubble">
42-
You underestimate my power!
43-
</div>
44-
</div>
45-
<div className="max-w-full chat chat-start">
46-
<div className="text-white chat-bubble">
47-
You underestimate my power!
48-
</div>
49-
</div>
50-
<div className="max-w-full chat chat-end">
51-
<div className="text-white bg-gray-600 chat-bubble">
52-
You underestimate my power!
53-
</div>
54-
</div>
55-
<div className="max-w-full chat chat-start">
56-
<div className="text-white chat-bubble">
57-
You underestimate my power!
58-
</div>
59-
</div>
60-
<div className="max-w-full chat chat-end">
61-
<div className="text-white bg-gray-600 chat-bubble">
62-
You underestimate my power!
63-
</div>
64-
</div>
65-
<div className="max-w-full chat chat-start">
66-
<div className="text-white chat-bubble">
67-
You underestimate my power!
68-
</div>
69-
</div>
70-
<div className="max-w-full chat chat-end">
71-
<div className="text-white bg-gray-600 chat-bubble">
72-
You underestimate my power!
73-
</div>
74-
</div>
75-
<div className="max-w-full chat chat-start">
76-
<div className="text-white chat-bubble">
77-
You underestimate my power!
78-
</div>
79-
</div>
104+
<div
105+
ref={messagesRef}
106+
className="h-96 w-full overflow-y-auto rounded-md bg-slate-900 p-3 scrollbar-thin scrollbar-track-transparent scrollbar-corner-transparent"
107+
>
108+
{messages.map((message) =>
109+
message.role === 'user' ? (
110+
<div className="chat chat-end max-w-full">
111+
<div className="chat-bubble bg-gray-600 text-white">
112+
{message.content}
113+
</div>
114+
</div>
115+
) : (
116+
<div className="chat chat-start max-w-full">
117+
<div className="chat-bubble text-white">
118+
{message.loading ? (
119+
<BeatLoader color="#e3e3e3" size={10} />
120+
) : (
121+
message.content
122+
)}
123+
</div>
124+
</div>
125+
),
126+
)}
80127
</div>
81128
</div>
82129
<div className="relative mt-4">
83130
<textarea
84-
className="w-full p-4 pr-16 rounded-md outline-none resize-none"
131+
value={input}
132+
onChange={(e) => setInput(e.target.value)}
85133
rows={2}
134+
className="w-full resize-none rounded-md p-4 pr-16 outline-none"
86135
/>
87-
<button className="absolute flex items-center justify-center p-2 bg-white rounded-full right-3 top-5">
136+
<button
137+
disabled={!input}
138+
onClick={handleSendMessage}
139+
className="absolute right-3 top-5 flex items-center justify-center rounded-full bg-white p-2 transition-all disabled:opacity-50"
140+
>
88141
<Send className="size-6 stroke-[#121212]" />
89142
</button>
90143
</div>

web/src/pages/basic/basic.types.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export interface BasicBody {
2+
max_tokens: number;
3+
min_tokens: number;
4+
service: string;
5+
input: string;
6+
}
7+
8+
export interface BasicResponse {
9+
output: string;
10+
}
11+
12+
export interface BasicMessage {
13+
role: string;
14+
content: string;
15+
loading?: boolean;
16+
}

0 commit comments

Comments
 (0)