diff --git a/resources/js/admin/mobile/EventAnalyticsPage.tsx b/resources/js/admin/mobile/EventAnalyticsPage.tsx index 31c9d08..307321e 100644 --- a/resources/js/admin/mobile/EventAnalyticsPage.tsx +++ b/resources/js/admin/mobile/EventAnalyticsPage.tsx @@ -13,7 +13,7 @@ import { MobileCard, CTAButton, KpiTile, SkeletonCard } from './components/Primi import { getEventAnalytics, EventAnalytics } from '../api'; import { ApiError } from '../lib/apiError'; import { useAdminTheme } from './theme'; -import { resolveMaxCount } from './lib/analytics'; +import { resolveMaxCount, resolveTimelineHours } from './lib/analytics'; import { adminPath } from '../constants'; export default function MobileEventAnalyticsPage() { @@ -98,7 +98,7 @@ export default function MobileEventAnalyticsPage() { const hasTimeline = timeline.length > 0; const hasContributors = contributors.length > 0; const hasTasks = tasks.length > 0; - const timeframeHours = 12; + const timeframeHours = resolveTimelineHours(timeline.map((point) => point.timestamp), 12); // Prepare chart data const maxTimelineCount = resolveMaxCount(timeline.map((point) => point.count)); diff --git a/resources/js/admin/mobile/__tests__/analytics.test.ts b/resources/js/admin/mobile/__tests__/analytics.test.ts index e332270..9834085 100644 --- a/resources/js/admin/mobile/__tests__/analytics.test.ts +++ b/resources/js/admin/mobile/__tests__/analytics.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { resolveMaxCount } from '../lib/analytics'; +import { resolveMaxCount, resolveTimelineHours } from '../lib/analytics'; describe('resolveMaxCount', () => { it('defaults to 1 for empty input', () => { @@ -14,3 +14,20 @@ describe('resolveMaxCount', () => { expect(resolveMaxCount([0])).toBe(1); }); }); + +describe('resolveTimelineHours', () => { + it('uses fallback when data is missing', () => { + expect(resolveTimelineHours([], 12)).toBe(12); + }); + + it('calculates rounded hours from timestamps', () => { + const start = new Date('2024-01-01T10:00:00Z').toISOString(); + const end = new Date('2024-01-01T21:00:00Z').toISOString(); + expect(resolveTimelineHours([start, end], 12)).toBe(11); + }); + + it('never returns less than 1', () => { + const start = new Date('2024-01-01T10:00:00Z').toISOString(); + expect(resolveTimelineHours([start, start], 12)).toBe(1); + }); +}); diff --git a/resources/js/admin/mobile/lib/analytics.ts b/resources/js/admin/mobile/lib/analytics.ts index cf2e9b4..9af13b9 100644 --- a/resources/js/admin/mobile/lib/analytics.ts +++ b/resources/js/admin/mobile/lib/analytics.ts @@ -5,3 +5,24 @@ export function resolveMaxCount(values: number[]): number { return Math.max(...values, 1); } + +export function resolveTimelineHours(timestamps: string[], fallbackHours = 12): number { + if (!Array.isArray(timestamps) || timestamps.length < 2) { + return fallbackHours; + } + + const times = timestamps + .map((value) => new Date(value).getTime()) + .filter((value) => Number.isFinite(value)); + + if (times.length < 2) { + return fallbackHours; + } + + const min = Math.min(...times); + const max = Math.max(...times); + const diff = Math.max(0, max - min); + const hours = diff / (1000 * 60 * 60); + + return Math.max(1, Math.round(hours)); +}