fix: store session token on signup and send it to /chat
Mirror to GitHub / mirror (push) Canceled after 0s

- web: App stores sessionToken and passes to useChat; useChat sends Authorization header
- web: ChatPanel adds wursor-message-user/agent test hooks
- verified full UI flow (signup -> chat -> working -> reply -> approve -> preview)
This commit is contained in:
SinachPat
2026-08-17 21:16:43 +01:00
parent 060b181e71
commit e9de6ba62c
3 changed files with 50 additions and 30 deletions
+20 -6
View File
@@ -5,15 +5,29 @@ import { Preview } from './components/Preview.tsx';
import { SignUp } from './components/SignUp.tsx';
import { useChat } from './hooks/useChat.ts';
export function App() {
const [signedUp, setSignedUp] = useState(false);
const [applied, setApplied] = useState(false);
const chat = useChat();
async function signUp(email: string, password: string): Promise<string> {
const res = await fetch('/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
if (!res.ok) {
const body = (await res.json().catch(() => null)) as { error?: string } | null;
throw new Error(body?.error ?? 'Sign up failed');
}
const body = (await res.json()) as { sessionToken: string };
return body.sessionToken;
}
if (!signedUp) {
export function App() {
const [sessionToken, setSessionToken] = useState<string | null>(null);
const [applied, setApplied] = useState(false);
const chat = useChat(sessionToken);
if (sessionToken === null) {
return (
<div className="auth-screen">
<SignUp onSignUp={async () => setSignedUp(true)} />
<SignUp onSignUp={async (email, password) => setSessionToken(await signUp(email, password))} />
</div>
);
}
+1 -1
View File
@@ -30,7 +30,7 @@ export function ChatPanel({ messages, status, onSend }: ChatPanelProps) {
) : (
<ul className="chat-list">
{messages.map((message) => (
<li key={message.id} className={`message message-${message.role}`}>
<li key={message.id} className={`message message-${message.role} wursor-message-${message.role}`}>
{message.text}
</li>
))}
+29 -23
View File
@@ -14,35 +14,41 @@ function mockReply(text: string, heading: string | undefined): string {
: 'Done — your change is ready to preview.';
}
export function useChat() {
export function useChat(sessionToken: string | null) {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [status, setStatus] = useState<ChatStatus>('idle');
const [heading, setHeading] = useState('Welcome to our site');
const send = useCallback(async (text: string) => {
const nextHeading = extractHeading(text);
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'user', text }]);
setStatus('working');
const send = useCallback(
async (text: string) => {
const nextHeading = extractHeading(text);
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'user', text }]);
setStatus('working');
try {
const res = await fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text }),
});
if (!res.ok) throw new Error('chat unavailable');
const body = (await res.json()) as { reply?: string };
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'agent', text: body.reply ?? 'Done' }]);
} catch {
await new Promise((resolve) => setTimeout(resolve, 1200));
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'agent', text: mockReply(text, nextHeading) }]);
}
try {
const res = await fetch('/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(sessionToken !== null ? { Authorization: `Bearer ${sessionToken}` } : {}),
},
body: JSON.stringify({ message: text }),
});
if (!res.ok) throw new Error('chat unavailable');
const body = (await res.json()) as { reply?: string };
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'agent', text: body.reply ?? 'Done' }]);
} catch {
await new Promise((resolve) => setTimeout(resolve, 1200));
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'agent', text: mockReply(text, nextHeading) }]);
}
if (nextHeading !== undefined) {
setHeading(nextHeading);
}
setStatus('done');
}, []);
if (nextHeading !== undefined) {
setHeading(nextHeading);
}
setStatus('done');
},
[sessionToken],
);
return { messages, status, heading, send };
}