Commit Graph

29 Commits

Author SHA1 Message Date
c4b6f9a438 fix: 5 bug fixes — #533 #531 #529 #527 #547
#533: Remove redundant Call History top header (duplicate TopBar)
#531: Block logout during active call (confirm dialog + UCID check)
#529: Block outbound calls when agent is on Break/Training
#527: Remove updatePatient during appointment creation (was mutating
      shared Patient entity, affecting all past appointments)
#547: SLA rules seeded via API (config issue, not code)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:26:55 +05:30
0fc9375729 fix: prevent SIP disconnect during active call
disconnectSip() now guards against disconnect when outboundPending
or outboundActive is true. Accepts force=true for intentional
disconnects (logout, page unload, component unmount). Prevents
React re-render cycles from killing the SIP WebSocket mid-dial,
which was causing the call to drop and disposition modal to not appear.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:20:46 +05:30
6a2fc47226 fix: SIP disconnect on callState change + dispose sends agentId
- Fixed useEffect dependency bug: callState in deps caused cleanup
  (disconnectSip) to fire on every state transition, killing SIP
  mid-dial. Now uses useRef for callState in beforeunload handler
  with empty deps array — cleanup only fires on unmount.
- sendBeacon auto-dispose now includes agentId from agent config
- Disposition modal submit now includes agentId from agent config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:49:34 +05:30
fb92da113e fix: setup wizard role guard, Doctor.clinic removal, dial sends agent config
Defect 1: Setup wizard (/setup) now guarded by AdminSetupGuard —
CC agents and other non-admin roles are redirected to / instead of
seeing the setup wizard they can't complete.

Defect 3: Removed all references to Doctor.clinic (relation was
replaced by DoctorVisitSlot entity). Updated queries.ts,
appointments.tsx, transforms.ts, doctors.tsx, appointment-form.tsx.

Defect 6 (frontend side): Dial request now sends agentId and
campaignName from localStorage agent config so the sidecar dials
with the correct per-agent credentials, not global defaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:29:32 +05:30
72012f099c fix: three-layer ACW protection — prevent agent stuck in wrapping-up
Root cause: when an agent refreshes the page during or after a call,
the React state (UCID, callState, disposition modal) is wiped. The
SIP BYE event fires but no component exists to trigger the disposition
modal → no POST to /api/ozonetel/dispose → agent stuck in ACW.

Layer 1 (beforeunload warning):
  Shows browser's native "Leave page?" dialog during active calls.
  Agent can cancel and stay.

Layer 2 (sendBeacon auto-dispose):
  UCID persisted to localStorage when call activates. On page unload,
  navigator.sendBeacon fires /api/ozonetel/dispose with
  CALLBACK_REQUESTED. Guaranteed delivery even during page death.
  Cleared from localStorage when disposition modal submits normally.

Layer 3 lives in helix-engage-server (separate commit).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 12:31:45 +05:30
afd0829dc6 feat: design tokens — multi-hospital theming system
Backend (sidecar):
- ThemeService: read/write/backup/reset theme.json with versioning
- ThemeController: GET/PUT/POST /api/config/theme endpoints
- ConfigThemeModule registered in app

Frontend:
- ThemeTokenProvider: fetches theme, injects CSS variables on <html>
- Login page: logo, title, subtitle, Google/forgot toggles from tokens
- Sidebar: title, subtitle, active highlight from brand color scale
- AI chat: quick actions from tokens
- Branding settings page: 2-column layout, file upload for logo/favicon,
  single color picker with palette generation, font dropdowns, presets,
  pinned footer, versioning

