forked from vergnet/site-accueil-insa
358 lines
10 KiB
TypeScript
358 lines
10 KiB
TypeScript
/*!
|
|
* Matomo - free/libre analytics platform
|
|
*
|
|
* @link https://matomo.org
|
|
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*/
|
|
|
|
import {
|
|
reactive,
|
|
computed,
|
|
readonly,
|
|
} from 'vue';
|
|
import {
|
|
AjaxHelper,
|
|
translate,
|
|
Site,
|
|
} from 'CoreHome';
|
|
|
|
interface SiteWithMetrics extends Site {
|
|
label: string;
|
|
nb_actions: string|number;
|
|
nb_pageviews: string|number;
|
|
nb_visits: string|number;
|
|
pageviews_evolution: string;
|
|
revenue: string;
|
|
revenue_evolution: string;
|
|
visits_evolution: string;
|
|
ratio?: number|string;
|
|
previous_nb_visits?: string|number;
|
|
previous_Actions_nb_pageviews?: string|number;
|
|
previous_Goal_revenue?: string|number;
|
|
currencySymbol: string;
|
|
periodName: string;
|
|
previousRange: string;
|
|
tooltip?: string;
|
|
}
|
|
|
|
interface SiteTotals {
|
|
nb_actions: string|number;
|
|
nb_pageviews: string|number;
|
|
nb_visits: string|number;
|
|
nb_visits_lastdate: string|number;
|
|
revenue: string|number;
|
|
}
|
|
|
|
interface DashboardStoreState {
|
|
sites: SiteWithMetrics[];
|
|
isLoading: boolean;
|
|
pageSize: number;
|
|
currentPage: number;
|
|
totalVisits: string|number;
|
|
totalPageviews: string|number;
|
|
totalActions: string|number;
|
|
totalRevenue: string|number;
|
|
searchTerm: string;
|
|
lastVisits: string|number;
|
|
lastVisitsDate: string;
|
|
numberOfSites: number;
|
|
loadingMessage: string;
|
|
reverse: boolean;
|
|
sortColumn: string;
|
|
refreshInterval?: number;
|
|
errorLoadingSites: boolean;
|
|
}
|
|
|
|
interface GetAllWithGroupsResponse {
|
|
lastDate: string;
|
|
numSites: number;
|
|
sites: SiteWithMetrics[];
|
|
totals: SiteTotals;
|
|
}
|
|
|
|
const { NumberFormatter } = window;
|
|
|
|
class DashboardStore {
|
|
private privateState = reactive<DashboardStoreState>({
|
|
sites: [],
|
|
isLoading: false,
|
|
pageSize: 25,
|
|
currentPage: 0,
|
|
totalVisits: '?',
|
|
totalPageviews: '?',
|
|
totalActions: '?',
|
|
totalRevenue: '?',
|
|
searchTerm: '',
|
|
lastVisits: '?',
|
|
lastVisitsDate: '?',
|
|
numberOfSites: 0,
|
|
loadingMessage: translate('MultiSites_LoadingWebsites'),
|
|
reverse: true,
|
|
sortColumn: 'nb_visits',
|
|
refreshInterval: 0,
|
|
errorLoadingSites: false,
|
|
});
|
|
|
|
private refreshTimeout: ReturnType<typeof setTimeout>|null = null;
|
|
|
|
private fetchAbort: AbortController|null = null;
|
|
|
|
readonly state = computed(() => readonly(this.privateState));
|
|
|
|
readonly numberOfFilteredSites = computed(() => this.state.value.numberOfSites);
|
|
|
|
readonly numberOfPages = computed(
|
|
() => Math.ceil(this.numberOfFilteredSites.value / this.state.value.pageSize - 1),
|
|
);
|
|
|
|
readonly currentPagingOffset = computed(
|
|
() => Math.ceil(this.state.value.currentPage * this.state.value.pageSize),
|
|
);
|
|
|
|
readonly paginationLowerBound = computed(() => this.currentPagingOffset.value + 1);
|
|
|
|
readonly paginationUpperBound = computed(() => {
|
|
let end = this.currentPagingOffset.value + this.state.value.pageSize;
|
|
const max = this.numberOfFilteredSites.value;
|
|
|
|
if (end > max) {
|
|
end = max;
|
|
}
|
|
|
|
return end;
|
|
});
|
|
|
|
cancelRefereshInterval(): void {
|
|
if (this.refreshTimeout) {
|
|
clearTimeout(this.refreshTimeout);
|
|
this.refreshTimeout = null;
|
|
}
|
|
}
|
|
|
|
updateWebsitesList(report: GetAllWithGroupsResponse): void {
|
|
if (!report) {
|
|
this.onError();
|
|
return;
|
|
}
|
|
|
|
const allSites = report.sites;
|
|
allSites.forEach((site) => {
|
|
if (site.ratio !== 1 && site.ratio !== '1') {
|
|
const percent = NumberFormatter.formatPercent(
|
|
Math.round(parseInt(site.ratio! as string, 10) * 100),
|
|
);
|
|
|
|
let metricName = null;
|
|
let previousTotal = '0';
|
|
let currentTotal = '0';
|
|
let evolution = '0';
|
|
let previousTotalAdjusted = '0';
|
|
|
|
if (this.state.value.sortColumn === 'nb_visits'
|
|
|| this.state.value.sortColumn === 'visits_evolution'
|
|
) {
|
|
previousTotal = NumberFormatter.formatNumber(site.previous_nb_visits);
|
|
currentTotal = NumberFormatter.formatNumber(site.nb_visits);
|
|
evolution = NumberFormatter.formatPercent(site.visits_evolution);
|
|
metricName = translate('General_ColumnNbVisits');
|
|
previousTotalAdjusted = NumberFormatter.formatNumber(
|
|
Math.round(parseInt(site.previous_nb_visits as string, 10)
|
|
* parseInt(site.ratio as string, 10)),
|
|
);
|
|
}
|
|
|
|
if (this.state.value.sortColumn === 'pageviews_evolution') {
|
|
previousTotal = `${site.previous_Actions_nb_pageviews}`;
|
|
currentTotal = `${site.nb_pageviews}`;
|
|
evolution = NumberFormatter.formatPercent(site.pageviews_evolution);
|
|
metricName = translate('General_ColumnPageviews');
|
|
previousTotalAdjusted = NumberFormatter.formatNumber(
|
|
Math.round(parseInt(site.previous_Actions_nb_pageviews as string, 10)
|
|
* parseInt(site.ratio as string, 10)),
|
|
);
|
|
}
|
|
|
|
if (this.state.value.sortColumn === 'revenue_evolution') {
|
|
previousTotal = NumberFormatter.formatCurrency(
|
|
site.previous_Goal_revenue,
|
|
site.currencySymbol,
|
|
);
|
|
currentTotal = NumberFormatter.formatCurrency(site.revenue, site.currencySymbol);
|
|
evolution = NumberFormatter.formatPercent(site.revenue_evolution);
|
|
metricName = translate('General_ColumnRevenue');
|
|
previousTotalAdjusted = NumberFormatter.formatCurrency(
|
|
Math.round(parseInt(site.previous_Goal_revenue as string, 10)
|
|
* parseInt(site.ratio as string, 10)),
|
|
site.currencySymbol,
|
|
);
|
|
}
|
|
|
|
if (metricName) {
|
|
site.tooltip = `${translate('MultiSites_EvolutionComparisonIncomplete', [percent])}\n`;
|
|
site.tooltip += `${translate('MultiSites_EvolutionComparisonProportional', [
|
|
percent,
|
|
`${previousTotalAdjusted}`,
|
|
metricName,
|
|
`${previousTotal}`,
|
|
])}\n`;
|
|
|
|
switch (site.periodName) {
|
|
case 'day':
|
|
site.tooltip += translate('MultiSites_EvolutionComparisonDay', [
|
|
`${currentTotal}`,
|
|
metricName,
|
|
`${previousTotalAdjusted}`,
|
|
site.previousRange,
|
|
`${evolution}`,
|
|
]);
|
|
break;
|
|
|
|
case 'week':
|
|
site.tooltip += translate('MultiSites_EvolutionComparisonWeek', [
|
|
`${currentTotal}`,
|
|
metricName,
|
|
`${previousTotalAdjusted}`,
|
|
site.previousRange,
|
|
`${evolution}`,
|
|
]);
|
|
break;
|
|
|
|
case 'month':
|
|
site.tooltip += translate('MultiSites_EvolutionComparisonMonth', [
|
|
`${currentTotal}`,
|
|
metricName,
|
|
`${previousTotalAdjusted}`,
|
|
site.previousRange,
|
|
`${evolution}`,
|
|
]);
|
|
break;
|
|
|
|
case 'year':
|
|
site.tooltip += translate('MultiSites_EvolutionComparisonYear', [
|
|
`${currentTotal}`,
|
|
metricName,
|
|
`${previousTotalAdjusted}`,
|
|
site.previousRange,
|
|
`${evolution}`,
|
|
]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
this.privateState.totalVisits = report.totals.nb_visits;
|
|
this.privateState.totalPageviews = report.totals.nb_pageviews;
|
|
this.privateState.totalActions = report.totals.nb_actions;
|
|
this.privateState.totalRevenue = report.totals.revenue;
|
|
this.privateState.lastVisits = report.totals.nb_visits_lastdate;
|
|
this.privateState.sites = allSites;
|
|
this.privateState.numberOfSites = report.numSites;
|
|
this.privateState.lastVisitsDate = report.lastDate;
|
|
}
|
|
|
|
sortBy(metric: string): void {
|
|
if (this.state.value.sortColumn === metric) {
|
|
this.privateState.reverse = !this.state.value.reverse;
|
|
}
|
|
|
|
this.privateState.sortColumn = metric;
|
|
this.fetchAllSites();
|
|
}
|
|
|
|
previousPage(): void {
|
|
this.privateState.currentPage = this.state.value.currentPage - 1;
|
|
this.fetchAllSites();
|
|
}
|
|
|
|
nextPage(): void {
|
|
this.privateState.currentPage = this.state.value.currentPage + 1;
|
|
this.fetchAllSites();
|
|
}
|
|
|
|
searchSite(term: string): void {
|
|
this.privateState.searchTerm = term;
|
|
this.privateState.currentPage = 0;
|
|
this.fetchAllSites();
|
|
}
|
|
|
|
fetchAllSites(): Promise<void> {
|
|
if (this.fetchAbort) {
|
|
this.fetchAbort.abort();
|
|
this.fetchAbort = null;
|
|
|
|
this.cancelRefereshInterval();
|
|
}
|
|
|
|
this.privateState.isLoading = true;
|
|
this.privateState.errorLoadingSites = false;
|
|
const params: QueryParameters = {
|
|
method: 'MultiSites.getAllWithGroups',
|
|
hideMetricsDoc: '1',
|
|
filter_sort_order: 'asc',
|
|
filter_limit: this.state.value.pageSize,
|
|
filter_offset: this.currentPagingOffset.value,
|
|
showColumns: [
|
|
'label',
|
|
'nb_visits',
|
|
'nb_pageviews',
|
|
'visits_evolution',
|
|
'visits_evolution_trend',
|
|
'pageviews_evolution',
|
|
'pageviews_evolution_trend',
|
|
'revenue_evolution',
|
|
'revenue_evolution_trend',
|
|
'nb_actions,revenue',
|
|
].join(','),
|
|
};
|
|
|
|
if (this.privateState.searchTerm) {
|
|
params.pattern = this.privateState.searchTerm;
|
|
}
|
|
|
|
if (this.privateState.sortColumn) {
|
|
params.filter_sort_column = this.privateState.sortColumn;
|
|
}
|
|
|
|
if (this.privateState.reverse) {
|
|
params.filter_sort_order = 'desc';
|
|
}
|
|
|
|
this.fetchAbort = new AbortController();
|
|
return AjaxHelper.fetch<GetAllWithGroupsResponse>(
|
|
params,
|
|
{ abortController: this.fetchAbort },
|
|
).then((response) => {
|
|
this.updateWebsitesList(response);
|
|
}).catch(() => {
|
|
this.onError();
|
|
}).finally(() => {
|
|
this.privateState.isLoading = false;
|
|
this.fetchAbort = null;
|
|
|
|
if (this.state.value.refreshInterval && this.state.value.refreshInterval > 0) {
|
|
this.cancelRefereshInterval();
|
|
this.refreshTimeout = setTimeout(() => {
|
|
this.refreshTimeout = null;
|
|
this.fetchAllSites();
|
|
}, this.state.value.refreshInterval! * 1000);
|
|
}
|
|
});
|
|
}
|
|
|
|
private onError(): void {
|
|
this.privateState.errorLoadingSites = true;
|
|
this.privateState.sites = [];
|
|
}
|
|
|
|
setRefreshInterval(interval?: number): void {
|
|
this.privateState.refreshInterval = interval;
|
|
}
|
|
|
|
setPageSize(pageSize: number): void {
|
|
this.privateState.pageSize = pageSize;
|
|
}
|
|
}
|
|
|
|
export default new DashboardStore();
|