From 515e18653f5b6e9a54a5167403ed926e32dc6bdf Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Thu, 6 Mar 2025 20:42:51 +0100
Subject: [PATCH] add review changes and add decimal pipe

---
 src/app/api/dashboard.api.ts                  |   2 +-
 .../dashboard-statistics.component.html       |  46 ++++----
 .../dashboard-statistics.component.scss       |   7 +-
 .../dashboard-statistics.component.ts         | 102 +++---------------
 .../dashboard/dashboard.component.scss        |   4 +
 src/app/interceptor/interceptor.ts            |   2 +-
 src/app/models/dashboard-statistics.ts        |  42 ++++----
 src/app/pipes/decimal.pipe.ts                 |  16 +++
 8 files changed, 75 insertions(+), 146 deletions(-)
 create mode 100644 src/app/pipes/decimal.pipe.ts

diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts
index 435ea30..e81df04 100644
--- a/src/app/api/dashboard.api.ts
+++ b/src/app/api/dashboard.api.ts
@@ -8,7 +8,7 @@ import {
 } from '../models/dashboard-statistics';
 import { ApiResponse } from '../models/api-response';
 
-export const DASHBOARD_API_URL = '/api/v1/dashboard/statistics';
+export const DASHBOARD_API_URL = '/api/statistics';
 
 @Injectable({
   providedIn: 'root',
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index 75ab2a0..bd5d0df 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -2,18 +2,9 @@
   @let statistics = dashboardStatistics | async;
   @if (!statistics) {
     <div class="statistics__loader">
-      <div class="statistics__loader-time">
+      @for (_ of [].constructor(4); track $index) {
         <ngx-skeleton-loader count="7" />
-      </div>
-      <div class="statistics__loader-eth">
-        <ngx-skeleton-loader count="7" />
-      </div>
-      <div class="statistics__loader-protocol">
-        <ngx-skeleton-loader count="7" />
-      </div>
-      <div class="statistics__loader-ir">
-        <ngx-skeleton-loader count="7" />
-      </div>
+      }
     </div>
   }
   @else {
@@ -32,34 +23,35 @@
           </tr>
         </thead>
         <tbody>
-          <tr *ngIf="getProtocolETH() | async as protocol" class="statistics__table__header-eth">
-            <td>{{ protocol.name }}</td>
-            <td>{{ protocol.total_packets }}</td>
+          @let protocolEth = getETHStatistics(statistics.protocols);
+          <tr class="statistics__table__header-eth">
+            <td>{{ protocolEth.name }}</td>
+            <td>{{ protocolEth.total_packets | decimal }}</td>
             <td>
-              {{ (getPacketsPerSecond(protocol.name) | async) === 0 ? 0 : (getPacketsPerSecond(protocol.name) | async) }}
+              {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
             </td>
-            <td>{{ protocol.total_bytes }}</td>
+            <td>{{ protocolEth.total_bytes | decimal }}</td>
             <td>
-              {{ (getBytesPerSecond(protocol.name) | async) === 0 ? 0 : (getBytesPerSecond(protocol.name) | async) }}
+              {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
             </td>
           </tr>
         </tbody>
       </table>
       <table class="statistics__table__protocols">
         <tbody>
-          <ng-container *ngFor="let protocol of getProtocolOthers() | async">
+        @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
             <tr>
               <td>{{ protocol.name }}</td>
-              <td>{{ protocol.total_packets }}</td>
+              <td>{{ protocol.total_packets | decimal }}</td>
               <td>
-                {{ (getPacketsPerSecond(protocol.name) | async) === 0 ? 0 : (getPacketsPerSecond(protocol.name) | async) }}
+                {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
               </td>
-              <td>{{ protocol.total_bytes }}</td>
+              <td>{{ protocol.total_bytes | decimal }}</td>
               <td>
-                {{ (getBytesPerSecond(protocol.name) | async) === 0 ? 0 : (getBytesPerSecond(protocol.name) | async) }}
+                {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
               </td>
             </tr>
-          </ng-container>
+        }
         </tbody>
       </table>
       <table class="statistics__table__ir">
@@ -72,11 +64,11 @@
         </tr>
         </thead>
         <tbody>
-          <tr *ngIf="getIR() | async as information_rate" class="statistics__table_ir-content">
+          <tr class="statistics__table_ir-content">
             <td>Information Rate</td>
-            <td>{{ information_rate.min }}</td>
-            <td>{{ information_rate.max }}</td>
-            <td>{{ information_rate.current }}</td>
+            <td>{{ statistics.information_rate.min | decimal }}</td>
+            <td>{{ statistics.information_rate.max | decimal }}</td>
+            <td>{{ statistics.information_rate.current | decimal }}</td>
           </tr>
         </tbody>
       </table>
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
index d47873a..e11b5db 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
@@ -2,14 +2,10 @@
 @use 'sass:map';
 
 :host {
-  height: 100%;
-  width: 100%;
-
   ngx-skeleton-loader {
     display: flex;
     flex-direction: row;
     gap: map.get(vars.$spacing, 'md');
-
     ::ng-deep * {
       height: 50px;
     }
@@ -19,7 +15,8 @@
     display: flex;
     flex-direction: column;
     justify-content: space-between;
-    font-weight: bold;
+    font-weight: 500;
+    font-size: map.get(vars.$text, 'lg');
 
     &__table {
       &__time {
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index 99bf83c..d9040ee 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -6,115 +6,41 @@ import {
   signal,
 } from '@angular/core';
 import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
-import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
+import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
 import { DashboardApi } from '../../api/dashboard.api';
 import { interval, map, Observable, shareReplay, switchMap, tap } from 'rxjs';
-import { DashboardStatistics } from '../../models/dashboard-statistics';
+import {
+  DashboardStatistics,
+  ProtocolStatistics,
+} from '../../models/dashboard-statistics';
 import { PillComponent } from '../pill/pill.component';
 import { TimePipe } from '../../pipes/time.pipe';
+import { DecimalPipe } from '../../pipes/decimal.pipe';
 
 @Component({
   selector: 'app-dashboard-statistics',
-  imports: [NgxSkeletonLoaderComponent, AsyncPipe, TimePipe, NgIf, NgForOf],
+  imports: [NgxSkeletonLoaderComponent, AsyncPipe, TimePipe, DecimalPipe],
   templateUrl: './dashboard-statistics.component.html',
   styleUrl: './dashboard-statistics.component.scss',
 })
 export class DashboardStatisticsComponent {
   dashboardApi = inject(DashboardApi);
 
-  isLoading = signal<boolean>(false);
-
   dashboardStatistics = interval(1000).pipe(
     switchMap(() => this.dashboardApi.fetchStatistics()),
-    map(dashboardStatistics => ({
-      ...dashboardStatistics,
-      total_time: new Date(dashboardStatistics.total_time * 1000),
-    })),
     shareReplay(1)
   );
 
-  constructor() {
-    effect(() => {
-      this.isLoading.set(true);
-
-      this.dashboardApi.fetchStatistics().subscribe(data => {
-        this.isLoading.set(false);
-        this.dashboardApi.fetchStatistics().subscribe(() => {
-          this.isLoading.set(false);
-        });
-      });
-    });
-  }
-
-  getPacketsPerSecond(protocolName: string): Observable<number> {
-    return this.dashboardStatistics.pipe(
-      map(dashboardStatistics => {
-        const protocol = dashboardStatistics.protocols.find(
-          protocol => protocol.name === protocolName
-        );
-
-        if (!protocol) {
-          return 0;
-        }
-
-        if (protocol.total_packets == 0) {
-          return 0;
-        }
-
-        const totalPackets = protocol.total_packets;
-        const totalSeconds = dashboardStatistics.total_time.getTime() / 1000;
-        return totalPackets / totalSeconds;
-      })
-    );
-  }
-
-  getBytesPerSecond(protocolName: string): Observable<number> {
-    return this.dashboardStatistics.pipe(
-      map(dashboardStatistics => {
-        const protocol = dashboardStatistics.protocols.find(
-          protocol => protocol.name === protocolName
-        );
-
-        if (!protocol) {
-          return 0;
-        }
-
-        if (protocol.total_bytes == 0) {
-          return 0;
-        }
-
-        const totalBytes = protocol.total_bytes;
-        const totalSeconds = dashboardStatistics.total_time.getTime() / 1000;
-        return totalBytes / totalSeconds;
-      })
-    );
-  }
-
-  getProtocolETH() {
-    return this.dashboardStatistics.pipe(
-      map(dashboardStatistics => {
-        return dashboardStatistics.protocols.find(
-          protocol => protocol.name === 'ETH'
-        );
-      })
-    );
+  getPerSecond(value: number, time: Date): number {
+    const totalSeconds = time.getTime() / 1000;
+    return value / totalSeconds;
   }
 
-  getProtocolOthers() {
-    return this.dashboardStatistics.pipe(
-      map(dashboardStatistics => {
-        return dashboardStatistics.protocols.filter(
-          protocol => protocol.name !== 'ETH'
-        );
-      })
-    );
+  getETHStatistics(protocols: ProtocolStatistics[]): ProtocolStatistics {
+    return protocols.find(protocol => protocol.name === 'ETH')!;
   }
 
-  getIR() {
-    return this.dashboardStatistics.pipe(
-      map(dashboardStatistics => {
-        return dashboardStatistics.information_rate;
-      })
-    );
+  getProtocols(protocols: ProtocolStatistics[]): ProtocolStatistics[] {
+    return protocols.filter(protocol => protocol.name !== 'ETH');
   }
 }
diff --git a/src/app/components/dashboard/dashboard.component.scss b/src/app/components/dashboard/dashboard.component.scss
index 1938814..d11c2b9 100644
--- a/src/app/components/dashboard/dashboard.component.scss
+++ b/src/app/components/dashboard/dashboard.component.scss
@@ -29,6 +29,10 @@
     box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
     border-bottom: 1px solid map.get(vars.$grey, 30);
 
+    &-title {
+      font-size: map.get(vars.$text, 'lg');
+    }
+
     &:last-child {
       border-bottom: none;
     }
diff --git a/src/app/interceptor/interceptor.ts b/src/app/interceptor/interceptor.ts
index 1b55567..8e088ac 100644
--- a/src/app/interceptor/interceptor.ts
+++ b/src/app/interceptor/interceptor.ts
@@ -17,7 +17,7 @@ export const urls = [
     json: configurationList,
   },
   {
-    url: '/api/v1/dashboard/statistics',
+    url: '/api/statistics',
     json: dashboardStats,
   },
 ];
diff --git a/src/app/models/dashboard-statistics.ts b/src/app/models/dashboard-statistics.ts
index 2214b87..3a8befc 100644
--- a/src/app/models/dashboard-statistics.ts
+++ b/src/app/models/dashboard-statistics.ts
@@ -1,11 +1,15 @@
-export type DashboardStatistics = DashboardStatisticsDto;
-
 export interface ProtocolStatistics {
   name: string;
   total_packets: number;
   total_bytes: number;
 }
 
+export interface ProtocolStatisticsDto {
+  name: string;
+  'total-packets': number;
+  'total-bytes': number;
+}
+
 export interface InformationRate {
   min: number;
   max: number;
@@ -13,15 +17,23 @@ export interface InformationRate {
 }
 
 export interface DashboardStatisticsDto {
-  total_time: number;
+  'total-time': number;
+  protocols: ProtocolStatisticsDto[];
+  'information-rate': InformationRate;
+}
+
+export interface DashboardStatistics {
+  total_time: Date;
   protocols: ProtocolStatistics[];
   information_rate: InformationRate;
 }
 
-export function dtoToDashboardStatistics(dto: any): DashboardStatistics {
+export function dtoToDashboardStatistics(
+  dto: DashboardStatisticsDto
+): DashboardStatistics {
   return {
-    total_time: dto['total-time'],
-    protocols: dto.protocols.map((protocol: any) => ({
+    total_time: new Date(dto['total-time'] * 1000),
+    protocols: dto.protocols.map((protocol: ProtocolStatisticsDto) => ({
       name: protocol.name,
       total_packets: protocol['total-packets'],
       total_bytes: protocol['total-bytes'],
@@ -33,21 +45,3 @@ export function dtoToDashboardStatistics(dto: any): DashboardStatistics {
     },
   };
 }
-
-export function dashboardStatisticsToDto(
-  dashboardStatistics: DashboardStatistics
-): any {
-  return {
-    'total-time': dashboardStatistics.total_time,
-    protocols: dashboardStatistics.protocols.map(protocol => ({
-      name: protocol.name,
-      'total-packets': protocol.total_packets,
-      'total-bytes': protocol.total_bytes,
-    })),
-    'information-rate': {
-      min: dashboardStatistics.information_rate.min,
-      max: dashboardStatistics.information_rate.max,
-      current: dashboardStatistics.information_rate.current,
-    },
-  };
-}
diff --git a/src/app/pipes/decimal.pipe.ts b/src/app/pipes/decimal.pipe.ts
new file mode 100644
index 0000000..1d9a6e1
--- /dev/null
+++ b/src/app/pipes/decimal.pipe.ts
@@ -0,0 +1,16 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'decimal',
+})
+export class DecimalPipe implements PipeTransform {
+  transform(value: number | string, decimalPlaces: number = 2): string {
+    if (value == null || isNaN(Number(value))) {
+      return '';
+    }
+
+    let num = Number(value).toFixed(decimalPlaces);
+
+    return num.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
+  }
+}
-- 
GitLab