Theme CSS:
- Sidebar active/hover text now references --color-brand-400

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:50:36 +05:30
c3c3f4b3d7 feat: worklist sorting, contextual disposition, context panel redesign, notifications
- Worklist default sort descending (newest first), sortable column headers (PRIORITY, PATIENT, SLA) via React Aria
- Contextual disposition: auto-selects based on in-call actions (appointment → APPOINTMENT_BOOKED, enquiry → INFO_PROVIDED, transfer → FOLLOW_UP_SCHEDULED)
- Context panel redesign: collapsible AI Insight, Upcoming (appointments + follow-ups + linked patient), Recent (calls + activities) sections; auto-collapse on AI chat start
- Appointments added to DataProvider with APPOINTMENTS_QUERY, Appointment type, transform
- Notification bell for admin/supervisor: performance alerts (idle time, NPS, conversion thresholds) with toast on load + bell dropdown with dismiss; demo alerts as fallback
- Slideout z-index fix: added z-50 to slideout ModalOverlay matching modal component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:45:52 +05:30
daa2fbb0c2 fix: SIP driven by Agent entity, token refresh, network indicator
- SIP connection only for users with Agent entity (no env var fallback)
- Supervisor no longer intercepts CC agent calls
- Auth controller checks Agent entity for ALL roles, not just cc-agent
- Token refresh handles GraphQL UNAUTHENTICATED errors (200 with error body)
- Token refresh handles sidecar 400s from expired upstream tokens
- Network quality indicator in sidebar (offline/unstable/good)
- Ozonetel IDLE event mapped to ready state (fixes stuck calling after canceled call)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:44:48 +05:30
488f524f84 feat: SSE agent state, UCID fix, maint module, QA bug fixes
- Fix outbound disposition: store UCID from dial API response (root cause of silent disposition failure)
- SSE agent state: real-time Ozonetel state drives status toggle (ready/break/calling/in-call/acw)
- Maint module with OTP-protected endpoints (force-ready, unlock-agent, backfill, fix-timestamps)
- Maint OTP modal with PinInput component, keyboard shortcuts (Ctrl+Shift+R/U/B/T)
- Force-logout via SSE: admin unlock pushes force-logout to connected browsers
- Silence JsSIP debug flood, add structured lifecycle logging ([SIP], [DIAL], [DISPOSE], [AGENT-STATE])
- Centralize date formatting with IST-aware formatters across 11 files
- Fix call history: non-overlapping aggregates (completed/missed), correct timestamp display
- Auto-dismiss CallWidget ended/failed state after 3 seconds
- Remove floating "Helix Phone" idle badge from all pages
- Fix dead code in agent-state endpoint (auto-assign was unreachable after return)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:44:48 +05:30
710609dfee refactor: centralise outbound dial into useSip().dialOutbound()
- Single dialOutbound() in sip-provider handles all outbound state:
  callState, callerNumber, outboundPending, API call, error recovery
- ClickToCallButton, PhoneActionCell, Dialler all use dialOutbound()
- Removed direct Jotai atom manipulation from calling components
- Removed setOutboundPending imports from components
- SIP disconnects on provider unmount + auth logout
- Dialler input is now editable (type or numpad)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:49:10 +05:30
13e81ba9fb fix: await logout before navigating, prevent cancelled fetch
- Logout is now async — awaits sidecar /auth/logout before clearing tokens
- confirmSignOut awaits logout() before navigate('/login')
- 5 second timeout on logout fetch to prevent indefinite hang
- Added console.warn on logout failure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 15:22:39 +05:30
3afa4f20b2 feat: dynamic SIP from agentConfig, logout cleanup, heartbeat
- SIP provider reads credentials from agentConfig (login response)
- Auth logout calls sidecar to unlock Redis + Ozonetel logout
- AppShell heartbeat every 5 min for CC agents
- Login stores agentConfig in localStorage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 21:24:47 +05:30
d6ef2b70d8 feat: track UCID from SIP headers for Ozonetel disposition
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:33:46 +05:30
edd2aa689d feat: post-call workflow — disposition, appointment booking, follow-up creation
ActiveCallCard now handles the full post-call flow:
- Call ends → Disposition form appears (6 options + notes)
- "Appointment Booked" → Opens appointment booking slideout
- "Follow-up Needed" → Auto-creates follow-up in platform
- Other dispositions → Logs call and returns to worklist
- "Book Appt" button available during active call too
- Creates Call record in platform on disposition submit
- Removed auto-reset to idle (ActiveCallCard manages lifecycle)
- "Back to Worklist" resets SIP state via Jotai atoms

Also fixes:
- All 7 GraphQL queries corrected (LINKS subfields, field renames)
- Campaign edit button moved to bottom-right
- Avg Response Time uses Math.abs for seed data edge case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:24:46 +05:30
567f9f2d72 feat: agent detail page, campaign edit slideout, integration config, auth persistence
Agent Detail (/agent/:id):
- Individual agent performance page with KPI cards + call log table
- Clickable agent names in dashboard table link to detail view
- Back button to Team Dashboard

