- Collapsible sidebar with Jotai atom (icon-only mode, persisted to localStorage) - 2-panel call desk: worklist (60%) + context panel (40%) with AI + Lead 360 tabs - Inline AI call prep card — known lead summary or unknown caller script - Active call card with compact Answer/Decline buttons - Worklist panel with human-readable labels, priority badges, click-to-select - Context panel auto-switches to Lead 360 when lead selected or call incoming - Browser ringtone via Web Audio API on incoming calls - Sonner + Untitled UI IconNotification for toast system - apiClient pattern: centralized post/get/graphql with auto-toast on errors - Remove duplicate avatar from top bar, hide floating widget on call desk - Fix Link routing in collapsed sidebar (was using <a> causing full page reload) - Fix GraphQL field names: adStatus→status, platformUrl needs subfield selection - Silent mode for DataProvider queries to prevent toast spam Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 KiB
Call Desk Redesign + Ozonetel Dial API
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Rebuild the call desk into a 2-panel layout with collapsible sidebar, inline AI assistant, and Ozonetel outbound dial integration.
Architecture: The call desk becomes the agent's cockpit — a 2-panel layout (main 60% + context 40%) with the worklist always visible. The left nav sidebar becomes collapsible (icon-only mode) to maximize workspace. AI is inline within the call flow, not a separate tab. Outbound calls go through Ozonetel REST API (dialCustomer → agent SIP ring → bridge to customer).
Tech Stack: React 19, Jotai atoms, Untitled UI components, FontAwesome Pro Duotone icons, NestJS sidecar, Ozonetel CloudAgent REST API
File Structure
Sidecar (helix-engage-server)
src/ozonetel/ozonetel-agent.service.ts— ALREADY DONE:dialCustomer()method addedsrc/ozonetel/ozonetel-agent.controller.ts— ALREADY DONE:POST /api/ozonetel/dialendpoint added
Frontend (helix-engage)
Modified files:
src/components/layout/sidebar.tsx— Add collapse/expand toggle, icon-only modesrc/components/layout/app-shell.tsx— Pass collapse state to sidebar, adjust main content marginsrc/pages/call-desk.tsx— Complete rewrite: 2-panel layout with worklist + context panelsrc/components/call-desk/ai-chat-panel.tsx— Move to context panel, full-height, always visiblesrc/components/call-desk/incoming-call-card.tsx— Simplify for inline use (no idle/waiting states)src/components/call-desk/click-to-call-button.tsx— ALREADY DONE: Uses Ozonetel dial API
New files:
src/state/sidebar-state.ts— Jotai atom for sidebar collapsed state (persisted to localStorage)src/components/call-desk/worklist-panel.tsx— Worklist section: missed calls, follow-ups, assigned leadssrc/components/call-desk/context-panel.tsx— Right panel: AI chat + lead 360 tabssrc/components/call-desk/call-prep-card.tsx— Inline AI prep card (known lead summary / unknown caller script)src/components/call-desk/active-call-card.tsx— Compact caller info + controls during active call
Task 1: Collapsible Sidebar
Files:
-
Create:
src/state/sidebar-state.ts -
Modify:
src/components/layout/sidebar.tsx -
Modify:
src/components/layout/app-shell.tsx -
Step 1: Create sidebar Jotai atom
// src/state/sidebar-state.ts
import { atom } from 'jotai';
const stored = localStorage.getItem('helix_sidebar_collapsed');
export const sidebarCollapsedAtom = atom<boolean>(stored === 'true');
- Step 2: Add collapse toggle to sidebar
In sidebar.tsx:
-
Add a collapse button (chevron icon) at the top-right of the sidebar
-
When collapsed: sidebar width shrinks from 292px to 64px, show only icons (no labels, no section headers)
-
NavItemBase gets a
collapsedprop — renders icon-only with tooltip -
Account card at bottom: show only avatar when collapsed
-
Logo: show only "H" icon when collapsed
-
Persist state to localStorage via Jotai atom
-
Step 3: Wire AppShell to sidebar collapse state
In app-shell.tsx:
-
Read
sidebarCollapsedAtomwithuseAtom -
Pass collapsed state to
<Sidebar collapsed={collapsed} /> -
Adjust the invisible spacer width from 292px to 64px when collapsed
-
Step 4: Verify sidebar works in both states
Manual test:
-
Click collapse button → sidebar shrinks to icons-only, tooltips show on hover
-
Click expand button → sidebar returns to full width
-
Refresh page → collapsed state persists
-
Step 5: Commit
git add src/state/sidebar-state.ts src/components/layout/sidebar.tsx src/components/layout/app-shell.tsx
git commit -m "feat: add collapsible sidebar with icon-only mode"
Task 2: Worklist Panel Component
Files:
-
Create:
src/components/call-desk/worklist-panel.tsx -
Step 1: Create worklist panel
A vertical list component that renders three sections:
- Missed Calls (red border) — from
useWorklist().missedCalls - Follow-ups Due (amber/blue border) — from
useWorklist().followUps - Assigned Leads (brand border) — from
useWorklist().marketingLeads
Each item is a compact card:
- Lead name, phone number, service interest
- Priority/SLA badge
- Click-to-call button (uses Ozonetel dial via existing
ClickToCallButton) - Clicking the card (not the call button) selects it and loads context in the right panel
Props:
interface WorklistPanelProps {
onSelectLead: (lead: WorklistLead) => void;
selectedLeadId: string | null;
}
- Step 2: Verify worklist renders with seeded data
Manual test: worklist shows Priya, Ravi, Deepa, Vijay with phone numbers and services
- Step 3: Commit
git add src/components/call-desk/worklist-panel.tsx
git commit -m "feat: add worklist panel component"
Task 3: Call Prep Card (Inline AI)
Files:
-
Create:
src/components/call-desk/call-prep-card.tsx -
Step 1: Create call prep card for known leads
When a call comes in from a known lead, this card shows:
-
Lead name, status, score
-
AI summary (from
lead.aiSummary) -
AI suggested action (from
lead.aiSuggestedAction) -
Recent activity (last 3 activities)
-
Campaign attribution
-
Step 2: Add unknown caller variant
When a call comes in from an unknown number:
- "Unknown Caller" header with the phone number
- "No record found" message
- Suggested script: Ask name, DOB, service interest, how they heard about us, offer to book consultation
- "Create Lead" button to create a new lead from the call
Props:
interface CallPrepCardProps {
lead: Lead | null;
callerPhone: string;
activities: LeadActivity[];
}
- Step 3: Commit
git add src/components/call-desk/call-prep-card.tsx
git commit -m "feat: add inline AI call prep card"
Task 4: Context Panel
Files:
-
Create:
src/components/call-desk/context-panel.tsx -
Modify:
src/components/call-desk/ai-chat-panel.tsx— remove header, make full-height -
Step 1: Create context panel with tabs
Right panel (40% width) with two tabs:
- AI Assistant — The existing
AiChatPanel, now full-height with callerContext auto-set from selected lead - Lead 360 — Summary of selected lead: profile, appointments, call history, activities
When no lead is selected: show AI Assistant tab by default with quick prompts. When a lead is selected (from worklist click or incoming call): auto-switch to Lead 360 tab, pre-populate AI context.
- Step 2: Update AiChatPanel for inline use
Remove the standalone header (it's now inside the context panel tab). Make it flex-1 to fill available height. Auto-send a prep message when callerContext changes (e.g., "Tell me about the patient on the line").
- Step 3: Commit
git add src/components/call-desk/context-panel.tsx src/components/call-desk/ai-chat-panel.tsx
git commit -m "feat: add context panel with AI + Lead 360 tabs"
Task 5: Active Call Card
Files:
-
Create:
src/components/call-desk/active-call-card.tsx -
Step 1: Create compact active call card
Replaces the worklist section when a call is active. Shows:
- Caller name/number
- Call duration timer
- Call controls: Mute, Hold, Hangup
- Answer/Reject buttons (during ringing)
- Disposition form (after call ends)
Uses Jotai SIP atoms for call state.
- Step 2: Commit
git add src/components/call-desk/active-call-card.tsx
git commit -m "feat: add compact active call card"
Task 6: Call Desk Page Rewrite
Files:
-
Modify:
src/pages/call-desk.tsx— Complete rewrite -
Step 1: Rewrite call desk with 2-panel layout
┌──────────────────────────────────┬─────────────────────────────┐
│ MAIN (60%) │ CONTEXT (40%) │
│ │ │
│ ┌─ Status Bar ───────────────┐ │ Context Panel │
│ │ ● Ready · Rekha · 4 items │ │ (AI Chat | Lead 360) │
│ └────────────────────────────┘ │ │
│ │ │
│ When IDLE: │ │
│ ┌─ Worklist Panel ───────────┐ │ │
│ │ (missed calls, follow-ups, │ │ │
│ │ assigned leads) │ │ │
│ └────────────────────────────┘ │ │
│ │ │
│ When CALL ACTIVE: │ │
│ ┌─ Active Call Card ─────────┐ │ │
│ │ (caller info, controls) │ │ │
│ └────────────────────────────┘ │ │
│ ┌─ Call Prep Card ───────────┐ │ │
│ │ (AI summary, suggested │ │ │
│ │ action, recent activity) │ │ │
│ └────────────────────────────┘ │ │
│ │ │
│ ┌─ Today's Calls ────────────┐ │ │
│ │ (call log, always visible) │ │ │
│ └────────────────────────────┘ │ │
└──────────────────────────────────┴─────────────────────────────┘
Key behaviors:
-
Clicking a worklist item selects it → context panel shows lead 360 + AI context
-
Incoming call → active call card replaces worklist, call prep card appears inline, context panel auto-loads lead data
-
Unknown caller → call prep shows script for new caller
-
After disposition → returns to worklist view
-
Step 2: Remove old sidebar tab (Stats/AI) from call desk
Stats move into a collapsible section at the top of the main panel or into the top bar. AI is now always in the context panel.
- Step 3: Wire SIP call events to call desk state
When SIP ringing-in fires:
- Look up caller by phone number (from worklist data or platform query)
- If found → set active lead, show call prep with AI summary
- If not found → show unknown caller prep card
- Context panel auto-switches to lead 360 (if found) or AI assistant (if unknown)
- Step 4: Verify end-to-end flow
Manual test:
- Login as Rekha → call desk shows worklist with 4 leads
- Click Priya → context panel shows her lead 360 with AI summary
- Click "Call" on Priya → Ozonetel dials, SIP rings agent
- Call from unknown number → unknown caller prep card appears
- Step 5: Commit
git add src/pages/call-desk.tsx
git commit -m "feat: redesign call desk — 2-panel layout with inline AI"
Task 7: Final Integration Test
- Step 1: Run the AI flow test harness
cd helix-engage && npx tsx scripts/test-ai-flow.ts
Expected: ALL TESTS PASSED (steps 1-9)
- Step 2: Manual smoke test
- Login as Rekha (rekha.cc@globalhospital.com / Global@123)
- Sidebar collapses and expands correctly
- Call desk shows worklist with real platform data (4 assigned leads)
- Clicking a lead loads context panel with lead details
- AI assistant responds to queries with real platform data
- Click-to-call triggers Ozonetel dial API (SIP rings agent)
- Phone shows "Ready" status
- Step 3: Commit all remaining changes
git add -A
git commit -m "feat: complete call desk redesign — collapsible nav, 2-panel layout, inline AI, Ozonetel dial"