back
bolt.new 生成 チャットアプリ(Chat) 修正例 shadcnUI + React
id: 172, 2024-10-12
概要:
生成AI的な、bolt.new使用して。アプリ作成後、機能追加等のメモになります。
- 例で。簡単なチャット作成します
- 追加プロンプトで、追加できない部分(失敗) を手作業で修正内容です。
[ 公開日: 2024/10/12 ]
構成
- bolt.new
- shadcn/ui
- Express.js
- esbuild
- typescript
関連
- 画面レイアウト、参考
https://sizu.me/knaka0209/posts/ufz2vrcx7zsr
作成したコード
https://github.com/kuc-arc-f/bolt_3chat/tree/main/chat3
dev-start
bun run build
bun run dev
追加した機能など
- server側データ保存 (reactの変数保存でしたので、再読み込みデータ削除される修正)
- ecxpress側の配列変数に保存。
- 投稿、削除機能
- スレッド返信時の、追加ボタン削除
- 投稿データのソート変更、新着を上側
- 投稿データ、レイアウト変更など。
- 各投稿データの dialog表示は、生成AIが失敗したので。次に検討
- TOP画面
- chat3/src/App.tsx
- https://github.com/kuc-arc-f/bolt_3chat/blob/main/chat3/src/App.tsx
....
function App() {
const [messages, setMessages] = useState<Message[]>([]);
const [inputMessage, setInputMessage] = useState("");
const [replyingTo, setReplyingTo] = useState<number | null>(null);
//
useEffect(() => {
(async() => {
const d = await CrudIndex.getList();
//data = d;
setMessages(d);
console.log(d);
})()
}, []);
const handleSendMessage = async () => {
try{
if (inputMessage.trim() === "") {
console.error("error, none-inputMessage");
return false;
}
const newMessage: Message = {
id: Date.now(),
text: inputMessage,
sender: "user",
parentId: replyingTo,
};
const resulte = await CrudIndex.create(newMessage);
setMessages(resulte);
setInputMessage("");
// ボットの応答をシミュレート
setTimeout(async() => {
if(replyingTo){
setReplyingTo(null)
return;
}
const botResponse: Message = {
id: Date.now() + 1,
text: "こんにちは!どのようなご用件でしょうか?",
sender: "bot",
parentId: null,
};
const resulte = await CrudIndex.create(botResponse);
console.log(resulte);
setMessages(resulte);
//setReplyingTo(null);
}, 1000);
} catch (e) {
console.error(e);
}
};
const handleReply = (messageId: number) => {
setReplyingTo(messageId);
};
//
const handleDelete = async (messageId: string) => {
try{
const resulte = await CrudIndex.delete(messageId);
const d = await CrudIndex.getList();
setMessages(d);
} catch (e) {
console.error(e);
}
};
const renderMessage = (message: Message) => (
<Card key={message.id} className={`mb-4 ${message.sender === "user" ? "ml-auto" : "mr-auto"} max-w-[80%]`}>
{/* <div>{JSON.stringify(message)}</div> */}
<div className={`p-3 rounded-lg ${
message.sender === "user" ? "bg-primary text-primary-foreground" : "bg-secondary text-secondary-foreground"
}`}>
{message.text}
</div>
{!message.parentId? (
<Button variant="ghost" size="sm" className="mt-1" onClick={() => handleReply(message.id)}>
<Reply className="h-4 w-4 mr-1" /> 返信
</Button>
) : null }
<Button variant="ghost" size="sm" className="mt-1" onClick={() => {
console.log("id=", message.id);
if (window.confirm("Delete OK?")) {
handleDelete(message.id);
}
}}>
<Trash className="h-4 w-4 mr-1" /> Delete
</Button>
</Card>
);
const renderThread = (parentMessage: Message) => {
const replies = messages.filter(m => m.parentId === parentMessage.id);
console.log(replies);
return (
<div key={parentMessage.id} className="mb-6">
{renderMessage(parentMessage)}
{replies.length > 0 && (
<div className="ml-8 border-l-2 border-gray-200 pl-4">
{replies.map(renderMessage)}
</div>
)}
</div>
);
};
const topLevelMessages = messages.filter(m => !m.parentId);
//
return (
<div className="flex flex-col h-screen max-w-2xl mx-auto">
<header className="bg-primary text-primary-foreground p-4">
<h1 className="text-2xl font-bold flex items-center">
<MessageCircle className="mr-2" />
チャットアプリ
</h1>
</header>
{/* Input_area */}
<div className="p-4 bg-background">
{replyingTo && (
<div className="text-sm text-muted-foreground mb-2">
返信中: {messages.find(m => m.id === replyingTo)?.text}
<Button variant="ghost" size="sm" onClick={() => setReplyingTo(null)}>キャンセル</Button>
</div>
)}
<div className="flex space-x-2">
<Input
type="text"
placeholder="メッセージを入力..."
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
onKeyPress={(e) => {
if (e.key === "Enter") {
handleSendMessage();
}
}}
/>
<Button onClick={handleSendMessage}>
<Send className="h-4 w-4" />
</Button>
</div>
</div>
{/* ScrollArea */}
<ScrollArea className="flex-grow p-4">
{topLevelMessages.map(renderThread)}
</ScrollArea>
</div>
);
}