feat(frontend): add React SPA with chat, auth, and admin pages

- Vite 6 + React 19 + TypeScript + Tailwind 4 + Zustand 5
- Login page with JWT auth
- Chat interface: MessageList, ChatInput, ChatContainer
- WebSocket hook with auto-reconnect and exponential backoff
- Sidebar with new chat button + session navigation
- Admin dashboard placeholder
- 57 modules, 242KB JS, TypeScript zero errors
This commit is contained in:
Aska committed 2026-08-12 11:47:22 +08:00
1 parent 192144563b
commit 4a71965686
35 files changed
+3146

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
import { create } from 'zustand'
import type { Message, IotDevice } from '../types/chat'
interface ChatState {
messages: Message[]
isStreaming: boolean
currentSessionId: string | null
iotDevices: IotDevice[]
inputText: string
setInput: (text: string) => void
setSessionId: (id: string) => void
addMessage: (msg: Message) => void
appendToLast: (content: string) => void
setStreaming: (v: boolean) => void
setIotDevices: (d: IotDevice[]) => void
clearMessages: () => void
}
export const useChatStore = create<ChatState>((set, get) => ({
messages: [],
isStreaming: false,
currentSessionId: null,
iotDevices: [],
inputText: '',
setInput: (text) => set({ inputText: text }),
setSessionId: (id) => set({ currentSessionId: id }),
setStreaming: (v) => set({ isStreaming: v }),
setIotDevices: (d) => set({ iotDevices: d }),
addMessage: (msg) => set((s) => ({ messages: [...s.messages, msg] })),
appendToLast: (content) => {
const msgs = [...get().messages]
if (msgs.length > 0) {
msgs[msgs.length - 1] = { ...msgs[msgs.length - 1], content: msgs[msgs.length - 1].content + content }
}
set({ messages: msgs })
},
clearMessages: () => set({ messages: [] }),
}))