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();
}}
/>