added Patient info from Patient master
Helix Engage — Frontend
Call center CRM frontend for healthcare lead management. Built on the FortyTwo platform.
Owner: Mouli
Architecture
┌─────────────────────┐ ┌──────────────────────┐ ┌─────────────────────┐
│ helix-engage │ │ helix-engage-server │ │ FortyTwo Platform │
│ (this repo) │────▶│ (sidecar) │────▶│ (backend) │
│ React frontend │ │ NestJS REST API │ │ GraphQL API │
│ Port 5173 (dev) │ │ Port 4100 │ │ Port 4000 │
└─────────────────────┘ └──────────────────────┘ └─────────────────────┘
│ │
│ SIP/WebRTC │ Ozonetel CloudAgent APIs
▼ ▼
┌───────────┐ ┌──────────────┐
│ Ozonetel │ │ Ozonetel │
│ SIP (444) │ │ REST APIs │
└───────────┘ └──────────────┘
Three repos:
| Repo | Purpose | Owner |
|---|---|---|
helix-engage (this) |
React frontend | Mouli |
helix-engage-server |
NestJS sidecar — Ozonetel + Platform bridge | Karthik |
helix-engage-app |
FortyTwo SDK app — entity schemas (Call, Lead, etc.) | Shared |
Getting Started
npm install
npm run dev # http://localhost:5173
npm run build # TypeScript check + production build
Environment Variables (set at build time or in .env)
| Variable | Purpose | Dev Default | Production |
|---|---|---|---|
VITE_API_URL |
Platform GraphQL | http://localhost:4000 |
https://engage-api.srv1477139.hstgr.cloud |
VITE_SIDECAR_URL |
Sidecar REST API | http://localhost:4100 |
https://engage-api.srv1477139.hstgr.cloud |
VITE_SIP_URI |
Ozonetel SIP URI | — | sip:523590@blr-pub-rtc4.ozonetel.com |
VITE_SIP_PASSWORD |
SIP password | — | 523590 |
VITE_SIP_WS_SERVER |
SIP WebSocket | — | wss://blr-pub-rtc4.ozonetel.com:444 |
Production build command:
VITE_API_URL=https://engage-api.srv1477139.hstgr.cloud \
VITE_SIDECAR_URL=https://engage-api.srv1477139.hstgr.cloud \
VITE_SIP_URI=sip:523590@blr-pub-rtc4.ozonetel.com \
VITE_SIP_PASSWORD=523590 \
VITE_SIP_WS_SERVER=wss://blr-pub-rtc4.ozonetel.com:444 \
npm run build
Tech Stack
- React 19 + TypeScript + Vite
- Tailwind CSS 4 with semantic color tokens (
text-primary,bg-brand-section— never raw colors liketext-gray-900) - React Aria Components for accessibility (imports always prefixed
Aria*) - Jotai for SIP/call state
- React Context for auth, data, theme
- FontAwesome Pro Duotone icons
- Untitled UI component library (
src/components/base/,src/components/application/)
Project Structure
src/
├── pages/ # Route-level pages
│ ├── call-desk.tsx # Main CC agent workspace — THE CORE PAGE
│ ├── login.tsx # Auth page (centered card on blue bg)
│ ├── call-history.tsx # CDR log viewer
│ ├── my-performance.tsx # Agent KPI dashboard
│ ├── team-dashboard.tsx # Supervisor overview
│ ├── all-leads.tsx # Lead master table
│ └── campaigns.tsx # Campaign listing
│
├── components/
│ ├── call-desk/ # ⚡ Call center components — WHERE MOST WORK HAPPENS
│ │ ├── active-call-card.tsx # In-call UI + post-call disposition flow
│ │ ├── worklist-panel.tsx # Agent task queue with tabs + sub-tabs
│ │ ├── context-panel.tsx # AI assistant + Lead 360 sidebar
│ │ ├── disposition-form.tsx # Post-call outcome selector
│ │ ├── appointment-form.tsx # Book appointment during/after call
│ │ ├── agent-status-toggle.tsx # Ready/Break/Training/Offline toggle
│ │ ├── transfer-dialog.tsx # Call transfer
│ │ ├── enquiry-form.tsx # General enquiry capture
│ │ ├── live-transcript.tsx # Real-time transcription (Deepgram)
│ │ └── phone-action-cell.tsx # Click-to-call in table rows
│ ├── base/ # Untitled UI primitives (Button, Input, Select, Badge)
│ ├── application/ # Complex UI (Table, Modal, Tabs, DatePicker, Nav)
│ ├── layout/ # Sidebar — role-based navigation
│ └── dashboard/ # KPI cards, charts, missed queue widget
│
├── providers/
│ ├── sip-provider.tsx # SIP WebRTC — call lifecycle management
│ ├── auth-provider.tsx # User session, roles (executive/admin/cc-agent)
│ ├── data-provider.tsx # Bulk entity loader (leads, campaigns, calls)
│ └── theme-provider.tsx # Light/dark mode
│
├── hooks/
│ ├── use-worklist.ts # Polls sidecar /api/worklist every 30s
│ ├── use-call-assist.ts # Live transcript via Socket.IO
│ └── use-sip-phone.ts # Low-level SIP.js wrapper
│
├── lib/
│ ├── api-client.ts # REST + GraphQL client (auth, queries, sidecar calls)
│ ├── queries.ts # Platform GraphQL query strings
│ └── format.ts # Phone/date formatting
│
├── state/
│ └── sip-state.ts # Jotai atoms (callState, callerNumber, isMuted, etc.)
│
└── types/
└── entities.ts # Lead, Patient, Call, Appointment, etc.
Troubleshooting Guide — Where to Look
"The call desk isn't working"
File: src/pages/call-desk.tsx
This is the orchestrator. It uses useSip() for call state, useWorklist() for the task queue, and renders either ActiveCallCard (in-call) or WorklistPanel (idle). Start here, then drill into whichever child component is misbehaving.
"Calls aren't connecting / SIP errors"
File: src/providers/sip-provider.tsx + src/state/sip-state.ts
Check VITE_SIP_* env vars. Ozonetel SIP WebSocket runs on port 444 — VPNs block it. If WebSocket hangs at "connecting", turn off VPN. Also check browser console for SIP.js registration errors.
"Worklist not loading / empty"
File: src/hooks/use-worklist.ts
This polls GET /api/worklist on the sidecar every 30s. Open browser Network tab → filter for /api/worklist. Common causes: sidecar is down, auth token expired, or agent name doesn't match any assigned leads.
"Missed calls not appearing / sub-tabs empty"
File: src/components/call-desk/worklist-panel.tsx
Missed calls come from the sidecar worklist response. The sub-tabs filter by callbackstatus field. If all sub-tabs are empty, the sidecar ingestion may not be running (check sidecar logs for MissedQueueService).
"Disposition / appointment not saving"
File: src/components/call-desk/active-call-card.tsx → handleDisposition()
Posts to sidecar POST /api/ozonetel/dispose. Errors are caught silently (non-blocking). Check browser Network tab for the dispose request/response, then check sidecar logs.
"Login broken / Failed to fetch"
File: src/pages/login.tsx + src/lib/api-client.ts
Login calls apiClient.login() → sidecar /auth/login → platform GraphQL. Most common cause: wrong VITE_API_URL (built with localhost instead of production URL). Always set env vars at build time.
"UI component looks wrong"
Files: src/components/base/ (primitives), src/components/application/ (complex)
These come from the Untitled UI library. Design tokens are in src/styles/theme.css. Brand colors were rebuilt from logo blue rgb(32, 96, 160).
"Navigation / role-based access"
File: src/components/layout/sidebar.tsx
Navigation groups are defined per role (admin, cc-agent, executive). Routes are registered in src/main.tsx.
Data Flow
User action
│
▼
Component (e.g. ActiveCallCard)
│
├──▶ Sidecar REST API (via apiClient.post/get)
│ e.g. /api/ozonetel/dispose, /api/worklist
│
├──▶ Platform GraphQL (via apiClient.graphql)
│ e.g. leads, appointments, patients queries
│
└──▶ SIP.js (via useSip() hook)
Call control: answer, hangup, mute, hold
Key pattern: The frontend talks to TWO backends:
- Sidecar (REST) — for Ozonetel telephony operations and worklist
- Platform (GraphQL) — for entity CRUD (leads, appointments, patients)
Conventions
- File naming: kebab-case (
worklist-panel.tsx) - Colors: Semantic tokens only (
text-primary,bg-brand-section) - Icons:
@fortawesome/pro-duotone-svg-icons+faIcon()wrapper insrc/lib/icon-wrapper.ts - React Aria: Always prefix imports (
Button as AriaButton) - Transitions:
transition duration-100 ease-linear
Git Workflow
dev— active developmentmaster— stable baseline- Always build with production env vars before deploying