diff --git a/frontend/src/lib/components/CampaignTrendChart.svelte b/frontend/src/lib/components/CampaignTrendChart.svelte index 0831cb6..5780769 100644 --- a/frontend/src/lib/components/CampaignTrendChart.svelte +++ b/frontend/src/lib/components/CampaignTrendChart.svelte @@ -21,30 +21,10 @@ export let isLoading = false; export let onCampaignClick = (campaignId) => {}; - // Debounced loading state to prevent flash - let debouncedIsLoading = false; - let loadingTimeout; let hasAttemptedLoad = false; - const LOADING_DEBOUNCE_MS = 0; // show loading immediately - $: { - if (isLoading) { - // Mark that we've attempted to load - hasAttemptedLoad = true; - // Start showing loading after a delay - if (!loadingTimeout) { - loadingTimeout = setTimeout(() => { - debouncedIsLoading = true; - }, LOADING_DEBOUNCE_MS); - } - } else { - // Immediately hide loading and clear timeout - if (loadingTimeout) { - clearTimeout(loadingTimeout); - loadingTimeout = null; - } - debouncedIsLoading = false; - } + $: if (isLoading) { + hasAttemptedLoad = true; } // localStorage keys for persisting chart settings @@ -311,22 +291,6 @@ }; })(); - // Update chartData to use filteredCampaignStats, using sendStartAt as date, and sort by date ascending - $: chartData = filteredCampaignStats - .filter((c) => { - if (!c.campaignStartDate && !c.createdAt) { - console.warn('Skipping campaign stat with missing dates in chart data:', c); - return false; - } - return true; - }) - .map((c) => ({ - ...c, - date: c.campaignStartDate ? new Date(c.campaignStartDate) : new Date(c.createdAt), - name: c.campaignName || c.name || c.title || '' - })) - .sort((a, b) => a.date.getTime() - b.date.getTime()); - // --- Force chart rerender --- let chartKey = ''; $: chartKey = chartData @@ -725,6 +689,18 @@ const clampedValue = Math.max(0, Math.min(100, point[metric.key] || 0)); const y = yScale(clampedValue); + // Glow circle rendered behind main point + const glow = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); + glow.setAttribute('cx', x.toString()); + glow.setAttribute('cy', y.toString()); + glow.setAttribute('r', '8'); + glow.setAttribute('fill', metric.color); + glow.setAttribute('opacity', '0.2'); + glow.setAttribute('class', `chart-point-glow chart-point-glow-${metric.key}`); + glow.setAttribute('data-index', i.toString()); + glow.style.pointerEvents = 'none'; + svg.appendChild(glow); + // Main circle const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('cx', x.toString()); @@ -1149,7 +1125,7 @@ const metricValue = document.createElement('span'); metricValue.className = 'text-sm font-semibold ml-auto'; metricValue.style.color = metric.color; - metricValue.textContent = Math.round(data[metric.key] || 0).toString(); + metricValue.textContent = Math.round(data[metric.key] || 0) + '%'; metricLeft.appendChild(metricDot); metricLeft.appendChild(metricLabel); @@ -1239,9 +1215,6 @@ if (themeObserver) { themeObserver.disconnect(); } - if (loadingTimeout) { - clearTimeout(loadingTimeout); - } if (tooltipTimeout) { clearTimeout(tooltipTimeout); } @@ -1265,7 +1238,7 @@ class="chart-container w-full overflow-x-auto" style="height:0;overflow:hidden;visibility:hidden;position:absolute;" > - {#if isLoading || debouncedIsLoading} + {#if isLoading}
{:else}
- {#if hasAttemptedLoad && !isLoading && !debouncedIsLoading && campaignStats.length < 2} + {#if hasAttemptedLoad && !isLoading && campaignStats.length < 2}
@@ -1366,7 +1339,7 @@ > Trendline N: Moving Avg N: - No trendline stats to dsplay (trendStats is null or not enough data). + No trendline stats to display (trendStats is null or not enough data).
{/if}
@@ -1475,7 +1448,10 @@