first commit

This commit is contained in:
Urtzi Alfaro
2025-07-17 13:54:51 +02:00
parent 347ff51bd7
commit 5bb3e93da4
41 changed files with 10084 additions and 94 deletions

View File

@@ -0,0 +1,98 @@
// frontend/dashboard/src/api/services/authApi.ts
/**
* Authentication API service
*/
import { ApiClient } from '../base/apiClient';
import {
LoginRequest,
RegisterRequest,
TokenResponse,
UserProfile,
ApiResponse,
} from '../../types/api';
export class AuthApi {
constructor(private client: ApiClient) {}
async login(credentials: LoginRequest): Promise<TokenResponse> {
const response = await this.client.post<TokenResponse>('/auth/login', credentials);
// Store tokens
localStorage.setItem('access_token', response.access_token);
localStorage.setItem('refresh_token', response.refresh_token);
return response;
}
async register(userData: RegisterRequest): Promise<UserProfile> {
return this.client.post<UserProfile>('/auth/register', userData);
}
async logout(): Promise<void> {
try {
await this.client.post('/auth/logout');
} finally {
// Always clear local storage
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
localStorage.removeItem('user_profile');
}
}
async refreshToken(): Promise<TokenResponse> {
const refreshToken = localStorage.getItem('refresh_token');
if (!refreshToken) {
throw new Error('No refresh token available');
}
const response = await this.client.post<TokenResponse>('/auth/refresh', {
refresh_token: refreshToken,
});
// Update stored tokens
localStorage.setItem('access_token', response.access_token);
localStorage.setItem('refresh_token', response.refresh_token);
return response;
}
async getCurrentUser(): Promise<UserProfile> {
const profile = await this.client.get<UserProfile>('/auth/me');
localStorage.setItem('user_profile', JSON.stringify(profile));
return profile;
}
async updateProfile(updates: Partial<UserProfile>): Promise<UserProfile> {
return this.client.patch<UserProfile>('/auth/profile', updates);
}
async changePassword(currentPassword: string, newPassword: string): Promise<void> {
return this.client.post('/auth/change-password', {
current_password: currentPassword,
new_password: newPassword,
});
}
async requestPasswordReset(email: string): Promise<void> {
return this.client.post('/auth/password-reset', { email });
}
async confirmPasswordReset(token: string, newPassword: string): Promise<void> {
return this.client.post('/auth/password-reset/confirm', {
token,
new_password: newPassword,
});
}
// Helper methods
isAuthenticated(): boolean {
return !!localStorage.getItem('access_token');
}
getStoredUser(): UserProfile | null {
const stored = localStorage.getItem('user_profile');
return stored ? JSON.parse(stored) : null;
}
}

View File

@@ -0,0 +1,53 @@
// frontend/dashboard/src/api/services/dataApi.ts
/**
* External data API service (weather, traffic, etc.)
*/
import { ApiClient } from '../base/apiClient';
import { WeatherData, TrafficData } from '../../types/api';
export class DataApi {
constructor(private client: ApiClient) {}
async getWeatherData(
startDate: string,
endDate: string
): Promise<WeatherData[]> {
return this.client.get<WeatherData[]>('/data/weather', {
params: { start_date: startDate, end_date: endDate },
});
}
async getTrafficData(
startDate: string,
endDate: string
): Promise<TrafficData[]> {
return this.client.get<TrafficData[]>('/data/traffic', {
params: { start_date: startDate, end_date: endDate },
});
}
async getCurrentWeather(): Promise<WeatherData> {
return this.client.get<WeatherData>('/data/weather/current');
}
async getWeatherForecast(days: number = 7): Promise<WeatherData[]> {
return this.client.get<WeatherData[]>('/data/weather/forecast', {
params: { days },
});
}
async syncExternalData(): Promise<{ message: string; synced_records: number }> {
return this.client.post('/data/sync');
}
async getDataQuality(): Promise<{
weather_coverage: number;
traffic_coverage: number;
last_sync: string;
issues: string[];
}> {
return this.client.get('/data/quality');
}
}

View File

@@ -0,0 +1,48 @@
// frontend/dashboard/src/api/services/forecastingApi.ts
/**
* Forecasting API service
*/
import { ApiClient } from '../base/apiClient';
import {
ForecastRecord,
ForecastRequest,
ApiResponse,
} from '../../types/api';
export class ForecastingApi {
constructor(private client: ApiClient) {}
async getForecasts(request: ForecastRequest = {}): Promise<ForecastRecord[]> {
return this.client.get<ForecastRecord[]>('/forecasting/forecasts', {
params: request,
});
}
async getForecastByProduct(
productName: string,
daysAhead: number = 7
): Promise<ForecastRecord[]> {
return this.client.get<ForecastRecord[]>(`/forecasting/forecasts/${productName}`, {
params: { days_ahead: daysAhead },
});
}
async generateForecast(request: ForecastRequest): Promise<ForecastRecord[]> {
return this.client.post<ForecastRecord[]>('/forecasting/generate', request);
}
async updateForecast(forecastId: string, adjustments: Partial<ForecastRecord>): Promise<ForecastRecord> {
return this.client.patch<ForecastRecord>(`/forecasting/forecasts/${forecastId}`, adjustments);
}
async deleteForecast(forecastId: string): Promise<void> {
return this.client.delete(`/forecasting/forecasts/${forecastId}`);
}
async getProductPerformance(productName: string, days: number = 30): Promise<any> {
return this.client.get(`/forecasting/performance/${productName}`, {
params: { days },
});
}
}

