HyperSaaS
FrontendChat

Session UI

Main chat container with resizable panels and responsive layout.

ChatSessionUI is the top-level container for an active chat conversation. It orchestrates messages, the map panel, the document viewer, and the settings sheet.

Props

interface ChatSessionUIProps {
  chatSession: ChatSession;
  enableDocumentStatusPolling?: boolean;
}

State Management

The component manages several pieces of state:

// Map visibility (synced with URL query params)
const [isMapVisible, setIsMapVisible] = useQueryParam("map");

// Document viewer tabs
const [openDocuments, setOpenDocuments] = useState<DocumentTab[]>([]);
const [activeDocumentId, setActiveDocumentId] = useState<string | null>(null);

// Mobile document sheet
const [isMobileDocumentSheetOpen, setIsMobileDocumentSheetOpen] = useState(false);

// Document processing status
const [documentStatuses, setDocumentStatuses] = useState<DocumentStatus[]>([]);

Desktop Layout (Resizable Panels)

On desktop, the chat uses ResizablePanelGroup for a flexible multi-panel layout:

┌─────────────────┬──────────────┬──────────────────┐
│                  │              │                   │
│   Message List   │  Google Map  │ Document Viewer   │
│   + Input Form   │  (optional)  │   (optional)      │
│                  │              │                   │
└─────────────────┴──────────────┴──────────────────┘
  • Panel 1 (Messages): Always visible, min 30% width
  • Panel 2 (Map): Toggled via header button, shows Google Maps with location markers
  • Panel 3 (Documents): Opens when clicking a citation source, tabbed document viewer

Users can drag panel borders to resize.

Mobile Layout

On mobile, the layout stacks vertically:

┌──────────────────┐
│  Chat Header     │
├──────────────────┤
│                  │
│  Message List    │
│                  │
├──────────────────┤
│  Input Form      │
└──────────────────┘

      + Sheet modals for Map & Documents

Documents and map open in Sheet components (slide-up panels).

Document Status Polling

When enableDocumentStatusPolling is true, the component polls document processing status every 5 seconds:

useEffect(() => {
  if (!enableDocumentStatusPolling) return;

  const interval = setInterval(async () => {
    const statuses = await fetchDocumentStatuses(chatSession.id);
    setDocumentStatuses(statuses);
  }, 5000);

  return () => clearInterval(interval);
}, []);

This keeps the UI updated when documents are being ingested in the background.

Citation Click Flow

When a user clicks a citation source in a message:

  1. onCitationClick(documentId, chunkId) is called
  2. If document not already open, add to openDocuments tabs
  3. Set activeDocumentId to the clicked document
  4. Pass highlightChunkId to the document viewer
  5. On mobile, open the document sheet

Settings Sheet

The ChatSessionSettingsForm opens as a side sheet. It shows only the settings the chat's model takes, from the backend's model catalog (GET /api/workspaces/{id}/ai-models/):

SettingForStored as
NameEvery chatname
ModelEvery chat; models outside the plan are lockedai_model
InstructionsEvery chatsystem_prompt
Response style: Precise (default), Balanced, CreativeModels that take temperaturetemperature (0.2, 0.7, 1.0)
Reasoning effortGPT-5, o3, o4-minimodel_parameters.reasoning_effort
Extended thinking, with a budgetClaudemodel_parameters.thinking
Reply length, up to the model's limitEvery chatmax_tokens
Advanced: temperature, Top P, Top K, penalties, seed, stop sequencesEach where the model takes itthe chat's fields, or model_parameters
  • An empty setting shows its default, never a blank box, and each one can be reset to it.
  • Claude takes temperature or Top P, not both, so setting one clears the other; with extended thinking on, neither applies and they're hidden.
  • Switching model drops the settings the new one can't take.
  • Save sends only what changed, by PATCH, and shows the backend's reason if it refuses ("The Free plan doesn't include …"). Reset goes back to what's saved.

Below the settings, knowledge bases can be attached and detached.

Location Sheet

When a location tag is clicked in a message:

  1. onLocationClick(location) is called
  2. A floating sheet opens with LocationDetailView
  3. Shows location name, address, and details
  4. Map panel centers on the location marker

On this page