Replace submodules with full folder contents
This commit is contained in:
@ -0,0 +1,338 @@
|
||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||
import { CurrencyPipe, NgClass } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
import { NgApexchartsModule } from 'ng-apexcharts';
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { ApexOptions } from 'ng-apexcharts';
|
||||
|
||||
interface DashboardMetrics {
|
||||
machine_title: string;
|
||||
machine_count: number;
|
||||
clients: number;
|
||||
company_users: number;
|
||||
client_users: number;
|
||||
transactions: number;
|
||||
sales: string;
|
||||
error?: string;
|
||||
transaction_trends?: { date: string; transactions: number }[];
|
||||
sales_distribution?: { [key: string]: number };
|
||||
client_user_categories?: { [key: string]: number };
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'dashboard-example',
|
||||
standalone: true,
|
||||
templateUrl: './example.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [
|
||||
RouterModule,
|
||||
CommonModule,
|
||||
TranslocoModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatRippleModule,
|
||||
MatMenuModule,
|
||||
MatTabsModule,
|
||||
MatButtonToggleModule,
|
||||
NgApexchartsModule,
|
||||
MatTableModule,
|
||||
]
|
||||
})
|
||||
export class ExampleComponent implements OnInit {
|
||||
machineTitle: string = 'Loading...';
|
||||
machineCount: number = 0;
|
||||
clients: number = 0;
|
||||
companyUsers: number = 0;
|
||||
clientUsers: number = 0;
|
||||
transactions: number = 0;
|
||||
sales: string = '₹0.00';
|
||||
errorMessage: string = '';
|
||||
loading: boolean = false;
|
||||
barChartOptions: Partial<ApexOptions>;
|
||||
lineChartOptions: Partial<ApexOptions>;
|
||||
doughnutChartOptions: Partial<ApexOptions>;
|
||||
pieChartOptions: Partial<ApexOptions>;
|
||||
|
||||
private readonly baseUrl = environment.apiUrl || 'http://localhost:5000';
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
// Initialize bar chart options with mock data
|
||||
this.barChartOptions = {
|
||||
series: [{
|
||||
name: 'Metrics',
|
||||
data: [150, 80, 120, 60]
|
||||
}],
|
||||
chart: {
|
||||
type: 'bar',
|
||||
height: 350
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: false,
|
||||
columnWidth: '55%'
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
xaxis: {
|
||||
categories: ['Machines', 'Clients', 'Company Users', 'Client Users']
|
||||
},
|
||||
colors: ['#3B82F6', '#EF4444', '#F59E0B', '#EF4444'],
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: (val) => `${val}`
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize line chart options with mock data
|
||||
this.lineChartOptions = {
|
||||
series: [{
|
||||
name: 'Transactions',
|
||||
data: [10, 15, 8, 12, 20]
|
||||
}],
|
||||
chart: {
|
||||
type: 'line',
|
||||
height: 350
|
||||
},
|
||||
stroke: {
|
||||
width: 3,
|
||||
curve: 'smooth'
|
||||
},
|
||||
xaxis: {
|
||||
type: 'category',
|
||||
categories: ['2025-08-15', '2025-08-16', '2025-08-17', '2025-08-18', '2025-08-19']
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: 'Transactions'
|
||||
}
|
||||
},
|
||||
colors: ['#EF4444'],
|
||||
tooltip: {
|
||||
x: {
|
||||
format: 'dd MMM yyyy'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize doughnut chart options with mock data
|
||||
this.doughnutChartOptions = {
|
||||
series: [40, 30, 20],
|
||||
chart: {
|
||||
type: 'donut',
|
||||
height: 350
|
||||
},
|
||||
labels: ['Product A', 'Product B', 'Product C'],
|
||||
colors: ['#10B981', '#F59E0B', '#8B5CF6'],
|
||||
responsive: [{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: { width: 200 },
|
||||
legend: { position: 'bottom' }
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
// Initialize pie chart options with mock data
|
||||
this.pieChartOptions = {
|
||||
series: [50, 30, 20],
|
||||
chart: {
|
||||
type: 'pie',
|
||||
height: 350
|
||||
},
|
||||
labels: ['Premium', 'Standard', 'Basic'],
|
||||
colors: ['#EF4444', '#6B7280', '#34D399'],
|
||||
responsive: [{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: { width: 200 },
|
||||
legend: { position: 'bottom' }
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.fetchDashboardMetrics('all');
|
||||
}
|
||||
|
||||
updateMachine(filter: 'active' | 'inactive' | 'all') {
|
||||
this.fetchDashboardMetrics(filter);
|
||||
}
|
||||
|
||||
private fetchDashboardMetrics(filter: string) {
|
||||
this.loading = true;
|
||||
this.machineTitle = 'Loading...';
|
||||
this.errorMessage = '';
|
||||
|
||||
const url = `${this.baseUrl}/dashboard-metrics?machine_filter=${filter}`;
|
||||
console.log('Fetching from URL:', url);
|
||||
|
||||
this.http.get<DashboardMetrics>(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).subscribe({
|
||||
next: (response) => {
|
||||
console.log('API Response:', response);
|
||||
this.loading = false;
|
||||
|
||||
if (response.error) {
|
||||
this.handleError(`Server Error: ${response.error}`);
|
||||
} else {
|
||||
this.updateDashboardData(response);
|
||||
}
|
||||
},
|
||||
error: (error: HttpErrorResponse) => {
|
||||
console.error('HTTP Error:', error);
|
||||
this.loading = false;
|
||||
this.handleHttpError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateDashboardData(response: DashboardMetrics) {
|
||||
this.machineTitle = response.machine_title || 'Machines';
|
||||
this.machineCount = response.machine_count || 0;
|
||||
this.clients = response.clients || 0;
|
||||
this.companyUsers = response.company_users || 0;
|
||||
this.clientUsers = response.client_users || 0;
|
||||
this.transactions = response.transactions || 0;
|
||||
this.sales = `₹${response.sales || '0.00'}`;
|
||||
this.errorMessage = '';
|
||||
|
||||
// Update bar chart
|
||||
this.barChartOptions = {
|
||||
...this.barChartOptions,
|
||||
series: [{
|
||||
name: 'Metrics',
|
||||
data: [
|
||||
this.machineCount,
|
||||
this.clients,
|
||||
this.companyUsers,
|
||||
this.clientUsers
|
||||
]
|
||||
}]
|
||||
};
|
||||
|
||||
// Update line chart with transaction trends
|
||||
if (response.transaction_trends) {
|
||||
this.lineChartOptions = {
|
||||
...this.lineChartOptions,
|
||||
series: [{
|
||||
name: 'Transactions',
|
||||
data: response.transaction_trends.map(item => item.transactions)
|
||||
}],
|
||||
xaxis: {
|
||||
...this.lineChartOptions.xaxis,
|
||||
categories: response.transaction_trends.map(item => item.date)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Update doughnut chart with sales distribution
|
||||
if (response.sales_distribution) {
|
||||
this.doughnutChartOptions = {
|
||||
...this.doughnutChartOptions,
|
||||
series: Object.values(response.sales_distribution),
|
||||
labels: Object.keys(response.sales_distribution)
|
||||
};
|
||||
}
|
||||
|
||||
// Update pie chart with client user categories
|
||||
if (response.client_user_categories) {
|
||||
this.pieChartOptions = {
|
||||
...this.pieChartOptions,
|
||||
series: Object.values(response.client_user_categories),
|
||||
labels: Object.keys(response.client_user_categories)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private handleError(message: string) {
|
||||
this.errorMessage = message;
|
||||
this.resetDashboardData();
|
||||
}
|
||||
|
||||
private handleHttpError(error: HttpErrorResponse) {
|
||||
let errorMessage = 'Failed to load data. ';
|
||||
|
||||
if (error.status === 0) {
|
||||
errorMessage += 'Cannot connect to server. Please check if the Flask server is running on the correct port.';
|
||||
} else if (error.status === 404) {
|
||||
errorMessage += 'API endpoint not found. Please check the server routing.';
|
||||
} else if (error.status >= 500) {
|
||||
errorMessage += 'Internal server error. Please check the server logs.';
|
||||
} else {
|
||||
errorMessage += `Status: ${error.status} - ${error.statusText}. `;
|
||||
|
||||
if (error.error && typeof error.error === 'string' && error.error.includes('<!doctype')) {
|
||||
errorMessage += 'Server returned HTML instead of JSON. Check your proxy configuration.';
|
||||
} else {
|
||||
errorMessage += `Details: ${error.error?.error || error.message || 'Unknown error'}`;
|
||||
}
|
||||
}
|
||||
|
||||
this.handleError(errorMessage);
|
||||
}
|
||||
|
||||
private resetDashboardData() {
|
||||
this.machineTitle = 'Error';
|
||||
this.machineCount = 0;
|
||||
this.clients = 0;
|
||||
this.companyUsers = 0;
|
||||
this.clientUsers = 0;
|
||||
this.transactions = 0;
|
||||
this.sales = '₹0.00';
|
||||
|
||||
// Reset chart data
|
||||
this.barChartOptions = {
|
||||
...this.barChartOptions,
|
||||
series: [{
|
||||
name: 'Metrics',
|
||||
data: [0, 0, 0, 0]
|
||||
}]
|
||||
};
|
||||
|
||||
this.lineChartOptions = {
|
||||
...this.lineChartOptions,
|
||||
series: [{
|
||||
name: 'Transactions',
|
||||
data: []
|
||||
}],
|
||||
xaxis: {
|
||||
...this.lineChartOptions.xaxis,
|
||||
categories: []
|
||||
}
|
||||
};
|
||||
|
||||
this.doughnutChartOptions = {
|
||||
...this.doughnutChartOptions,
|
||||
series: [],
|
||||
labels: []
|
||||
};
|
||||
|
||||
this.pieChartOptions = {
|
||||
...this.pieChartOptions,
|
||||
series: [],
|
||||
labels: []
|
||||
};
|
||||
}
|
||||
|
||||
retryFetch() {
|
||||
this.fetchDashboardMetrics('all');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user