Campaign Edit Slideout:
- Edit button on each campaign card
- Slideout with name, status, budget, dates
- Saves via updateCampaign GraphQL mutation

Integration Config Slideout:
- Configure button on each integration card
- Per-integration form fields (Ozonetel, WhatsApp, Facebook, etc.)
- Copy webhook URL, OAuth placeholder buttons

Auth Persistence:
- User data persisted to localStorage on login
- Session restored on page refresh — no more logout on F5
- Stale tokens cleaned up automatically

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:32:58 +05:30
4c6cae9d65 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>
2026-03-19 12:26:13 +05:30
526ad18159 feat: call desk redesign — 2-panel layout, collapsible sidebar, inline AI, ringtone
- 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>
2026-03-18 18:33:36 +05:30
61901eb8fb feat: wire frontend to platform data, migrate to Jotai + Vercel AI SDK
- Replace mock DataProvider with real GraphQL queries through sidecar
- Add queries.ts and transforms.ts for platform field name mapping
- Migrate SIP state from React Context to Jotai atoms (React 19 compat)
- Add singleton SIP manager to survive StrictMode remounts
- Remove hardcoded Olivia/Sienna accounts from nav menu
- Add password eye toggle, remember me checkbox, forgot password link
- Fix worklist hook to transform platform field names
- Add seed scripts for clinics, health packages, lab tests
- Update test harness for new doctor→clinic relation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:44:45 +05:30
66ad398b81 feat: wire real auth — login returns user profile with role from platform, remove mock users and role selector tabs 2026-03-18 10:42:54 +05:30
125aeae41c fix: prevent duplicate SIP registration (module-level guard), extract real caller number from X-CALLERNO header 2026-03-18 08:33:45 +05:30
dfc4a0cd44 fix: move Ozonetel agent login to sidecar auth flow — frontend only handles SIP, sidecar handles REST login 2026-03-18 07:43:29 +05:30
36b3a5d34d feat: Ozonetel SIP integration — agent login, SIP registration, inbound call flow working
Known issues to fix:
- Must refresh page after each call (SIP session not resetting to idle properly)
- Decline/reject call not working
- Caller ID shows DID instead of original caller (Ozonetel IVR config issue with call:cid)
- Socket.IO reconnect noise in console (sidecar not running)
2026-03-17 21:20:32 +05:30
d54d54f5f3 fix: prevent StrictMode double-mount from killing SIP WebSocket connection 2026-03-17 20:08:22 +05:30
b2cc3d7012 feat: add floating call widget with SIP controls, click-to-call, and SIP provider
Introduce a shared SipProvider context so all components use the same SIP
connection. Add a floating CallWidget (idle pill, ringing, active with
disposition, ended states) visible for CC agents on every page. Add a
ClickToCallButton for the worklist. Wire SIP status badge and worklist
into the call-desk page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:08:46 +05:30
45bae9c1c0 chore: rename Ramaiah Memorial Hospital to Global Hospital
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 08:59:13 +05:30
26c352e2cc feat: 3-role auth, role-based routing, role-specific sidebar navigation
Add cc-agent role alongside executive and admin. Login page now has 3 tabs
(Marketing Executive, Call Center, Admin). RoleRouter renders the appropriate
home page per role. Sidebar shows completely different nav items per role with
role subtitle. Placeholder pages added for Team Dashboard, Call Desk, Call
History, and Follow-ups.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:24:25 +05:30
530dfa1aa4 feat: add Call, LeadIngestionSource types and mock data, AI fields on leads
- Add CallDirection, CallStatus, CallDisposition, Call types to entities.ts
- Add IntegrationStatus, AuthStatus, IngestionPlatform, LeadIngestionSource types
- Add aiSummary and aiSuggestedAction fields to Lead type
- Create src/mocks/calls.ts with 15 INBOUND COMPLETED calls across 3 agents
- Create src/mocks/ingestion-sources.ts with 6 integration sources (ACTIVE/WARNING/ERROR)
- Update mockLeads with AI summaries on ~20 leads (new, contacted, spam cohorts)
- Expose calls, ingestionSources, and addCall() in DataContext

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 18:20:41 +05:30
dc68577477 feat: add auth and data providers with mock data hooks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 14:34:23 +05:30
3a338b33dd chore: initial Untitled UI Vite scaffold with FontAwesome Pro 2026-03-16 14:23:23 +05:30