fix: Replace unsafe .toFixed() calls with safeFixed() in analytics views

- AnalyticsView: avg_players, uptime_percentage
- WipeAnalyticsView: success_rate, population curve, durations, CSV export
- PlayerRetentionView: retention percentages, session duration, tooltip
- MapAnalyticsView: rotation effectiveness, performance metrics, table

All analytics views now use safe formatter utilities with optional chaining
to prevent null/undefined runtime errors when displaying numeric data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell
2026-02-15 21:56:04 -05:00
parent daa9c3035f
commit 26e717ac96
18 changed files with 111 additions and 53 deletions

View File

@@ -5,6 +5,7 @@ import * as echarts from 'echarts'
import type { ECharts } from 'echarts'
import { useApi } from '@/composables/useApi'
import type { MapAnalyticsSummary } from '@/types'
import { safeFixed } from '@/utils/formatters'
const api = useApi()
@@ -112,9 +113,9 @@ const downloadCSV = () => {
m.map_name,
m.seed ?? 'N/A',
m.times_used,
m.avg_players.toFixed(1),
safeFixed(m.avg_players, 1),
m.peak_players,
m.effectiveness_score.toFixed(1)
safeFixed(m.effectiveness_score, 1)
])
const csv = [headers.join(','), ...rows.map(r => r.join(','))].join('\n')
@@ -183,7 +184,7 @@ onMounted(() => {
{{ analytics.best_performing_map ?? 'No data' }}
</p>
<p class="text-xs text-neutral-600 mt-1" v-if="analytics.maps.length > 0">
Avg {{ analytics.maps[0]?.avg_players.toFixed(1) }} players
Avg {{ safeFixed(analytics?.maps?.[0]?.avg_players, 1) }} players
</p>
</div>
@@ -193,7 +194,7 @@ onMounted(() => {
<p class="text-sm text-neutral-400">Rotation Effectiveness</p>
</div>
<p class="text-xl font-bold text-neutral-100">
{{ analytics.rotation_effectiveness.toFixed(1) }}%
{{ safeFixed(analytics?.rotation_effectiveness, 1) }}%
</p>
<p class="text-xs text-neutral-600 mt-1">Overall rotation health</p>
</div>
@@ -245,7 +246,7 @@ onMounted(() => {
<td class="py-3 px-4 text-neutral-200 font-medium">{{ map.map_name }}</td>
<td class="py-3 px-4 text-neutral-400">{{ map.seed ?? '—' }}</td>
<td class="py-3 px-4 text-right text-neutral-300">{{ map.times_used }}</td>
<td class="py-3 px-4 text-right text-neutral-300">{{ map.avg_players.toFixed(1) }}</td>
<td class="py-3 px-4 text-right text-neutral-300">{{ safeFixed(map.avg_players, 1) }}</td>
<td class="py-3 px-4 text-right text-neutral-300">{{ map.peak_players }}</td>
<td class="py-3 px-4 text-right">
<span
@@ -256,7 +257,7 @@ onMounted(() => {
'bg-red-500/10 text-red-400': map.effectiveness_score < 60
}"
>
{{ map.effectiveness_score.toFixed(1) }}%
{{ safeFixed(map.effectiveness_score, 1) }}%
</span>
</td>
</tr>