Replace submodules with full folder contents

This commit is contained in:
2025-10-14 17:07:03 +05:30
parent 8805b6146e
commit c24f610178
909 changed files with 116738 additions and 3 deletions

View File

@ -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');
}
}