New session creation page, + button on History
- /history/new: compose first message, creates web session, sends, redirects - POST /api/sessions proxy route - History page gets + button in header
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const body = await req.text();
|
||||
try {
|
||||
const res = await fetch(BACKEND + "/api/sessions", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body,
|
||||
});
|
||||
const data = await res.text();
|
||||
return new NextResponse(data, {
|
||||
status: res.status,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
} catch {
|
||||
return NextResponse.json({ error: "backend unreachable" }, { status: 502 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ArrowLeft, Send, Loader2 } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function NewSessionPage() {
|
||||
const router = useRouter();
|
||||
const [message, setMessage] = useState("");
|
||||
const [sending, setSending] = useState(false);
|
||||
|
||||
const create = async () => {
|
||||
if (!message.trim() || sending) return;
|
||||
setSending(true);
|
||||
try {
|
||||
// Create session
|
||||
const res = await fetch("/api/sessions", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ source: "web" }),
|
||||
});
|
||||
const data = await res.json();
|
||||
const sessionId = data.session?.id;
|
||||
if (!sessionId) throw new Error("No session ID");
|
||||
|
||||
// Send first message
|
||||
await fetch("/api/sessions/" + sessionId + "/chat", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ message: message.trim() }),
|
||||
});
|
||||
|
||||
router.push("/history/" + sessionId);
|
||||
} catch {
|
||||
setSending(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/history" className="p-1 -ml-1 rounded-lg active:bg-white/[0.04]">
|
||||
<ArrowLeft size={20} style={{ color: "var(--text-2)" }} />
|
||||
</Link>
|
||||
<h1 className="text-[15px] font-medium" style={{ color: "var(--text-1)" }}>New Session</h1>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
placeholder="What do you need?"
|
||||
className="w-full min-h-[120px] p-4 rounded-2xl text-[14px] resize-none outline-none transition-colors"
|
||||
style={{
|
||||
background: "var(--bg-raised)",
|
||||
border: "1px solid var(--border)",
|
||||
color: "var(--text-1)",
|
||||
}}
|
||||
autoFocus
|
||||
disabled={sending}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={create}
|
||||
disabled={!message.trim() || sending}
|
||||
className="btn-accent w-full flex items-center justify-center gap-2"
|
||||
>
|
||||
{sending ? (
|
||||
<><Loader2 size={16} className="animate-spin" /> Creating session...</>
|
||||
) : (
|
||||
<><Send size={16} /> Send</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+12
-2
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Search, X } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Search, X, Plus } from "lucide-react";
|
||||
import { useSessions, useSessionSearch } from "@/lib/hooks";
|
||||
import { SessionCard } from "@/components/SessionCard";
|
||||
|
||||
@@ -24,7 +25,16 @@ export default function HistoryPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-xl font-semibold" style={{ color: "var(--text-1)" }}>History</h1>
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-semibold" style={{ color: "var(--text-1)" }}>History</h1>
|
||||
<Link
|
||||
href="/history/new"
|
||||
className="p-2 rounded-xl active:scale-95 transition-all"
|
||||
style={{ background: "var(--accent-dim)", color: "var(--accent)" }}
|
||||
>
|
||||
<Plus size={18} />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2" style={{ color: "var(--text-3)" }} />
|
||||
|
||||
Reference in New Issue
Block a user