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>
This commit is contained in:
2026-03-24 22:03:48 +05:30
parent ae94a390df
commit 488f524f84
21 changed files with 462 additions and 107 deletions

View File

@@ -8,6 +8,7 @@ const LinkExternal01: FC<{ className?: string }> = ({ className }) => <FontAweso
import { Button } from '@/components/base/buttons/button';
import { CampaignStatusBadge } from '@/components/shared/status-badge';
import { formatDateOnly } from '@/lib/format';
import type { Campaign } from '@/types/entities';
interface CampaignHeroProps {
@@ -15,12 +16,9 @@ interface CampaignHeroProps {
}
const formatDateRange = (startDate: string | null, endDate: string | null): string => {
const fmt = (d: string) =>
new Intl.DateTimeFormat('en-IN', { month: 'short', day: 'numeric', year: 'numeric' }).format(new Date(d));
if (!startDate) return '--';
if (!endDate) return `${fmt(startDate)} \u2014 Ongoing`;
return `${fmt(startDate)} \u2014 ${fmt(endDate)}`;
if (!endDate) return `${formatDateOnly(startDate)} \u2014 Ongoing`;
return `${formatDateOnly(startDate)} \u2014 ${formatDateOnly(endDate)}`;
};
const formatDuration = (startDate: string | null, endDate: string | null): string => {