mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-12-21 10:57:08 +00:00
Fuse v12.0.0
This commit is contained in:
@@ -0,0 +1,676 @@
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { ApexOptions } from 'ng-apexcharts';
|
||||
import { AnalyticsService } from 'app/modules/admin/dashboards/analytics/analytics.service';
|
||||
|
||||
@Component({
|
||||
selector : 'analytics',
|
||||
templateUrl : './analytics.component.html',
|
||||
encapsulation : ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AnalyticsComponent implements OnInit, OnDestroy
|
||||
{
|
||||
chartVisitors: ApexOptions;
|
||||
chartConversions: ApexOptions;
|
||||
chartImpressions: ApexOptions;
|
||||
chartVisits: ApexOptions;
|
||||
chartVisitorsVsPageViews: ApexOptions;
|
||||
data: any;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
chartAge: ApexOptions;
|
||||
averagePurchaseValueOptions: ApexOptions;
|
||||
browsersOptions: ApexOptions;
|
||||
channelsOptions: ApexOptions;
|
||||
devicesOptions: ApexOptions;
|
||||
chartGender: ApexOptions;
|
||||
chartLanguage: ApexOptions;
|
||||
chartNewVsReturning: ApexOptions;
|
||||
refundsOptions: ApexOptions;
|
||||
totalVisitsOptions: ApexOptions;
|
||||
uniqueVisitorsOptions: ApexOptions;
|
||||
uniquePurchasesOptions: ApexOptions;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(
|
||||
private _analyticsService: AnalyticsService,
|
||||
private _router: Router
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Get the data
|
||||
this._analyticsService.data$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((data) => {
|
||||
|
||||
// Store the data
|
||||
this.data = data;
|
||||
|
||||
// Prepare the chart data
|
||||
this._prepareChartData();
|
||||
});
|
||||
|
||||
// Attach SVG fill fixer to all ApexCharts
|
||||
window['Apex'] = {
|
||||
chart: {
|
||||
events: {
|
||||
mounted: (chart: any, options?: any) => {
|
||||
this._fixSvgFill(chart.el);
|
||||
},
|
||||
updated: (chart: any, options?: any) => {
|
||||
this._fixSvgFill(chart.el);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* On destroy
|
||||
*/
|
||||
ngOnDestroy(): void
|
||||
{
|
||||
// Unsubscribe from all subscriptions
|
||||
this._unsubscribeAll.next();
|
||||
this._unsubscribeAll.complete();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Private methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fix the SVG fill references. This fix must be applied to all ApexCharts
|
||||
* charts in order to fix 'black color on gradient fills on certain browsers'
|
||||
* issue caused by the '<base>' tag.
|
||||
*
|
||||
* Fix based on https://gist.github.com/Kamshak/c84cdc175209d1a30f711abd6a81d472
|
||||
*
|
||||
* @param element
|
||||
* @private
|
||||
*/
|
||||
private _fixSvgFill(element: Element): void
|
||||
{
|
||||
// Current URL
|
||||
const currentURL = this._router.url;
|
||||
|
||||
// 1. Find all elements with 'fill' attribute within the element
|
||||
// 2. Filter out the ones that doesn't have cross reference so we only left with the ones that use the 'url(#id)' syntax
|
||||
// 3. Insert the 'currentURL' at the front of the 'fill' attribute value
|
||||
Array.from(element.querySelectorAll('*[fill]'))
|
||||
.filter((el) => el.getAttribute('fill').indexOf('url(') !== -1)
|
||||
.forEach((el) => {
|
||||
const attrVal = el.getAttribute('fill');
|
||||
el.setAttribute('fill', `url(${currentURL}${attrVal.slice(attrVal.indexOf('#'))}`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the chart data from the data
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private _prepareChartData(): void
|
||||
{
|
||||
// Visitors
|
||||
this.chartVisitors = {
|
||||
chart : {
|
||||
animations: {
|
||||
speed : 400,
|
||||
animateGradually: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
width : '100%',
|
||||
height : '100%',
|
||||
type : 'area',
|
||||
toolbar : {
|
||||
show: false
|
||||
},
|
||||
zoom : {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
colors : ['#818CF8'],
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
fill : {
|
||||
colors: ['#312E81']
|
||||
},
|
||||
grid : {
|
||||
show : true,
|
||||
borderColor: '#334155',
|
||||
padding : {
|
||||
top : 10,
|
||||
bottom: -40,
|
||||
left : 0,
|
||||
right : 0
|
||||
},
|
||||
position : 'back',
|
||||
xaxis : {
|
||||
lines: {
|
||||
show: true
|
||||
}
|
||||
}
|
||||
},
|
||||
series : this.data.visitors.series,
|
||||
stroke : {
|
||||
width: 2
|
||||
},
|
||||
tooltip : {
|
||||
followCursor: true,
|
||||
theme : 'dark',
|
||||
x : {
|
||||
format: 'MMM dd, yyyy'
|
||||
},
|
||||
y : {
|
||||
formatter(value: number): string
|
||||
{
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
xaxis : {
|
||||
axisBorder: {
|
||||
show: false
|
||||
},
|
||||
axisTicks : {
|
||||
show: false
|
||||
},
|
||||
crosshairs: {
|
||||
stroke: {
|
||||
color : '#475569',
|
||||
dashArray: 0,
|
||||
width : 2
|
||||
}
|
||||
},
|
||||
labels : {
|
||||
offsetY: -20,
|
||||
style : {
|
||||
colors: '#CBD5E1'
|
||||
}
|
||||
},
|
||||
tickAmount: 20,
|
||||
tooltip : {
|
||||
enabled: false
|
||||
},
|
||||
type : 'datetime'
|
||||
},
|
||||
yaxis : {
|
||||
axisTicks : {
|
||||
show: false
|
||||
},
|
||||
axisBorder: {
|
||||
show: false
|
||||
},
|
||||
min : min => min - 750,
|
||||
max : max => max + 250,
|
||||
tickAmount: 5,
|
||||
show : false
|
||||
}
|
||||
};
|
||||
|
||||
// Conversions
|
||||
this.chartConversions = {
|
||||
chart : {
|
||||
animations: {
|
||||
enabled: false
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'area',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#38BDF8'],
|
||||
fill : {
|
||||
colors : ['#38BDF8'],
|
||||
opacity: 0.5
|
||||
},
|
||||
series : this.data.conversions.series,
|
||||
stroke : {
|
||||
curve: 'smooth'
|
||||
},
|
||||
tooltip: {
|
||||
followCursor: true,
|
||||
theme : 'dark'
|
||||
},
|
||||
xaxis : {
|
||||
type : 'category',
|
||||
categories: this.data.conversions.labels
|
||||
},
|
||||
yaxis : {
|
||||
labels: {
|
||||
formatter: (val) => {
|
||||
return val.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Impressions
|
||||
this.chartImpressions = {
|
||||
chart : {
|
||||
animations: {
|
||||
enabled: false
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'area',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#34D399'],
|
||||
fill : {
|
||||
colors : ['#34D399'],
|
||||
opacity: 0.5
|
||||
},
|
||||
series : this.data.impressions.series,
|
||||
stroke : {
|
||||
curve: 'smooth'
|
||||
},
|
||||
tooltip: {
|
||||
followCursor: true,
|
||||
theme : 'dark'
|
||||
},
|
||||
xaxis : {
|
||||
type : 'category',
|
||||
categories: this.data.impressions.labels
|
||||
},
|
||||
yaxis : {
|
||||
labels: {
|
||||
formatter: (val) => {
|
||||
return val.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Visits
|
||||
this.chartVisits = {
|
||||
chart : {
|
||||
animations: {
|
||||
enabled: false
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'area',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#FB7185'],
|
||||
fill : {
|
||||
colors : ['#FB7185'],
|
||||
opacity: 0.5
|
||||
},
|
||||
series : this.data.visits.series,
|
||||
stroke : {
|
||||
curve: 'smooth'
|
||||
},
|
||||
tooltip: {
|
||||
followCursor: true,
|
||||
theme : 'dark'
|
||||
},
|
||||
xaxis : {
|
||||
type : 'category',
|
||||
categories: this.data.visits.labels
|
||||
},
|
||||
yaxis : {
|
||||
labels: {
|
||||
formatter: (val) => {
|
||||
return val.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Visitors vs Page Views
|
||||
this.chartVisitorsVsPageViews = {
|
||||
chart : {
|
||||
animations: {
|
||||
enabled: false
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'area',
|
||||
toolbar : {
|
||||
show: false
|
||||
},
|
||||
zoom : {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
colors : ['#64748B', '#94A3B8'],
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
fill : {
|
||||
colors : ['#64748B', '#94A3B8'],
|
||||
opacity: 0.5
|
||||
},
|
||||
grid : {
|
||||
show : false,
|
||||
padding: {
|
||||
bottom: -40,
|
||||
left : 0,
|
||||
right : 0
|
||||
}
|
||||
},
|
||||
legend : {
|
||||
show: false
|
||||
},
|
||||
series : this.data.visitorsVsPageViews.series,
|
||||
stroke : {
|
||||
curve: 'smooth',
|
||||
width: 2
|
||||
},
|
||||
tooltip : {
|
||||
followCursor: true,
|
||||
theme : 'dark',
|
||||
x : {
|
||||
format: 'MMM dd, yyyy'
|
||||
}
|
||||
},
|
||||
xaxis : {
|
||||
axisBorder: {
|
||||
show: false
|
||||
},
|
||||
labels : {
|
||||
offsetY: -20,
|
||||
rotate : 0,
|
||||
style : {
|
||||
colors: 'var(--fuse-text-secondary)'
|
||||
}
|
||||
},
|
||||
tickAmount: 3,
|
||||
tooltip : {
|
||||
enabled: false
|
||||
},
|
||||
type : 'datetime'
|
||||
},
|
||||
yaxis : {
|
||||
labels : {
|
||||
style: {
|
||||
colors: 'var(--fuse-text-secondary)'
|
||||
}
|
||||
},
|
||||
max : max => max + 250,
|
||||
min : min => min - 250,
|
||||
show : false,
|
||||
tickAmount: 5
|
||||
}
|
||||
};
|
||||
|
||||
// New vs. returning
|
||||
this.chartNewVsReturning = {
|
||||
chart : {
|
||||
animations: {
|
||||
speed : 400,
|
||||
animateGradually: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'donut',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#3182CE', '#63B3ED'],
|
||||
labels : this.data.newVsReturning.labels,
|
||||
plotOptions: {
|
||||
pie: {
|
||||
customScale : 0.9,
|
||||
expandOnClick: false,
|
||||
donut : {
|
||||
size: '70%'
|
||||
}
|
||||
}
|
||||
},
|
||||
series : this.data.newVsReturning.series,
|
||||
states : {
|
||||
hover : {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
},
|
||||
active: {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip : {
|
||||
enabled : true,
|
||||
fillSeriesColor: false,
|
||||
theme : 'dark',
|
||||
custom : ({
|
||||
seriesIndex,
|
||||
w
|
||||
}) => {
|
||||
return `<div class="flex items-center h-8 min-h-8 max-h-8 px-3">
|
||||
<div class="w-3 h-3 rounded-full" style="background-color: ${w.config.colors[seriesIndex]};"></div>
|
||||
<div class="ml-2 text-md leading-none">${w.config.labels[seriesIndex]}:</div>
|
||||
<div class="ml-2 text-md font-bold leading-none">${w.config.series[seriesIndex]}%</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Gender
|
||||
this.chartGender = {
|
||||
chart : {
|
||||
animations: {
|
||||
speed : 400,
|
||||
animateGradually: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'donut',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#319795', '#4FD1C5'],
|
||||
labels : this.data.gender.labels,
|
||||
plotOptions: {
|
||||
pie: {
|
||||
customScale : 0.9,
|
||||
expandOnClick: false,
|
||||
donut : {
|
||||
size: '70%'
|
||||
}
|
||||
}
|
||||
},
|
||||
series : this.data.gender.series,
|
||||
states : {
|
||||
hover : {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
},
|
||||
active: {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip : {
|
||||
enabled : true,
|
||||
fillSeriesColor: false,
|
||||
theme : 'dark',
|
||||
custom : ({
|
||||
seriesIndex,
|
||||
w
|
||||
}) => {
|
||||
return `<div class="flex items-center h-8 min-h-8 max-h-8 px-3">
|
||||
<div class="w-3 h-3 rounded-full" style="background-color: ${w.config.colors[seriesIndex]};"></div>
|
||||
<div class="ml-2 text-md leading-none">${w.config.labels[seriesIndex]}:</div>
|
||||
<div class="ml-2 text-md font-bold leading-none">${w.config.series[seriesIndex]}%</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Age
|
||||
this.chartAge = {
|
||||
chart : {
|
||||
animations: {
|
||||
speed : 400,
|
||||
animateGradually: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'donut',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#DD6B20', '#F6AD55'],
|
||||
labels : this.data.age.labels,
|
||||
plotOptions: {
|
||||
pie: {
|
||||
customScale : 0.9,
|
||||
expandOnClick: false,
|
||||
donut : {
|
||||
size: '70%'
|
||||
}
|
||||
}
|
||||
},
|
||||
series : this.data.age.series,
|
||||
states : {
|
||||
hover : {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
},
|
||||
active: {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip : {
|
||||
enabled : true,
|
||||
fillSeriesColor: false,
|
||||
theme : 'dark',
|
||||
custom : ({
|
||||
seriesIndex,
|
||||
w
|
||||
}) => {
|
||||
return `<div class="flex items-center h-8 min-h-8 max-h-8 px-3">
|
||||
<div class="w-3 h-3 rounded-full" style="background-color: ${w.config.colors[seriesIndex]};"></div>
|
||||
<div class="ml-2 text-md leading-none">${w.config.labels[seriesIndex]}:</div>
|
||||
<div class="ml-2 text-md font-bold leading-none">${w.config.series[seriesIndex]}%</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Language
|
||||
this.chartLanguage = {
|
||||
chart : {
|
||||
animations: {
|
||||
speed : 400,
|
||||
animateGradually: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
foreColor : 'inherit',
|
||||
height : '100%',
|
||||
type : 'donut',
|
||||
sparkline : {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
colors : ['#805AD5', '#B794F4'],
|
||||
labels : this.data.language.labels,
|
||||
plotOptions: {
|
||||
pie: {
|
||||
customScale : 0.9,
|
||||
expandOnClick: false,
|
||||
donut : {
|
||||
size: '70%'
|
||||
}
|
||||
}
|
||||
},
|
||||
series : this.data.language.series,
|
||||
states : {
|
||||
hover : {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
},
|
||||
active: {
|
||||
filter: {
|
||||
type: 'none'
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip : {
|
||||
enabled : true,
|
||||
fillSeriesColor: false,
|
||||
theme : 'dark',
|
||||
custom : ({
|
||||
seriesIndex,
|
||||
w
|
||||
}) => {
|
||||
return `<div class="flex items-center h-8 min-h-8 max-h-8 px-3">
|
||||
<div class="w-3 h-3 rounded-full" style="background-color: ${w.config.colors[seriesIndex]};"></div>
|
||||
<div class="ml-2 text-md leading-none">${w.config.labels[seriesIndex]}:</div>
|
||||
<div class="ml-2 text-md font-bold leading-none">${w.config.series[seriesIndex]}%</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Track by function for ngFor loops
|
||||
*
|
||||
* @param index
|
||||
* @param item
|
||||
*/
|
||||
trackByFn(index: number, item: any): any
|
||||
{
|
||||
return item.id || index;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user