mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 10:23:27 +00:00
192 lines
9.3 KiB
Markdown
192 lines
9.3 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:**
|
|
```bash
|
|
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 like `text-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:
|
|
1. **Sidecar** (REST) — for Ozonetel telephony operations and worklist
|
|
2. **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 in `src/lib/icon-wrapper.ts`
|
|
- **React Aria**: Always prefix imports (`Button as AriaButton`)
|
|
- **Transitions**: `transition duration-100 ease-linear`
|
|
|
|
## Git Workflow
|
|
|
|
- `dev` — active development
|
|
- `master` — stable baseline
|
|
- Always build with production env vars before deploying
|