saridsa2 8470dd03c7 fix: UI polish — nav labels, date picker, rules engine, error messages
- Sidebar: removed "Master" from nav labels (Leads, Patients, Appointments, Call Log)
- Appointment form: Dept + Doctor in 2-col row, Date below, disabled cascade
- DatePicker: placement="bottom start" + shouldFlip fixes popover positioning
- Team Performance: default to "Week", grid KPI cards, chart legend spacing
- Rules Engine: manual save (removed auto-debounce), Reset to Defaults uses
  DEFAULT_PRIORITY_CONFIG (no template endpoint), removed dead saveTimerRef
- Automation rules: 6 showcase cards with trigger/condition/action, replaced
  agent-specific rule with generic round-robin
- Recording analysis: friendly error message with retry instead of raw Deepgram error
- Sidebar active/hover: brand color reference for theming

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:55:16 +05:30

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 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.tsxhandleDisposition() 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
Description
No description provided
Readme 3.4 MiB
Languages
TypeScript 96.1%
CSS 3.8%