| @@ -2679,6 +2679,11 @@ | |||||
| "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", | "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "claygl": { | |||||
| "version": "1.3.0", | |||||
| "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz", | |||||
| "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==" | |||||
| }, | |||||
| "clean-stack": { | "clean-stack": { | ||||
| "version": "2.2.0", | "version": "2.2.0", | ||||
| "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", | ||||
| @@ -3419,6 +3424,31 @@ | |||||
| "domhandler": "^4.2.0" | "domhandler": "^4.2.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "echarts": { | |||||
| "version": "5.3.0", | |||||
| "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.0.tgz", | |||||
| "integrity": "sha512-zENufmwFE6WjM+24tW3xQq4ICqQtI0CGj4bDVDNd3BK3LtaA/5wBp+64ykIyKy3QElz0cieKqSYP4FX9Lv9MwQ==", | |||||
| "requires": { | |||||
| "tslib": "2.3.0", | |||||
| "zrender": "5.3.0" | |||||
| }, | |||||
| "dependencies": { | |||||
| "tslib": { | |||||
| "version": "2.3.0", | |||||
| "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", | |||||
| "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" | |||||
| } | |||||
| } | |||||
| }, | |||||
| "echarts-gl": { | |||||
| "version": "2.0.8", | |||||
| "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.8.tgz", | |||||
| "integrity": "sha512-ayFmjLxdF9pRpnh1Lz5aOgjnLqL3WIGu0t4Bt+oFwXGsViU2XcjCkHZARsZdv05lySow8eMD9JYZGXfLpuqYng==", | |||||
| "requires": { | |||||
| "claygl": "^1.2.1", | |||||
| "zrender": "^5.1.1" | |||||
| } | |||||
| }, | |||||
| "ee-first": { | "ee-first": { | ||||
| "version": "1.1.1", | "version": "1.1.1", | ||||
| "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", | ||||
| @@ -5650,6 +5680,14 @@ | |||||
| "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "ngx-echarts": { | |||||
| "version": "8.0.1", | |||||
| "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-8.0.1.tgz", | |||||
| "integrity": "sha512-CP+WnCcnMCNpCL9BVmDIZmhGSVPnkJhhFbQEKt0nrwV0L6d4QTAGZ+e4y6G1zTTFKkIMPHpaO0nhtDRgSXAW/w==", | |||||
| "requires": { | |||||
| "tslib": "^2.3.0" | |||||
| } | |||||
| }, | |||||
| "nice-napi": { | "nice-napi": { | ||||
| "version": "1.0.2", | "version": "1.0.2", | ||||
| "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", | "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", | ||||
| @@ -8229,6 +8267,21 @@ | |||||
| "requires": { | "requires": { | ||||
| "tslib": "^2.0.0" | "tslib": "^2.0.0" | ||||
| } | } | ||||
| }, | |||||
| "zrender": { | |||||
| "version": "5.3.0", | |||||
| "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.0.tgz", | |||||
| "integrity": "sha512-Ln2QB5uqI1ftNYMtCRxd+XDq6MOttLgam2tmhKAVA+j0ko47UT+VNlDvKTkqe4K2sJhBvB0EhYNLebqlCTjatQ==", | |||||
| "requires": { | |||||
| "tslib": "2.3.0" | |||||
| }, | |||||
| "dependencies": { | |||||
| "tslib": { | |||||
| "version": "2.3.0", | |||||
| "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", | |||||
| "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -18,6 +18,9 @@ | |||||
| "@angular/platform-browser": "~13.1.0", | "@angular/platform-browser": "~13.1.0", | ||||
| "@angular/platform-browser-dynamic": "~13.1.0", | "@angular/platform-browser-dynamic": "~13.1.0", | ||||
| "@angular/router": "~13.1.0", | "@angular/router": "~13.1.0", | ||||
| "echarts": "^5.3.0", | |||||
| "echarts-gl": "^2.0.8", | |||||
| "ngx-echarts": "^8.0.1", | |||||
| "rxjs": "~7.4.0", | "rxjs": "~7.4.0", | ||||
| "tslib": "^2.3.0", | "tslib": "^2.3.0", | ||||
| "zone.js": "~0.11.4" | "zone.js": "~0.11.4" | ||||
| @@ -1,7 +1,8 @@ | |||||
| import { NgModule } from '@angular/core'; | import { NgModule } from '@angular/core'; | ||||
| import { BrowserModule } from '@angular/platform-browser'; | import { BrowserModule } from '@angular/platform-browser'; | ||||
| import { NgxEchartsModule } from 'ngx-echarts'; | |||||
| import { AppRoutingModule } from './app-routing.module'; | import { AppRoutingModule } from './app-routing.module'; | ||||
| import { AppComponent } from './app.component'; | import { AppComponent } from './app.component'; | ||||
| import { LoginComponent } from './login/login.component'; | import { LoginComponent } from './login/login.component'; | ||||
| import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||||
| @@ -12,21 +13,24 @@ import { ReportComponent } from './dashboard/report/report.component'; | |||||
| import { SettingsComponent } from './dashboard/settings/settings.component'; | import { SettingsComponent } from './dashboard/settings/settings.component'; | ||||
| @NgModule({ | @NgModule({ | ||||
| declarations: [ | |||||
| AppComponent, | |||||
| LoginComponent, | |||||
| DashboardComponent, | |||||
| GraphComponent, | |||||
| TableComponent, | |||||
| ReportComponent, | |||||
| SettingsComponent | |||||
| ], | |||||
| imports: [ | |||||
| BrowserModule, | |||||
| AppRoutingModule, | |||||
| BrowserAnimationsModule | |||||
| ], | |||||
| providers: [], | |||||
| bootstrap: [AppComponent] | |||||
| declarations: [ | |||||
| AppComponent, | |||||
| LoginComponent, | |||||
| DashboardComponent, | |||||
| GraphComponent, | |||||
| TableComponent, | |||||
| ReportComponent, | |||||
| SettingsComponent | |||||
| ], | |||||
| imports: [ | |||||
| BrowserModule, | |||||
| AppRoutingModule, | |||||
| BrowserAnimationsModule, | |||||
| NgxEchartsModule.forRoot({ | |||||
| echarts: () => import('echarts'), | |||||
| }), | |||||
| ], | |||||
| providers: [], | |||||
| bootstrap: [AppComponent] | |||||
| }) | }) | ||||
| export class AppModule { } | export class AppModule { } | ||||
| @@ -1,11 +1,27 @@ | |||||
| <div class="subpage"> | <div class="subpage"> | ||||
| <header> | |||||
| <header class="main-header"> | |||||
| <h2> Dashboard </h2> | <h2> Dashboard </h2> | ||||
| </header> | </header> | ||||
| <section class="analytics"> | <section class="analytics"> | ||||
| <div class="card"> | <div class="card"> | ||||
| <div class="line-chart"></div> | |||||
| <div echarts [options]="chartOption"></div> | |||||
| </div> | |||||
| <div class="card"> | |||||
| <div echarts [options]="chartOption1"></div> | |||||
| </div> | |||||
| <div class="card"> | |||||
| <div echarts [options]="options"></div> | |||||
| </div> | |||||
| <div class="card"> | |||||
| <div echarts [options]="chartOption4"></div> | |||||
| </div> | |||||
| <div class="card"> | |||||
| <div echarts [options]="chartOption5"></div> | |||||
| </div> | </div> | ||||
| </section> | </section> | ||||
| </div> | </div> | ||||
| @@ -0,0 +1,18 @@ | |||||
| .analytics { | |||||
| display: grid; | |||||
| grid-template-columns: 1fr 1fr 1fr; | |||||
| grid-gap: 20px; | |||||
| } | |||||
| .card { | |||||
| padding: 0; | |||||
| height: 300px; | |||||
| &:nth-child(3) { | |||||
| height: 450px; | |||||
| } | |||||
| &:nth-child(4), &:nth-child(5) { | |||||
| margin-top: -150px; | |||||
| } | |||||
| } | |||||
| @@ -1,15 +1,184 @@ | |||||
| import { Component, OnInit } from '@angular/core'; | import { Component, OnInit } from '@angular/core'; | ||||
| import { EChartsOption } from 'echarts'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-graph', | |||||
| templateUrl: './graph.component.html', | |||||
| styleUrls: ['./graph.component.scss'] | |||||
| selector: 'app-graph', | |||||
| templateUrl: './graph.component.html', | |||||
| styleUrls: ['./graph.component.scss'] | |||||
| }) | }) | ||||
| export class GraphComponent implements OnInit { | export class GraphComponent implements OnInit { | ||||
| primaryColor = window.getComputedStyle(document.documentElement).getPropertyValue('--primary'); | |||||
| secondaryColor = window.getComputedStyle(document.documentElement).getPropertyValue('--secondary'); | |||||
| constructor() { } | |||||
| chartOption: EChartsOption = { | |||||
| title: { | |||||
| text: 'Partners registered this week', | |||||
| left: 'center', | |||||
| top: 15, | |||||
| textStyle: { | |||||
| fontSize: 15, | |||||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||||
| }, | |||||
| }, | |||||
| height: 180, | |||||
| offset: 0, | |||||
| xAxis: { | |||||
| type: 'category', | |||||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||||
| }, | |||||
| yAxis: { | |||||
| type: 'value', | |||||
| }, | |||||
| series: [ | |||||
| { | |||||
| data: [820, 932, 901, 934, 1290, 1330, 1320], | |||||
| type: 'line', | |||||
| color: this.primaryColor | |||||
| }, | |||||
| ], | |||||
| }; | |||||
| ngOnInit(): void { | |||||
| } | |||||
| chartOption4: EChartsOption = { | |||||
| title: { | |||||
| text: 'Goals completed', | |||||
| left: 'center', | |||||
| top: 15, | |||||
| textStyle: { | |||||
| fontSize: 15, | |||||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||||
| }, | |||||
| }, | |||||
| height: 180, | |||||
| offset: 0, | |||||
| xAxis: { | |||||
| type: 'category', | |||||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||||
| }, | |||||
| yAxis: { | |||||
| type: 'value', | |||||
| }, | |||||
| series: [ | |||||
| { | |||||
| data: [11, 200, 300, 50, 0, 60, 0], | |||||
| type: 'line', | |||||
| color: this.primaryColor | |||||
| }, | |||||
| ], | |||||
| }; | |||||
| chartOption5: EChartsOption = { | |||||
| title: { | |||||
| text: 'Goals missed vs completed', | |||||
| left: 'center', | |||||
| top: 15, | |||||
| textStyle: { | |||||
| fontSize: 15, | |||||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||||
| }, | |||||
| }, | |||||
| height: 180, | |||||
| offset: 0, | |||||
| xAxis: { | |||||
| type: 'category', | |||||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||||
| }, | |||||
| yAxis: { | |||||
| type: 'value', | |||||
| }, | |||||
| series: [ | |||||
| { | |||||
| data: [220, 0, 100, 20, 0, 290, 0], | |||||
| type: 'line', | |||||
| color: this.secondaryColor | |||||
| }, | |||||
| { | |||||
| data: [11, 200, 300, 50, 0, 60, 0], | |||||
| type: 'line', | |||||
| color: this.primaryColor | |||||
| } | |||||
| ], | |||||
| }; | |||||
| chartOption1: EChartsOption = { | |||||
| title: { | |||||
| text: 'Relative registeration count', | |||||
| left: 'center', | |||||
| top: 15, | |||||
| textStyle: { | |||||
| fontSize: 15, | |||||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||||
| }, | |||||
| }, | |||||
| height: 180, | |||||
| offset: 0, | |||||
| xAxis: { | |||||
| type: 'category', | |||||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||||
| }, | |||||
| yAxis: { | |||||
| type: 'value', | |||||
| }, | |||||
| series: [ | |||||
| { | |||||
| data: [820, 932, 901, 934, 1290, 1330, 1320], | |||||
| type: 'bar', | |||||
| color: this.primaryColor | |||||
| }, | |||||
| { | |||||
| data: [1320, 901, 934, 932, 1290, 1330, 820], | |||||
| type: 'bar', | |||||
| color: this.secondaryColor | |||||
| }, | |||||
| ], | |||||
| animationEasing: 'elasticOut', | |||||
| animationDelayUpdate: (idx) => idx * 5, | |||||
| }; | |||||
| options: EChartsOption = { | |||||
| title: { | |||||
| text: 'Partners by category', | |||||
| left: 'center', | |||||
| top: 20, | |||||
| textStyle: { | |||||
| fontSize: 20, | |||||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||||
| }, | |||||
| }, | |||||
| height: 500, | |||||
| visualMap: { | |||||
| show: false, | |||||
| min: 80, | |||||
| max: 600, | |||||
| inRange: { | |||||
| colorLightness: [0, 1], | |||||
| }, | |||||
| }, | |||||
| series: [ | |||||
| { | |||||
| name: 'Counters', | |||||
| type: 'pie', | |||||
| radius: '55%', | |||||
| center: ['50%', '50%'], | |||||
| color: this.primaryColor, | |||||
| data: [ | |||||
| { value: 335, name: 'C-1' }, | |||||
| { value: 310, name: 'C-2' }, | |||||
| { value: 274, name: 'C-3' }, | |||||
| { value: 235, name: 'C-4' }, | |||||
| { value: 400, name: 'C-5' }, | |||||
| ].sort((a, b) => a.value - b.value), | |||||
| roseType: 'radius', | |||||
| animationType: 'scale', | |||||
| animationEasing: 'elasticOut', | |||||
| animationDelay: () => Math.random() * 200, | |||||
| }, | |||||
| ], | |||||
| }; | |||||
| constructor() { } | |||||
| ngOnInit(): void { | |||||
| } | |||||
| } | } | ||||
| @@ -102,4 +102,16 @@ | |||||
| .subpage { | .subpage { | ||||
| padding: 20px; | padding: 20px; | ||||
| height: 100vh; | |||||
| width: 100%; | |||||
| overflow: auto; | |||||
| .main-header { | |||||
| margin-bottom: 20px; | |||||
| h2 { | |||||
| color: var(--secondary-text); | |||||
| font-size: 30px; | |||||
| } | |||||
| } | |||||
| } | } | ||||