@spacinbox/sdk 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +23 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -6
- package/dist/index.d.ts +10 -6
- package/dist/index.js +23 -13
- package/dist/index.js.map +1 -1
- package/dist/widget.global.js +25 -15
- package/dist/widget.global.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/widget/state.ts","../src/widget/modules/api/mock.ts","../src/widget/modules/visitor/service.ts","../src/widget/modules/api/service.ts","../src/index.ts","../src/widget/mount.tsx","../src/widget/Widget.tsx","../src/widget/components/Layout.tsx","../src/widget/ui/Loader.tsx","../src/widget/hooks/useNewMessage.tsx","../src/widget/modules/socket/service.ts","../src/widget/hooks/useQuery.ts","../src/widget/pages/conversation.tsx","../src/widget/hooks/useMessages.ts","../src/widget/hooks/useMutation.ts","../src/widget/modules/conversation/components/Header.tsx","../src/widget/router.ts","../src/widget/ui/Avatar.tsx","../src/widget/ui/Button.tsx","../src/widget/ui/Group.tsx","../src/widget/ui/Indicator.tsx","../src/widget/ui/Text.tsx","../src/widget/modules/conversation/components/InputMessage.tsx","../src/widget/modules/conversation/components/MessageList.tsx","../src/widget/modules/conversation/components/DateSeparator.tsx","../src/widget/modules/conversation/components/MessageBubble.tsx","../src/widget/modules/conversation/components/ResolvedBanner.tsx","../src/widget/ui/Stack.tsx","../src/widget/modules/socket/useOnTyping.ts","../src/widget/modules/socket/useTyping.ts","../src/widget/pages/home.tsx","../src/widget/ui/Card.tsx","../src/widget/ui/Title.tsx","../src/widget/compiled-css.ts"],"sourcesContent":["import { signal } from '@preact/signals'\n\nexport interface WidgetUser {\n userId: string\n email?: string\n name?: string\n}\n\nexport const appId = signal<string | null>(null)\nexport const visitorId = signal<string | null>(null)\nexport const sessionToken = signal<string | null>(null)\nexport const tokenExpiresAt = signal<number | null>(null)\nexport const isOpen = signal(false)\nexport const currentUser = signal<WidgetUser | null>(null)\nexport const metadata = signal<Record<string, unknown>>({})\nexport const isOnline = signal(true)\nexport const isSetup = signal(false)\nexport const refetchSessionCounter = signal(0)\n","import type {\n Agent,\n Conversation,\n CreateConversationDto,\n CreateSessionDto,\n CreateSessionResponse,\n GetSessionResponse,\n IdentifyVisitorDto,\n IdentifyVisitorResponse,\n ListMessagesParams,\n Message,\n MessagesPage,\n SendMessageDto,\n SocketTokenResponse,\n} from './types'\n\nconst AGENTS: Agent[] = [\n { id: 'agent-1', name: 'Alice Martin', picture: undefined },\n { id: 'agent-2', name: 'Bob Chen', picture: undefined },\n]\n\nconst CONVERSATIONS: Conversation[] = [\n {\n id: 'conv-1',\n agentId: AGENTS[1].id,\n agent: AGENTS[1],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n {\n id: 'conv-2',\n agentId: AGENTS[0].id,\n agent: AGENTS[0],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n {\n id: 'conv-3',\n agentId: AGENTS[1].id,\n agent: AGENTS[1],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n {\n id: 'conv-4',\n agentId: AGENTS[0].id,\n agent: AGENTS[0],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n]\nconst MESSAGES: Message[] = []\n// Tracks pending auto-close timers per conversation (for demo)\nconst autoCloseTimers = new Map<string, ReturnType<typeof setTimeout>>()\n\nconst delay = (ms = 300) => new Promise((res) => setTimeout(res, ms))\n\nexport const mockService = {\n async createSession(_dto: CreateSessionDto): Promise<CreateSessionResponse> {\n await delay()\n return {\n access_token: `mock-token-${Date.now()}`,\n token_type: 'Bearer',\n expires_in: 3600,\n visitor_id: _dto.visitorId,\n }\n },\n\n async getSession(): Promise<GetSessionResponse> {\n return { count_notifications: 1 }\n },\n\n async identifyVisitor(_dto: IdentifyVisitorDto): Promise<IdentifyVisitorResponse> {\n await delay()\n return { visitor_id: null, access_token: null }\n },\n\n async getAgents(): Promise<Agent[]> {\n await delay()\n return AGENTS\n },\n\n async getConversation(conversationId: string): Promise<Conversation> {\n await delay()\n const conv = CONVERSATIONS.find((c) => c.id === conversationId)\n if (!conv) throw new Error(`Conversation ${conversationId} not found`)\n return conv\n },\n\n async reopenConversation(conversationId: string): Promise<void> {\n await delay()\n const conv = CONVERSATIONS.find((c) => c.id === conversationId)\n if (conv) conv.status = 'OPEN'\n },\n\n async getConversationSocketToken(conversationId: string): Promise<SocketTokenResponse> {\n await delay()\n return { access_token: `mock-conv-socket-token-${conversationId}-${Date.now()}` }\n },\n\n async createConversation(dto: CreateConversationDto): Promise<Conversation> {\n await delay()\n\n const conversation: Conversation = {\n id: `conv-${Date.now()}`,\n agentId: dto.agentId,\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n messages: [],\n unread_contact_count: 0,\n }\n\n if (dto.text) {\n const message: Message = {\n id: `msg-${Date.now()}`,\n sender: 'user',\n text: dto.text,\n createdAt: new Date().toISOString(),\n conversationId: conversation.id,\n }\n\n conversation.messages?.push(message)\n // Auto-close after 8s to simulate agent resolving (demo only)\n scheduleAutoClose(conversation.id)\n }\n\n CONVERSATIONS.push(conversation)\n return conversation\n },\n\n async getConversations(): Promise<Conversation[]> {\n await delay()\n return CONVERSATIONS.map((conv) => {\n const all = [\n ...(conv.messages ?? []),\n ...MESSAGES.filter((m) => m.conversationId === conv.id),\n ]\n const lastMessage = all.sort(\n (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),\n )[0]\n return { ...conv, lastMessage }\n })\n },\n\n async getMessages(conversationId: string, _params?: ListMessagesParams): Promise<MessagesPage> {\n await delay()\n const messages = MESSAGES.filter((m) => m.conversationId === conversationId)\n return { messages, hasMore: false, nextCursor: null }\n },\n\n async sendMessage(conversationId: string, dto: SendMessageDto): Promise<Message> {\n await delay()\n const message: Message = {\n id: `msg-${Date.now()}`,\n conversationId,\n text: dto.text,\n sender: 'user',\n createdAt: new Date().toISOString(),\n }\n MESSAGES.push(message)\n // Auto-close after 8s to simulate agent resolving (demo only)\n scheduleAutoClose(conversationId)\n return message\n },\n}\n\nfunction scheduleAutoClose(conversationId: string) {\n const existing = autoCloseTimers.get(conversationId)\n if (existing) clearTimeout(existing)\n const timer = setTimeout(() => {\n const conv = CONVERSATIONS.find((c) => c.id === conversationId)\n if (conv) conv.status = 'CLOSED'\n autoCloseTimers.delete(conversationId)\n }, 8000)\n autoCloseTimers.set(conversationId, timer)\n}\n","import type { WidgetUser } from '../../state'\nimport { isOnline, isSetup, sessionToken, tokenExpiresAt, visitorId } from '../../state'\nimport { ApiService } from '../api/service'\n\nconst STORAGE_KEY = 'spacinbox_vid'\nconst REFRESH_THRESHOLD_MS = 60_000 // refresh if less than 60s remaining\n\nexport const VisitorService = {\n async init(): Promise<void> {\n let id = localStorage.getItem(STORAGE_KEY)\n\n if (!id) {\n id = crypto.randomUUID()\n localStorage.setItem(STORAGE_KEY, id)\n }\n\n visitorId.value = id\n\n await this.refreshSession(id)\n\n isSetup.value = true\n },\n\n async refreshSession(visitor_id = visitorId.value): Promise<void> {\n if (!visitor_id) {\n return\n }\n try {\n const response = await ApiService.createSession({ visitorId: visitor_id })\n sessionToken.value = response.access_token\n visitorId.value = response.visitor_id\n localStorage.setItem(STORAGE_KEY, response.visitor_id)\n tokenExpiresAt.value = Date.now() + response.expires_in * 1000\n } catch (err) {\n isOnline.value = false\n throw err\n }\n },\n\n isTokenExpiringSoon(): boolean {\n if (!tokenExpiresAt.value) return true\n return tokenExpiresAt.value - Date.now() < REFRESH_THRESHOLD_MS\n },\n\n identify(user: WidgetUser) {\n ApiService.identifyVisitor({\n externalId: user.userId,\n name: user.name,\n email: user.email,\n }).then(({ visitor_id, access_token }) => {\n if (access_token) {\n sessionToken.value = access_token\n }\n\n if (visitor_id && visitor_id !== visitorId.value) {\n visitorId.value = visitor_id\n localStorage.setItem(STORAGE_KEY, visitor_id)\n }\n })\n },\n\n clear() {\n localStorage.removeItem(STORAGE_KEY)\n visitorId.value = null\n sessionToken.value = null\n tokenExpiresAt.value = null\n isSetup.value = false\n },\n}\n","import { appId, sessionToken, visitorId } from '../../state'\nimport { mockService } from './mock'\nimport type {\n Agent,\n Conversation,\n CreateConversationDto,\n CreateSessionDto,\n CreateSessionResponse,\n GetSessionResponse,\n IdentifyVisitorDto,\n IdentifyVisitorResponse,\n ListMessagesParams,\n Message,\n MessagesPage,\n SendMessageDto,\n SocketTokenResponse,\n} from './types'\n\nconst BASE_URL = __API_URL__\nconst IS_MOCKED = __API_MOCKED__\n\nasync function doFetch(method: string, path: string, body?: unknown): Promise<Response> {\n if (!appId.value) throw new Error('Spacinbox: boot() must be called before any API request')\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-app-id': appId.value,\n 'x-visitor-id': visitorId.value ?? '',\n }\n\n if (sessionToken.value) {\n headers['Authorization'] = `Bearer ${sessionToken.value}`\n }\n\n return fetch(`${BASE_URL}/widget${path}`, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n}\n\nasync function request<T>(method: string, path: string, body?: unknown): Promise<T> {\n // Proactive refresh if token is expiring soon (skip for createSession itself)\n if (path !== '/sessions') {\n const { VisitorService } = await import('../visitor/service')\n if (VisitorService.isTokenExpiringSoon()) {\n await VisitorService.refreshSession()\n }\n }\n\n let res = await doFetch(method, path, body)\n\n // Reactive refresh on 401\n if (res.status === 401 && path !== '/sessions') {\n const { VisitorService } = await import('../visitor/service')\n await VisitorService.refreshSession()\n res = await doFetch(method, path, body)\n }\n\n if (!res.ok) throw new Error(`[Spacinbox] ${method} ${path} failed with status ${res.status}`)\n\n return res.json()\n}\n\nexport const ApiService = IS_MOCKED\n ? mockService\n : {\n createSession(dto: CreateSessionDto): Promise<CreateSessionResponse> {\n return request('POST', '/sessions', dto)\n },\n\n getSession(): Promise<GetSessionResponse> {\n return request('GET', '/sessions')\n },\n\n identifyVisitor(dto: IdentifyVisitorDto): Promise<IdentifyVisitorResponse> {\n return request('POST', '/visitors/identify', dto)\n },\n\n getAgents(): Promise<Agent[]> {\n return request('GET', '/agents')\n },\n\n getConversations(): Promise<Conversation[]> {\n return request('GET', '/conversations')\n },\n\n createConversation(dto: CreateConversationDto): Promise<Conversation> {\n return request('POST', '/conversations', dto)\n },\n\n getConversation(conversationId: string): Promise<Conversation> {\n return request('GET', `/conversations/${conversationId}`)\n },\n\n reopenConversation(conversationId: string): Promise<void> {\n return request('POST', `/conversations/${conversationId}/reopen`)\n },\n\n getConversationSocketToken(conversationId: string): Promise<SocketTokenResponse> {\n return request('GET', `/conversations/${conversationId}/token`)\n },\n\n getMessages(conversationId: string, params?: ListMessagesParams): Promise<MessagesPage> {\n const qs = new URLSearchParams()\n if (params?.before) qs.set('before', params.before)\n if (params?.limit) qs.set('limit', String(params.limit))\n const query = qs.toString()\n return request(\n 'GET',\n `/conversations/${conversationId}/messages${query ? `?${query}` : ''}`,\n )\n },\n\n sendMessage(conversationId: string, dto: SendMessageDto): Promise<Message> {\n return request('POST', `/conversations/${conversationId}/messages`, dto)\n },\n }\n","import { mountWidget } from './widget/mount'\nimport { BootOptions } from './widget/types'\n\nexport type { WidgetUser } from './widget/state'\n\ntype Controller = ReturnType<typeof mountWidget>\n\nlet controller: Controller | null = null\n\nconst Spacinbox = {\n boot(options: BootOptions) {\n if (typeof document === 'undefined') {\n return\n }\n if (controller) {\n return\n }\n controller = mountWidget(options)\n },\n identify(user: Parameters<Controller['identify']>[0]) {\n controller?.identify(user)\n },\n setMetadata(data: Record<string, unknown>) {\n controller?.setMetadata(data)\n },\n open() {\n controller?.open()\n },\n close() {\n controller?.close()\n },\n shutdown() {\n controller?.shutdown()\n controller = null\n },\n}\n\nexport default Spacinbox\n","import { render } from 'preact'\nimport { Widget } from './Widget'\nimport styles from './compiled-css'\nimport { SocketService } from './modules/socket/service'\nimport { VisitorService } from './modules/visitor/service'\nimport { resetRouter } from './router'\nimport type { WidgetUser } from './state'\nimport { appId, currentUser, isOpen, metadata, sessionToken, visitorId } from './state'\nimport { BootOptions } from './types'\n\nexport function mountWidget(options: BootOptions) {\n const { appId: id, hideButton = false } = options\n appId.value = id\n\n VisitorService.init().then(() => SocketService.connect())\n\n const host = document.createElement('div')\n host.id = 'spacinbox-widget'\n document.body.appendChild(host)\n\n const shadow = host.attachShadow({ mode: 'open' })\n const sheet = new CSSStyleSheet()\n sheet.replaceSync(styles)\n shadow.adoptedStyleSheets = [sheet]\n\n const mountPoint = document.createElement('div')\n shadow.appendChild(mountPoint)\n render(<Widget hideButton={hideButton} />, mountPoint)\n\n return {\n open() {\n isOpen.value = true\n },\n close() {\n isOpen.value = false\n },\n identify(user: WidgetUser) {\n currentUser.value = user\n VisitorService.identify(user)\n },\n setMetadata(data: Record<string, unknown>) {\n metadata.value = { ...metadata.value, ...data }\n },\n shutdown() {\n render(null, mountPoint)\n host.remove()\n isOpen.value = false\n currentUser.value = null\n metadata.value = {}\n visitorId.value = null\n sessionToken.value = null\n resetRouter()\n VisitorService.clear()\n SocketService.disconnect()\n },\n }\n}\n","import { MessageCircle, X } from 'lucide-preact'\nimport { useEffect } from 'preact/hooks'\nimport { Layout } from './components/Layout'\nimport { useOnNewMessage } from './hooks/useNewMessage'\nimport { useQuery } from './hooks/useQuery'\nimport { ApiService } from './modules/api/service'\nimport { Conversation } from './pages/conversation'\nimport { Home } from './pages/home'\nimport { currentRoute } from './router'\nimport { isOpen, isSetup, refetchSessionCounter, sessionToken } from './state'\nimport { Indicator } from './ui/Indicator'\n\nconst renderPage = () => {\n const route = currentRoute.value\n switch (route.page) {\n case 'home':\n return <Home />\n case 'conversation':\n return <Conversation conversationId={route.params?.conversationId} />\n }\n}\n\ntype Props = {\n hideButton: boolean\n}\n\nconst Internal = ({ hideButton }: Props) => {\n const sessionQuery = useQuery({\n queryFn: () => ApiService.getSession(),\n queryKey: ['session'],\n enabled: !!sessionToken.value,\n })\n\n useOnNewMessage(() => {\n sessionQuery.refetch()\n })\n\n useEffect(() => {\n if (sessionQuery.loading) {\n return\n }\n sessionQuery.refetch()\n }, [refetchSessionCounter.value])\n\n const countNotifications = sessionQuery.data?.count_notifications ?? 0\n\n return (\n <div>\n <Layout isOpen={isOpen.value}>{renderPage()}</Layout>\n\n {!hideButton && (\n <button\n onClick={() => (isOpen.value = !isOpen.value)}\n class=\"fixed bottom-4 right-4 w-14 h-14 bg-blue-600 hover:bg-blue-700 text-white rounded-full shadow-lg flex items-center justify-center text-2xl transition-colors cursor-pointer\"\n aria-label={isOpen.value ? 'Close support chat' : 'Open support chat'}\n >\n <Indicator\n label={countNotifications}\n visible={countNotifications > 0}\n position=\"top-right\"\n size=\"md\"\n color=\"red\"\n >\n {isOpen.value ? <X /> : <MessageCircle />}\n </Indicator>\n </button>\n )}\n </div>\n )\n}\n\nexport const Widget = (props: Props) => {\n if (!isSetup.value) {\n return <></>\n }\n\n return <Internal {...props} />\n}\n","import { ReactNode } from 'preact/compat'\nimport { isOnline } from '../state'\nimport { Loader } from '../ui/Loader'\n\ntype Props = {\n isOpen: boolean\n children: ReactNode\n}\n\nexport const Layout = ({ isOpen, children }: Props) => {\n return (\n <div\n class={`fixed bottom-20 right-4 w-80 h-112 bg-white rounded-xl shadow-2xl border border-gray-200 flex flex-col overflow-hidden ${!isOpen && 'hidden'}`}\n >\n {!isOnline.value && (\n <div class=\"bg-amber-50 border-b border-amber-200 px-3 py-2 text-xs text-amber-700 text-center\">\n Connecting... <Loader />\n </div>\n )}\n <div class=\"flex-1 overflow-y-auto\">{children}</div>\n </div>\n )\n}\n","import { Loader2 } from 'lucide-preact'\n\ntype Props = {\n size?: number\n class?: string\n}\n\nexport const Loader = ({ size = 20, class: cls }: Props) => (\n <Loader2 size={size} class={`animate-spin text-inherit ${cls ?? ''}`} />\n)\n","import { useEffect } from 'preact/hooks'\nimport { socket, SocketService } from '../modules/socket/service'\n\n// type Props = {}\n\nexport const useOnNewMessage = (handler: (...args: any[]) => any) => {\n useEffect(() => {\n if (!socket.value) {\n return\n }\n\n SocketService.on('new-message', () => handler())\n\n return () => {\n SocketService.off('new-message', () => handler())\n }\n }, [socket.value])\n}\n","import { signal } from '@preact/signals'\nimport { io, Socket } from 'socket.io-client'\nimport { isOnline, sessionToken } from '../../state'\nimport { ApiService } from '../api/service'\nimport { VisitorService } from '../visitor/service'\n\nexport const socket = signal<Socket | null>(null)\n\nexport const SocketService = {\n async connect(): Promise<void> {\n const token = sessionToken.value\n\n socket.value = io(__WS_URL__, {\n auth: { token },\n reconnection: true,\n })\n\n socket.value.on('connect', () => {\n isOnline.value = true\n })\n\n socket.value.on('disconnect', (reason) => {\n if (reason !== 'io client disconnect') {\n isOnline.value = false\n }\n })\n\n socket.value.on('connect_error', async (err) => {\n if (err.message === 'Missing token' || err.message === 'Invalid token') {\n await VisitorService.refreshSession()\n\n if (socket.value) {\n socket.value.auth = { token: sessionToken.value }\n socket.value.connect()\n }\n } else {\n isOnline.value = false\n }\n })\n },\n\n async joinRoom(conversationId: string): Promise<void> {\n if (!socket.value) {\n return\n }\n\n const { access_token: token } = await ApiService.getConversationSocketToken(conversationId)\n\n return new Promise((resolve, reject) => {\n socket.value!.emit('join-room', { token }, (response: { ok: boolean }) => {\n if (!response?.ok) {\n reject(new Error())\n } else {\n resolve()\n }\n })\n })\n },\n\n leaveRoom(conversationId: string): void {\n socket.value?.emit('leave-room', { room_id: `conversation:${conversationId}` })\n },\n\n typingStart(conversationId: string) {\n socket.value?.emit('typing-start', { room_id: `conversation:${conversationId}` })\n },\n\n typingStop(conversationId: string) {\n socket.value?.emit('typing-stop', { room_id: `conversation:${conversationId}` })\n },\n\n on<T>(event: string, handler: (payload: T) => void): void {\n socket.value?.on(event, handler)\n },\n\n off<T>(event: string, handler: (payload: T) => void): void {\n socket.value?.off(event, handler)\n },\n\n disconnect(): void {\n socket.value?.disconnect()\n socket.value = null\n },\n}\n","import { useCallback, useEffect, useState } from 'preact/hooks'\n\ntype QueryKey = string | readonly unknown[]\n\ntype QueryState<T> = {\n data: T | null\n loading: boolean\n error: Error | null\n isSuccess: boolean\n isFetched: boolean\n}\n\ntype QueryOptions<T> = {\n queryKey: QueryKey\n queryFn: () => Promise<T>\n enabled?: boolean\n cache?: boolean\n onSuccess?: (data: T) => void\n onError?: (error: Error) => void\n onSettled?: (data: T | null, error: Error | null) => void\n}\n\nconst cache = new Map<string, unknown>()\n\nexport const clearQueryCache = () => cache.clear()\n\nexport const invalidateQuery = (queryKey: QueryKey) => cache.delete(serializeKey(queryKey))\n\nfunction serializeKey(key: QueryKey): string {\n return typeof key === 'string' ? key : JSON.stringify(key)\n}\n\nexport function useQuery<T>({ queryKey, queryFn, enabled = true, cache: useCache = true, onSuccess, onError, onSettled }: QueryOptions<T>) {\n const key = serializeKey(queryKey)\n const cached = useCache ? cache.get(key) as T | undefined : undefined\n\n const [refetchCounter, setRefetchCounter] = useState(0)\n\n const [state, setState] = useState<QueryState<T>>(\n cached !== undefined\n ? { data: cached, loading: false, error: null, isSuccess: true, isFetched: true }\n : { data: null, loading: enabled, error: null, isSuccess: false, isFetched: false }\n )\n\n useEffect(() => {\n if (!enabled) return\n\n let cancelled = false\n\n const isRefetch = refetchCounter > 0\n if (cached === undefined || isRefetch) {\n setState(s => ({ ...s, loading: true, error: null, isSuccess: false }))\n }\n\n queryFn()\n .then(data => {\n if (cancelled) return\n if (useCache) cache.set(key, data)\n setState({ data, loading: false, error: null, isSuccess: true, isFetched: true })\n onSuccess?.(data)\n onSettled?.(data, null)\n })\n .catch((error: Error) => {\n if (cancelled) return\n setState(s => ({ ...s, loading: false, error, isSuccess: false, isFetched: true }))\n onError?.(error)\n onSettled?.(null, error)\n })\n\n return () => { cancelled = true }\n }, [key, enabled, refetchCounter])\n\n const refetch = useCallback(() => setRefetchCounter(c => c + 1), [])\n\n return { ...state, refetch }\n}\n","import { useSignal } from '@preact/signals'\nimport { useEffect } from 'preact/hooks'\nimport { useMessages } from '../hooks/useMessages'\nimport { useMutation } from '../hooks/useMutation'\nimport { invalidateQuery, useQuery } from '../hooks/useQuery'\nimport { ApiService } from '../modules/api/service'\nimport type { Message } from '../modules/api/types'\nimport { Header } from '../modules/conversation/components/Header'\nimport { InputMessage } from '../modules/conversation/components/InputMessage'\nimport { MessageList } from '../modules/conversation/components/MessageList'\nimport { ResolvedBanner } from '../modules/conversation/components/ResolvedBanner'\nimport { SocketService } from '../modules/socket/service'\nimport { useOnTyping } from '../modules/socket/useOnTyping'\nimport { useTyping } from '../modules/socket/useTyping'\nimport { goBack } from '../router'\nimport { refetchSessionCounter } from '../state'\n\ntype Props = {\n conversationId?: string\n}\n\nexport const Conversation = (props: Props) => {\n const conversationId = useSignal<string | undefined>(props.conversationId)\n const isCreating = useSignal(false)\n\n const agentsQuery = useQuery({\n queryKey: ['agents'],\n queryFn: () => ApiService.getAgents(),\n })\n\n const conversationQuery = useQuery({\n queryKey: [`conversation-${conversationId}`],\n queryFn: () => ApiService.getConversation(conversationId.value!),\n enabled: !!conversationId.value,\n })\n\n const { messages, hasMore, loadingMore, loadMore, append, replace, remove } = useMessages(\n conversationId.value,\n )\n\n const reopenMutation = useMutation({\n mutationFn: () => ApiService.reopenConversation(conversationId.value!),\n onSuccess: () => conversationQuery.refetch(),\n })\n\n const agent = conversationQuery.data?.agent ?? agentsQuery.data?.[0]\n\n const isResolved = conversationQuery.data?.status === 'CLOSED'\n const isOpen = conversationQuery.data?.status === 'OPEN'\n\n const canConnectSocket = conversationId.value && isOpen\n\n const onNewMessage = (message: Message) => {\n append(message)\n }\n\n useEffect(() => {\n if (!conversationId.value) {\n return\n }\n\n SocketService.on('conversation-updated', () => conversationQuery.refetch())\n\n return () => {\n SocketService.off('conversation-updated', () => conversationQuery.refetch())\n }\n }, [conversationId.value])\n\n useEffect(() => {\n if (!canConnectSocket) {\n return\n }\n\n const id = conversationId.value!\n\n SocketService.joinRoom(id)\n .then(() => {\n refetchSessionCounter.value += 1\n })\n .catch((error) => {})\n SocketService.on('new-message', onNewMessage)\n\n return () => {\n SocketService.leaveRoom(id)\n SocketService.off('new-message', onNewMessage)\n }\n }, [canConnectSocket])\n\n const send = async (text: string) => {\n if (!agent || isCreating.value) return\n stopTyping()\n\n const tempId = `temp-${Date.now()}`\n const optimistic: Message = {\n id: tempId,\n conversationId: conversationId.value ?? 'pending',\n text,\n sender: 'user',\n createdAt: new Date().toISOString(),\n }\n\n append(optimistic)\n\n try {\n if (!conversationId.value) {\n isCreating.value = true\n const conversation = await ApiService.createConversation({ agentId: agent.id, text })\n conversationId.value = conversation.id\n invalidateQuery(['conversations'])\n } else {\n const message = await ApiService.sendMessage(conversationId.value, { text })\n replace(tempId, message)\n }\n } catch {\n remove(tempId)\n } finally {\n isCreating.value = false\n }\n }\n\n const handleYes = () => {\n goBack()\n }\n\n const handleNo = () => {\n reopenMutation.mutate()\n }\n\n const { onType, stopTyping } = useTyping({ room_id: conversationId.value ?? '' })\n const { isTyping } = useOnTyping({ room_id: conversationId.value })\n\n const disabled = !agent || isCreating.value\n\n return (\n <div class=\"flex flex-col h-full\">\n <Header\n agent={agent}\n loading={!agent && (agentsQuery.loading || conversationQuery.loading)}\n />\n\n <MessageList\n messages={messages}\n agent={agent}\n scrollKey={isResolved}\n hasMore={hasMore}\n loadingMore={loadingMore}\n onLoadMore={loadMore}\n isTyping={isTyping}\n />\n\n {isResolved ? (\n <ResolvedBanner onYes={handleYes} onNo={handleNo} />\n ) : (\n <InputMessage onSend={send} onType={onType} disabled={disabled} />\n )}\n </div>\n )\n}\n","import { useCallback, useEffect, useRef, useState } from 'preact/hooks'\nimport { ApiService } from '../modules/api/service'\nimport type { Message } from '../modules/api/types'\n\ntype State = {\n messages: Message[]\n hasMore: boolean\n nextCursor: string | null\n loading: boolean\n loadingMore: boolean\n}\n\nexport function useMessages(conversationId: string | undefined, limit = 30) {\n const [state, setState] = useState<State>({\n messages: [],\n hasMore: false,\n nextCursor: null,\n loading: !!conversationId,\n loadingMore: false,\n })\n\n // Ref to read current state inside callbacks without stale closure\n const stateRef = useRef(state)\n stateRef.current = state\n\n useEffect(() => {\n if (!conversationId) return\n let cancelled = false\n\n setState({ messages: [], hasMore: false, nextCursor: null, loading: true, loadingMore: false })\n\n ApiService.getMessages(conversationId, { limit })\n .then(({ messages, hasMore, nextCursor }) => {\n if (cancelled) {\n return\n }\n setState({ messages, hasMore, nextCursor, loading: false, loadingMore: false })\n })\n .catch(() => {\n if (cancelled) return\n setState((s) => ({ ...s, loading: false }))\n })\n\n return () => {\n cancelled = true\n }\n }, [conversationId])\n\n const loadMore = useCallback(async () => {\n const { hasMore, nextCursor, loadingMore } = stateRef.current\n if (!hasMore || loadingMore || !nextCursor || !conversationId) return\n\n setState((s) => ({ ...s, loadingMore: true }))\n\n try {\n const {\n messages: older,\n hasMore: newHasMore,\n nextCursor: newCursor,\n } = await ApiService.getMessages(conversationId, { before: nextCursor, limit })\n setState((s) => ({\n ...s,\n messages: [...s.messages, ...older],\n hasMore: newHasMore,\n nextCursor: newCursor,\n loadingMore: false,\n }))\n } catch {\n setState((s) => ({ ...s, loadingMore: false }))\n }\n }, [conversationId])\n\n const append = useCallback((message: Message) => {\n setState((item) => {\n if (item.messages.some((m) => m.id === message.id)) {\n return item\n }\n return { ...item, messages: [message, ...item.messages] }\n })\n }, [])\n\n const replace = useCallback((tempId: string, message: Message) => {\n setState((s) => ({\n ...s,\n messages: s.messages\n .filter((m) => m.id !== message.id)\n .map((m) => (m.id === tempId ? message : m)),\n }))\n }, [])\n\n const remove = useCallback((id: string) => {\n setState((s) => ({ ...s, messages: s.messages.filter((m) => m.id !== id) }))\n }, [])\n\n return { ...state, loadMore, append, replace, remove }\n}\n","import { useState } from 'preact/hooks'\n\ntype MutationState<T> = {\n data: T | null\n loading: boolean\n error: Error | null\n isSuccess: boolean\n isFetched: boolean\n}\n\ntype MutationOptions<T, V> = {\n mutationFn: (variables: V) => Promise<T>\n onSuccess?: (data: T, variables: V) => void\n onError?: (error: Error, variables: V) => void\n onSettled?: (data: T | null, error: Error | null, variables: V) => void\n}\n\nexport function useMutation<T, V = void>({ mutationFn, onSuccess, onError, onSettled }: MutationOptions<T, V>) {\n const [state, setState] = useState<MutationState<T>>({\n data: null,\n loading: false,\n error: null,\n isSuccess: false,\n isFetched: false,\n })\n\n const mutate = async (variables: V) => {\n setState({ data: null, loading: true, error: null, isSuccess: false, isFetched: false })\n\n try {\n const data = await mutationFn(variables)\n setState({ data, loading: false, error: null, isSuccess: true, isFetched: true })\n onSuccess?.(data, variables)\n onSettled?.(data, null, variables)\n return data\n } catch (error) {\n const err = error as Error\n setState({ data: null, loading: false, error: err, isSuccess: false, isFetched: true })\n onError?.(err, variables)\n onSettled?.(null, err, variables)\n }\n }\n\n return { ...state, mutate }\n}\n","import { ArrowLeft } from 'lucide-preact'\nimport { goBack } from '../../../router'\nimport { Avatar } from '../../../ui/Avatar'\nimport { Button } from '../../../ui/Button'\nimport { Group } from '../../../ui/Group'\nimport { Indicator } from '../../../ui/Indicator'\nimport { Text } from '../../../ui/Text'\nimport type { Agent } from '../../api/types'\n\ntype Props = {\n agent?: Agent\n loading?: boolean\n}\nexport const Header = ({ agent, loading }: Props) => (\n <Group class=\"border-b border-neutral-100 p-2\">\n <Button variant=\"light\" onClick={goBack} aria-label=\"Back\">\n <ArrowLeft />\n </Button>\n\n {loading ? (\n <div class=\"w-8 h-8 rounded-full bg-neutral-200 animate-pulse shrink-0\" />\n ) : agent ? (\n <>\n <Indicator color=\"green\">\n <Avatar size=\"sm\" src={agent.picture}>\n {agent.name.charAt(0)}\n </Avatar>\n </Indicator>\n <Text weight=\"medium\">{agent.name}</Text>\n </>\n ) : null}\n </Group>\n)\n","import { computed, signal } from '@preact/signals'\n\nexport type Page = 'home' | 'conversation'\n\ntype RouteParams = {\n conversationId?: string\n}\n\ntype RouteEntry = {\n page: Page\n params?: RouteParams\n}\n\nexport const pageStack = signal<RouteEntry[]>([{ page: 'home' }])\n\nexport const currentRoute = computed(() => pageStack.value.at(-1)!)\nexport const currentPage = computed(() => currentRoute.value.page)\nexport const canGoBack = computed(() => pageStack.value.length > 1)\n\nexport const navigate = (page: Page, params?: RouteParams) => {\n pageStack.value = [...pageStack.value, { page, params }]\n}\n\nexport const goBack = () => {\n if (pageStack.value.length > 1)\n pageStack.value = pageStack.value.slice(0, -1)\n}\n\nexport const resetRouter = () => {\n pageStack.value = [{ page: 'home' }]\n}\n","type Props = {\n src?: string\n children?: string\n size?: 'sm' | 'md' | 'lg' | number\n class?: string\n}\n\nconst sizes = {\n sm: 'w-7 h-7 text-xs',\n md: 'w-9 h-9 text-sm',\n lg: 'w-12 h-12 text-base',\n}\n\nexport const Avatar = ({ src, children, size = 'md', class: cls }: Props) => {\n const sizeClass = typeof size === 'number' ? '' : sizes[size]\n const sizeStyle = typeof size === 'number' ? { width: `${size}px`, height: `${size}px`, fontSize: `${Math.round(size * 0.4)}px` } : undefined\n\n const base = `inline-flex items-center justify-center rounded-full overflow-hidden shrink-0 bg-blue-100 text-blue-700 font-medium border-2 border-blue-400 ${sizeClass} ${cls ?? ''}`\n\n if (src) {\n return <img src={src} class={`${base} object-cover`} style={sizeStyle} alt={children ?? ''} />\n }\n\n return <span class={base} style={sizeStyle}>{children ? children.charAt(0).toUpperCase() : '?'}</span>\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n onClick?: () => void\n variant?: 'filled' | 'subtle' | 'outline' | 'light'\n fullWidth?: boolean\n class?: string\n}\n\nconst variants = {\n filled: 'bg-blue-600 hover:bg-blue-700 text-white',\n subtle: 'bg-neutral-100 hover:bg-neutral-200 text-neutral-800',\n light: 'bg-transparent hover:text-neutral-800 text-neutral-500',\n outline: 'border border-neutral-200 hover:bg-neutral-50 text-neutral-800',\n}\n\nexport const Button = ({ children, onClick, variant = 'filled', fullWidth, class: cls }: Props) => (\n <button\n onClick={onClick}\n class={`\n inline-flex items-center justify-center gap-2\n px-4 py-2 rounded-lg text-sm font-medium\n transition-colors cursor-pointer\n ${variants[variant]}\n ${fullWidth ? 'w-full' : ''}\n ${cls ?? ''}\n `}\n >\n {children}\n </button>\n)\n","import { ReactNode } from 'preact/compat'\n\nimport type { CSSProperties } from 'preact/compat'\nimport { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n gap?: 'xs' | 'sm' | 'md' | 'lg' | number\n justify?: 'start' | 'center' | 'end' | 'between'\n align?: 'start' | 'center' | 'end'\n class?: string\n}\n\nconst gaps: Record<string, string> = {\n xs: 'gap-1',\n sm: 'gap-2',\n md: 'gap-4',\n lg: 'gap-6',\n}\n\nconst justifies = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n}\n\nconst aligns = {\n start: 'items-start',\n center: 'items-center',\n end: 'items-end',\n}\n\nexport const Group = ({ children, gap = 'sm', justify = 'start', align = 'center', class: cls }: Props) => {\n const gapClass = typeof gap === 'number' ? '' : gaps[gap]\n const gapStyle: CSSProperties = typeof gap === 'number' ? { gap: `${gap * 4}px` } : {}\n\n return (\n <div class={`flex flex-row ${gapClass} ${justifies[justify]} ${aligns[align]} ${cls ?? ''}`} style={gapStyle}>\n {children}\n </div>\n )\n}\n","import type { ComponentChildren } from 'preact'\n\nconst colors = {\n default: 'bg-blue-500',\n green: 'bg-green-500',\n red: 'bg-red-500',\n}\n\nconst positions = {\n 'top-right': 'top-0 right-0 translate-x-1/2 -translate-y-1/2',\n 'bottom-right': 'bottom-0 right-0',\n}\n\nconst sizes = {\n sm: { dot: 'w-2.5 h-2.5', badge: 'h-4 min-w-4 text-[10px]' },\n md: { dot: 'w-3.5 h-3.5', badge: 'h-5 min-w-5 text-xs' },\n lg: { dot: 'w-4 h-4', badge: 'h-6 min-w-6 text-sm' },\n}\n\ntype Offset = { x?: number; y?: number }\n\ntype Props = {\n children: ComponentChildren\n active?: boolean\n visible?: boolean\n color?: keyof typeof colors\n label?: string | number\n size?: keyof typeof sizes\n position?: keyof typeof positions\n offset?: Offset\n}\n\nexport const Indicator = ({\n children,\n active = true,\n visible = true,\n color = 'default',\n label,\n size = 'sm',\n position = 'bottom-right',\n offset,\n}: Props) => {\n const show = active && visible\n const offsetStyle = offset\n ? { transform: `translate(calc(50% + ${offset.x ?? 0}px), calc(-50% + ${offset.y ?? 0}px))` }\n : undefined\n\n return (\n <div class=\"relative inline-flex\">\n {children}\n {show &&\n (label !== undefined ? (\n <span\n style={offsetStyle}\n class={`absolute ${positions[position]} ${sizes[size].badge} px-1 ${colors[color]} text-white font-semibold rounded-full flex items-center justify-center`}\n >\n {label}\n </span>\n ) : (\n <span\n style={offsetStyle}\n class={`absolute ${positions[position]} ${sizes[size].dot} ${colors[color]} border-2 border-white rounded-full`}\n />\n ))}\n </div>\n )\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n weight?: 'normal' | 'medium' | 'semibold'\n color?: 'default' | 'dimmed'\n lineClamp?: number\n class?: string\n}\n\nconst sizes = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n}\n\nconst weights = {\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n}\n\nconst colors = {\n default: 'text-neutral-900',\n dimmed: 'text-neutral-400',\n}\n\nexport const Text = ({\n children,\n size = 'sm',\n weight = 'normal',\n color = 'default',\n lineClamp,\n class: cls,\n}: Props) => {\n const clampStyle = lineClamp\n ? {\n overflow: 'hidden',\n display: '-webkit-box',\n WebkitLineClamp: lineClamp,\n WebkitBoxOrient: 'vertical' as const,\n }\n : undefined\n\n return (\n <p class={`${sizes[size]} ${weights[weight]} ${colors[color]} ${cls ?? ''}`} style={clampStyle}>\n {children}\n </p>\n )\n}\n","import { useEffect, useRef } from 'preact/hooks'\nimport { Send } from 'lucide-preact'\n\ntype Props = {\n onSend: (text: string) => void\n onType?: () => void\n disabled?: boolean\n}\n\nexport const InputMessage = ({ onSend, onType, disabled }: Props) => {\n const ref = useRef<HTMLTextAreaElement>(null)\n\n useEffect(() => {\n if (!disabled) ref.current?.focus()\n }, [disabled])\n\n const resize = () => {\n const el = ref.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${el.scrollHeight}px`\n }\n\n const submit = () => {\n const el = ref.current\n if (!el || disabled) return\n const text = el.value.trim()\n if (!text) return\n onSend(text)\n el.value = ''\n el.style.height = 'auto'\n }\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Enter') return\n\n if (e.metaKey || e.ctrlKey) {\n // CMD/Ctrl + Enter → insert newline at cursor\n e.preventDefault()\n const el = ref.current!\n const start = el.selectionStart ?? el.value.length\n const end = el.selectionEnd ?? el.value.length\n el.value = el.value.slice(0, start) + '\\n' + el.value.slice(end)\n el.selectionStart = el.selectionEnd = start + 1\n resize()\n } else if (!e.shiftKey) {\n // Enter alone → send\n e.preventDefault()\n submit()\n }\n // Shift + Enter → default textarea newline\n }\n\n return (\n <div class=\"flex items-end gap-2 px-3 py-3 border-t border-neutral-100\">\n <textarea\n ref={ref}\n rows={1}\n placeholder=\"Write a message...\"\n onInput={() => { resize(); onType?.() }}\n onKeyDown={onKeyDown}\n disabled={disabled}\n class=\"flex-1 text-sm bg-neutral-100 rounded-2xl px-4 py-2 outline-none placeholder:text-neutral-400 disabled:opacity-50 resize-none overflow-y-auto leading-5\"\n style={{ maxHeight: '120px' }}\n />\n <button\n onClick={submit}\n disabled={disabled}\n class=\"w-8 h-8 flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white rounded-full transition-colors cursor-pointer shrink-0 disabled:opacity-50 disabled:cursor-not-allowed mb-0.5\"\n aria-label=\"Send\"\n >\n <Send size={14} />\n </button>\n </div>\n )\n}\n","import { Fragment } from 'preact'\nimport { useEffect, useRef } from 'preact/hooks'\nimport { Loader } from '../../../ui/Loader'\nimport type { Agent, Message } from '../../api/types'\nimport { DateSeparator } from './DateSeparator'\nimport { MessageBubble } from './MessageBubble'\n\ntype Props = {\n messages: Message[]\n agent?: Agent\n scrollKey?: unknown\n hasMore?: boolean\n loadingMore?: boolean\n onLoadMore?: () => void\n isTyping?: boolean\n}\n\nfunction isSameDay(a: string, b: string): boolean {\n return new Date(a).toDateString() === new Date(b).toDateString()\n}\n\nexport const MessageList = ({\n messages,\n agent,\n scrollKey,\n hasMore,\n loadingMore,\n onLoadMore,\n isTyping,\n}: Props) => {\n const containerRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const container = containerRef.current\n if (!container) {\n return\n }\n\n const onScroll = () => {\n const canTrigger =\n Math.abs(container.scrollTop) > container.scrollHeight - container.clientHeight - 100\n\n if (hasMore && !loadingMore && canTrigger) {\n onLoadMore?.()\n }\n }\n\n container.addEventListener('scroll', onScroll, { passive: true })\n return () => container.removeEventListener('scroll', onScroll)\n }, [hasMore, loadingMore, onLoadMore])\n\n return (\n <div class=\"flex-1 flex flex-col overflow-hidden\">\n <div ref={containerRef} class=\"flex-1 overflow-y-auto flex flex-col-reverse gap-1 px-3 py-4\">\n {isTyping && (\n <div class=\"flex gap-2 items-end\">\n <div class=\"w-7 h-7 rounded-full bg-neutral-200 shrink-0 overflow-hidden flex items-center justify-center text-xs font-semibold text-neutral-600 self-end mb-0.5\">\n {agent?.picture\n ? <img src={agent.picture} alt={agent.name} class=\"w-full h-full object-cover\" />\n : (agent?.name?.charAt(0) ?? '?')\n }\n </div>\n <div class=\"bg-neutral-100 rounded-2xl rounded-bl-sm px-3 py-2.5 flex gap-1 items-center\">\n <span class=\"w-1.5 h-1.5 rounded-full bg-neutral-400 animate-bounce\" style={{ animationDelay: '0ms' }} />\n <span class=\"w-1.5 h-1.5 rounded-full bg-neutral-400 animate-bounce\" style={{ animationDelay: '150ms' }} />\n <span class=\"w-1.5 h-1.5 rounded-full bg-neutral-400 animate-bounce\" style={{ animationDelay: '300ms' }} />\n </div>\n </div>\n )}\n\n {messages.map((msg, i) => {\n const next = messages[i + 1]\n const showDate = !next || !isSameDay(next.createdAt, msg.createdAt)\n const isFirstInGroup = showDate || next?.sender !== msg.sender\n\n return (\n <Fragment key={msg.id}>\n <MessageBubble message={msg} agent={agent} isFirstInGroup={isFirstInGroup} />\n {showDate && <DateSeparator date={msg.createdAt} />}\n </Fragment>\n )\n })}\n\n <div\n class={`flex justify-center py-2 border-b border-neutral-100 ${!loadingMore && 'opacity-0'}`}\n >\n <Loader size={16} />\n </div>\n </div>\n </div>\n )\n}\n","type Props = {\n date: string\n}\n\nfunction formatLabel(dateStr: string): string {\n const date = new Date(dateStr)\n const today = new Date()\n const yesterday = new Date(today)\n yesterday.setDate(today.getDate() - 1)\n\n const sameDay = (a: Date, b: Date) =>\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n\n if (sameDay(date, today)) return 'Today'\n if (sameDay(date, yesterday)) return 'Yesterday'\n\n return date\n .toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' })\n .replace(',', '')\n}\n\nexport const DateSeparator = ({ date }: Props) => (\n <div class=\"flex items-center gap-2 my-3\">\n <div class=\"flex-1 h-px bg-neutral-200\" />\n <span class=\"text-xs text-neutral-400 font-medium px-1\">{formatLabel(date)}</span>\n <div class=\"flex-1 h-px bg-neutral-200\" />\n </div>\n)\n","import type { Agent, Message } from '../../api/types'\n\ntype Props = {\n message: Message\n agent?: Agent\n isFirstInGroup: boolean\n}\n\nfunction formatTime(dateStr: string): string {\n return new Date(dateStr).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\nexport const MessageBubble = ({ message, agent, isFirstInGroup }: Props) => {\n const isUser = message.sender === 'user'\n\n return (\n <div class={`flex gap-2 items-end ${isUser ? 'flex-row-reverse' : 'flex-row'}`}>\n {!isUser && (\n isFirstInGroup ? (\n <div class=\"w-7 h-7 rounded-full bg-neutral-200 shrink-0 overflow-hidden flex items-center justify-center text-xs font-semibold text-neutral-600 self-end mb-0.5\">\n {agent?.picture\n ? <img src={agent.picture} alt={agent.name} class=\"w-full h-full object-cover\" />\n : (agent?.name?.charAt(0) ?? '?')\n }\n </div>\n ) : (\n <div class=\"w-7 shrink-0\" />\n )\n )}\n\n <div class={`flex flex-col gap-0.5 max-w-[72%] ${isUser ? 'items-end' : 'items-start'}`}>\n {!isUser && isFirstInGroup && (\n <span class=\"text-xs text-neutral-500 font-semibold px-1\">{agent?.name}</span>\n )}\n\n <div class={`relative px-3 pt-2 pb-5 min-w-18 rounded-2xl text-sm leading-snug whitespace-pre-wrap ${\n isUser\n ? 'bg-blue-600 text-white rounded-br-sm'\n : 'bg-neutral-100 text-neutral-900 rounded-bl-sm'\n }`}>\n {message.text}\n <span class={`absolute bottom-1.5 right-2.5 text-[10px] leading-none ${\n isUser ? 'text-blue-200' : 'text-neutral-400'\n }`}>\n {formatTime(message.createdAt)}\n </span>\n </div>\n </div>\n </div>\n )\n}\n","import { CheckCircle } from 'lucide-preact'\nimport { useEffect, useState } from 'preact/hooks'\nimport { Button } from '../../../ui/Button'\nimport { Group } from '../../../ui/Group'\nimport { Stack } from '../../../ui/Stack'\nimport { Text } from '../../../ui/Text'\n\ntype Props = {\n onYes: () => void\n onNo: () => void\n}\n\nexport const ResolvedBanner = ({ onYes, onNo }: Props) => {\n const [thanked, setThanked] = useState(false)\n\n useEffect(() => {\n if (!thanked) return\n const timer = setTimeout(onYes, 3000)\n return () => clearTimeout(timer)\n }, [thanked])\n\n if (thanked) {\n return (\n <Stack class=\"border-t border-neutral-100 p-4 min-h-[175px]\" align=\"center\">\n <CheckCircle size={20} class=\"text-green-500\" />\n <Text size=\"sm\" weight=\"semibold\">\n Glad we could help\n </Text>\n <Text size=\"sm\" color=\"dimmed\">\n See you next time\n </Text>\n </Stack>\n )\n }\n\n return (\n <Stack class=\"border-t border-neutral-100 p-4 min-h-[175px]\" align=\"center\">\n <CheckCircle size={20} class=\"text-green-500\" />\n\n <Stack gap={0} align=\"center\">\n <Text size=\"sm\">This conversation has been resolved</Text>\n <Text size=\"sm\" color=\"dimmed\">\n Did we answer your question?\n </Text>\n </Stack>\n\n <Group class=\"w-full\">\n <Button class=\"flex-1\" variant=\"outline\" fullWidth onClick={onNo}>\n <Stack gap={0}>\n <Text>No</Text>\n <Text size=\"xs\" color=\"dimmed\">\n I need more help\n </Text>\n </Stack>\n </Button>\n\n <Button class=\"flex-1\" onClick={() => setThanked(true)}>\n <Stack gap={0}>\n <Text class=\"text-white\" weight=\"semibold\">\n Yes\n </Text>\n <Text size=\"xs\" class=\"text-white\">\n Thanks\n </Text>\n </Stack>\n </Button>\n </Group>\n </Stack>\n )\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n gap?: 'xs' | 'sm' | 'md' | 'lg' | number\n align?: 'start' | 'center' | 'end' | 'stretch'\n justify?: 'start' | 'center' | 'end' | 'between'\n class?: string\n}\n\nconst gaps = {\n xs: 'gap-1',\n sm: 'gap-2',\n md: 'gap-4',\n lg: 'gap-6',\n}\n\nconst aligns = {\n start: 'items-start',\n center: 'items-center',\n end: 'items-end',\n stretch: 'items-stretch',\n}\n\nconst justifies = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n}\n\nexport const Stack = ({ children, gap = 'md', align, justify, class: cls }: Props) => {\n const gapClass = (gaps as any)[gap] ?? `gap-${gap}`\n\n return (\n <div class={`flex flex-col ${gapClass} ${align ? aligns[align] : ''} ${justify ? justifies[justify] : ''} ${cls ?? ''}`}>\n {children}\n </div>\n )\n}\n","import { useEffect, useRef, useState } from 'preact/hooks'\nimport { socket } from './service'\n\ntype Payload = { room_id: string }\n\ntype Props = {\n room_id?: string\n}\n\nconst TYPING_TIMEOUT_MS = 10000\n\nexport const useOnTyping = ({ room_id }: Props) => {\n const [isTyping, setIsTyping] = useState(false)\n const stopTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const clearStopTimer = () => {\n if (stopTimerRef.current) {\n clearTimeout(stopTimerRef.current)\n stopTimerRef.current = null\n }\n }\n\n const stopTyping = () => {\n clearStopTimer()\n setIsTyping(false)\n }\n\n useEffect(() => {\n if (!socket.value) {\n return\n }\n\n const handlerStart = (payload: Payload) => {\n const canSkip = room_id && !payload.room_id.includes(room_id)\n\n if (canSkip) {\n return\n }\n\n setIsTyping(true)\n clearStopTimer()\n stopTimerRef.current = setTimeout(stopTyping, TYPING_TIMEOUT_MS)\n }\n\n const handlerStop = (payload: Payload) => {\n const canSkip = room_id && !payload.room_id.includes(room_id)\n\n if (canSkip) {\n return\n }\n\n stopTyping()\n }\n\n socket.value.on('typing-start', handlerStart)\n socket.value.on('typing-stop', handlerStop)\n\n return () => {\n socket.value?.off('typing-start', handlerStart)\n socket.value?.off('typing-stop', handlerStop)\n clearStopTimer()\n }\n }, [room_id, socket])\n\n return { isTyping }\n}\n","import { useRef } from 'preact/hooks'\nimport { socket, SocketService } from './service'\n\ntype Props = {\n room_id: string\n}\n\nconst TYPING_START_DELAY_MS = 3000\nconst TYPING_HEARTBEAT_MS = 5000\nconst TYPING_STOP_DELAY_MS = 5000\n\nexport const useTyping = ({ room_id }: Props) => {\n const startTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const stopTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const lastEmitRef = useRef<number>(0)\n\n const onType = () => {\n if (!socket.value) {\n return\n }\n\n const now = Date.now()\n\n // Heartbeat: re-emit typing-start while actively typing\n if (lastEmitRef.current > 0 && now - lastEmitRef.current >= TYPING_HEARTBEAT_MS) {\n SocketService.typingStart(room_id)\n lastEmitRef.current = now\n }\n\n // Start delay: only emit typing-start after 3s of sustained typing\n if (lastEmitRef.current === 0 && !startTimerRef.current) {\n startTimerRef.current = setTimeout(() => {\n SocketService.typingStart(room_id)\n lastEmitRef.current = Date.now()\n startTimerRef.current = null\n }, TYPING_START_DELAY_MS)\n }\n\n // Reset stop timer on each keystroke\n if (stopTimerRef.current) {\n clearTimeout(stopTimerRef.current)\n }\n\n stopTimerRef.current = setTimeout(() => {\n if (startTimerRef.current) {\n clearTimeout(startTimerRef.current)\n startTimerRef.current = null\n }\n if (lastEmitRef.current > 0) {\n SocketService.typingStop(room_id)\n lastEmitRef.current = 0\n }\n stopTimerRef.current = null\n }, TYPING_STOP_DELAY_MS)\n }\n\n const stopTyping = () => {\n if (startTimerRef.current) {\n clearTimeout(startTimerRef.current)\n startTimerRef.current = null\n }\n if (stopTimerRef.current) {\n clearTimeout(stopTimerRef.current)\n stopTimerRef.current = null\n }\n if (lastEmitRef.current > 0) {\n SocketService.typingStop(room_id)\n lastEmitRef.current = 0\n }\n }\n\n return { onType, stopTyping }\n}\n","import { ChevronRight, SendHorizonal } from 'lucide-preact'\nimport { useEffect } from 'preact/hooks'\nimport { useOnNewMessage } from '../hooks/useNewMessage'\nimport { useQuery } from '../hooks/useQuery'\nimport { ApiService } from '../modules/api/service'\nimport { navigate } from '../router'\nimport { currentUser, visitorId } from '../state'\nimport { Avatar } from '../ui/Avatar'\nimport { Card } from '../ui/Card'\nimport { Group } from '../ui/Group'\nimport { Indicator } from '../ui/Indicator'\nimport { Stack } from '../ui/Stack'\nimport { Text } from '../ui/Text'\nimport { Title } from '../ui/Title'\n\nexport const Home = () => {\n const agentsQuery = useQuery({ queryKey: ['agents'], queryFn: () => ApiService.getAgents() })\n const conversationsQuery = useQuery({\n queryKey: ['conversations'],\n queryFn: () => ApiService.getConversations(),\n })\n\n const agents = agentsQuery.data ?? []\n const conversations = conversationsQuery.data ?? []\n\n const userName = currentUser.value?.name\n\n useOnNewMessage(() => {\n conversationsQuery.refetch()\n })\n\n useEffect(() => {\n conversationsQuery.refetch()\n }, [visitorId.value])\n\n return (\n <Stack class=\"flex flex-col p-4 gradient-header\">\n <Group justify=\"end\">\n {agents?.map((agent) => (\n <Indicator key={agent.id} color=\"green\">\n <Avatar src={agent.picture}>{agent.name}</Avatar>\n </Indicator>\n ))}\n </Group>\n\n <Stack gap={0} class=\"mt-12\">\n <Title color=\"dimmed\" lineClamp={2}>\n {userName ? `Hey ${userName} 👋` : `Hey 👋`}\n </Title>\n <Title>How can we help?</Title>\n </Stack>\n\n <Card class=\"mb-8\" onClick={() => navigate('conversation')}>\n <Group align=\"center\" justify=\"between\">\n <Stack gap={0}>\n <Text class=\"font-semibold\">Send us a message</Text>\n <Text color=\"dimmed\">Usual reply time is a few minutes</Text>\n </Stack>\n <SendHorizonal />\n </Group>\n </Card>\n\n {conversations && conversations.length > 0 && (\n <Stack gap={2}>\n <Text color=\"dimmed\" class=\"text-xs font-medium uppercase tracking-wide px-1\">\n Previous conversations\n </Text>\n <Stack gap={1}>\n {conversations.map((conv) => {\n const agent = conv.agent\n\n return (\n <Card\n key={conv.id}\n onClick={() => navigate('conversation', { conversationId: conv.id })}\n >\n <Group align=\"center\" justify=\"between\">\n <Group align=\"center\" gap={2}>\n <Avatar size=\"sm\" src={agent?.picture}>\n {agent?.name}\n </Avatar>\n <Stack gap={0}>\n <Text class=\"font-medium text-xs\">{agent?.name ?? 'Support'}</Text>\n <Text color=\"dimmed\" class=\"text-xs truncate max-w-[180px]\">\n {conv.lastMessage?.text ?? 'No messages yet'}\n </Text>\n </Stack>\n </Group>\n <Indicator\n color=\"red\"\n label={conv.unread_contact_count}\n visible={conv.unread_contact_count > 0}\n position=\"top-right\"\n offset={{ x: -36, y: 15 }}\n >\n <ChevronRight size={14} class=\"text-neutral-400 shrink-0\" />\n </Indicator>\n </Group>\n </Card>\n )\n })}\n </Stack>\n </Stack>\n )}\n </Stack>\n )\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n onClick?: () => void\n class?: string\n}\n\nexport const Card = ({ children, onClick, class: cls }: Props) => (\n <div\n onClick={onClick}\n class={`\n p-4 rounded-lg border border-neutral-200 bg-white\n ${onClick ? 'cursor-pointer hover:bg-neutral-50 transition-colors' : ''}\n ${cls ?? ''}\n `}\n >\n {children}\n </div>\n)\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n order?: 1 | 2 | 3\n color?: 'default' | 'dimmed' | string\n lineClamp?: number\n class?: string\n}\n\nconst styles: Record<1 | 2 | 3, { tag: 'h1' | 'h2' | 'h3'; cls: string }> = {\n 1: { tag: 'h1', cls: 'text-2xl font-semibold' },\n 2: { tag: 'h2', cls: 'text-lg font-semibold' },\n 3: { tag: 'h3', cls: 'text-base font-medium' },\n}\n\nconst colors = {\n default: 'text-neutral-800',\n dimmed: 'text-neutral-400',\n}\n\nexport const Title = ({ children, order = 1, color = 'default', lineClamp, class: cls }: Props) => {\n const { tag: Tag, cls: base } = styles[order]\n\n const colorClass = (colors as any)[color] ?? color\n const clampStyle = lineClamp\n ? { overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: lineClamp, WebkitBoxOrient: 'vertical' as const }\n : undefined\n\n return <Tag class={`${base} ${cls ?? ''} ${colorClass}`} style={clampStyle}>{children}</Tag>\n}\n","export default \"/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\\n@layer properties;\\n@layer theme, base, components, utilities;\\n@layer theme {\\n :root, :host {\\n --font-sans: ui-sans-serif, system-ui, sans-serif, \\\"Apple Color Emoji\\\",\\n \\\"Segoe UI Emoji\\\", \\\"Segoe UI Symbol\\\", \\\"Noto Color Emoji\\\";\\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\",\\n \\\"Courier New\\\", monospace;\\n --color-red-500: oklch(63.7% 0.237 25.331);\\n --color-amber-50: oklch(98.7% 0.022 95.277);\\n --color-amber-200: oklch(92.4% 0.12 95.746);\\n --color-amber-700: oklch(55.5% 0.163 48.998);\\n --color-green-500: oklch(72.3% 0.219 149.579);\\n --color-blue-100: oklch(93.2% 0.032 255.585);\\n --color-blue-200: oklch(88.2% 0.059 254.128);\\n --color-blue-400: oklch(70.7% 0.165 254.624);\\n --color-blue-500: oklch(62.3% 0.214 259.815);\\n --color-blue-600: oklch(54.6% 0.245 262.881);\\n --color-blue-700: oklch(48.8% 0.243 264.376);\\n --color-gray-200: oklch(92.8% 0.006 264.531);\\n --color-neutral-50: oklch(98.5% 0 0);\\n --color-neutral-100: oklch(97% 0 0);\\n --color-neutral-200: oklch(92.2% 0 0);\\n --color-neutral-300: oklch(87% 0 0);\\n --color-neutral-400: oklch(70.8% 0 0);\\n --color-neutral-500: oklch(55.6% 0 0);\\n --color-neutral-600: oklch(43.9% 0 0);\\n --color-neutral-800: oklch(26.9% 0 0);\\n --color-neutral-900: oklch(20.5% 0 0);\\n --color-white: #fff;\\n --spacing: 0.25rem;\\n --text-xs: 0.75rem;\\n --text-xs--line-height: calc(1 / 0.75);\\n --text-sm: 0.875rem;\\n --text-sm--line-height: calc(1.25 / 0.875);\\n --text-base: 1rem;\\n --text-base--line-height: calc(1.5 / 1);\\n --text-lg: 1.125rem;\\n --text-lg--line-height: calc(1.75 / 1.125);\\n --text-xl: 1.25rem;\\n --text-xl--line-height: calc(1.75 / 1.25);\\n --text-2xl: 1.5rem;\\n --text-2xl--line-height: calc(2 / 1.5);\\n --font-weight-normal: 400;\\n --font-weight-medium: 500;\\n --font-weight-semibold: 600;\\n --tracking-wide: 0.025em;\\n --leading-snug: 1.375;\\n --radius-sm: 0.25rem;\\n --radius-lg: 0.5rem;\\n --radius-xl: 0.75rem;\\n --radius-2xl: 1rem;\\n --animate-spin: spin 1s linear infinite;\\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\\n --animate-bounce: bounce 1s infinite;\\n --default-transition-duration: 150ms;\\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\\n --default-font-family: var(--font-sans);\\n --default-mono-font-family: var(--font-mono);\\n }\\n}\\n@layer base {\\n *, ::after, ::before, ::backdrop, ::file-selector-button {\\n box-sizing: border-box;\\n margin: 0;\\n padding: 0;\\n border: 0 solid;\\n }\\n html, :host {\\n line-height: 1.5;\\n -webkit-text-size-adjust: 100%;\\n tab-size: 4;\\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, \\\"Apple Color Emoji\\\", \\\"Segoe UI Emoji\\\", \\\"Segoe UI Symbol\\\", \\\"Noto Color Emoji\\\");\\n font-feature-settings: var(--default-font-feature-settings, normal);\\n font-variation-settings: var(--default-font-variation-settings, normal);\\n -webkit-tap-highlight-color: transparent;\\n }\\n hr {\\n height: 0;\\n color: inherit;\\n border-top-width: 1px;\\n }\\n abbr:where([title]) {\\n -webkit-text-decoration: underline dotted;\\n text-decoration: underline dotted;\\n }\\n h1, h2, h3, h4, h5, h6 {\\n font-size: inherit;\\n font-weight: inherit;\\n }\\n a {\\n color: inherit;\\n -webkit-text-decoration: inherit;\\n text-decoration: inherit;\\n }\\n b, strong {\\n font-weight: bolder;\\n }\\n code, kbd, samp, pre {\\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace);\\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\\n font-size: 1em;\\n }\\n small {\\n font-size: 80%;\\n }\\n sub, sup {\\n font-size: 75%;\\n line-height: 0;\\n position: relative;\\n vertical-align: baseline;\\n }\\n sub {\\n bottom: -0.25em;\\n }\\n sup {\\n top: -0.5em;\\n }\\n table {\\n text-indent: 0;\\n border-color: inherit;\\n border-collapse: collapse;\\n }\\n :-moz-focusring {\\n outline: auto;\\n }\\n progress {\\n vertical-align: baseline;\\n }\\n summary {\\n display: list-item;\\n }\\n ol, ul, menu {\\n list-style: none;\\n }\\n img, svg, video, canvas, audio, iframe, embed, object {\\n display: block;\\n vertical-align: middle;\\n }\\n img, video {\\n max-width: 100%;\\n height: auto;\\n }\\n button, input, select, optgroup, textarea, ::file-selector-button {\\n font: inherit;\\n font-feature-settings: inherit;\\n font-variation-settings: inherit;\\n letter-spacing: inherit;\\n color: inherit;\\n border-radius: 0;\\n background-color: transparent;\\n opacity: 1;\\n }\\n :where(select:is([multiple], [size])) optgroup {\\n font-weight: bolder;\\n }\\n :where(select:is([multiple], [size])) optgroup option {\\n padding-inline-start: 20px;\\n }\\n ::file-selector-button {\\n margin-inline-end: 4px;\\n }\\n ::placeholder {\\n opacity: 1;\\n }\\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\\n ::placeholder {\\n color: currentcolor;\\n @supports (color: color-mix(in lab, red, red)) {\\n color: color-mix(in oklab, currentcolor 50%, transparent);\\n }\\n }\\n }\\n textarea {\\n resize: vertical;\\n }\\n ::-webkit-search-decoration {\\n -webkit-appearance: none;\\n }\\n ::-webkit-date-and-time-value {\\n min-height: 1lh;\\n text-align: inherit;\\n }\\n ::-webkit-datetime-edit {\\n display: inline-flex;\\n }\\n ::-webkit-datetime-edit-fields-wrapper {\\n padding: 0;\\n }\\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\\n padding-block: 0;\\n }\\n ::-webkit-calendar-picker-indicator {\\n line-height: 1;\\n }\\n :-moz-ui-invalid {\\n box-shadow: none;\\n }\\n button, input:where([type=\\\"button\\\"], [type=\\\"reset\\\"], [type=\\\"submit\\\"]), ::file-selector-button {\\n appearance: button;\\n }\\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\\n height: auto;\\n }\\n [hidden]:where(:not([hidden=\\\"until-found\\\"])) {\\n display: none !important;\\n }\\n}\\n@layer utilities {\\n .visible {\\n visibility: visible;\\n }\\n .absolute {\\n position: absolute;\\n }\\n .fixed {\\n position: fixed;\\n }\\n .relative {\\n position: relative;\\n }\\n .start {\\n inset-inline-start: var(--spacing);\\n }\\n .end {\\n inset-inline-end: var(--spacing);\\n }\\n .top-0 {\\n top: calc(var(--spacing) * 0);\\n }\\n .right-0 {\\n right: calc(var(--spacing) * 0);\\n }\\n .right-2\\\\.5 {\\n right: calc(var(--spacing) * 2.5);\\n }\\n .right-4 {\\n right: calc(var(--spacing) * 4);\\n }\\n .bottom-0 {\\n bottom: calc(var(--spacing) * 0);\\n }\\n .bottom-1\\\\.5 {\\n bottom: calc(var(--spacing) * 1.5);\\n }\\n .bottom-4 {\\n bottom: calc(var(--spacing) * 4);\\n }\\n .bottom-20 {\\n bottom: calc(var(--spacing) * 20);\\n }\\n .container {\\n width: 100%;\\n @media (width >= 40rem) {\\n max-width: 40rem;\\n }\\n @media (width >= 48rem) {\\n max-width: 48rem;\\n }\\n @media (width >= 64rem) {\\n max-width: 64rem;\\n }\\n @media (width >= 80rem) {\\n max-width: 80rem;\\n }\\n @media (width >= 96rem) {\\n max-width: 96rem;\\n }\\n }\\n .my-3 {\\n margin-block: calc(var(--spacing) * 3);\\n }\\n .mt-12 {\\n margin-top: calc(var(--spacing) * 12);\\n }\\n .mb-0\\\\.5 {\\n margin-bottom: calc(var(--spacing) * 0.5);\\n }\\n .mb-8 {\\n margin-bottom: calc(var(--spacing) * 8);\\n }\\n .flex {\\n display: flex;\\n }\\n .hidden {\\n display: none;\\n }\\n .inline-flex {\\n display: inline-flex;\\n }\\n .h-1\\\\.5 {\\n height: calc(var(--spacing) * 1.5);\\n }\\n .h-2\\\\.5 {\\n height: calc(var(--spacing) * 2.5);\\n }\\n .h-3\\\\.5 {\\n height: calc(var(--spacing) * 3.5);\\n }\\n .h-4 {\\n height: calc(var(--spacing) * 4);\\n }\\n .h-5 {\\n height: calc(var(--spacing) * 5);\\n }\\n .h-6 {\\n height: calc(var(--spacing) * 6);\\n }\\n .h-7 {\\n height: calc(var(--spacing) * 7);\\n }\\n .h-8 {\\n height: calc(var(--spacing) * 8);\\n }\\n .h-9 {\\n height: calc(var(--spacing) * 9);\\n }\\n .h-12 {\\n height: calc(var(--spacing) * 12);\\n }\\n .h-14 {\\n height: calc(var(--spacing) * 14);\\n }\\n .h-112 {\\n height: calc(var(--spacing) * 112);\\n }\\n .h-full {\\n height: 100%;\\n }\\n .h-px {\\n height: 1px;\\n }\\n .min-h-\\\\[175px\\\\] {\\n min-height: 175px;\\n }\\n .w-1\\\\.5 {\\n width: calc(var(--spacing) * 1.5);\\n }\\n .w-2\\\\.5 {\\n width: calc(var(--spacing) * 2.5);\\n }\\n .w-3\\\\.5 {\\n width: calc(var(--spacing) * 3.5);\\n }\\n .w-4 {\\n width: calc(var(--spacing) * 4);\\n }\\n .w-7 {\\n width: calc(var(--spacing) * 7);\\n }\\n .w-8 {\\n width: calc(var(--spacing) * 8);\\n }\\n .w-9 {\\n width: calc(var(--spacing) * 9);\\n }\\n .w-12 {\\n width: calc(var(--spacing) * 12);\\n }\\n .w-14 {\\n width: calc(var(--spacing) * 14);\\n }\\n .w-80 {\\n width: calc(var(--spacing) * 80);\\n }\\n .w-full {\\n width: 100%;\\n }\\n .max-w-\\\\[72\\\\%\\\\] {\\n max-width: 72%;\\n }\\n .max-w-\\\\[180px\\\\] {\\n max-width: 180px;\\n }\\n .min-w-4 {\\n min-width: calc(var(--spacing) * 4);\\n }\\n .min-w-5 {\\n min-width: calc(var(--spacing) * 5);\\n }\\n .min-w-6 {\\n min-width: calc(var(--spacing) * 6);\\n }\\n .min-w-18 {\\n min-width: calc(var(--spacing) * 18);\\n }\\n .flex-1 {\\n flex: 1;\\n }\\n .shrink-0 {\\n flex-shrink: 0;\\n }\\n .translate-x-1\\\\/2 {\\n --tw-translate-x: calc(1 / 2 * 100%);\\n translate: var(--tw-translate-x) var(--tw-translate-y);\\n }\\n .-translate-y-1\\\\/2 {\\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\\n translate: var(--tw-translate-x) var(--tw-translate-y);\\n }\\n .transform {\\n transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);\\n }\\n .animate-bounce {\\n animation: var(--animate-bounce);\\n }\\n .animate-pulse {\\n animation: var(--animate-pulse);\\n }\\n .animate-spin {\\n animation: var(--animate-spin);\\n }\\n .cursor-pointer {\\n cursor: pointer;\\n }\\n .resize {\\n resize: both;\\n }\\n .resize-none {\\n resize: none;\\n }\\n .flex-col {\\n flex-direction: column;\\n }\\n .flex-col-reverse {\\n flex-direction: column-reverse;\\n }\\n .flex-row {\\n flex-direction: row;\\n }\\n .flex-row-reverse {\\n flex-direction: row-reverse;\\n }\\n .flex-wrap {\\n flex-wrap: wrap;\\n }\\n .items-center {\\n align-items: center;\\n }\\n .items-end {\\n align-items: flex-end;\\n }\\n .items-start {\\n align-items: flex-start;\\n }\\n .items-stretch {\\n align-items: stretch;\\n }\\n .justify-between {\\n justify-content: space-between;\\n }\\n .justify-center {\\n justify-content: center;\\n }\\n .justify-end {\\n justify-content: flex-end;\\n }\\n .justify-start {\\n justify-content: flex-start;\\n }\\n .gap-0\\\\.5 {\\n gap: calc(var(--spacing) * 0.5);\\n }\\n .gap-1 {\\n gap: calc(var(--spacing) * 1);\\n }\\n .gap-2 {\\n gap: calc(var(--spacing) * 2);\\n }\\n .gap-4 {\\n gap: calc(var(--spacing) * 4);\\n }\\n .gap-6 {\\n gap: calc(var(--spacing) * 6);\\n }\\n .self-end {\\n align-self: flex-end;\\n }\\n .truncate {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n }\\n .overflow-hidden {\\n overflow: hidden;\\n }\\n .overflow-y-auto {\\n overflow-y: auto;\\n }\\n .rounded-2xl {\\n border-radius: var(--radius-2xl);\\n }\\n .rounded-full {\\n border-radius: calc(infinity * 1px);\\n }\\n .rounded-lg {\\n border-radius: var(--radius-lg);\\n }\\n .rounded-xl {\\n border-radius: var(--radius-xl);\\n }\\n .rounded-br-sm {\\n border-bottom-right-radius: var(--radius-sm);\\n }\\n .rounded-bl-sm {\\n border-bottom-left-radius: var(--radius-sm);\\n }\\n .border {\\n border-style: var(--tw-border-style);\\n border-width: 1px;\\n }\\n .border-2 {\\n border-style: var(--tw-border-style);\\n border-width: 2px;\\n }\\n .border-t {\\n border-top-style: var(--tw-border-style);\\n border-top-width: 1px;\\n }\\n .border-b {\\n border-bottom-style: var(--tw-border-style);\\n border-bottom-width: 1px;\\n }\\n .border-amber-200 {\\n border-color: var(--color-amber-200);\\n }\\n .border-blue-400 {\\n border-color: var(--color-blue-400);\\n }\\n .border-gray-200 {\\n border-color: var(--color-gray-200);\\n }\\n .border-neutral-100 {\\n border-color: var(--color-neutral-100);\\n }\\n .border-neutral-200 {\\n border-color: var(--color-neutral-200);\\n }\\n .border-white {\\n border-color: var(--color-white);\\n }\\n .bg-amber-50 {\\n background-color: var(--color-amber-50);\\n }\\n .bg-blue-100 {\\n background-color: var(--color-blue-100);\\n }\\n .bg-blue-500 {\\n background-color: var(--color-blue-500);\\n }\\n .bg-blue-600 {\\n background-color: var(--color-blue-600);\\n }\\n .bg-green-500 {\\n background-color: var(--color-green-500);\\n }\\n .bg-neutral-100 {\\n background-color: var(--color-neutral-100);\\n }\\n .bg-neutral-200 {\\n background-color: var(--color-neutral-200);\\n }\\n .bg-neutral-400 {\\n background-color: var(--color-neutral-400);\\n }\\n .bg-red-500 {\\n background-color: var(--color-red-500);\\n }\\n .bg-transparent {\\n background-color: transparent;\\n }\\n .bg-white {\\n background-color: var(--color-white);\\n }\\n .object-cover {\\n object-fit: cover;\\n }\\n .p-2 {\\n padding: calc(var(--spacing) * 2);\\n }\\n .p-4 {\\n padding: calc(var(--spacing) * 4);\\n }\\n .px-1 {\\n padding-inline: calc(var(--spacing) * 1);\\n }\\n .px-3 {\\n padding-inline: calc(var(--spacing) * 3);\\n }\\n .px-4 {\\n padding-inline: calc(var(--spacing) * 4);\\n }\\n .py-2 {\\n padding-block: calc(var(--spacing) * 2);\\n }\\n .py-2\\\\.5 {\\n padding-block: calc(var(--spacing) * 2.5);\\n }\\n .py-3 {\\n padding-block: calc(var(--spacing) * 3);\\n }\\n .py-4 {\\n padding-block: calc(var(--spacing) * 4);\\n }\\n .pt-2 {\\n padding-top: calc(var(--spacing) * 2);\\n }\\n .pb-5 {\\n padding-bottom: calc(var(--spacing) * 5);\\n }\\n .text-center {\\n text-align: center;\\n }\\n .text-2xl {\\n font-size: var(--text-2xl);\\n line-height: var(--tw-leading, var(--text-2xl--line-height));\\n }\\n .text-base {\\n font-size: var(--text-base);\\n line-height: var(--tw-leading, var(--text-base--line-height));\\n }\\n .text-lg {\\n font-size: var(--text-lg);\\n line-height: var(--tw-leading, var(--text-lg--line-height));\\n }\\n .text-sm {\\n font-size: var(--text-sm);\\n line-height: var(--tw-leading, var(--text-sm--line-height));\\n }\\n .text-xl {\\n font-size: var(--text-xl);\\n line-height: var(--tw-leading, var(--text-xl--line-height));\\n }\\n .text-xs {\\n font-size: var(--text-xs);\\n line-height: var(--tw-leading, var(--text-xs--line-height));\\n }\\n .text-\\\\[10px\\\\] {\\n font-size: 10px;\\n }\\n .leading-5 {\\n --tw-leading: calc(var(--spacing) * 5);\\n line-height: calc(var(--spacing) * 5);\\n }\\n .leading-none {\\n --tw-leading: 1;\\n line-height: 1;\\n }\\n .leading-snug {\\n --tw-leading: var(--leading-snug);\\n line-height: var(--leading-snug);\\n }\\n .font-medium {\\n --tw-font-weight: var(--font-weight-medium);\\n font-weight: var(--font-weight-medium);\\n }\\n .font-normal {\\n --tw-font-weight: var(--font-weight-normal);\\n font-weight: var(--font-weight-normal);\\n }\\n .font-semibold {\\n --tw-font-weight: var(--font-weight-semibold);\\n font-weight: var(--font-weight-semibold);\\n }\\n .tracking-wide {\\n --tw-tracking: var(--tracking-wide);\\n letter-spacing: var(--tracking-wide);\\n }\\n .whitespace-pre-wrap {\\n white-space: pre-wrap;\\n }\\n .text-amber-700 {\\n color: var(--color-amber-700);\\n }\\n .text-blue-200 {\\n color: var(--color-blue-200);\\n }\\n .text-blue-700 {\\n color: var(--color-blue-700);\\n }\\n .text-green-500 {\\n color: var(--color-green-500);\\n }\\n .text-inherit {\\n color: inherit;\\n }\\n .text-neutral-400 {\\n color: var(--color-neutral-400);\\n }\\n .text-neutral-500 {\\n color: var(--color-neutral-500);\\n }\\n .text-neutral-600 {\\n color: var(--color-neutral-600);\\n }\\n .text-neutral-800 {\\n color: var(--color-neutral-800);\\n }\\n .text-neutral-900 {\\n color: var(--color-neutral-900);\\n }\\n .text-white {\\n color: var(--color-white);\\n }\\n .uppercase {\\n text-transform: uppercase;\\n }\\n .opacity-0 {\\n opacity: 0%;\\n }\\n .shadow {\\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\\n }\\n .shadow-2xl {\\n --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));\\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\\n }\\n .shadow-lg {\\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\\n }\\n .outline {\\n outline-style: var(--tw-outline-style);\\n outline-width: 1px;\\n }\\n .transition-colors {\\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;\\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\\n transition-duration: var(--tw-duration, var(--default-transition-duration));\\n }\\n .outline-none {\\n --tw-outline-style: none;\\n outline-style: none;\\n }\\n .placeholder\\\\:text-neutral-400 {\\n &::placeholder {\\n color: var(--color-neutral-400);\\n }\\n }\\n .hover\\\\:bg-blue-700 {\\n &:hover {\\n @media (hover: hover) {\\n background-color: var(--color-blue-700);\\n }\\n }\\n }\\n .hover\\\\:bg-neutral-50 {\\n &:hover {\\n @media (hover: hover) {\\n background-color: var(--color-neutral-50);\\n }\\n }\\n }\\n .hover\\\\:bg-neutral-200 {\\n &:hover {\\n @media (hover: hover) {\\n background-color: var(--color-neutral-200);\\n }\\n }\\n }\\n .hover\\\\:text-neutral-800 {\\n &:hover {\\n @media (hover: hover) {\\n color: var(--color-neutral-800);\\n }\\n }\\n }\\n .disabled\\\\:cursor-not-allowed {\\n &:disabled {\\n cursor: not-allowed;\\n }\\n }\\n .disabled\\\\:opacity-50 {\\n &:disabled {\\n opacity: 50%;\\n }\\n }\\n}\\n*, ::before, ::after {\\n --tw-border-style: solid;\\n}\\n.gradient-header {\\n background: linear-gradient(to bottom, var(--color-neutral-200) 0%, var(--color-white) 60%);\\n}\\n.lucide {\\n height: 1em;\\n width: 1em;\\n display: inline-block;\\n}\\n::-webkit-scrollbar {\\n width: 4px;\\n}\\n::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n::-webkit-scrollbar-thumb {\\n background: var(--color-neutral-300);\\n border-radius: 9999px;\\n}\\n@property --tw-translate-x {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0;\\n}\\n@property --tw-translate-y {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0;\\n}\\n@property --tw-translate-z {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0;\\n}\\n@property --tw-rotate-x {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-rotate-y {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-rotate-z {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-skew-x {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-skew-y {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-border-style {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: solid;\\n}\\n@property --tw-leading {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-font-weight {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-tracking {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-shadow-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-shadow-alpha {\\n syntax: \\\"<percentage>\\\";\\n inherits: false;\\n initial-value: 100%;\\n}\\n@property --tw-inset-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-inset-shadow-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-inset-shadow-alpha {\\n syntax: \\\"<percentage>\\\";\\n inherits: false;\\n initial-value: 100%;\\n}\\n@property --tw-ring-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-ring-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-inset-ring-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-inset-ring-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-ring-inset {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-ring-offset-width {\\n syntax: \\\"<length>\\\";\\n inherits: false;\\n initial-value: 0px;\\n}\\n@property --tw-ring-offset-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: #fff;\\n}\\n@property --tw-ring-offset-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-outline-style {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: solid;\\n}\\n@keyframes spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n@keyframes pulse {\\n 50% {\\n opacity: 0.5;\\n }\\n}\\n@keyframes bounce {\\n 0%, 100% {\\n transform: translateY(-25%);\\n animation-timing-function: cubic-bezier(0.8, 0, 1, 1);\\n }\\n 50% {\\n transform: none;\\n animation-timing-function: cubic-bezier(0, 0, 0.2, 1);\\n }\\n}\\n@layer properties {\\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\\n *, ::before, ::after, ::backdrop {\\n --tw-translate-x: 0;\\n --tw-translate-y: 0;\\n --tw-translate-z: 0;\\n --tw-rotate-x: initial;\\n --tw-rotate-y: initial;\\n --tw-rotate-z: initial;\\n --tw-skew-x: initial;\\n --tw-skew-y: initial;\\n --tw-border-style: solid;\\n --tw-leading: initial;\\n --tw-font-weight: initial;\\n --tw-tracking: initial;\\n --tw-shadow: 0 0 #0000;\\n --tw-shadow-color: initial;\\n --tw-shadow-alpha: 100%;\\n --tw-inset-shadow: 0 0 #0000;\\n --tw-inset-shadow-color: initial;\\n --tw-inset-shadow-alpha: 100%;\\n --tw-ring-color: initial;\\n --tw-ring-shadow: 0 0 #0000;\\n --tw-inset-ring-color: initial;\\n --tw-inset-ring-shadow: 0 0 #0000;\\n --tw-ring-inset: initial;\\n --tw-ring-offset-width: 0px;\\n --tw-ring-offset-color: #fff;\\n --tw-ring-offset-shadow: 0 0 #0000;\\n --tw-outline-style: solid;\\n }\\n }\\n}\\n\"\n"],"mappings":"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","names":["init_service","VisitorService","init_service","import_preact","import_lucide_preact","import_hooks","import_jsx_runtime","isOpen","import_signals","init_service","import_hooks","init_service","import_signals","import_hooks","import_hooks","init_service","import_hooks","init_service","import_lucide_preact","import_signals","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","sizes","import_jsx_runtime","sizes","colors","import_jsx_runtime","import_hooks","import_lucide_preact","import_jsx_runtime","import_hooks","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_lucide_preact","import_hooks","import_jsx_runtime","gaps","aligns","justifies","import_jsx_runtime","import_hooks","import_hooks","import_jsx_runtime","isOpen","import_lucide_preact","import_hooks","init_service","import_jsx_runtime","import_jsx_runtime","colors","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/widget/state.ts","../src/widget/modules/api/mock.ts","../src/widget/modules/visitor/service.ts","../src/widget/modules/api/service.ts","../src/index.ts","../src/widget/mount.tsx","../src/widget/Widget.tsx","../src/widget/components/Layout.tsx","../src/widget/ui/Loader.tsx","../src/widget/hooks/useNewMessage.tsx","../src/widget/modules/socket/service.ts","../src/widget/hooks/useQuery.ts","../src/widget/pages/conversation.tsx","../src/widget/hooks/useMessages.ts","../src/widget/hooks/useMutation.ts","../src/widget/modules/conversation/components/Header.tsx","../src/widget/router.ts","../src/widget/ui/Avatar.tsx","../src/widget/ui/Button.tsx","../src/widget/ui/Group.tsx","../src/widget/ui/Indicator.tsx","../src/widget/ui/Text.tsx","../src/widget/modules/conversation/components/InputMessage.tsx","../src/widget/modules/conversation/components/MessageList.tsx","../src/widget/modules/conversation/components/DateSeparator.tsx","../src/widget/modules/conversation/components/MessageBubble.tsx","../src/widget/modules/conversation/components/ResolvedBanner.tsx","../src/widget/ui/Stack.tsx","../src/widget/modules/socket/useOnTyping.ts","../src/widget/modules/socket/useTyping.ts","../src/widget/pages/home.tsx","../src/widget/ui/Card.tsx","../src/widget/ui/Title.tsx","../src/widget/compiled-css.ts"],"sourcesContent":["import { signal } from '@preact/signals'\n\nexport interface WidgetUser {\n userId: string\n email?: string\n name?: string\n}\n\nexport const appId = signal<string | null>(null)\nexport const visitorId = signal<string | null>(null)\nexport const sessionToken = signal<string | null>(null)\nexport const tokenExpiresAt = signal<number | null>(null)\nexport const isOpen = signal(false)\nexport const currentUser = signal<WidgetUser | null>(null)\nexport const metadata = signal<Record<string, unknown>>({})\nexport const isOnline = signal(true)\nexport const isSetup = signal(false)\nexport const refetchSessionCounter = signal(0)\n","import type {\n Agent,\n Conversation,\n CreateConversationDto,\n CreateSessionDto,\n CreateSessionResponse,\n GetSessionResponse,\n IdentifyVisitorDto,\n IdentifyVisitorResponse,\n ListMessagesParams,\n Message,\n MessagesPage,\n SendMessageDto,\n SocketTokenResponse,\n} from './types'\n\nconst AGENTS: Agent[] = [\n { id: 'agent-1', name: 'Alice Martin', picture: undefined },\n { id: 'agent-2', name: 'Bob Chen', picture: undefined },\n]\n\nconst CONVERSATIONS: Conversation[] = [\n {\n id: 'conv-1',\n agentId: AGENTS[1].id,\n agent: AGENTS[1],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n {\n id: 'conv-2',\n agentId: AGENTS[0].id,\n agent: AGENTS[0],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n {\n id: 'conv-3',\n agentId: AGENTS[1].id,\n agent: AGENTS[1],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n {\n id: 'conv-4',\n agentId: AGENTS[0].id,\n agent: AGENTS[0],\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n unread_contact_count: 0,\n },\n]\nconst MESSAGES: Message[] = []\n// Tracks pending auto-close timers per conversation (for demo)\nconst autoCloseTimers = new Map<string, ReturnType<typeof setTimeout>>()\n\nconst delay = (ms = 300) => new Promise((res) => setTimeout(res, ms))\n\nexport const mockService = {\n async createSession(_dto: CreateSessionDto): Promise<CreateSessionResponse> {\n await delay()\n return {\n access_token: `mock-token-${Date.now()}`,\n token_type: 'Bearer',\n expires_in: 3600,\n visitor_id: _dto.visitorId,\n }\n },\n\n async getSession(): Promise<GetSessionResponse> {\n return { count_notifications: 1 }\n },\n\n async identifyVisitor(_dto: IdentifyVisitorDto): Promise<IdentifyVisitorResponse> {\n await delay()\n return { visitor_id: null, access_token: null }\n },\n\n async getAgents(): Promise<Agent[]> {\n await delay()\n return AGENTS\n },\n\n async getConversation(conversationId: string): Promise<Conversation> {\n await delay()\n const conv = CONVERSATIONS.find((c) => c.id === conversationId)\n if (!conv) throw new Error(`Conversation ${conversationId} not found`)\n return conv\n },\n\n async reopenConversation(conversationId: string): Promise<void> {\n await delay()\n const conv = CONVERSATIONS.find((c) => c.id === conversationId)\n if (conv) conv.status = 'OPEN'\n },\n\n async getConversationSocketToken(conversationId: string): Promise<SocketTokenResponse> {\n await delay()\n return { access_token: `mock-conv-socket-token-${conversationId}-${Date.now()}` }\n },\n\n async createConversation(dto: CreateConversationDto): Promise<Conversation> {\n await delay()\n\n const conversation: Conversation = {\n id: `conv-${Date.now()}`,\n agentId: dto.agentId,\n status: 'OPEN',\n createdAt: new Date().toISOString(),\n messages: [],\n unread_contact_count: 0,\n }\n\n if (dto.text) {\n const message: Message = {\n id: `msg-${Date.now()}`,\n sender: 'user',\n text: dto.text,\n createdAt: new Date().toISOString(),\n conversationId: conversation.id,\n }\n\n conversation.messages?.push(message)\n // Auto-close after 8s to simulate agent resolving (demo only)\n scheduleAutoClose(conversation.id)\n }\n\n CONVERSATIONS.push(conversation)\n return conversation\n },\n\n async getConversations(): Promise<Conversation[]> {\n await delay()\n return CONVERSATIONS.map((conv) => {\n const all = [\n ...(conv.messages ?? []),\n ...MESSAGES.filter((m) => m.conversationId === conv.id),\n ]\n const lastMessage = all.sort(\n (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),\n )[0]\n return { ...conv, lastMessage }\n })\n },\n\n async getMessages(conversationId: string, _params?: ListMessagesParams): Promise<MessagesPage> {\n await delay()\n const messages = MESSAGES.filter((m) => m.conversationId === conversationId)\n return { messages, hasMore: false, nextCursor: null }\n },\n\n async sendMessage(conversationId: string, dto: SendMessageDto): Promise<Message> {\n await delay()\n const message: Message = {\n id: `msg-${Date.now()}`,\n conversationId,\n text: dto.text,\n sender: 'user',\n createdAt: new Date().toISOString(),\n }\n MESSAGES.push(message)\n // Auto-close after 8s to simulate agent resolving (demo only)\n scheduleAutoClose(conversationId)\n return message\n },\n}\n\nfunction scheduleAutoClose(conversationId: string) {\n const existing = autoCloseTimers.get(conversationId)\n if (existing) clearTimeout(existing)\n const timer = setTimeout(() => {\n const conv = CONVERSATIONS.find((c) => c.id === conversationId)\n if (conv) conv.status = 'CLOSED'\n autoCloseTimers.delete(conversationId)\n }, 8000)\n autoCloseTimers.set(conversationId, timer)\n}\n","import type { WidgetUser } from '../../state'\nimport { isOnline, isSetup, sessionToken, tokenExpiresAt, visitorId } from '../../state'\nimport { ApiService } from '../api/service'\n\nconst STORAGE_KEY = 'spacinbox_vid'\nconst REFRESH_THRESHOLD_MS = 60_000 // refresh if less than 60s remaining\n\nexport const VisitorService = {\n async init(): Promise<void> {\n let id = localStorage.getItem(STORAGE_KEY)\n\n if (!id) {\n id = crypto.randomUUID()\n localStorage.setItem(STORAGE_KEY, id)\n }\n\n visitorId.value = id\n\n await this.refreshSession(id)\n\n isSetup.value = true\n },\n\n async refreshSession(visitor_id = visitorId.value): Promise<void> {\n if (!visitor_id) {\n return\n }\n try {\n const response = await ApiService.createSession({ visitorId: visitor_id })\n sessionToken.value = response.access_token\n visitorId.value = response.visitor_id\n localStorage.setItem(STORAGE_KEY, response.visitor_id)\n tokenExpiresAt.value = Date.now() + response.expires_in * 1000\n } catch (err) {\n isOnline.value = false\n throw err\n }\n },\n\n isTokenExpiringSoon(): boolean {\n if (!tokenExpiresAt.value) return true\n return tokenExpiresAt.value - Date.now() < REFRESH_THRESHOLD_MS\n },\n\n async identify(user: WidgetUser): Promise<{ success: boolean }> {\n return await ApiService.identifyVisitor({\n externalId: user.userId,\n name: user.name,\n email: user.email,\n })\n .then(({ visitor_id, access_token }) => {\n if (access_token) {\n sessionToken.value = access_token\n }\n\n if (visitor_id && visitor_id !== visitorId.value) {\n visitorId.value = visitor_id\n localStorage.setItem(STORAGE_KEY, visitor_id)\n }\n\n return { success: true }\n })\n .catch(() => ({ success: false }))\n },\n\n clear() {\n localStorage.removeItem(STORAGE_KEY)\n visitorId.value = null\n sessionToken.value = null\n tokenExpiresAt.value = null\n isSetup.value = false\n },\n}\n","import { appId, sessionToken, visitorId } from '../../state'\nimport { mockService } from './mock'\nimport type {\n Agent,\n Conversation,\n CreateConversationDto,\n CreateSessionDto,\n CreateSessionResponse,\n GetSessionResponse,\n IdentifyVisitorDto,\n IdentifyVisitorResponse,\n ListMessagesParams,\n Message,\n MessagesPage,\n SendMessageDto,\n SocketTokenResponse,\n} from './types'\n\nconst BASE_URL = __API_URL__\nconst IS_MOCKED = __API_MOCKED__\n\nasync function doFetch(method: string, path: string, body?: unknown): Promise<Response> {\n if (!appId.value) throw new Error('Spacinbox: boot() must be called before any API request')\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-app-id': appId.value,\n 'x-visitor-id': visitorId.value ?? '',\n }\n\n if (sessionToken.value) {\n headers['Authorization'] = `Bearer ${sessionToken.value}`\n }\n\n return fetch(`${BASE_URL}/widget${path}`, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n}\n\nasync function request<T>(method: string, path: string, body?: unknown): Promise<T> {\n // Proactive refresh if token is expiring soon (skip for createSession itself)\n if (path !== '/sessions') {\n const { VisitorService } = await import('../visitor/service')\n if (VisitorService.isTokenExpiringSoon()) {\n await VisitorService.refreshSession()\n }\n }\n\n let res = await doFetch(method, path, body)\n\n // Reactive refresh on 401\n if (res.status === 401 && path !== '/sessions') {\n const { VisitorService } = await import('../visitor/service')\n await VisitorService.refreshSession()\n res = await doFetch(method, path, body)\n }\n\n if (!res.ok) throw new Error(`[Spacinbox] ${method} ${path} failed with status ${res.status}`)\n\n return res.json()\n}\n\nexport const ApiService = IS_MOCKED\n ? mockService\n : {\n createSession(dto: CreateSessionDto): Promise<CreateSessionResponse> {\n return request('POST', '/sessions', dto)\n },\n\n getSession(): Promise<GetSessionResponse> {\n return request('GET', '/sessions')\n },\n\n identifyVisitor(dto: IdentifyVisitorDto): Promise<IdentifyVisitorResponse> {\n return request('POST', '/visitors/identify', dto)\n },\n\n getAgents(): Promise<Agent[]> {\n return request('GET', '/agents')\n },\n\n getConversations(): Promise<Conversation[]> {\n return request('GET', '/conversations')\n },\n\n createConversation(dto: CreateConversationDto): Promise<Conversation> {\n return request('POST', '/conversations', dto)\n },\n\n getConversation(conversationId: string): Promise<Conversation> {\n return request('GET', `/conversations/${conversationId}`)\n },\n\n reopenConversation(conversationId: string): Promise<void> {\n return request('POST', `/conversations/${conversationId}/reopen`)\n },\n\n getConversationSocketToken(conversationId: string): Promise<SocketTokenResponse> {\n return request('GET', `/conversations/${conversationId}/token`)\n },\n\n getMessages(conversationId: string, params?: ListMessagesParams): Promise<MessagesPage> {\n const qs = new URLSearchParams()\n if (params?.before) qs.set('before', params.before)\n if (params?.limit) qs.set('limit', String(params.limit))\n const query = qs.toString()\n return request(\n 'GET',\n `/conversations/${conversationId}/messages${query ? `?${query}` : ''}`,\n )\n },\n\n sendMessage(conversationId: string, dto: SendMessageDto): Promise<Message> {\n return request('POST', `/conversations/${conversationId}/messages`, dto)\n },\n }\n","import { mountWidget } from './widget/mount'\nimport { BootOptions } from './widget/types'\n\nexport type { WidgetUser } from './widget/state'\n\ntype Controller = Awaited<ReturnType<typeof mountWidget>>\n\nlet controller: Controller | null = null\nlet bootPromise: Promise<void> | null = null\n\nconst Spacinbox = {\n boot(options: BootOptions): Promise<void> {\n if (typeof document === 'undefined') {\n return Promise.resolve()\n }\n if (bootPromise) {\n return bootPromise\n }\n\n bootPromise = mountWidget(options).then((instance) => {\n controller = instance\n })\n\n return bootPromise\n },\n async identify(user: Parameters<Controller['identify']>[0]) {\n if (!controller) {\n return { success: false }\n }\n\n return controller.identify(user)\n },\n setMetadata(data: Record<string, unknown>) {\n controller?.setMetadata(data)\n },\n open() {\n controller?.open()\n },\n close() {\n controller?.close()\n },\n shutdown() {\n controller?.shutdown()\n controller = null\n bootPromise = null\n },\n}\n\nexport default Spacinbox\n","import { render } from 'preact'\nimport { Widget } from './Widget'\nimport styles from './compiled-css'\nimport { SocketService } from './modules/socket/service'\nimport { VisitorService } from './modules/visitor/service'\nimport { resetRouter } from './router'\nimport type { WidgetUser } from './state'\nimport { appId, currentUser, isOpen, metadata, sessionToken, visitorId } from './state'\nimport { BootOptions } from './types'\n\nexport async function mountWidget(options: BootOptions) {\n const { appId: id, hideButton = false } = options\n appId.value = id\n\n const host = document.createElement('div')\n host.id = 'spacinbox-widget'\n document.body.appendChild(host)\n\n const shadow = host.attachShadow({ mode: 'open' })\n const sheet = new CSSStyleSheet()\n sheet.replaceSync(styles)\n shadow.adoptedStyleSheets = [sheet]\n\n const mountPoint = document.createElement('div')\n shadow.appendChild(mountPoint)\n render(<Widget hideButton={hideButton} />, mountPoint)\n\n await VisitorService.init()\n await SocketService.connect()\n\n return {\n open() {\n isOpen.value = true\n },\n close() {\n isOpen.value = false\n },\n identify(user: WidgetUser) {\n currentUser.value = user\n return VisitorService.identify(user)\n },\n setMetadata(data: Record<string, unknown>) {\n metadata.value = { ...metadata.value, ...data }\n },\n shutdown() {\n render(null, mountPoint)\n host.remove()\n isOpen.value = false\n currentUser.value = null\n metadata.value = {}\n visitorId.value = null\n sessionToken.value = null\n resetRouter()\n VisitorService.clear()\n SocketService.disconnect()\n },\n }\n}\n","import { MessageCircle, X } from 'lucide-preact'\nimport { useEffect } from 'preact/hooks'\nimport { Layout } from './components/Layout'\nimport { useOnNewMessage } from './hooks/useNewMessage'\nimport { useQuery } from './hooks/useQuery'\nimport { ApiService } from './modules/api/service'\nimport { Conversation } from './pages/conversation'\nimport { Home } from './pages/home'\nimport { currentRoute } from './router'\nimport { isOpen, isSetup, refetchSessionCounter, sessionToken } from './state'\nimport { Indicator } from './ui/Indicator'\n\nconst renderPage = () => {\n const route = currentRoute.value\n switch (route.page) {\n case 'home':\n return <Home />\n case 'conversation':\n return <Conversation conversationId={route.params?.conversationId} />\n }\n}\n\ntype Props = {\n hideButton: boolean\n}\n\nconst Internal = ({ hideButton }: Props) => {\n const sessionQuery = useQuery({\n queryFn: () => ApiService.getSession(),\n queryKey: ['session'],\n enabled: !!sessionToken.value,\n })\n\n useOnNewMessage(() => {\n sessionQuery.refetch()\n })\n\n useEffect(() => {\n if (sessionQuery.loading) {\n return\n }\n sessionQuery.refetch()\n }, [refetchSessionCounter.value])\n\n const countNotifications = sessionQuery.data?.count_notifications ?? 0\n\n return (\n <div>\n <Layout isOpen={isOpen.value}>{renderPage()}</Layout>\n\n {!hideButton && (\n <button\n onClick={() => (isOpen.value = !isOpen.value)}\n class=\"fixed bottom-4 right-4 w-14 h-14 bg-blue-600 hover:bg-blue-700 text-white rounded-full shadow-lg flex items-center justify-center text-2xl transition-colors cursor-pointer\"\n aria-label={isOpen.value ? 'Close support chat' : 'Open support chat'}\n >\n <Indicator\n label={countNotifications}\n visible={countNotifications > 0}\n position=\"top-right\"\n size=\"md\"\n color=\"red\"\n >\n {isOpen.value ? <X /> : <MessageCircle />}\n </Indicator>\n </button>\n )}\n </div>\n )\n}\n\nexport const Widget = (props: Props) => {\n if (!isSetup.value) {\n return <></>\n }\n\n return <Internal {...props} />\n}\n","import { ReactNode } from 'preact/compat'\nimport { isOnline } from '../state'\nimport { Loader } from '../ui/Loader'\n\ntype Props = {\n isOpen: boolean\n children: ReactNode\n}\n\nexport const Layout = ({ isOpen, children }: Props) => {\n return (\n <div\n class={`fixed bottom-20 right-4 w-80 h-112 bg-white rounded-xl shadow-2xl border border-gray-200 flex flex-col overflow-hidden ${!isOpen && 'hidden'}`}\n >\n {!isOnline.value && (\n <div class=\"bg-amber-50 border-b border-amber-200 px-3 py-2 text-xs text-amber-700 text-center\">\n Connecting... <Loader />\n </div>\n )}\n <div class=\"flex-1 overflow-y-auto\">{children}</div>\n </div>\n )\n}\n","import { Loader2 } from 'lucide-preact'\n\ntype Props = {\n size?: number\n class?: string\n}\n\nexport const Loader = ({ size = 20, class: cls }: Props) => (\n <Loader2 size={size} class={`animate-spin text-inherit ${cls ?? ''}`} />\n)\n","import { useEffect } from 'preact/hooks'\nimport { socket, SocketService } from '../modules/socket/service'\n\n// type Props = {}\n\nexport const useOnNewMessage = (handler: (...args: any[]) => any) => {\n useEffect(() => {\n if (!socket.value) {\n return\n }\n\n SocketService.on('new-message', () => handler())\n\n return () => {\n SocketService.off('new-message', () => handler())\n }\n }, [socket.value])\n}\n","import { signal } from '@preact/signals'\nimport { io, Socket } from 'socket.io-client'\nimport { isOnline, sessionToken } from '../../state'\nimport { ApiService } from '../api/service'\nimport { VisitorService } from '../visitor/service'\n\nexport const socket = signal<Socket | null>(null)\n\nexport const SocketService = {\n async connect(): Promise<void> {\n const token = sessionToken.value\n\n socket.value = io(__WS_URL__, {\n auth: { token },\n reconnection: true,\n })\n\n socket.value.on('connect', () => {\n isOnline.value = true\n })\n\n socket.value.on('disconnect', (reason) => {\n if (reason !== 'io client disconnect') {\n isOnline.value = false\n }\n })\n\n socket.value.on('connect_error', async (err) => {\n if (err.message === 'Missing token' || err.message === 'Invalid token') {\n await VisitorService.refreshSession()\n\n if (socket.value) {\n socket.value.auth = { token: sessionToken.value }\n socket.value.connect()\n }\n } else {\n isOnline.value = false\n }\n })\n },\n\n async joinRoom(conversationId: string): Promise<void> {\n if (!socket.value) {\n return\n }\n\n const { access_token: token } = await ApiService.getConversationSocketToken(conversationId)\n\n return new Promise((resolve, reject) => {\n socket.value!.emit('join-room', { token }, (response: { ok: boolean }) => {\n if (!response?.ok) {\n reject(new Error())\n } else {\n resolve()\n }\n })\n })\n },\n\n leaveRoom(conversationId: string): void {\n socket.value?.emit('leave-room', { room_id: `conversation:${conversationId}` })\n },\n\n typingStart(conversationId: string) {\n socket.value?.emit('typing-start', { room_id: `conversation:${conversationId}` })\n },\n\n typingStop(conversationId: string) {\n socket.value?.emit('typing-stop', { room_id: `conversation:${conversationId}` })\n },\n\n on<T>(event: string, handler: (payload: T) => void): void {\n socket.value?.on(event, handler)\n },\n\n off<T>(event: string, handler: (payload: T) => void): void {\n socket.value?.off(event, handler)\n },\n\n disconnect(): void {\n socket.value?.disconnect()\n socket.value = null\n },\n}\n","import { useCallback, useEffect, useState } from 'preact/hooks'\n\ntype QueryKey = string | readonly unknown[]\n\ntype QueryState<T> = {\n data: T | null\n loading: boolean\n error: Error | null\n isSuccess: boolean\n isFetched: boolean\n}\n\ntype QueryOptions<T> = {\n queryKey: QueryKey\n queryFn: () => Promise<T>\n enabled?: boolean\n cache?: boolean\n onSuccess?: (data: T) => void\n onError?: (error: Error) => void\n onSettled?: (data: T | null, error: Error | null) => void\n}\n\nconst cache = new Map<string, unknown>()\n\nexport const clearQueryCache = () => cache.clear()\n\nexport const invalidateQuery = (queryKey: QueryKey) => cache.delete(serializeKey(queryKey))\n\nfunction serializeKey(key: QueryKey): string {\n return typeof key === 'string' ? key : JSON.stringify(key)\n}\n\nexport function useQuery<T>({ queryKey, queryFn, enabled = true, cache: useCache = true, onSuccess, onError, onSettled }: QueryOptions<T>) {\n const key = serializeKey(queryKey)\n const cached = useCache ? cache.get(key) as T | undefined : undefined\n\n const [refetchCounter, setRefetchCounter] = useState(0)\n\n const [state, setState] = useState<QueryState<T>>(\n cached !== undefined\n ? { data: cached, loading: false, error: null, isSuccess: true, isFetched: true }\n : { data: null, loading: enabled, error: null, isSuccess: false, isFetched: false }\n )\n\n useEffect(() => {\n if (!enabled) return\n\n let cancelled = false\n\n const isRefetch = refetchCounter > 0\n if (cached === undefined || isRefetch) {\n setState(s => ({ ...s, loading: true, error: null, isSuccess: false }))\n }\n\n queryFn()\n .then(data => {\n if (cancelled) return\n if (useCache) cache.set(key, data)\n setState({ data, loading: false, error: null, isSuccess: true, isFetched: true })\n onSuccess?.(data)\n onSettled?.(data, null)\n })\n .catch((error: Error) => {\n if (cancelled) return\n setState(s => ({ ...s, loading: false, error, isSuccess: false, isFetched: true }))\n onError?.(error)\n onSettled?.(null, error)\n })\n\n return () => { cancelled = true }\n }, [key, enabled, refetchCounter])\n\n const refetch = useCallback(() => setRefetchCounter(c => c + 1), [])\n\n return { ...state, refetch }\n}\n","import { useSignal } from '@preact/signals'\nimport { useEffect } from 'preact/hooks'\nimport { useMessages } from '../hooks/useMessages'\nimport { useMutation } from '../hooks/useMutation'\nimport { invalidateQuery, useQuery } from '../hooks/useQuery'\nimport { ApiService } from '../modules/api/service'\nimport type { Message } from '../modules/api/types'\nimport { Header } from '../modules/conversation/components/Header'\nimport { InputMessage } from '../modules/conversation/components/InputMessage'\nimport { MessageList } from '../modules/conversation/components/MessageList'\nimport { ResolvedBanner } from '../modules/conversation/components/ResolvedBanner'\nimport { SocketService } from '../modules/socket/service'\nimport { useOnTyping } from '../modules/socket/useOnTyping'\nimport { useTyping } from '../modules/socket/useTyping'\nimport { goBack } from '../router'\nimport { refetchSessionCounter } from '../state'\n\ntype Props = {\n conversationId?: string\n}\n\nexport const Conversation = (props: Props) => {\n const conversationId = useSignal<string | undefined>(props.conversationId)\n const isCreating = useSignal(false)\n\n const agentsQuery = useQuery({\n queryKey: ['agents'],\n queryFn: () => ApiService.getAgents(),\n })\n\n const conversationQuery = useQuery({\n queryKey: [`conversation-${conversationId}`],\n queryFn: () => ApiService.getConversation(conversationId.value!),\n enabled: !!conversationId.value,\n })\n\n const { messages, hasMore, loadingMore, loadMore, append, replace, remove } = useMessages(\n conversationId.value,\n )\n\n const reopenMutation = useMutation({\n mutationFn: () => ApiService.reopenConversation(conversationId.value!),\n onSuccess: () => conversationQuery.refetch(),\n })\n\n const agent = conversationQuery.data?.agent ?? agentsQuery.data?.[0]\n\n const isResolved = conversationQuery.data?.status === 'CLOSED'\n const isOpen = conversationQuery.data?.status === 'OPEN'\n\n const canConnectSocket = conversationId.value && isOpen\n\n const onNewMessage = (message: Message) => {\n append(message)\n }\n\n useEffect(() => {\n if (!conversationId.value) {\n return\n }\n\n SocketService.on('conversation-updated', () => conversationQuery.refetch())\n\n return () => {\n SocketService.off('conversation-updated', () => conversationQuery.refetch())\n }\n }, [conversationId.value])\n\n useEffect(() => {\n if (!canConnectSocket) {\n return\n }\n\n const id = conversationId.value!\n\n SocketService.joinRoom(id)\n .then(() => {\n refetchSessionCounter.value += 1\n })\n .catch((error) => {})\n SocketService.on('new-message', onNewMessage)\n\n return () => {\n SocketService.leaveRoom(id)\n SocketService.off('new-message', onNewMessage)\n }\n }, [canConnectSocket])\n\n const send = async (text: string) => {\n if (!agent || isCreating.value) return\n stopTyping()\n\n const tempId = `temp-${Date.now()}`\n const optimistic: Message = {\n id: tempId,\n conversationId: conversationId.value ?? 'pending',\n text,\n sender: 'user',\n createdAt: new Date().toISOString(),\n }\n\n append(optimistic)\n\n try {\n if (!conversationId.value) {\n isCreating.value = true\n const conversation = await ApiService.createConversation({ agentId: agent.id, text })\n conversationId.value = conversation.id\n invalidateQuery(['conversations'])\n } else {\n const message = await ApiService.sendMessage(conversationId.value, { text })\n replace(tempId, message)\n }\n } catch {\n remove(tempId)\n } finally {\n isCreating.value = false\n }\n }\n\n const handleYes = () => {\n goBack()\n }\n\n const handleNo = () => {\n reopenMutation.mutate()\n }\n\n const { onType, stopTyping } = useTyping({ room_id: conversationId.value ?? '' })\n const { isTyping } = useOnTyping({ room_id: conversationId.value })\n\n const disabled = !agent || isCreating.value\n\n return (\n <div class=\"flex flex-col h-full\">\n <Header\n agent={agent}\n loading={!agent && (agentsQuery.loading || conversationQuery.loading)}\n />\n\n <MessageList\n messages={messages}\n agent={agent}\n scrollKey={isResolved}\n hasMore={hasMore}\n loadingMore={loadingMore}\n onLoadMore={loadMore}\n isTyping={isTyping}\n />\n\n {isResolved ? (\n <ResolvedBanner onYes={handleYes} onNo={handleNo} />\n ) : (\n <InputMessage onSend={send} onType={onType} disabled={disabled} />\n )}\n </div>\n )\n}\n","import { useCallback, useEffect, useRef, useState } from 'preact/hooks'\nimport { ApiService } from '../modules/api/service'\nimport type { Message } from '../modules/api/types'\n\ntype State = {\n messages: Message[]\n hasMore: boolean\n nextCursor: string | null\n loading: boolean\n loadingMore: boolean\n}\n\nexport function useMessages(conversationId: string | undefined, limit = 30) {\n const [state, setState] = useState<State>({\n messages: [],\n hasMore: false,\n nextCursor: null,\n loading: !!conversationId,\n loadingMore: false,\n })\n\n // Ref to read current state inside callbacks without stale closure\n const stateRef = useRef(state)\n stateRef.current = state\n\n useEffect(() => {\n if (!conversationId) return\n let cancelled = false\n\n setState({ messages: [], hasMore: false, nextCursor: null, loading: true, loadingMore: false })\n\n ApiService.getMessages(conversationId, { limit })\n .then(({ messages, hasMore, nextCursor }) => {\n if (cancelled) {\n return\n }\n setState({ messages, hasMore, nextCursor, loading: false, loadingMore: false })\n })\n .catch(() => {\n if (cancelled) return\n setState((s) => ({ ...s, loading: false }))\n })\n\n return () => {\n cancelled = true\n }\n }, [conversationId])\n\n const loadMore = useCallback(async () => {\n const { hasMore, nextCursor, loadingMore } = stateRef.current\n if (!hasMore || loadingMore || !nextCursor || !conversationId) return\n\n setState((s) => ({ ...s, loadingMore: true }))\n\n try {\n const {\n messages: older,\n hasMore: newHasMore,\n nextCursor: newCursor,\n } = await ApiService.getMessages(conversationId, { before: nextCursor, limit })\n setState((s) => ({\n ...s,\n messages: [...s.messages, ...older],\n hasMore: newHasMore,\n nextCursor: newCursor,\n loadingMore: false,\n }))\n } catch {\n setState((s) => ({ ...s, loadingMore: false }))\n }\n }, [conversationId])\n\n const append = useCallback((message: Message) => {\n setState((item) => {\n if (item.messages.some((m) => m.id === message.id)) {\n return item\n }\n return { ...item, messages: [message, ...item.messages] }\n })\n }, [])\n\n const replace = useCallback((tempId: string, message: Message) => {\n setState((s) => ({\n ...s,\n messages: s.messages\n .filter((m) => m.id !== message.id)\n .map((m) => (m.id === tempId ? message : m)),\n }))\n }, [])\n\n const remove = useCallback((id: string) => {\n setState((s) => ({ ...s, messages: s.messages.filter((m) => m.id !== id) }))\n }, [])\n\n return { ...state, loadMore, append, replace, remove }\n}\n","import { useState } from 'preact/hooks'\n\ntype MutationState<T> = {\n data: T | null\n loading: boolean\n error: Error | null\n isSuccess: boolean\n isFetched: boolean\n}\n\ntype MutationOptions<T, V> = {\n mutationFn: (variables: V) => Promise<T>\n onSuccess?: (data: T, variables: V) => void\n onError?: (error: Error, variables: V) => void\n onSettled?: (data: T | null, error: Error | null, variables: V) => void\n}\n\nexport function useMutation<T, V = void>({ mutationFn, onSuccess, onError, onSettled }: MutationOptions<T, V>) {\n const [state, setState] = useState<MutationState<T>>({\n data: null,\n loading: false,\n error: null,\n isSuccess: false,\n isFetched: false,\n })\n\n const mutate = async (variables: V) => {\n setState({ data: null, loading: true, error: null, isSuccess: false, isFetched: false })\n\n try {\n const data = await mutationFn(variables)\n setState({ data, loading: false, error: null, isSuccess: true, isFetched: true })\n onSuccess?.(data, variables)\n onSettled?.(data, null, variables)\n return data\n } catch (error) {\n const err = error as Error\n setState({ data: null, loading: false, error: err, isSuccess: false, isFetched: true })\n onError?.(err, variables)\n onSettled?.(null, err, variables)\n }\n }\n\n return { ...state, mutate }\n}\n","import { ArrowLeft } from 'lucide-preact'\nimport { goBack } from '../../../router'\nimport { Avatar } from '../../../ui/Avatar'\nimport { Button } from '../../../ui/Button'\nimport { Group } from '../../../ui/Group'\nimport { Indicator } from '../../../ui/Indicator'\nimport { Text } from '../../../ui/Text'\nimport type { Agent } from '../../api/types'\n\ntype Props = {\n agent?: Agent\n loading?: boolean\n}\nexport const Header = ({ agent, loading }: Props) => (\n <Group class=\"border-b border-neutral-100 p-2\">\n <Button variant=\"light\" onClick={goBack} aria-label=\"Back\">\n <ArrowLeft />\n </Button>\n\n {loading ? (\n <div class=\"w-8 h-8 rounded-full bg-neutral-200 animate-pulse shrink-0\" />\n ) : agent ? (\n <>\n <Indicator color=\"green\">\n <Avatar size=\"sm\" src={agent.picture}>\n {agent.name.charAt(0)}\n </Avatar>\n </Indicator>\n <Text weight=\"medium\">{agent.name}</Text>\n </>\n ) : null}\n </Group>\n)\n","import { computed, signal } from '@preact/signals'\n\nexport type Page = 'home' | 'conversation'\n\ntype RouteParams = {\n conversationId?: string\n}\n\ntype RouteEntry = {\n page: Page\n params?: RouteParams\n}\n\nexport const pageStack = signal<RouteEntry[]>([{ page: 'home' }])\n\nexport const currentRoute = computed(() => pageStack.value.at(-1)!)\nexport const currentPage = computed(() => currentRoute.value.page)\nexport const canGoBack = computed(() => pageStack.value.length > 1)\n\nexport const navigate = (page: Page, params?: RouteParams) => {\n pageStack.value = [...pageStack.value, { page, params }]\n}\n\nexport const goBack = () => {\n if (pageStack.value.length > 1)\n pageStack.value = pageStack.value.slice(0, -1)\n}\n\nexport const resetRouter = () => {\n pageStack.value = [{ page: 'home' }]\n}\n","type Props = {\n src?: string\n children?: string\n size?: 'sm' | 'md' | 'lg' | number\n class?: string\n}\n\nconst sizes = {\n sm: 'w-7 h-7 text-xs',\n md: 'w-9 h-9 text-sm',\n lg: 'w-12 h-12 text-base',\n}\n\nexport const Avatar = ({ src, children, size = 'md', class: cls }: Props) => {\n const sizeClass = typeof size === 'number' ? '' : sizes[size]\n const sizeStyle = typeof size === 'number' ? { width: `${size}px`, height: `${size}px`, fontSize: `${Math.round(size * 0.4)}px` } : undefined\n\n const base = `inline-flex items-center justify-center rounded-full overflow-hidden shrink-0 bg-blue-100 text-blue-700 font-medium border-2 border-blue-400 ${sizeClass} ${cls ?? ''}`\n\n if (src) {\n return <img src={src} class={`${base} object-cover`} style={sizeStyle} alt={children ?? ''} />\n }\n\n return <span class={base} style={sizeStyle}>{children ? children.charAt(0).toUpperCase() : '?'}</span>\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n onClick?: () => void\n variant?: 'filled' | 'subtle' | 'outline' | 'light'\n fullWidth?: boolean\n class?: string\n}\n\nconst variants = {\n filled: 'bg-blue-600 hover:bg-blue-700 text-white',\n subtle: 'bg-neutral-100 hover:bg-neutral-200 text-neutral-800',\n light: 'bg-transparent hover:text-neutral-800 text-neutral-500',\n outline: 'border border-neutral-200 hover:bg-neutral-50 text-neutral-800',\n}\n\nexport const Button = ({ children, onClick, variant = 'filled', fullWidth, class: cls }: Props) => (\n <button\n onClick={onClick}\n class={`\n inline-flex items-center justify-center gap-2\n px-4 py-2 rounded-lg text-sm font-medium\n transition-colors cursor-pointer\n ${variants[variant]}\n ${fullWidth ? 'w-full' : ''}\n ${cls ?? ''}\n `}\n >\n {children}\n </button>\n)\n","import { ReactNode } from 'preact/compat'\n\nimport type { CSSProperties } from 'preact/compat'\nimport { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n gap?: 'xs' | 'sm' | 'md' | 'lg' | number\n justify?: 'start' | 'center' | 'end' | 'between'\n align?: 'start' | 'center' | 'end'\n class?: string\n}\n\nconst gaps: Record<string, string> = {\n xs: 'gap-1',\n sm: 'gap-2',\n md: 'gap-4',\n lg: 'gap-6',\n}\n\nconst justifies = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n}\n\nconst aligns = {\n start: 'items-start',\n center: 'items-center',\n end: 'items-end',\n}\n\nexport const Group = ({ children, gap = 'sm', justify = 'start', align = 'center', class: cls }: Props) => {\n const gapClass = typeof gap === 'number' ? '' : gaps[gap]\n const gapStyle: CSSProperties = typeof gap === 'number' ? { gap: `${gap * 4}px` } : {}\n\n return (\n <div class={`flex flex-row ${gapClass} ${justifies[justify]} ${aligns[align]} ${cls ?? ''}`} style={gapStyle}>\n {children}\n </div>\n )\n}\n","import type { ComponentChildren } from 'preact'\n\nconst colors = {\n default: 'bg-blue-500',\n green: 'bg-green-500',\n red: 'bg-red-500',\n}\n\nconst positions = {\n 'top-right': 'top-0 right-0 translate-x-1/2 -translate-y-1/2',\n 'bottom-right': 'bottom-0 right-0',\n}\n\nconst sizes = {\n sm: { dot: 'w-2.5 h-2.5', badge: 'h-4 min-w-4 text-[10px]' },\n md: { dot: 'w-3.5 h-3.5', badge: 'h-5 min-w-5 text-xs' },\n lg: { dot: 'w-4 h-4', badge: 'h-6 min-w-6 text-sm' },\n}\n\ntype Offset = { x?: number; y?: number }\n\ntype Props = {\n children: ComponentChildren\n active?: boolean\n visible?: boolean\n color?: keyof typeof colors\n label?: string | number\n size?: keyof typeof sizes\n position?: keyof typeof positions\n offset?: Offset\n}\n\nexport const Indicator = ({\n children,\n active = true,\n visible = true,\n color = 'default',\n label,\n size = 'sm',\n position = 'bottom-right',\n offset,\n}: Props) => {\n const show = active && visible\n const offsetStyle = offset\n ? { transform: `translate(calc(50% + ${offset.x ?? 0}px), calc(-50% + ${offset.y ?? 0}px))` }\n : undefined\n\n return (\n <div class=\"relative inline-flex\">\n {children}\n {show &&\n (label !== undefined ? (\n <span\n style={offsetStyle}\n class={`absolute ${positions[position]} ${sizes[size].badge} px-1 ${colors[color]} text-white font-semibold rounded-full flex items-center justify-center`}\n >\n {label}\n </span>\n ) : (\n <span\n style={offsetStyle}\n class={`absolute ${positions[position]} ${sizes[size].dot} ${colors[color]} border-2 border-white rounded-full`}\n />\n ))}\n </div>\n )\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n weight?: 'normal' | 'medium' | 'semibold'\n color?: 'default' | 'dimmed'\n lineClamp?: number\n class?: string\n}\n\nconst sizes = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n}\n\nconst weights = {\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n}\n\nconst colors = {\n default: 'text-neutral-900',\n dimmed: 'text-neutral-400',\n}\n\nexport const Text = ({\n children,\n size = 'sm',\n weight = 'normal',\n color = 'default',\n lineClamp,\n class: cls,\n}: Props) => {\n const clampStyle = lineClamp\n ? {\n overflow: 'hidden',\n display: '-webkit-box',\n WebkitLineClamp: lineClamp,\n WebkitBoxOrient: 'vertical' as const,\n }\n : undefined\n\n return (\n <p class={`${sizes[size]} ${weights[weight]} ${colors[color]} ${cls ?? ''}`} style={clampStyle}>\n {children}\n </p>\n )\n}\n","import { useEffect, useRef } from 'preact/hooks'\nimport { Send } from 'lucide-preact'\n\ntype Props = {\n onSend: (text: string) => void\n onType?: () => void\n disabled?: boolean\n}\n\nexport const InputMessage = ({ onSend, onType, disabled }: Props) => {\n const ref = useRef<HTMLTextAreaElement>(null)\n\n useEffect(() => {\n if (!disabled) ref.current?.focus()\n }, [disabled])\n\n const resize = () => {\n const el = ref.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${el.scrollHeight}px`\n }\n\n const submit = () => {\n const el = ref.current\n if (!el || disabled) return\n const text = el.value.trim()\n if (!text) return\n onSend(text)\n el.value = ''\n el.style.height = 'auto'\n }\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Enter') return\n\n if (e.metaKey || e.ctrlKey) {\n // CMD/Ctrl + Enter → insert newline at cursor\n e.preventDefault()\n const el = ref.current!\n const start = el.selectionStart ?? el.value.length\n const end = el.selectionEnd ?? el.value.length\n el.value = el.value.slice(0, start) + '\\n' + el.value.slice(end)\n el.selectionStart = el.selectionEnd = start + 1\n resize()\n } else if (!e.shiftKey) {\n // Enter alone → send\n e.preventDefault()\n submit()\n }\n // Shift + Enter → default textarea newline\n }\n\n return (\n <div class=\"flex items-end gap-2 px-3 py-3 border-t border-neutral-100\">\n <textarea\n ref={ref}\n rows={1}\n placeholder=\"Write a message...\"\n onInput={() => { resize(); onType?.() }}\n onKeyDown={onKeyDown}\n disabled={disabled}\n class=\"flex-1 text-sm bg-neutral-100 rounded-2xl px-4 py-2 outline-none placeholder:text-neutral-400 disabled:opacity-50 resize-none overflow-y-auto leading-5\"\n style={{ maxHeight: '120px' }}\n />\n <button\n onClick={submit}\n disabled={disabled}\n class=\"w-8 h-8 flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white rounded-full transition-colors cursor-pointer shrink-0 disabled:opacity-50 disabled:cursor-not-allowed mb-0.5\"\n aria-label=\"Send\"\n >\n <Send size={14} />\n </button>\n </div>\n )\n}\n","import { Fragment } from 'preact'\nimport { useEffect, useRef } from 'preact/hooks'\nimport { Loader } from '../../../ui/Loader'\nimport type { Agent, Message } from '../../api/types'\nimport { DateSeparator } from './DateSeparator'\nimport { MessageBubble } from './MessageBubble'\n\ntype Props = {\n messages: Message[]\n agent?: Agent\n scrollKey?: unknown\n hasMore?: boolean\n loadingMore?: boolean\n onLoadMore?: () => void\n isTyping?: boolean\n}\n\nfunction isSameDay(a: string, b: string): boolean {\n return new Date(a).toDateString() === new Date(b).toDateString()\n}\n\nexport const MessageList = ({\n messages,\n agent,\n scrollKey,\n hasMore,\n loadingMore,\n onLoadMore,\n isTyping,\n}: Props) => {\n const containerRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const container = containerRef.current\n if (!container) {\n return\n }\n\n const onScroll = () => {\n const canTrigger =\n Math.abs(container.scrollTop) > container.scrollHeight - container.clientHeight - 100\n\n if (hasMore && !loadingMore && canTrigger) {\n onLoadMore?.()\n }\n }\n\n container.addEventListener('scroll', onScroll, { passive: true })\n return () => container.removeEventListener('scroll', onScroll)\n }, [hasMore, loadingMore, onLoadMore])\n\n return (\n <div class=\"flex-1 flex flex-col overflow-hidden\">\n <div ref={containerRef} class=\"flex-1 overflow-y-auto flex flex-col-reverse gap-1 px-3 py-4\">\n {isTyping && (\n <div class=\"flex gap-2 items-end\">\n <div class=\"w-7 h-7 rounded-full bg-neutral-200 shrink-0 overflow-hidden flex items-center justify-center text-xs font-semibold text-neutral-600 self-end mb-0.5\">\n {agent?.picture\n ? <img src={agent.picture} alt={agent.name} class=\"w-full h-full object-cover\" />\n : (agent?.name?.charAt(0) ?? '?')\n }\n </div>\n <div class=\"bg-neutral-100 rounded-2xl rounded-bl-sm px-3 py-2.5 flex gap-1 items-center\">\n <span class=\"w-1.5 h-1.5 rounded-full bg-neutral-400 animate-bounce\" style={{ animationDelay: '0ms' }} />\n <span class=\"w-1.5 h-1.5 rounded-full bg-neutral-400 animate-bounce\" style={{ animationDelay: '150ms' }} />\n <span class=\"w-1.5 h-1.5 rounded-full bg-neutral-400 animate-bounce\" style={{ animationDelay: '300ms' }} />\n </div>\n </div>\n )}\n\n {messages.map((msg, i) => {\n const next = messages[i + 1]\n const showDate = !next || !isSameDay(next.createdAt, msg.createdAt)\n const isFirstInGroup = showDate || next?.sender !== msg.sender\n\n return (\n <Fragment key={msg.id}>\n <MessageBubble message={msg} agent={agent} isFirstInGroup={isFirstInGroup} />\n {showDate && <DateSeparator date={msg.createdAt} />}\n </Fragment>\n )\n })}\n\n <div\n class={`flex justify-center py-2 border-b border-neutral-100 ${!loadingMore && 'opacity-0'}`}\n >\n <Loader size={16} />\n </div>\n </div>\n </div>\n )\n}\n","type Props = {\n date: string\n}\n\nfunction formatLabel(dateStr: string): string {\n const date = new Date(dateStr)\n const today = new Date()\n const yesterday = new Date(today)\n yesterday.setDate(today.getDate() - 1)\n\n const sameDay = (a: Date, b: Date) =>\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n\n if (sameDay(date, today)) return 'Today'\n if (sameDay(date, yesterday)) return 'Yesterday'\n\n return date\n .toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' })\n .replace(',', '')\n}\n\nexport const DateSeparator = ({ date }: Props) => (\n <div class=\"flex items-center gap-2 my-3\">\n <div class=\"flex-1 h-px bg-neutral-200\" />\n <span class=\"text-xs text-neutral-400 font-medium px-1\">{formatLabel(date)}</span>\n <div class=\"flex-1 h-px bg-neutral-200\" />\n </div>\n)\n","import type { Agent, Message } from '../../api/types'\n\ntype Props = {\n message: Message\n agent?: Agent\n isFirstInGroup: boolean\n}\n\nfunction formatTime(dateStr: string): string {\n return new Date(dateStr).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\nexport const MessageBubble = ({ message, agent, isFirstInGroup }: Props) => {\n const isUser = message.sender === 'user'\n\n return (\n <div class={`flex gap-2 items-end ${isUser ? 'flex-row-reverse' : 'flex-row'}`}>\n {!isUser && (\n isFirstInGroup ? (\n <div class=\"w-7 h-7 rounded-full bg-neutral-200 shrink-0 overflow-hidden flex items-center justify-center text-xs font-semibold text-neutral-600 self-end mb-0.5\">\n {agent?.picture\n ? <img src={agent.picture} alt={agent.name} class=\"w-full h-full object-cover\" />\n : (agent?.name?.charAt(0) ?? '?')\n }\n </div>\n ) : (\n <div class=\"w-7 shrink-0\" />\n )\n )}\n\n <div class={`flex flex-col gap-0.5 max-w-[72%] ${isUser ? 'items-end' : 'items-start'}`}>\n {!isUser && isFirstInGroup && (\n <span class=\"text-xs text-neutral-500 font-semibold px-1\">{agent?.name}</span>\n )}\n\n <div class={`relative px-3 pt-2 pb-5 min-w-18 rounded-2xl text-sm leading-snug whitespace-pre-wrap ${\n isUser\n ? 'bg-blue-600 text-white rounded-br-sm'\n : 'bg-neutral-100 text-neutral-900 rounded-bl-sm'\n }`}>\n {message.text}\n <span class={`absolute bottom-1.5 right-2.5 text-[10px] leading-none ${\n isUser ? 'text-blue-200' : 'text-neutral-400'\n }`}>\n {formatTime(message.createdAt)}\n </span>\n </div>\n </div>\n </div>\n )\n}\n","import { CheckCircle } from 'lucide-preact'\nimport { useEffect, useState } from 'preact/hooks'\nimport { Button } from '../../../ui/Button'\nimport { Group } from '../../../ui/Group'\nimport { Stack } from '../../../ui/Stack'\nimport { Text } from '../../../ui/Text'\n\ntype Props = {\n onYes: () => void\n onNo: () => void\n}\n\nexport const ResolvedBanner = ({ onYes, onNo }: Props) => {\n const [thanked, setThanked] = useState(false)\n\n useEffect(() => {\n if (!thanked) return\n const timer = setTimeout(onYes, 3000)\n return () => clearTimeout(timer)\n }, [thanked])\n\n if (thanked) {\n return (\n <Stack class=\"border-t border-neutral-100 p-4 min-h-[175px]\" align=\"center\">\n <CheckCircle size={20} class=\"text-green-500\" />\n <Text size=\"sm\" weight=\"semibold\">\n Glad we could help\n </Text>\n <Text size=\"sm\" color=\"dimmed\">\n See you next time\n </Text>\n </Stack>\n )\n }\n\n return (\n <Stack class=\"border-t border-neutral-100 p-4 min-h-[175px]\" align=\"center\">\n <CheckCircle size={20} class=\"text-green-500\" />\n\n <Stack gap={0} align=\"center\">\n <Text size=\"sm\">This conversation has been resolved</Text>\n <Text size=\"sm\" color=\"dimmed\">\n Did we answer your question?\n </Text>\n </Stack>\n\n <Group class=\"w-full\">\n <Button class=\"flex-1\" variant=\"outline\" fullWidth onClick={onNo}>\n <Stack gap={0}>\n <Text>No</Text>\n <Text size=\"xs\" color=\"dimmed\">\n I need more help\n </Text>\n </Stack>\n </Button>\n\n <Button class=\"flex-1\" onClick={() => setThanked(true)}>\n <Stack gap={0}>\n <Text class=\"text-white\" weight=\"semibold\">\n Yes\n </Text>\n <Text size=\"xs\" class=\"text-white\">\n Thanks\n </Text>\n </Stack>\n </Button>\n </Group>\n </Stack>\n )\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n gap?: 'xs' | 'sm' | 'md' | 'lg' | number\n align?: 'start' | 'center' | 'end' | 'stretch'\n justify?: 'start' | 'center' | 'end' | 'between'\n class?: string\n}\n\nconst gaps = {\n xs: 'gap-1',\n sm: 'gap-2',\n md: 'gap-4',\n lg: 'gap-6',\n}\n\nconst aligns = {\n start: 'items-start',\n center: 'items-center',\n end: 'items-end',\n stretch: 'items-stretch',\n}\n\nconst justifies = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n}\n\nexport const Stack = ({ children, gap = 'md', align, justify, class: cls }: Props) => {\n const gapClass = (gaps as any)[gap] ?? `gap-${gap}`\n\n return (\n <div class={`flex flex-col ${gapClass} ${align ? aligns[align] : ''} ${justify ? justifies[justify] : ''} ${cls ?? ''}`}>\n {children}\n </div>\n )\n}\n","import { useEffect, useRef, useState } from 'preact/hooks'\nimport { socket } from './service'\n\ntype Payload = { room_id: string }\n\ntype Props = {\n room_id?: string\n}\n\nconst TYPING_TIMEOUT_MS = 10000\n\nexport const useOnTyping = ({ room_id }: Props) => {\n const [isTyping, setIsTyping] = useState(false)\n const stopTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const clearStopTimer = () => {\n if (stopTimerRef.current) {\n clearTimeout(stopTimerRef.current)\n stopTimerRef.current = null\n }\n }\n\n const stopTyping = () => {\n clearStopTimer()\n setIsTyping(false)\n }\n\n useEffect(() => {\n if (!socket.value) {\n return\n }\n\n const handlerStart = (payload: Payload) => {\n const canSkip = room_id && !payload.room_id.includes(room_id)\n\n if (canSkip) {\n return\n }\n\n setIsTyping(true)\n clearStopTimer()\n stopTimerRef.current = setTimeout(stopTyping, TYPING_TIMEOUT_MS)\n }\n\n const handlerStop = (payload: Payload) => {\n const canSkip = room_id && !payload.room_id.includes(room_id)\n\n if (canSkip) {\n return\n }\n\n stopTyping()\n }\n\n socket.value.on('typing-start', handlerStart)\n socket.value.on('typing-stop', handlerStop)\n\n return () => {\n socket.value?.off('typing-start', handlerStart)\n socket.value?.off('typing-stop', handlerStop)\n clearStopTimer()\n }\n }, [room_id, socket])\n\n return { isTyping }\n}\n","import { useRef } from 'preact/hooks'\nimport { socket, SocketService } from './service'\n\ntype Props = {\n room_id: string\n}\n\nconst TYPING_START_DELAY_MS = 3000\nconst TYPING_HEARTBEAT_MS = 5000\nconst TYPING_STOP_DELAY_MS = 5000\n\nexport const useTyping = ({ room_id }: Props) => {\n const startTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const stopTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const lastEmitRef = useRef<number>(0)\n\n const onType = () => {\n if (!socket.value) {\n return\n }\n\n const now = Date.now()\n\n // Heartbeat: re-emit typing-start while actively typing\n if (lastEmitRef.current > 0 && now - lastEmitRef.current >= TYPING_HEARTBEAT_MS) {\n SocketService.typingStart(room_id)\n lastEmitRef.current = now\n }\n\n // Start delay: only emit typing-start after 3s of sustained typing\n if (lastEmitRef.current === 0 && !startTimerRef.current) {\n startTimerRef.current = setTimeout(() => {\n SocketService.typingStart(room_id)\n lastEmitRef.current = Date.now()\n startTimerRef.current = null\n }, TYPING_START_DELAY_MS)\n }\n\n // Reset stop timer on each keystroke\n if (stopTimerRef.current) {\n clearTimeout(stopTimerRef.current)\n }\n\n stopTimerRef.current = setTimeout(() => {\n if (startTimerRef.current) {\n clearTimeout(startTimerRef.current)\n startTimerRef.current = null\n }\n if (lastEmitRef.current > 0) {\n SocketService.typingStop(room_id)\n lastEmitRef.current = 0\n }\n stopTimerRef.current = null\n }, TYPING_STOP_DELAY_MS)\n }\n\n const stopTyping = () => {\n if (startTimerRef.current) {\n clearTimeout(startTimerRef.current)\n startTimerRef.current = null\n }\n if (stopTimerRef.current) {\n clearTimeout(stopTimerRef.current)\n stopTimerRef.current = null\n }\n if (lastEmitRef.current > 0) {\n SocketService.typingStop(room_id)\n lastEmitRef.current = 0\n }\n }\n\n return { onType, stopTyping }\n}\n","import { ChevronRight, SendHorizonal } from 'lucide-preact'\nimport { useEffect } from 'preact/hooks'\nimport { useOnNewMessage } from '../hooks/useNewMessage'\nimport { useQuery } from '../hooks/useQuery'\nimport { ApiService } from '../modules/api/service'\nimport { navigate } from '../router'\nimport { currentUser, visitorId } from '../state'\nimport { Avatar } from '../ui/Avatar'\nimport { Card } from '../ui/Card'\nimport { Group } from '../ui/Group'\nimport { Indicator } from '../ui/Indicator'\nimport { Stack } from '../ui/Stack'\nimport { Text } from '../ui/Text'\nimport { Title } from '../ui/Title'\n\nexport const Home = () => {\n const agentsQuery = useQuery({ queryKey: ['agents'], queryFn: () => ApiService.getAgents() })\n const conversationsQuery = useQuery({\n queryKey: ['conversations'],\n queryFn: () => ApiService.getConversations(),\n })\n\n const agents = agentsQuery.data ?? []\n const conversations = conversationsQuery.data ?? []\n\n const userName = currentUser.value?.name\n\n useOnNewMessage(() => {\n conversationsQuery.refetch()\n })\n\n useEffect(() => {\n conversationsQuery.refetch()\n }, [visitorId.value])\n\n return (\n <Stack class=\"flex flex-col p-4 gradient-header\">\n <Group justify=\"end\">\n {agents?.map((agent) => (\n <Indicator key={agent.id} color=\"green\">\n <Avatar src={agent.picture}>{agent.name}</Avatar>\n </Indicator>\n ))}\n </Group>\n\n <Stack gap={0} class=\"mt-12\">\n <Title color=\"dimmed\" lineClamp={2}>\n {userName ? `Hey ${userName} 👋` : `Hey 👋`}\n </Title>\n <Title>How can we help?</Title>\n </Stack>\n\n <Card class=\"mb-8\" onClick={() => navigate('conversation')}>\n <Group align=\"center\" justify=\"between\">\n <Stack gap={0}>\n <Text class=\"font-semibold\">Send us a message</Text>\n <Text color=\"dimmed\">Usual reply time is a few minutes</Text>\n </Stack>\n <SendHorizonal />\n </Group>\n </Card>\n\n {conversations && conversations.length > 0 && (\n <Stack gap={2}>\n <Text color=\"dimmed\" class=\"text-xs font-medium uppercase tracking-wide px-1\">\n Previous conversations\n </Text>\n <Stack gap={1}>\n {conversations.map((conv) => {\n const agent = conv.agent\n\n return (\n <Card\n key={conv.id}\n onClick={() => navigate('conversation', { conversationId: conv.id })}\n >\n <Group align=\"center\" justify=\"between\">\n <Group align=\"center\" gap={2}>\n <Avatar size=\"sm\" src={agent?.picture}>\n {agent?.name}\n </Avatar>\n <Stack gap={0}>\n <Text class=\"font-medium text-xs\">{agent?.name ?? 'Support'}</Text>\n <Text color=\"dimmed\" class=\"text-xs truncate max-w-[180px]\">\n {conv.lastMessage?.text ?? 'No messages yet'}\n </Text>\n </Stack>\n </Group>\n <Indicator\n color=\"red\"\n label={conv.unread_contact_count}\n visible={conv.unread_contact_count > 0}\n position=\"top-right\"\n offset={{ x: -36, y: 15 }}\n >\n <ChevronRight size={14} class=\"text-neutral-400 shrink-0\" />\n </Indicator>\n </Group>\n </Card>\n )\n })}\n </Stack>\n </Stack>\n )}\n </Stack>\n )\n}\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n onClick?: () => void\n class?: string\n}\n\nexport const Card = ({ children, onClick, class: cls }: Props) => (\n <div\n onClick={onClick}\n class={`\n p-4 rounded-lg border border-neutral-200 bg-white\n ${onClick ? 'cursor-pointer hover:bg-neutral-50 transition-colors' : ''}\n ${cls ?? ''}\n `}\n >\n {children}\n </div>\n)\n","import { ReactNode } from 'preact/compat'\n\ntype Props = {\n children: ReactNode\n order?: 1 | 2 | 3\n color?: 'default' | 'dimmed' | string\n lineClamp?: number\n class?: string\n}\n\nconst styles: Record<1 | 2 | 3, { tag: 'h1' | 'h2' | 'h3'; cls: string }> = {\n 1: { tag: 'h1', cls: 'text-2xl font-semibold' },\n 2: { tag: 'h2', cls: 'text-lg font-semibold' },\n 3: { tag: 'h3', cls: 'text-base font-medium' },\n}\n\nconst colors = {\n default: 'text-neutral-800',\n dimmed: 'text-neutral-400',\n}\n\nexport const Title = ({ children, order = 1, color = 'default', lineClamp, class: cls }: Props) => {\n const { tag: Tag, cls: base } = styles[order]\n\n const colorClass = (colors as any)[color] ?? color\n const clampStyle = lineClamp\n ? { overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: lineClamp, WebkitBoxOrient: 'vertical' as const }\n : undefined\n\n return <Tag class={`${base} ${cls ?? ''} ${colorClass}`} style={clampStyle}>{children}</Tag>\n}\n","export default \"/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\\n@layer properties;\\n@layer theme, base, components, utilities;\\n@layer theme {\\n :root, :host {\\n --font-sans: ui-sans-serif, system-ui, sans-serif, \\\"Apple Color Emoji\\\",\\n \\\"Segoe UI Emoji\\\", \\\"Segoe UI Symbol\\\", \\\"Noto Color Emoji\\\";\\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\",\\n \\\"Courier New\\\", monospace;\\n --color-red-500: oklch(63.7% 0.237 25.331);\\n --color-amber-50: oklch(98.7% 0.022 95.277);\\n --color-amber-200: oklch(92.4% 0.12 95.746);\\n --color-amber-700: oklch(55.5% 0.163 48.998);\\n --color-green-500: oklch(72.3% 0.219 149.579);\\n --color-blue-100: oklch(93.2% 0.032 255.585);\\n --color-blue-200: oklch(88.2% 0.059 254.128);\\n --color-blue-400: oklch(70.7% 0.165 254.624);\\n --color-blue-500: oklch(62.3% 0.214 259.815);\\n --color-blue-600: oklch(54.6% 0.245 262.881);\\n --color-blue-700: oklch(48.8% 0.243 264.376);\\n --color-gray-200: oklch(92.8% 0.006 264.531);\\n --color-neutral-50: oklch(98.5% 0 0);\\n --color-neutral-100: oklch(97% 0 0);\\n --color-neutral-200: oklch(92.2% 0 0);\\n --color-neutral-300: oklch(87% 0 0);\\n --color-neutral-400: oklch(70.8% 0 0);\\n --color-neutral-500: oklch(55.6% 0 0);\\n --color-neutral-600: oklch(43.9% 0 0);\\n --color-neutral-800: oklch(26.9% 0 0);\\n --color-neutral-900: oklch(20.5% 0 0);\\n --color-white: #fff;\\n --spacing: 0.25rem;\\n --text-xs: 0.75rem;\\n --text-xs--line-height: calc(1 / 0.75);\\n --text-sm: 0.875rem;\\n --text-sm--line-height: calc(1.25 / 0.875);\\n --text-base: 1rem;\\n --text-base--line-height: calc(1.5 / 1);\\n --text-lg: 1.125rem;\\n --text-lg--line-height: calc(1.75 / 1.125);\\n --text-xl: 1.25rem;\\n --text-xl--line-height: calc(1.75 / 1.25);\\n --text-2xl: 1.5rem;\\n --text-2xl--line-height: calc(2 / 1.5);\\n --font-weight-normal: 400;\\n --font-weight-medium: 500;\\n --font-weight-semibold: 600;\\n --tracking-wide: 0.025em;\\n --leading-snug: 1.375;\\n --radius-sm: 0.25rem;\\n --radius-lg: 0.5rem;\\n --radius-xl: 0.75rem;\\n --radius-2xl: 1rem;\\n --animate-spin: spin 1s linear infinite;\\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\\n --animate-bounce: bounce 1s infinite;\\n --default-transition-duration: 150ms;\\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\\n --default-font-family: var(--font-sans);\\n --default-mono-font-family: var(--font-mono);\\n }\\n}\\n@layer base {\\n *, ::after, ::before, ::backdrop, ::file-selector-button {\\n box-sizing: border-box;\\n margin: 0;\\n padding: 0;\\n border: 0 solid;\\n }\\n html, :host {\\n line-height: 1.5;\\n -webkit-text-size-adjust: 100%;\\n tab-size: 4;\\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, \\\"Apple Color Emoji\\\", \\\"Segoe UI Emoji\\\", \\\"Segoe UI Symbol\\\", \\\"Noto Color Emoji\\\");\\n font-feature-settings: var(--default-font-feature-settings, normal);\\n font-variation-settings: var(--default-font-variation-settings, normal);\\n -webkit-tap-highlight-color: transparent;\\n }\\n hr {\\n height: 0;\\n color: inherit;\\n border-top-width: 1px;\\n }\\n abbr:where([title]) {\\n -webkit-text-decoration: underline dotted;\\n text-decoration: underline dotted;\\n }\\n h1, h2, h3, h4, h5, h6 {\\n font-size: inherit;\\n font-weight: inherit;\\n }\\n a {\\n color: inherit;\\n -webkit-text-decoration: inherit;\\n text-decoration: inherit;\\n }\\n b, strong {\\n font-weight: bolder;\\n }\\n code, kbd, samp, pre {\\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace);\\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\\n font-size: 1em;\\n }\\n small {\\n font-size: 80%;\\n }\\n sub, sup {\\n font-size: 75%;\\n line-height: 0;\\n position: relative;\\n vertical-align: baseline;\\n }\\n sub {\\n bottom: -0.25em;\\n }\\n sup {\\n top: -0.5em;\\n }\\n table {\\n text-indent: 0;\\n border-color: inherit;\\n border-collapse: collapse;\\n }\\n :-moz-focusring {\\n outline: auto;\\n }\\n progress {\\n vertical-align: baseline;\\n }\\n summary {\\n display: list-item;\\n }\\n ol, ul, menu {\\n list-style: none;\\n }\\n img, svg, video, canvas, audio, iframe, embed, object {\\n display: block;\\n vertical-align: middle;\\n }\\n img, video {\\n max-width: 100%;\\n height: auto;\\n }\\n button, input, select, optgroup, textarea, ::file-selector-button {\\n font: inherit;\\n font-feature-settings: inherit;\\n font-variation-settings: inherit;\\n letter-spacing: inherit;\\n color: inherit;\\n border-radius: 0;\\n background-color: transparent;\\n opacity: 1;\\n }\\n :where(select:is([multiple], [size])) optgroup {\\n font-weight: bolder;\\n }\\n :where(select:is([multiple], [size])) optgroup option {\\n padding-inline-start: 20px;\\n }\\n ::file-selector-button {\\n margin-inline-end: 4px;\\n }\\n ::placeholder {\\n opacity: 1;\\n }\\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\\n ::placeholder {\\n color: currentcolor;\\n @supports (color: color-mix(in lab, red, red)) {\\n color: color-mix(in oklab, currentcolor 50%, transparent);\\n }\\n }\\n }\\n textarea {\\n resize: vertical;\\n }\\n ::-webkit-search-decoration {\\n -webkit-appearance: none;\\n }\\n ::-webkit-date-and-time-value {\\n min-height: 1lh;\\n text-align: inherit;\\n }\\n ::-webkit-datetime-edit {\\n display: inline-flex;\\n }\\n ::-webkit-datetime-edit-fields-wrapper {\\n padding: 0;\\n }\\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\\n padding-block: 0;\\n }\\n ::-webkit-calendar-picker-indicator {\\n line-height: 1;\\n }\\n :-moz-ui-invalid {\\n box-shadow: none;\\n }\\n button, input:where([type=\\\"button\\\"], [type=\\\"reset\\\"], [type=\\\"submit\\\"]), ::file-selector-button {\\n appearance: button;\\n }\\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\\n height: auto;\\n }\\n [hidden]:where(:not([hidden=\\\"until-found\\\"])) {\\n display: none !important;\\n }\\n}\\n@layer utilities {\\n .visible {\\n visibility: visible;\\n }\\n .absolute {\\n position: absolute;\\n }\\n .fixed {\\n position: fixed;\\n }\\n .relative {\\n position: relative;\\n }\\n .start {\\n inset-inline-start: var(--spacing);\\n }\\n .end {\\n inset-inline-end: var(--spacing);\\n }\\n .top-0 {\\n top: calc(var(--spacing) * 0);\\n }\\n .right-0 {\\n right: calc(var(--spacing) * 0);\\n }\\n .right-2\\\\.5 {\\n right: calc(var(--spacing) * 2.5);\\n }\\n .right-4 {\\n right: calc(var(--spacing) * 4);\\n }\\n .bottom-0 {\\n bottom: calc(var(--spacing) * 0);\\n }\\n .bottom-1\\\\.5 {\\n bottom: calc(var(--spacing) * 1.5);\\n }\\n .bottom-4 {\\n bottom: calc(var(--spacing) * 4);\\n }\\n .bottom-20 {\\n bottom: calc(var(--spacing) * 20);\\n }\\n .container {\\n width: 100%;\\n @media (width >= 40rem) {\\n max-width: 40rem;\\n }\\n @media (width >= 48rem) {\\n max-width: 48rem;\\n }\\n @media (width >= 64rem) {\\n max-width: 64rem;\\n }\\n @media (width >= 80rem) {\\n max-width: 80rem;\\n }\\n @media (width >= 96rem) {\\n max-width: 96rem;\\n }\\n }\\n .my-3 {\\n margin-block: calc(var(--spacing) * 3);\\n }\\n .mt-12 {\\n margin-top: calc(var(--spacing) * 12);\\n }\\n .mb-0\\\\.5 {\\n margin-bottom: calc(var(--spacing) * 0.5);\\n }\\n .mb-8 {\\n margin-bottom: calc(var(--spacing) * 8);\\n }\\n .flex {\\n display: flex;\\n }\\n .hidden {\\n display: none;\\n }\\n .inline-flex {\\n display: inline-flex;\\n }\\n .h-1\\\\.5 {\\n height: calc(var(--spacing) * 1.5);\\n }\\n .h-2\\\\.5 {\\n height: calc(var(--spacing) * 2.5);\\n }\\n .h-3\\\\.5 {\\n height: calc(var(--spacing) * 3.5);\\n }\\n .h-4 {\\n height: calc(var(--spacing) * 4);\\n }\\n .h-5 {\\n height: calc(var(--spacing) * 5);\\n }\\n .h-6 {\\n height: calc(var(--spacing) * 6);\\n }\\n .h-7 {\\n height: calc(var(--spacing) * 7);\\n }\\n .h-8 {\\n height: calc(var(--spacing) * 8);\\n }\\n .h-9 {\\n height: calc(var(--spacing) * 9);\\n }\\n .h-12 {\\n height: calc(var(--spacing) * 12);\\n }\\n .h-14 {\\n height: calc(var(--spacing) * 14);\\n }\\n .h-112 {\\n height: calc(var(--spacing) * 112);\\n }\\n .h-full {\\n height: 100%;\\n }\\n .h-px {\\n height: 1px;\\n }\\n .min-h-\\\\[175px\\\\] {\\n min-height: 175px;\\n }\\n .w-1\\\\.5 {\\n width: calc(var(--spacing) * 1.5);\\n }\\n .w-2\\\\.5 {\\n width: calc(var(--spacing) * 2.5);\\n }\\n .w-3\\\\.5 {\\n width: calc(var(--spacing) * 3.5);\\n }\\n .w-4 {\\n width: calc(var(--spacing) * 4);\\n }\\n .w-7 {\\n width: calc(var(--spacing) * 7);\\n }\\n .w-8 {\\n width: calc(var(--spacing) * 8);\\n }\\n .w-9 {\\n width: calc(var(--spacing) * 9);\\n }\\n .w-12 {\\n width: calc(var(--spacing) * 12);\\n }\\n .w-14 {\\n width: calc(var(--spacing) * 14);\\n }\\n .w-80 {\\n width: calc(var(--spacing) * 80);\\n }\\n .w-full {\\n width: 100%;\\n }\\n .max-w-\\\\[72\\\\%\\\\] {\\n max-width: 72%;\\n }\\n .max-w-\\\\[180px\\\\] {\\n max-width: 180px;\\n }\\n .min-w-4 {\\n min-width: calc(var(--spacing) * 4);\\n }\\n .min-w-5 {\\n min-width: calc(var(--spacing) * 5);\\n }\\n .min-w-6 {\\n min-width: calc(var(--spacing) * 6);\\n }\\n .min-w-18 {\\n min-width: calc(var(--spacing) * 18);\\n }\\n .flex-1 {\\n flex: 1;\\n }\\n .shrink-0 {\\n flex-shrink: 0;\\n }\\n .translate-x-1\\\\/2 {\\n --tw-translate-x: calc(1 / 2 * 100%);\\n translate: var(--tw-translate-x) var(--tw-translate-y);\\n }\\n .-translate-y-1\\\\/2 {\\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\\n translate: var(--tw-translate-x) var(--tw-translate-y);\\n }\\n .transform {\\n transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);\\n }\\n .animate-bounce {\\n animation: var(--animate-bounce);\\n }\\n .animate-pulse {\\n animation: var(--animate-pulse);\\n }\\n .animate-spin {\\n animation: var(--animate-spin);\\n }\\n .cursor-pointer {\\n cursor: pointer;\\n }\\n .resize {\\n resize: both;\\n }\\n .resize-none {\\n resize: none;\\n }\\n .flex-col {\\n flex-direction: column;\\n }\\n .flex-col-reverse {\\n flex-direction: column-reverse;\\n }\\n .flex-row {\\n flex-direction: row;\\n }\\n .flex-row-reverse {\\n flex-direction: row-reverse;\\n }\\n .flex-wrap {\\n flex-wrap: wrap;\\n }\\n .items-center {\\n align-items: center;\\n }\\n .items-end {\\n align-items: flex-end;\\n }\\n .items-start {\\n align-items: flex-start;\\n }\\n .items-stretch {\\n align-items: stretch;\\n }\\n .justify-between {\\n justify-content: space-between;\\n }\\n .justify-center {\\n justify-content: center;\\n }\\n .justify-end {\\n justify-content: flex-end;\\n }\\n .justify-start {\\n justify-content: flex-start;\\n }\\n .gap-0\\\\.5 {\\n gap: calc(var(--spacing) * 0.5);\\n }\\n .gap-1 {\\n gap: calc(var(--spacing) * 1);\\n }\\n .gap-2 {\\n gap: calc(var(--spacing) * 2);\\n }\\n .gap-4 {\\n gap: calc(var(--spacing) * 4);\\n }\\n .gap-6 {\\n gap: calc(var(--spacing) * 6);\\n }\\n .self-end {\\n align-self: flex-end;\\n }\\n .truncate {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n }\\n .overflow-hidden {\\n overflow: hidden;\\n }\\n .overflow-y-auto {\\n overflow-y: auto;\\n }\\n .rounded-2xl {\\n border-radius: var(--radius-2xl);\\n }\\n .rounded-full {\\n border-radius: calc(infinity * 1px);\\n }\\n .rounded-lg {\\n border-radius: var(--radius-lg);\\n }\\n .rounded-xl {\\n border-radius: var(--radius-xl);\\n }\\n .rounded-br-sm {\\n border-bottom-right-radius: var(--radius-sm);\\n }\\n .rounded-bl-sm {\\n border-bottom-left-radius: var(--radius-sm);\\n }\\n .border {\\n border-style: var(--tw-border-style);\\n border-width: 1px;\\n }\\n .border-2 {\\n border-style: var(--tw-border-style);\\n border-width: 2px;\\n }\\n .border-t {\\n border-top-style: var(--tw-border-style);\\n border-top-width: 1px;\\n }\\n .border-b {\\n border-bottom-style: var(--tw-border-style);\\n border-bottom-width: 1px;\\n }\\n .border-amber-200 {\\n border-color: var(--color-amber-200);\\n }\\n .border-blue-400 {\\n border-color: var(--color-blue-400);\\n }\\n .border-gray-200 {\\n border-color: var(--color-gray-200);\\n }\\n .border-neutral-100 {\\n border-color: var(--color-neutral-100);\\n }\\n .border-neutral-200 {\\n border-color: var(--color-neutral-200);\\n }\\n .border-white {\\n border-color: var(--color-white);\\n }\\n .bg-amber-50 {\\n background-color: var(--color-amber-50);\\n }\\n .bg-blue-100 {\\n background-color: var(--color-blue-100);\\n }\\n .bg-blue-500 {\\n background-color: var(--color-blue-500);\\n }\\n .bg-blue-600 {\\n background-color: var(--color-blue-600);\\n }\\n .bg-green-500 {\\n background-color: var(--color-green-500);\\n }\\n .bg-neutral-100 {\\n background-color: var(--color-neutral-100);\\n }\\n .bg-neutral-200 {\\n background-color: var(--color-neutral-200);\\n }\\n .bg-neutral-400 {\\n background-color: var(--color-neutral-400);\\n }\\n .bg-red-500 {\\n background-color: var(--color-red-500);\\n }\\n .bg-transparent {\\n background-color: transparent;\\n }\\n .bg-white {\\n background-color: var(--color-white);\\n }\\n .object-cover {\\n object-fit: cover;\\n }\\n .p-2 {\\n padding: calc(var(--spacing) * 2);\\n }\\n .p-4 {\\n padding: calc(var(--spacing) * 4);\\n }\\n .px-1 {\\n padding-inline: calc(var(--spacing) * 1);\\n }\\n .px-3 {\\n padding-inline: calc(var(--spacing) * 3);\\n }\\n .px-4 {\\n padding-inline: calc(var(--spacing) * 4);\\n }\\n .py-2 {\\n padding-block: calc(var(--spacing) * 2);\\n }\\n .py-2\\\\.5 {\\n padding-block: calc(var(--spacing) * 2.5);\\n }\\n .py-3 {\\n padding-block: calc(var(--spacing) * 3);\\n }\\n .py-4 {\\n padding-block: calc(var(--spacing) * 4);\\n }\\n .pt-2 {\\n padding-top: calc(var(--spacing) * 2);\\n }\\n .pb-5 {\\n padding-bottom: calc(var(--spacing) * 5);\\n }\\n .text-center {\\n text-align: center;\\n }\\n .text-2xl {\\n font-size: var(--text-2xl);\\n line-height: var(--tw-leading, var(--text-2xl--line-height));\\n }\\n .text-base {\\n font-size: var(--text-base);\\n line-height: var(--tw-leading, var(--text-base--line-height));\\n }\\n .text-lg {\\n font-size: var(--text-lg);\\n line-height: var(--tw-leading, var(--text-lg--line-height));\\n }\\n .text-sm {\\n font-size: var(--text-sm);\\n line-height: var(--tw-leading, var(--text-sm--line-height));\\n }\\n .text-xl {\\n font-size: var(--text-xl);\\n line-height: var(--tw-leading, var(--text-xl--line-height));\\n }\\n .text-xs {\\n font-size: var(--text-xs);\\n line-height: var(--tw-leading, var(--text-xs--line-height));\\n }\\n .text-\\\\[10px\\\\] {\\n font-size: 10px;\\n }\\n .leading-5 {\\n --tw-leading: calc(var(--spacing) * 5);\\n line-height: calc(var(--spacing) * 5);\\n }\\n .leading-none {\\n --tw-leading: 1;\\n line-height: 1;\\n }\\n .leading-snug {\\n --tw-leading: var(--leading-snug);\\n line-height: var(--leading-snug);\\n }\\n .font-medium {\\n --tw-font-weight: var(--font-weight-medium);\\n font-weight: var(--font-weight-medium);\\n }\\n .font-normal {\\n --tw-font-weight: var(--font-weight-normal);\\n font-weight: var(--font-weight-normal);\\n }\\n .font-semibold {\\n --tw-font-weight: var(--font-weight-semibold);\\n font-weight: var(--font-weight-semibold);\\n }\\n .tracking-wide {\\n --tw-tracking: var(--tracking-wide);\\n letter-spacing: var(--tracking-wide);\\n }\\n .whitespace-pre-wrap {\\n white-space: pre-wrap;\\n }\\n .text-amber-700 {\\n color: var(--color-amber-700);\\n }\\n .text-blue-200 {\\n color: var(--color-blue-200);\\n }\\n .text-blue-700 {\\n color: var(--color-blue-700);\\n }\\n .text-green-500 {\\n color: var(--color-green-500);\\n }\\n .text-inherit {\\n color: inherit;\\n }\\n .text-neutral-400 {\\n color: var(--color-neutral-400);\\n }\\n .text-neutral-500 {\\n color: var(--color-neutral-500);\\n }\\n .text-neutral-600 {\\n color: var(--color-neutral-600);\\n }\\n .text-neutral-800 {\\n color: var(--color-neutral-800);\\n }\\n .text-neutral-900 {\\n color: var(--color-neutral-900);\\n }\\n .text-white {\\n color: var(--color-white);\\n }\\n .uppercase {\\n text-transform: uppercase;\\n }\\n .opacity-0 {\\n opacity: 0%;\\n }\\n .shadow {\\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\\n }\\n .shadow-2xl {\\n --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));\\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\\n }\\n .shadow-lg {\\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\\n }\\n .outline {\\n outline-style: var(--tw-outline-style);\\n outline-width: 1px;\\n }\\n .transition-colors {\\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;\\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\\n transition-duration: var(--tw-duration, var(--default-transition-duration));\\n }\\n .outline-none {\\n --tw-outline-style: none;\\n outline-style: none;\\n }\\n .placeholder\\\\:text-neutral-400 {\\n &::placeholder {\\n color: var(--color-neutral-400);\\n }\\n }\\n .hover\\\\:bg-blue-700 {\\n &:hover {\\n @media (hover: hover) {\\n background-color: var(--color-blue-700);\\n }\\n }\\n }\\n .hover\\\\:bg-neutral-50 {\\n &:hover {\\n @media (hover: hover) {\\n background-color: var(--color-neutral-50);\\n }\\n }\\n }\\n .hover\\\\:bg-neutral-200 {\\n &:hover {\\n @media (hover: hover) {\\n background-color: var(--color-neutral-200);\\n }\\n }\\n }\\n .hover\\\\:text-neutral-800 {\\n &:hover {\\n @media (hover: hover) {\\n color: var(--color-neutral-800);\\n }\\n }\\n }\\n .disabled\\\\:cursor-not-allowed {\\n &:disabled {\\n cursor: not-allowed;\\n }\\n }\\n .disabled\\\\:opacity-50 {\\n &:disabled {\\n opacity: 50%;\\n }\\n }\\n}\\n*, ::before, ::after {\\n --tw-border-style: solid;\\n}\\n.gradient-header {\\n background: linear-gradient(to bottom, var(--color-neutral-200) 0%, var(--color-white) 60%);\\n}\\n.lucide {\\n height: 1em;\\n width: 1em;\\n display: inline-block;\\n}\\n::-webkit-scrollbar {\\n width: 4px;\\n}\\n::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n::-webkit-scrollbar-thumb {\\n background: var(--color-neutral-300);\\n border-radius: 9999px;\\n}\\n@property --tw-translate-x {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0;\\n}\\n@property --tw-translate-y {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0;\\n}\\n@property --tw-translate-z {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0;\\n}\\n@property --tw-rotate-x {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-rotate-y {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-rotate-z {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-skew-x {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-skew-y {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-border-style {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: solid;\\n}\\n@property --tw-leading {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-font-weight {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-tracking {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-shadow-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-shadow-alpha {\\n syntax: \\\"<percentage>\\\";\\n inherits: false;\\n initial-value: 100%;\\n}\\n@property --tw-inset-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-inset-shadow-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-inset-shadow-alpha {\\n syntax: \\\"<percentage>\\\";\\n inherits: false;\\n initial-value: 100%;\\n}\\n@property --tw-ring-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-ring-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-inset-ring-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-inset-ring-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-ring-inset {\\n syntax: \\\"*\\\";\\n inherits: false;\\n}\\n@property --tw-ring-offset-width {\\n syntax: \\\"<length>\\\";\\n inherits: false;\\n initial-value: 0px;\\n}\\n@property --tw-ring-offset-color {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: #fff;\\n}\\n@property --tw-ring-offset-shadow {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: 0 0 #0000;\\n}\\n@property --tw-outline-style {\\n syntax: \\\"*\\\";\\n inherits: false;\\n initial-value: solid;\\n}\\n@keyframes spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n@keyframes pulse {\\n 50% {\\n opacity: 0.5;\\n }\\n}\\n@keyframes bounce {\\n 0%, 100% {\\n transform: translateY(-25%);\\n animation-timing-function: cubic-bezier(0.8, 0, 1, 1);\\n }\\n 50% {\\n transform: none;\\n animation-timing-function: cubic-bezier(0, 0, 0.2, 1);\\n }\\n}\\n@layer properties {\\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\\n *, ::before, ::after, ::backdrop {\\n --tw-translate-x: 0;\\n --tw-translate-y: 0;\\n --tw-translate-z: 0;\\n --tw-rotate-x: initial;\\n --tw-rotate-y: initial;\\n --tw-rotate-z: initial;\\n --tw-skew-x: initial;\\n --tw-skew-y: initial;\\n --tw-border-style: solid;\\n --tw-leading: initial;\\n --tw-font-weight: initial;\\n --tw-tracking: initial;\\n --tw-shadow: 0 0 #0000;\\n --tw-shadow-color: initial;\\n --tw-shadow-alpha: 100%;\\n --tw-inset-shadow: 0 0 #0000;\\n --tw-inset-shadow-color: initial;\\n --tw-inset-shadow-alpha: 100%;\\n --tw-ring-color: initial;\\n --tw-ring-shadow: 0 0 #0000;\\n --tw-inset-ring-color: initial;\\n --tw-inset-ring-shadow: 0 0 #0000;\\n --tw-ring-inset: initial;\\n --tw-ring-offset-width: 0px;\\n --tw-ring-offset-color: #fff;\\n --tw-ring-offset-shadow: 0 0 #0000;\\n --tw-outline-style: solid;\\n }\\n }\\n}\\n\"\n"],"mappings":"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","names":["init_service","VisitorService","init_service","import_preact","import_lucide_preact","import_hooks","import_jsx_runtime","isOpen","import_signals","init_service","import_hooks","init_service","import_signals","import_hooks","import_hooks","init_service","import_hooks","init_service","import_lucide_preact","import_signals","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","sizes","import_jsx_runtime","sizes","colors","import_jsx_runtime","import_hooks","import_lucide_preact","import_jsx_runtime","import_hooks","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_lucide_preact","import_hooks","import_jsx_runtime","gaps","aligns","justifies","import_jsx_runtime","import_hooks","import_hooks","import_jsx_runtime","isOpen","import_lucide_preact","import_hooks","init_service","import_jsx_runtime","import_jsx_runtime","colors","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|