(input: {
projectId: string;
startDate: string;
endDate: string;
steps: string[];
windowHours?: number;
groupBy?: 'session_id' | 'profile_id';
})
| 449 | import { getSettingsForProject } from './organization.service'; |
| 450 | |
| 451 | export async function getFunnelCore(input: { |
| 452 | projectId: string; |
| 453 | startDate: string; |
| 454 | endDate: string; |
| 455 | steps: string[]; |
| 456 | windowHours?: number; |
| 457 | groupBy?: 'session_id' | 'profile_id'; |
| 458 | }) { |
| 459 | const { timezone } = await getSettingsForProject(input.projectId); |
| 460 | const eventSeries = input.steps.map((name, index) => ({ |
| 461 | id: String(index + 1), |
| 462 | type: 'event' as const, |
| 463 | name, |
| 464 | displayName: name, |
| 465 | segment: 'user' as const, |
| 466 | filters: [], |
| 467 | })); |
| 468 | |
| 469 | const result = await funnelService.getFunnel({ |
| 470 | projectId: input.projectId, |
| 471 | startDate: input.startDate, |
| 472 | endDate: input.endDate, |
| 473 | series: eventSeries, |
| 474 | breakdowns: [], |
| 475 | chartType: 'funnel', |
| 476 | interval: 'day', |
| 477 | range: 'custom', |
| 478 | previous: false, |
| 479 | metric: 'sum', |
| 480 | options: { |
| 481 | type: 'funnel', |
| 482 | funnelWindow: input.windowHours ?? 24, |
| 483 | funnelGroup: input.groupBy ?? 'session_id', |
| 484 | }, |
| 485 | timezone, |
| 486 | }); |
| 487 | |
| 488 | const primarySeries = result[0]; |
| 489 | if (!primarySeries) { |
| 490 | return { |
| 491 | steps: [], |
| 492 | totalUsers: 0, |
| 493 | completedUsers: 0, |
| 494 | overallConversionRate: 0, |
| 495 | }; |
| 496 | } |
| 497 | |
| 498 | const steps = primarySeries.steps.map((step, index) => ({ |
| 499 | step: index + 1, |
| 500 | eventName: step.event.displayName || step.event.name, |
| 501 | users: step.count, |
| 502 | conversionRateFromStart: Math.round(step.percent * 100) / 100, |
| 503 | dropoffPercent: |
| 504 | step.dropoffPercent != null |
| 505 | ? Math.round(step.dropoffPercent * 100) / 100 |
| 506 | : null, |
| 507 | isHighestDropoff: step.isHighestDropoff, |
| 508 | })); |
no test coverage detected