add tests to dashboard

This commit is contained in:
Ronni Skansing
2025-08-30 18:02:07 +02:00
parent 7ad60ebecd
commit e089e0cc7d
5 changed files with 161 additions and 36 deletions
+15 -2
View File
@@ -74,6 +74,15 @@ const appendQuery = (query) => {
if (query.search) {
urlQuery += `&search=${query.search}`;
}
// Handle additional parameters
const knownParams = ['currentPage', 'perPage', 'page', 'sortBy', 'sortOrder', 'search'];
for (const [key, value] of Object.entries(query)) {
if (!knownParams.includes(key) && value !== undefined && value !== null) {
urlQuery += `&${key}=${encodeURIComponent(value)}`;
}
}
return urlQuery;
};
/**
@@ -648,8 +657,12 @@ export class API {
* Get campaigns stats
* if no company ID is provided it retrieves the global stats including all companies
*/
getStats: async (companyID = null) => {
return await getJSON(this.getPath(`/campaign/statistics?${this.companyQuery(companyID)}`));
getStats: async (companyID = null, options = {}) => {
return await getJSON(
this.getPath(
`/campaign/statistics?${appendQuery(options)}${this.appendCompanyQuery(companyID)}`
)
);
},
/**
+91 -12
View File
@@ -22,6 +22,7 @@
import CampaignCalender from '$lib/components/CampaignCalendar.svelte';
import CampaignTrendChart from '$lib/components/CampaignTrendChart.svelte';
import { fetchAllRows } from '$lib/utils/api-utils';
import { tick } from 'svelte';
// services
const appStateService = AppStateService.instance;
@@ -67,6 +68,17 @@
let calendarStartDate = null;
let calendarEndDate = null;
// Toggle for including test campaigns
let includeTestCampaigns = false;
// Handler for when toggle changes
const handleToggleChange = async () => {
// Wait for binding to update
await tick();
// Refresh all data with new toggle state
await refresh(false);
};
// hooks
onMount(() => {
const context = appStateService.getContext();
@@ -91,7 +103,9 @@
if (showLoading) {
showIsLoading();
}
let res = await api.campaign.getStats(contextCompanyID);
let res = await api.campaign.getStats(contextCompanyID, {
includeTest: includeTestCampaigns
});
if (!res.success) {
throw res.error;
}
@@ -124,7 +138,7 @@
const a = api.campaign.getWithinDates(
calendarStartDate.toISOString(),
calendarEndDate.toISOString(),
options,
{ ...options, includeTest: includeTestCampaigns },
contextCompanyID
);
return a;
@@ -142,7 +156,15 @@
isActiveCampaignsLoading = true;
}
try {
const res = await api.campaign.getAllActive(activeTableURLParams, contextCompanyID);
const options = {
page: activeTableURLParams.currentPage,
perPage: activeTableURLParams.perPage,
sortBy: activeTableURLParams.sortBy,
sortOrder: activeTableURLParams.sortOrder,
search: activeTableURLParams.search,
includeTest: includeTestCampaigns
};
const res = await api.campaign.getAllActive(options, contextCompanyID);
if (!res.success) {
throw res.error;
}
@@ -162,7 +184,15 @@
isUpcomingCampaignsLoading = true;
}
try {
const res = await api.campaign.getAllUpcoming(scheduledTableURLParams, contextCompanyID);
const options = {
page: scheduledTableURLParams.currentPage,
perPage: scheduledTableURLParams.perPage,
sortBy: scheduledTableURLParams.sortBy,
sortOrder: scheduledTableURLParams.sortOrder,
search: scheduledTableURLParams.search,
includeTest: includeTestCampaigns
};
const res = await api.campaign.getAllUpcoming(options, contextCompanyID);
if (!res.success) {
throw res.error;
}
@@ -182,7 +212,15 @@
isFinishedCampaignsLoading = true;
}
try {
const res = await api.campaign.getAllFinished(completedTableURLParams, contextCompanyID);
const options = {
page: completedTableURLParams.currentPage,
perPage: completedTableURLParams.perPage,
sortBy: completedTableURLParams.sortBy,
sortOrder: completedTableURLParams.sortOrder,
search: completedTableURLParams.search,
includeTest: includeTestCampaigns
};
const res = await api.campaign.getAllFinished(options, contextCompanyID);
if (!res.success) {
throw res.error;
}
@@ -220,7 +258,15 @@
sortOrder: 'desc',
perPage: 10
});
const res = await api.campaign.getAllCampaignStats(statsParams, contextCompanyID);
const options = {
page: statsParams.currentPage,
perPage: statsParams.perPage,
sortBy: statsParams.sortBy,
sortOrder: statsParams.sortOrder,
search: statsParams.search,
includeTest: includeTestCampaigns
};
const res = await api.campaign.getAllCampaignStats(options, contextCompanyID);
if (!res.success) {
throw res.error;
}
@@ -245,17 +291,50 @@
<main>
<div class="flex justify-between">
<Headline>Dashboard</Headline>
<AutoRefresh
isLoading={false}
onRefresh={async () => {
await refresh(false);
}}
/>
<div class="flex gap-4 items-center">
<label class="flex items-center gap-2 text-sm">
<input
type="checkbox"
bind:checked={includeTestCampaigns}
on:change={handleToggleChange}
class="rounded"
/>
Include test campaigns
</label>
<AutoRefresh
isLoading={false}
onRefresh={async () => {
await refresh(false);
}}
/>
</div>
</div>
{#if contextCompanyName}
<SubHeadline>{contextCompanyName}</SubHeadline>
{/if}
{#if includeTestCampaigns}
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-3 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
<path
fill-rule="evenodd"
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
clip-rule="evenodd"
/>
</svg>
</div>
<div class="ml-3">
<p class="text-sm text-yellow-800">
<strong>Test campaigns included:</strong> The dashboard is currently showing both production
and test campaigns.
</p>
</div>
</div>
</div>
{/if}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8 mt-4">
<a href="/campaign">
<StatsCard