Skip to content

Commit c5f10d1

Browse files
committed
チャットフォームのクライアント側とサーバー側APIを連携
1 parent c979a92 commit c5f10d1

File tree

1 file changed

+121
-77
lines changed

1 file changed

+121
-77
lines changed

app/[docs_id]/chatForm.tsx

Lines changed: 121 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,156 @@
11
"use client";
22

3-
import { hello } from "./chatServer";
3+
import { useState, FormEvent } from "react";
44

5-
export function ChatForm() {return (
5+
interface ChatApiResponse {
6+
response: string;
7+
}
8+
9+
export function ChatForm() {
10+
const [inputValue, setInputValue] = useState("");
11+
const [response, setResponse] = useState("");
12+
const [isLoading, setIsLoading] = useState(false);
13+
14+
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
15+
e.preventDefault();
16+
setIsLoading(true);
17+
setResponse("");
18+
19+
try {
20+
const res = await fetch("/api/chat", {
21+
method: "POST",
22+
headers: {
23+
"Content-Type": "application/json",
24+
},
25+
body: JSON.stringify({ message: inputValue }),
26+
});
27+
28+
const data = (await res.json()) as ChatApiResponse;
29+
if (!res.ok) {
30+
throw new Error(data.response || "エラーが発生しました。");
31+
}
32+
setResponse(data.response);
33+
} catch (error: any) {
34+
setResponse(`エラー: ${error.message}`);
35+
} finally {
36+
setIsLoading(false);
37+
}
38+
};
39+
return (
640
<>
7-
<style jsx>{`
41+
<style jsx>{`
842
/* 簡単なCSSで見た目を整える(オプション) */
943
.form-container {
10-
background-color: white;
11-
border-radius: 10px;
12-
box-shadow: 0 4px 8px rgba(67, 204, 216, 0.86);
13-
padding: 20px;
14-
width: 90%;
15-
max-width: 1000px;
16-
display: flex;
17-
flex-direction: column;
44+
background-color: white;
45+
border-radius: 10px;
46+
box-shadow: 0 4px 8px rgba(67, 204, 216, 0.86);
47+
padding: 20px;
48+
width: 90%;
49+
max-width: 1000px;
50+
display: flex;
51+
flex-direction: column;
1852
}
1953
.input-area {
20-
border: 1px solid #ccc;
21-
border-radius: 8px;
22-
padding: 5px 15 px;
23-
margin-bottom: 15px;
24-
min-height: 150px; /* 入力欄の高さ */
25-
display: flex;
54+
border: 1px solid #ccc;
55+
border-radius: 8px;
56+
padding: 5px 15 px;
57+
margin-bottom: 15px;
58+
min-height: 150px; /* 入力欄の高さ */
59+
display: flex;
2660
}
2761
.text-input {
28-
border: none;
29-
outline: none;
30-
flex-grow: 1;
31-
font-size: 16px;
32-
resize: none; /* テキストエリアのリサイズを無効化 */
33-
overflow: auto;
34-
padding: 10px;
62+
border: none;
63+
outline: none;
64+
flex-grow: 1;
65+
font-size: 16px;
66+
resize: none; /* テキストエリアのリサイズを無効化 */
67+
overflow: auto;
68+
padding: 10px;
3569
}
3670
.controls {
37-
display: flex;
38-
align-items: center;
39-
justify-content: space-between;
71+
display: flex;
72+
align-items: center;
73+
justify-content: space-between;
4074
}
4175
.left-icons button {
42-
background: none;
43-
border: none;
44-
font-size: 24px;
45-
cursor: pointer;
46-
color: #555;
47-
margin-right: 15px;
48-
padding: 5px;
76+
background: none;
77+
border: none;
78+
font-size: 24px;
79+
cursor: pointer;
80+
color: #555;
81+
margin-right: 15px;
82+
padding: 5px;
4983
}
5084
.left-icons button:hover {
51-
color: #000;
85+
color: #000;
5286
}
5387
.left-icons span {
54-
font-size: 14px;
55-
vertical-align: middle;
56-
margin-left: 5px;
57-
color: #555;
88+
font-size: 14px;
89+
vertical-align: middle;
90+
margin-left: 5px;
91+
color: #555;
5892
}
5993
.right-controls {
60-
display: flex;
61-
align-items: center;
94+
display: flex;
95+
align-items: center;
6296
}
6397
.voice-icon button {
64-
background: none;
65-
border: none;
66-
font-size: 24px;
67-
cursor: pointer;
68-
color: #555;
69-
margin-right: 15px;
70-
padding: 5px;
98+
background: none;
99+
border: none;
100+
font-size: 24px;
101+
cursor: pointer;
102+
color: #555;
103+
margin-right: 15px;
104+
padding: 5px;
71105
}
72106
.voice-icon button:hover {
73-
color: #000;
107+
color: #000;
74108
}
75109
.send-button {
76-
background-color: #007bff; /* 青色の送信ボタン */
77-
color: white;
78-
border: none;
79-
border-radius: 50%; /* 丸いボタン */
80-
width: 40px;
81-
height: 40px;
82-
display: flex;
83-
justify-content: center;
84-
align-items: center;
85-
font-size: 20px;
86-
cursor: pointer;
87-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
88-
transition: background-color 0.3s ease;
110+
background-color: #007bff; /* 青色の送信ボタン */
111+
color: white;
112+
border: none;
113+
border-radius: 50%; /* 丸いボタン */
114+
width: 40px;
115+
height: 40px;
116+
display: flex;
117+
justify-content: center;
118+
align-items: center;
119+
font-size: 20px;
120+
cursor: pointer;
121+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
122+
transition: background-color 0.3s ease;
89123
}
90124
.send-button:hover {
91-
background-color: #0056b3;
125+
background-color: #0056b3;
92126
}
93-
`}</style>
127+
`}</style>
94128

95-
<div className="form-container">
129+
<form className="form-container" onSubmit={handleSubmit}>
96130
<div className="input-area">
97-
<textarea className="text-input" placeholder="質問を入力してください"></textarea>
131+
<textarea
132+
className="text-input"
133+
placeholder="質問を入力してください"
134+
value={inputValue}
135+
onChange={(e) => setInputValue(e.target.value)}
136+
disabled={isLoading}
137+
></textarea>
98138
</div>
99-
100139
<div className="controls">
101-
<div className="left-icons">
102-
103-
</div>
104-
<div className="right-controls">
105-
<button type="submit" className="send-button" title="送信">
106-
<span className="icon"></span>
107-
</button>
108-
</div>
140+
<div className="left-icons"></div>
141+
<div className="right-controls">
142+
<button
143+
type="submit"
144+
className="send-button"
145+
title="送信"
146+
disabled={isLoading}
147+
>
148+
<span className="icon"></span>
149+
</button>
150+
</div>
109151
</div>
110-
</div>
152+
</form>
153+
{response && <div className="response-container">{response}</div>}
111154
</>
112-
)}
155+
);
156+
}

0 commit comments

Comments
 (0)