mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: build all data pages — worklist table, call history, patients, dashboard, reports
Worklist (call-desk): - Upgrade to Untitled UI Table with columns: Priority, Patient, Phone, Type, SLA, Actions - Filter tabs: All Tasks / Missed Calls / Callbacks / Follow-ups with counts - Search by name or phone - SLA timer color-coded: green <15m, amber <30m, red >30m Call History: - Full table: Type (direction icon), Patient (matched from leads), Phone, Duration, Outcome, Agent, Recording (play/pause), Time - Search + All/Inbound/Outbound/Missed filter - Recording playback via native <audio> Patients: - New page with table: Patient (avatar+name+age), Contact, Type, Gender, Status, Actions - Search + status filter - Call + View Details actions - Added patients to DataProvider + transforms + queries - Route /patients added, sidebar nav updated for cc-agent + executive Supervisor Dashboard: - KPI cards: Total Calls, Inbound, Outbound, Missed - Performance metrics: Avg Response Time, Callback Time, Conversion % - Agent performance table with per-agent stats - Missed Call Queue - AI Assistant section - Day/Week/Month filter Reports: - ECharts bar chart: Call Volume Trend (7-day, Inbound vs Outbound) - ECharts donut chart: Call Outcomes (Booked, Follow-up, Info, Missed) - KPI cards with trend indicators (+/-%) - Route /reports, sidebar Analytics → /reports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
341
docs/superpowers/plans/2026-03-19-data-pages.md
Normal file
341
docs/superpowers/plans/2026-03-19-data-pages.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# Data Pages — Table Views, Dashboard, Reports
|
||||
|
||||
> **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:** Build all missing data presentation pages using Untitled UI Table component and Apache ECharts. Transform card-based views into proper sortable/filterable tables. Add supervisor dashboard with KPIs and reports with charts.
|
||||
|
||||
**Architecture:** All data comes from the platform via the DataProvider (already wired). Pages use the Untitled UI `Table` and `TableCard` components for consistent table presentation. Charts use `echarts-for-react`. Each page is a separate route — no shared state beyond DataProvider.
|
||||
|
||||
**Tech Stack:** React 19, Untitled UI Table (`src/components/application/table/table.tsx`), Apache ECharts (`echarts-for-react`), Jotai, existing DataProvider + apiClient pattern
|
||||
|
||||
**Deployed at:** https://engage.srv1477139.hstgr.cloud
|
||||
**Sidecar:** https://engage-api.srv1477139.hstgr.cloud
|
||||
**Platform:** https://fortytwo-dev.srv1477139.hstgr.cloud
|
||||
|
||||
---
|
||||
|
||||
## Important Context
|
||||
|
||||
### Untitled UI Table API
|
||||
```tsx
|
||||
import { Table, TableCard } from '@/components/application/table/table';
|
||||
import { TableBody } from 'react-aria-components';
|
||||
|
||||
<TableCard.Root size="sm">
|
||||
<TableCard.Header title="Worklist" badge={count} description="..." contentTrailing={<Button>...</Button>} />
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Head label="PATIENT" />
|
||||
<Table.Head label="PHONE" />
|
||||
</Table.Header>
|
||||
<Table.Body items={data}>
|
||||
{(item) => (
|
||||
<Table.Row id={item.id}>
|
||||
<Table.Cell>{item.name}</Table.Cell>
|
||||
<Table.Cell>{item.phone}</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</TableCard.Root>
|
||||
```
|
||||
|
||||
### Data Sources (all from DataProvider)
|
||||
- `leads` — Lead[] with contactName, contactPhone, status, source, aiSummary, etc.
|
||||
- `calls` — Call[] with direction, callStatus, durationSeconds, agentName, disposition, startedAt
|
||||
- `campaigns` — Campaign[] with metrics (impressions, clicks, converted, budget)
|
||||
- `followUps` — FollowUp[] with type, status, scheduledAt, priority
|
||||
- `leadActivities` — LeadActivity[] with activityType, summary, occurredAt
|
||||
- `ads` — Ad[] linked to campaigns
|
||||
|
||||
### Existing Pages (routes in main.tsx)
|
||||
- `/` — RoleRouter (redirects based on role)
|
||||
- `/leads` — AllLeadsPage
|
||||
- `/campaigns` — CampaignsPage
|
||||
- `/campaigns/:id` — CampaignDetailPage
|
||||
- `/outreach` — OutreachPage
|
||||
- `/follow-ups` — FollowUpsPage
|
||||
- `/call-history` — CallHistoryPage
|
||||
- `/call-desk` — CallDeskPage (2-panel with worklist + AI)
|
||||
- `/team-dashboard` — TeamDashboardPage
|
||||
- `/patient/:id` — Patient360Page
|
||||
|
||||
### Sidebar Navigation (by role)
|
||||
**admin:** Team Dashboard, Campaigns, Analytics, Integrations, Settings
|
||||
**cc-agent:** Call Desk, Follow-ups, Call History
|
||||
**executive:** Lead Workspace, All Leads, Campaigns, Outreach, Analytics
|
||||
|
||||
### API Pattern
|
||||
```tsx
|
||||
// All data fetched silently via DataProvider on mount
|
||||
const { leads, calls, followUps, campaigns, leadActivities, loading } = useData();
|
||||
// For sidecar-specific data:
|
||||
const worklist = apiClient.get<WorklistData>('/api/worklist');
|
||||
```
|
||||
|
||||
### Platform Field Mapping (SDK → Platform)
|
||||
- Lead: leadSource→source, leadStatus→status, firstContactedAt→firstContacted, lastContactedAt→lastContacted
|
||||
- Call: callDirection→direction, durationSeconds→durationSec
|
||||
- Campaign: campaignType→typeCustom, campaignStatus→status, impressionCount→impressions
|
||||
- FollowUp: followUpType→typeCustom, followUpStatus→status
|
||||
- Appointment: appointmentStatus→status, durationMinutes→durationMin
|
||||
|
||||
### Deploy Pattern
|
||||
```bash
|
||||
# Build frontend
|
||||
cd helix-engage
|
||||
VITE_API_URL=https://engage-api.srv1477139.hstgr.cloud \
|
||||
VITE_SIP_URI=sip:523590@blr-pub-rtc4.ozonetel.com \
|
||||
VITE_SIP_PASSWORD=Test123$ \
|
||||
VITE_SIP_WS_SERVER=wss://blr-pub-rtc4.ozonetel.com:444 \
|
||||
npm run build
|
||||
|
||||
# Upload to VPS
|
||||
scp -r -i /Users/satyasumansaridae/Downloads/fortytwoai_hostinger \
|
||||
dist/* root@148.230.67.184:/opt/fortytwo/helix-engage-frontend/
|
||||
|
||||
# Build + push sidecar (if sidecar changes)
|
||||
cd helix-engage-server && npm run build
|
||||
docker build --platform linux/amd64 -t 043728036361.dkr.ecr.ap-south-1.amazonaws.com/fortytwo-eap/helix-engage-sidecar:alpha .
|
||||
docker save 043728036361.dkr.ecr.ap-south-1.amazonaws.com/fortytwo-eap/helix-engage-sidecar:alpha | \
|
||||
ssh -i /Users/satyasumansaridae/Downloads/fortytwoai_hostinger root@148.230.67.184 "docker load"
|
||||
ssh -i /Users/satyasumansaridae/Downloads/fortytwoai_hostinger root@148.230.67.184 \
|
||||
"cd /opt/fortytwo && docker compose up -d --force-recreate sidecar"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Worklist Table Page
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/pages/call-desk.tsx` — keep the 2-panel layout but upgrade worklist to table
|
||||
- Modify: `src/components/call-desk/worklist-panel.tsx` — replace card list with Table component
|
||||
|
||||
The call desk's left panel worklist should use the Table component. Columns:
|
||||
- Priority (color badge: HIGH/MEDIUM/LOW/URGENT)
|
||||
- Patient name + age (e.g. "Priya Sharma · 1h ago")
|
||||
- Phone
|
||||
- Direction (icon: inbound/outbound)
|
||||
- Type (Missed Call / Callback / Follow-up / Lead)
|
||||
- Reason (truncated summary)
|
||||
- SLA timer (computed: time since created, color-coded green/amber/red)
|
||||
- Task State (PENDING/ATTEMPTED/SCHEDULED)
|
||||
- Actions (Call button + dismiss)
|
||||
|
||||
Filter tabs: All Tasks | Missed Calls | Callbacks | Follow-ups (with counts)
|
||||
Filter toggle: All / Inbound / Outbound
|
||||
Search: by patient name or phone
|
||||
|
||||
Data source: `useWorklist()` hook (sidecar `/api/worklist`)
|
||||
|
||||
- [ ] **Step 1:** Rewrite `worklist-panel.tsx` using `Table` + `TableCard` components
|
||||
- [ ] **Step 2:** Add filter tabs and search
|
||||
- [ ] **Step 3:** Add SLA timer computation (minutes since created, color thresholds: <15m green, <30m amber, >30m red)
|
||||
- [ ] **Step 4:** Type check and verify
|
||||
- [ ] **Step 5:** Commit
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Call History Table Page
|
||||
|
||||
**Files:**
|
||||
- Rewrite: `src/pages/call-history.tsx`
|
||||
- Modify: `src/lib/queries.ts` — add CALLS query if not already fetching all fields
|
||||
|
||||
Full call history table. Columns:
|
||||
- Type (inbound/outbound icon)
|
||||
- Patient (matched lead name or "Unknown")
|
||||
- Phone
|
||||
- Duration (formatted: 5m 12s)
|
||||
- Outcome (disposition badge: Appointment Booked, Follow-up Scheduled, Info Provided, Missed, No Answer)
|
||||
- Agent
|
||||
- Recording (Play button — uses `recordingUrl` from webhook data)
|
||||
- Time (formatted datetime)
|
||||
- Actions (View Details link)
|
||||
|
||||
Features:
|
||||
- Search by patient name or phone
|
||||
- Filter dropdown: All Calls / Inbound / Outbound / Missed
|
||||
- Sort by time (default: newest first)
|
||||
|
||||
Data source: `useData().calls` from DataProvider
|
||||
|
||||
- [ ] **Step 1:** Rewrite `call-history.tsx` with Table component
|
||||
- [ ] **Step 2:** Add search + filter dropdown
|
||||
- [ ] **Step 3:** Add recording playback (native `<audio>` element in a popover or inline)
|
||||
- [ ] **Step 4:** Type check and verify
|
||||
- [ ] **Step 5:** Commit
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Patients Listing Page
|
||||
|
||||
**Files:**
|
||||
- Create: `src/pages/patients.tsx`
|
||||
- Modify: `src/lib/queries.ts` — add PATIENTS_QUERY to DataProvider if not fetched
|
||||
- Modify: `src/providers/data-provider.tsx` — fetch patients
|
||||
- Modify: `src/main.tsx` — add `/patients` route
|
||||
|
||||
Patient table. Columns:
|
||||
- Patient (name + age/gender)
|
||||
- Contact (phone + email)
|
||||
- Location (from address field if available)
|
||||
- Last Visit (from appointments — most recent completed)
|
||||
- Next Appt (from appointments — next scheduled)
|
||||
- Status (active/inactive badge)
|
||||
- Actions (Call button + View Details link to `/patient/:id`)
|
||||
|
||||
Features:
|
||||
- Search by name or phone
|
||||
- Filter by status (active/inactive)
|
||||
- "Add Patient" button (opens modal or navigates to form)
|
||||
|
||||
Data source: Need to add patients to DataProvider. Query: `{ patients(first: 50) { edges { node { id name fullName phones emails dateOfBirth gender patientType } } } }`
|
||||
|
||||
- [ ] **Step 1:** Add patients to DataProvider + queries + transforms
|
||||
- [ ] **Step 2:** Create `patients.tsx` page with Table
|
||||
- [ ] **Step 3:** Add search + filter
|
||||
- [ ] **Step 4:** Add route to main.tsx and sidebar nav
|
||||
- [ ] **Step 5:** Type check and verify
|
||||
- [ ] **Step 6:** Commit
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Supervisor Dashboard
|
||||
|
||||
**Files:**
|
||||
- Rewrite: `src/pages/team-dashboard.tsx`
|
||||
|
||||
This is the admin/supervisor view. Sections:
|
||||
|
||||
**4a. KPI Cards (top row)**
|
||||
- Total Calls (count from calls array)
|
||||
- Inbound (filtered count)
|
||||
- Outbound (filtered count)
|
||||
- Missed (filtered count)
|
||||
|
||||
**4b. Performance Metrics (second row)**
|
||||
- Avg Lead Response Time (computed from lead firstContacted - createdAt)
|
||||
- Missed Callback Time (avg time since missed calls)
|
||||
- Call → Appointment % (calls with disposition APPOINTMENT_BOOKED / total)
|
||||
- Lead → Appointment % (leads with status APPOINTMENT_SET or CONVERTED / total)
|
||||
|
||||
**4c. Agent Performance Table**
|
||||
Columns: Agent, Calls (In/Out/Missed), Avg Handle Time, Conversion %, Active/Idle
|
||||
|
||||
Data: Aggregate calls by agentName, compute per-agent metrics
|
||||
|
||||
**4d. Missed Call Queue**
|
||||
List of recent missed calls with phone, age, priority
|
||||
|
||||
**4e. Supervisor AI Assistant**
|
||||
Reuse existing AiChatPanel with supervisor-specific quick prompts:
|
||||
- "Which agents have the highest conversions?"
|
||||
- "How many leads are pending contact?"
|
||||
- "Top missed callback risks?"
|
||||
|
||||
Data source: `useData().calls`, `useData().leads`, computed aggregations
|
||||
|
||||
- [ ] **Step 1:** Build KPI card component (reusable)
|
||||
- [ ] **Step 2:** Build agent performance table
|
||||
- [ ] **Step 3:** Build missed call queue section
|
||||
- [ ] **Step 4:** Add AI assistant section
|
||||
- [ ] **Step 5:** Wire Day/Week/Month filter (client-side date filtering)
|
||||
- [ ] **Step 6:** Type check and verify
|
||||
- [ ] **Step 7:** Commit
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Reports Page
|
||||
|
||||
**Files:**
|
||||
- Create: `src/pages/reports.tsx`
|
||||
- Modify: `src/main.tsx` — add `/reports` route (or reuse `/analytics`)
|
||||
|
||||
Charts page using Apache ECharts.
|
||||
|
||||
**5a. KPI Cards (top row)**
|
||||
- Total Calls (with +X% trend vs previous period)
|
||||
- Inbound
|
||||
- Outbound
|
||||
- Conversion %
|
||||
|
||||
**5b. Call Volume Trend (bar chart)**
|
||||
- X axis: days of week (Mon-Sun) or last 7/30 days
|
||||
- Y axis: call count
|
||||
- Two series: Inbound (gray) + Outbound (blue)
|
||||
- Use `echarts-for-react` with bar chart type
|
||||
|
||||
**5c. Call Outcomes (donut chart)**
|
||||
- Segments: Booked, Follow-up, Info Only, Missed
|
||||
- Computed from call dispositions
|
||||
- Center label: total count
|
||||
|
||||
Data source: `useData().calls` aggregated by date and disposition
|
||||
|
||||
ECharts pattern:
|
||||
```tsx
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
|
||||
const option = {
|
||||
xAxis: { type: 'category', data: ['Mon', 'Tue', ...] },
|
||||
yAxis: { type: 'value' },
|
||||
series: [
|
||||
{ name: 'Inbound', type: 'bar', data: [...] },
|
||||
{ name: 'Outbound', type: 'bar', data: [...] },
|
||||
],
|
||||
};
|
||||
|
||||
<ReactECharts option={option} style={{ height: 400 }} />
|
||||
```
|
||||
|
||||
- [ ] **Step 1:** Build KPI cards with trend indicators
|
||||
- [ ] **Step 2:** Build Call Volume Trend bar chart
|
||||
- [ ] **Step 3:** Build Call Outcomes donut chart
|
||||
- [ ] **Step 4:** Wire date range filter
|
||||
- [ ] **Step 5:** Add route to main.tsx and sidebar nav
|
||||
- [ ] **Step 6:** Type check and verify
|
||||
- [ ] **Step 7:** Commit
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Live Call Monitoring (Supervisor)
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/dashboard/live-calls-panel.tsx`
|
||||
- Modify: `src/pages/team-dashboard.tsx` — add live calls section
|
||||
|
||||
This requires real-time data from Ozonetel. Two approaches:
|
||||
|
||||
**Option A: Polling** — hit Ozonetel's agent status API every 10 seconds
|
||||
**Option B: WebSocket** — if Ozonetel exposes real-time WebSocket feeds
|
||||
|
||||
For MVP, use polling via the sidecar:
|
||||
- New sidecar endpoint: `GET /api/agents/live` — queries Ozonetel for current agent states
|
||||
- Returns: `[{ agentId, name, status, currentCall: { phone, duration, direction } }]`
|
||||
|
||||
The live calls panel shows:
|
||||
- Agent name + phone number + Inbound/Outbound badge
|
||||
- Call duration (live timer)
|
||||
- Whisper button (joins call silently — needs Ozonetel conference API)
|
||||
- Barge-in button (joins call audibly — needs Ozonetel conference API)
|
||||
|
||||
**NOTE:** Whisper/Barge-in require Ozonetel's conference/monitor APIs which may have the same auth issue as the dial API. Research needed.
|
||||
|
||||
- [ ] **Step 1:** Research Ozonetel live agent status API
|
||||
- [ ] **Step 2:** Create sidecar endpoint `GET /api/agents/live`
|
||||
- [ ] **Step 3:** Build `live-calls-panel.tsx` with polling
|
||||
- [ ] **Step 4:** Add to supervisor dashboard
|
||||
- [ ] **Step 5:** Research whisper/barge-in APIs
|
||||
- [ ] **Step 6:** Implement whisper/barge-in buttons (if API available)
|
||||
- [ ] **Step 7:** Commit
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Deploy and Verify
|
||||
|
||||
- [ ] **Step 1:** Build frontend with production env vars
|
||||
- [ ] **Step 2:** Upload to VPS
|
||||
- [ ] **Step 3:** Rebuild sidecar if changed, push to VPS
|
||||
- [ ] **Step 4:** Test all pages as each role (admin, cc-agent, executive)
|
||||
- [ ] **Step 5:** Commit all changes
|
||||
Reference in New Issue
Block a user