View File

@@ -0,0 +1,70 @@
// frontend/dashboard/src/api/services/salesApi.ts
/**
* Sales data API service
*/
import { ApiClient } from '../base/apiClient';
import {
SalesRecord,
CreateSalesRequest,
ApiResponse,
} from '../../types/api';
export interface SalesQuery {
start_date?: string;
end_date?: string;
product_name?: string;
limit?: number;
offset?: number;
}
export class SalesApi {
constructor(private client: ApiClient) {}
async getSales(query: SalesQuery = {}): Promise<SalesRecord[]> {
return this.client.get<SalesRecord[]>('/data/sales', {
params: query,
});
}
async createSalesRecord(salesData: CreateSalesRequest): Promise<SalesRecord> {
return this.client.post<SalesRecord>('/data/sales', salesData);
}
async updateSalesRecord(id: string, updates: Partial<CreateSalesRequest>): Promise<SalesRecord> {
return this.client.patch<SalesRecord>(`/data/sales/${id}`, updates);
}
async deleteSalesRecord(id: string): Promise<void> {
return this.client.delete(`/data/sales/${id}`);
}
async bulkCreateSales(salesData: CreateSalesRequest[]): Promise<SalesRecord[]> {
return this.client.post<SalesRecord[]>('/data/sales/bulk', salesData);
}
async uploadSalesFile(
file: File,
onProgress?: (progress: number) => void
): Promise<{ imported: number; errors: any[] }> {
return this.client.uploadFile('/data/sales/upload', file, onProgress);
}
async getSalesAnalytics(
startDate: string,
endDate: string
): Promise<{
totalRevenue: number;
totalQuantity: number;
topProducts: Array<{ product_name: string; quantity: number; revenue: number }>;
dailyTrends: Array<{ date: string; quantity: number; revenue: number }>;
}> {
return this.client.get('/data/sales/analytics', {
params: { start_date: startDate, end_date: endDate },
});
}
async getProductList(): Promise<string[]> {
return this.client.get<string[]>('/data/sales/products');
}
}

View File

@@ -0,0 +1,41 @@
// frontend/dashboard/src/api/services/tenantApi.ts
/**
* Tenant management API service
*/
import { ApiClient } from '../base/apiClient';
import { TenantInfo, NotificationSettings } from '../../types/api';
export class TenantApi {
constructor(private client: ApiClient) {}
async getCurrentTenant(): Promise<TenantInfo> {
return this.client.get<TenantInfo>('/tenants/current');
}
async updateTenant(updates: Partial<TenantInfo>): Promise<TenantInfo> {
return this.client.patch<TenantInfo>('/tenants/current', updates);
}
async getNotificationSettings(): Promise<NotificationSettings> {
return this.client.get<NotificationSettings>('/tenants/notifications');
}
async updateNotificationSettings(settings: Partial<NotificationSettings>): Promise<NotificationSettings> {
return this.client.patch<NotificationSettings>('/tenants/notifications', settings);
}
async testNotification(type: 'email' | 'whatsapp'): Promise<{ sent: boolean; message: string }> {
return this.client.post(`/tenants/notifications/test/${type}`);
}
async getTenantStats(): Promise<{
total_sales_records: number;
total_forecasts: number;
active_models: number;
last_training: string;
data_quality_score: number;
}> {
return this.client.get('/tenants/stats');
}
}

View File

@@ -0,0 +1,62 @@
// frontend/dashboard/src/api/services/trainingApi.ts
/**
* Training API service
*/
import { ApiClient } from '../base/apiClient';
import {
TrainingJobStatus,
TrainingRequest,
TrainedModel,
ApiResponse,
} from '../../types/api';
export class TrainingApi {
constructor(private client: ApiClient) {}
async startTraining(request: TrainingRequest = {}): Promise<TrainingJobStatus> {
return this.client.post<TrainingJobStatus>('/training/train', request);
}
async getTrainingStatus(jobId: string): Promise<TrainingJobStatus> {
return this.client.get<TrainingJobStatus>(`/training/status/${jobId}`);
}
async getTrainingJobs(limit: number = 10, offset: number = 0): Promise<TrainingJobStatus[]> {
return this.client.get<TrainingJobStatus[]>('/training/jobs', {
params: { limit, offset },
});
}
async getTrainedModels(): Promise<TrainedModel[]> {
return this.client.get<TrainedModel[]>('/training/models');
}
async cancelTraining(jobId: string): Promise<void> {
return this.client.delete(`/training/jobs/${jobId}`);
}
// WebSocket for real-time training progress
subscribeToTrainingProgress(
jobId: string,
onProgress: (progress: TrainingJobStatus) => void,
onError?: (error: Error) => void
): WebSocket {
const ws = this.client.createWebSocket(`/training/progress/${jobId}`);
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
onProgress(data);
} catch (error) {
onError?.(new Error('Failed to parse progress data'));
}
};
ws.onerror = (event) => {
onError?.(new Error('WebSocket connection error'));
};
return ws;
}
}