mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
- 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>
320 lines
12 KiB
Markdown
320 lines
12 KiB
Markdown
# 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 added
|
|
- `src/ozonetel/ozonetel-agent.controller.ts` — ALREADY DONE: `POST /api/ozonetel/dial` endpoint added
|
|
|
|
### Frontend (helix-engage)
|
|
|
|
**Modified files:**
|
|
- `src/components/layout/sidebar.tsx` — Add collapse/expand toggle, icon-only mode
|
|
- `src/components/layout/app-shell.tsx` — Pass collapse state to sidebar, adjust main content margin
|
|
- `src/pages/call-desk.tsx` — Complete rewrite: 2-panel layout with worklist + context panel
|
|
- `src/components/call-desk/ai-chat-panel.tsx` — Move to context panel, full-height, always visible
|
|
- `src/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 leads
|
|
- `src/components/call-desk/context-panel.tsx` — Right panel: AI chat + lead 360 tabs
|
|
- `src/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**
|
|
|
|
```typescript
|
|
// 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 `collapsed` prop — 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 `sidebarCollapsedAtom` with `useAtom`
|
|
- 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**
|
|
|
|
```bash
|
|
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:
|
|
1. **Missed Calls** (red border) — from `useWorklist().missedCalls`
|
|
2. **Follow-ups Due** (amber/blue border) — from `useWorklist().followUps`
|
|
3. **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:
|
|
```typescript
|
|
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**
|
|
|
|
```bash
|
|
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:
|
|
```typescript
|
|
interface CallPrepCardProps {
|
|
lead: Lead | null;
|
|
callerPhone: string;
|
|
activities: LeadActivity[];
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Commit**
|
|
|
|
```bash
|
|
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**
|
|
|
|
```bash
|
|
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**
|
|
|
|
```bash
|
|
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:
|
|
1. Look up caller by phone number (from worklist data or platform query)
|
|
2. If found → set active lead, show call prep with AI summary
|
|
3. If not found → show unknown caller prep card
|
|
4. Context panel auto-switches to lead 360 (if found) or AI assistant (if unknown)
|
|
|
|
- [ ] **Step 4: Verify end-to-end flow**
|
|
|
|
Manual test:
|
|
1. Login as Rekha → call desk shows worklist with 4 leads
|
|
2. Click Priya → context panel shows her lead 360 with AI summary
|
|
3. Click "Call" on Priya → Ozonetel dials, SIP rings agent
|
|
4. Call from unknown number → unknown caller prep card appears
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
```bash
|
|
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**
|
|
|
|
```bash
|
|
cd helix-engage && npx tsx scripts/test-ai-flow.ts
|
|
```
|
|
|
|
Expected: ALL TESTS PASSED (steps 1-9)
|
|
|
|
- [ ] **Step 2: Manual smoke test**
|
|
|
|
1. Login as Rekha (rekha.cc@globalhospital.com / Global@123)
|
|
2. Sidebar collapses and expands correctly
|
|
3. Call desk shows worklist with real platform data (4 assigned leads)
|
|
4. Clicking a lead loads context panel with lead details
|
|
5. AI assistant responds to queries with real platform data
|
|
6. Click-to-call triggers Ozonetel dial API (SIP rings agent)
|
|
7. Phone shows "Ready" status
|
|
|
|
- [ ] **Step 3: Commit all remaining changes**
|
|
|
|
```bash
|
|
git add -A
|
|
git commit -m "feat: complete call desk redesign — collapsible nav, 2-panel layout, inline AI, Ozonetel dial"
|
|
```
|