From 4b8479261926f2b9db4eeb661ded96fc48a5b14d Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Tue, 21 Apr 2026 13:08:59 +0530 Subject: [PATCH] fix: instant widget lead assignment + SSE notification Widget leads were invisible to agents for up to 90s (60s auto-assign poll + 30s worklist poll). Now triggers immediate auto-assign after lead creation and emits SSE worklistUpdate so agents see new widget leads and appointments instantly. Also excluded packages/ from tsconfig build to prevent widget source compilation errors. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/widget/widget.module.ts | 7 +++---- src/widget/widget.service.ts | 23 +++++++++++++++++++++++ tsconfig.build.json | 2 +- tsconfig.json | 2 +- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/widget/widget.module.ts b/src/widget/widget.module.ts index c841b52..3d4e738 100644 --- a/src/widget/widget.module.ts +++ b/src/widget/widget.module.ts @@ -7,12 +7,11 @@ import { PlatformModule } from '../platform/platform.module'; import { AuthModule } from '../auth/auth.module'; import { ConfigThemeModule } from '../config/config-theme.module'; import { CallerResolutionModule } from '../caller/caller-resolution.module'; +import { LeadsModule } from '../leads/leads.module'; +import { SupervisorModule } from '../supervisor/supervisor.module'; -// WidgetKeysService lives in ConfigThemeModule now — injected here via the -// module's exports. This module only owns the widget-facing API endpoints -// (init / chat / book / lead) plus the NestJS guards that consume the keys. @Module({ - imports: [PlatformModule, AuthModule, ConfigThemeModule, forwardRef(() => CallerResolutionModule)], + imports: [PlatformModule, AuthModule, ConfigThemeModule, forwardRef(() => CallerResolutionModule), LeadsModule, SupervisorModule], controllers: [WidgetController, WebhooksController], providers: [WidgetService, WidgetChatService], }) diff --git a/src/widget/widget.service.ts b/src/widget/widget.service.ts index bdf2846..41a0559 100644 --- a/src/widget/widget.service.ts +++ b/src/widget/widget.service.ts @@ -5,6 +5,8 @@ import type { WidgetInitResponse, WidgetBookRequest, WidgetLeadRequest } from '. import { ThemeService } from '../config/theme.service'; import { DOCTOR_VISIT_SLOTS_FRAGMENT, normalizeDoctors, type NormalizedDoctor } from '../shared/doctor-utils'; import { CallerResolutionService } from '../caller/caller-resolution.service'; +import { LeadAutoAssignService } from '../leads/lead-auto-assign.service'; +import { SupervisorService } from '../supervisor/supervisor.service'; // Dedup window: any lead created for this phone within the last 24h is // considered the same visitor's lead — chat + book + contact by the same @@ -27,6 +29,8 @@ export class WidgetService { private theme: ThemeService, private config: ConfigService, private caller: CallerResolutionService, + private autoAssign: LeadAutoAssignService, + private supervisor: SupervisorService, ) { this.apiKey = config.get('platform.apiKey') ?? ''; } @@ -274,6 +278,13 @@ export class WidgetService { const reference = appt.createAppointment.id.substring(0, 8).toUpperCase(); this.logger.log(`Widget booking: ${req.patientName} → ${req.doctorId} at ${req.scheduledAt} (ref: ${reference})`); + // Emit SSE so agents see the new appointment immediately + this.supervisor.emitWorklistUpdate({ + type: 'widget-appointment', + callerPhone: this.normalizePhone(req.patientPhone), + callerName: req.patientName, + }); + return { appointmentId: appt.createAppointment.id, reference }; } @@ -284,6 +295,18 @@ export class WidgetService { interestedService: req.interest ?? 'Website Enquiry', }); this.logger.log(`Widget contact: ${req.name} (${this.normalizePhone(req.phone)}) — ${req.interest ?? 'general'}`); + + // Trigger immediate auto-assign + SSE so agent sees the lead instantly + this.autoAssign.runOnce().then((result) => { + if (result.assigned > 0) { + this.supervisor.emitWorklistUpdate({ + type: 'widget-lead', + callerPhone: this.normalizePhone(req.phone), + callerName: req.name, + }); + } + }).catch(() => {}); + return { leadId }; } } diff --git a/tsconfig.build.json b/tsconfig.build.json index b9d2a4a..785cc68 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "widget-src", "public", "data", "**/*spec.ts"] + "exclude": ["node_modules", "test", "dist", "widget-src", "packages", "public", "data", "**/*spec.ts"] } diff --git a/tsconfig.json b/tsconfig.json index 8b6cc70..6b889f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,5 +22,5 @@ "strictBindCallApply": true, "noFallthroughCasesInSwitch": true }, - "exclude": ["widget-src", "public", "data"] + "exclude": ["widget-src", "packages", "public", "data"] }