From cd3baf028b25c4e584f5c59442f7eb2a7fa4e55f Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Wed, 17 Sep 2025 23:43:59 +0200 Subject: [PATCH] fix dashboard scroll to top issue Signed-off-by: Ronni Skansing --- .../lib/components/CampaignTrendChart.svelte | 17 ++-- frontend/src/routes/dashboard/+page.svelte | 88 ++++++++++++++++++- 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/frontend/src/lib/components/CampaignTrendChart.svelte b/frontend/src/lib/components/CampaignTrendChart.svelte index 2c22f40..d812857 100644 --- a/frontend/src/lib/components/CampaignTrendChart.svelte +++ b/frontend/src/lib/components/CampaignTrendChart.svelte @@ -58,6 +58,7 @@ } let chartContainer; + let sizingContainer; let width = 300; let height = 200; // Balanced height to prevent overflow let containerReady = false; @@ -777,9 +778,9 @@ } onMount(async () => { - if (chartContainer) { - await tick(); // Wait for DOM/layout - const containerWidth = chartContainer.clientWidth || 0; + await tick(); // Wait for DOM/layout + if (sizingContainer) { + const containerWidth = sizingContainer.parentElement?.clientWidth || 0; width = Math.min(Math.max(containerWidth, 300), containerWidth); // Minimum 300px but never exceed container if (width > 0) containerReady = true; resizeObserver = new ResizeObserver((entries) => { @@ -791,13 +792,13 @@ } } }); - resizeObserver.observe(chartContainer); + resizeObserver.observe(sizingContainer.parentElement || sizingContainer); } }); onDestroy(() => { - if (resizeObserver && chartContainer) { - resizeObserver.unobserve(chartContainer); + if (resizeObserver && sizingContainer) { + resizeObserver.unobserve(sizingContainer.parentElement || sizingContainer); } if (loadingTimeout) { clearTimeout(loadingTimeout); @@ -814,9 +815,9 @@
- + diff --git a/frontend/src/routes/dashboard/+page.svelte b/frontend/src/routes/dashboard/+page.svelte index b3ac2f4..e09f9e3 100644 --- a/frontend/src/routes/dashboard/+page.svelte +++ b/frontend/src/routes/dashboard/+page.svelte @@ -88,9 +88,9 @@ contextCompanyName = context.companyName; } refresh(); - activeTableURLParams.onChange(refreshActiveCampaigns); - scheduledTableURLParams.onChange(refreshScheduledCampaigns); - completedTableURLParams.onChange(refreshFinishedCampaigns); + activeTableURLParams.onChange(() => refreshActiveCampaigns(true)); + scheduledTableURLParams.onChange(() => refreshScheduledCampaigns(true)); + completedTableURLParams.onChange(() => refreshFinishedCampaigns(true)); return () => { activeTableURLParams.unsubscribe(); @@ -305,7 +305,87 @@ { - await refresh(false); + // refresh all data + let res = await api.campaign.getStats(contextCompanyID, { + includeTest: includeTestCampaigns + }); + if (!res.success) { + throw res.error; + } + await refreshRepeatOffenders(); + + active = res.data.active; + scheduled = res.data.upcoming; + finished = res.data.finished; + + // refresh table data directly like campaign page does + const activeOptions = { + page: activeTableURLParams.currentPage, + perPage: activeTableURLParams.perPage, + sortBy: activeTableURLParams.sortBy, + sortOrder: activeTableURLParams.sortOrder, + search: activeTableURLParams.search, + includeTest: includeTestCampaigns + }; + const activeRes = await api.campaign.getAllActive(activeOptions, contextCompanyID); + if (activeRes.success) { + activeCampaigns = []; + await tick(); + activeCampaigns = activeRes.data.rows; + } + + const scheduledOptions = { + page: scheduledTableURLParams.currentPage, + perPage: scheduledTableURLParams.perPage, + sortBy: scheduledTableURLParams.sortBy, + sortOrder: scheduledTableURLParams.sortOrder, + search: scheduledTableURLParams.search, + includeTest: includeTestCampaigns + }; + const scheduledRes = await api.campaign.getAllUpcoming( + scheduledOptions, + contextCompanyID + ); + if (scheduledRes.success) { + scheduledCampaigns = []; + await tick(); + scheduledCampaigns = scheduledRes.data.rows; + } + + const completedOptions = { + page: completedTableURLParams.currentPage, + perPage: completedTableURLParams.perPage, + sortBy: completedTableURLParams.sortBy, + sortOrder: completedTableURLParams.sortOrder, + search: completedTableURLParams.search, + includeTest: includeTestCampaigns + }; + const completedRes = await api.campaign.getAllFinished( + completedOptions, + contextCompanyID + ); + if (completedRes.success) { + completedCampaigns = []; + await tick(); + completedCampaigns = completedRes.data.rows; + } + + const statsOptions = { + page: 1, + perPage: 10, + sortBy: 'campaign_closed_at', + sortOrder: 'desc', + search: '', + includeTest: includeTestCampaigns + }; + const statsRes = await api.campaign.getAllCampaignStats(statsOptions, contextCompanyID); + if (statsRes.success) { + campaignStats = []; + await tick(); + campaignStats = statsRes.data.rows || []; + } + + await refreshCalendarCampaings(); }} />