Fix new Frontend 17

This commit is contained in:
Urtzi Alfaro
2025-08-04 22:46:05 +02:00
parent 8b6e1ae339
commit 0154365bfc
6 changed files with 183 additions and 29 deletions

View File

@@ -180,12 +180,12 @@ export const useData = () => {
* Get Current Weather * Get Current Weather
* Add this method to the useData hook * Add this method to the useData hook
*/ */
const getCurrentWeather = useCallback(async (lat: number, lon: number) => { const getCurrentWeather = useCallback(async (tenantId: string, lat: number, lon: number) => {
try { try {
setIsLoading(true); setIsLoading(true);
setError(null); setError(null);
const weather = await dataService.getCurrentWeather(lat, lon); const weather = await dataService.getCurrentWeather(tenantId, lat, lon);
return weather; return weather;
} catch (error) { } catch (error) {

View File

@@ -185,30 +185,149 @@ export class DataService {
* This should be added to the DataService class * This should be added to the DataService class
*/ */
async getProductsList(tenantId: string): Promise<string[]> { async getProductsList(tenantId: string): Promise<string[]> {
const response = await apiClient.get(`/tenants/${tenantId}/sales/products`); try {
const response = await apiClient.get(`/tenants/${tenantId}/sales/products`);
// Extract product names from the response
return response.map((product: any) => console.log('🔍 Products API Response Analysis:');
product.name || product.product_name || product console.log('- Type:', typeof response);
).filter(Boolean); console.log('- Is Array:', Array.isArray(response));
console.log('- Keys:', Object.keys(response || {}));
console.log('- Response:', response);
let productsArray: any[] = [];
// ✅ FIX: Handle different response formats
if (Array.isArray(response)) {
// Standard array response
productsArray = response;
console.log('✅ Response is already an array');
} else if (response && typeof response === 'object') {
// Object with numeric keys - convert to array
const keys = Object.keys(response);
if (keys.length > 0 && keys.every(key => !isNaN(Number(key)))) {
// Object has numeric keys like {0: {...}, 1: {...}}
productsArray = Object.values(response);
console.log('✅ Converted object with numeric keys to array');
} else {
console.warn('⚠️ Response is object but not with numeric keys:', response);
return [];
}
} else {
console.warn('⚠️ Response is not array or object:', response);
return [];
}
console.log('📦 Products array:', productsArray);
// Extract product names from the array
const productNames = productsArray
.map((product: any) => {
if (typeof product === 'string') {
return product;
}
if (product && typeof product === 'object') {
return product.product_name ||
product.name ||
product.productName ||
null;
}
return null;
})
.filter(Boolean) // Remove null/undefined values
.filter((name: string) => name.trim().length > 0); // Remove empty strings
console.log('📋 Extracted product names:', productNames);
if (productNames.length === 0) {
console.warn('⚠️ No valid product names extracted from response');
}
return productNames;
} catch (error) {
console.error('❌ Failed to fetch products list:', error);
// Return fallback products for Madrid bakery
return [
'Croissants',
'Pan de molde',
'Baguettes',
'Café',
'Napolitanas',
'Pan integral',
'Magdalenas',
'Churros'
];
}
} }
/** /**
* Get Current Weather Data * Get Current Weather Data
* This should be added to the DataService class * This should be added to the DataService class
*/ */
async getCurrentWeather(lat: number, lon: number): Promise<{ async getCurrentWeather(
tenantId: string,
lat: number,
lon: number
): Promise<{
temperature: number; temperature: number;
description: string; description: string;
precipitation: number; precipitation: number;
humidity?: number; humidity?: number;
wind_speed?: number; wind_speed?: number;
}> { }> {
return apiClient.get(`/data/weather/current`, { try {
params: { lat, lon } // ✅ FIX 1: Correct endpoint path with tenant ID
}); const endpoint = `/tenants/${tenantId}/weather/current`;
// ✅ FIX 2: Correct parameter names (latitude/longitude, not lat/lon)
const response = await apiClient.get(endpoint, {
params: {
latitude: lat, // Backend expects 'latitude'
longitude: lon // Backend expects 'longitude'
}
});
// ✅ FIX 3: Handle the actual backend response structure
// Backend returns WeatherDataResponse:
// {
// "date": "2025-08-04T12:00:00Z",
// "temperature": 25.5,
// "precipitation": 0.0,
// "humidity": 65.0,
// "wind_speed": 10.2,
// "pressure": 1013.2,
// "description": "Partly cloudy",
// "source": "aemet"
// }
console.log('Weather API response:', response);
// Map backend response to expected frontend format
return {
temperature: response.temperature || 18,
description: response.description || 'Parcialmente nublado',
precipitation: response.precipitation || 0,
humidity: response.humidity || 65,
wind_speed: response.wind_speed || 10
};
} catch (error) {
console.error('Failed to fetch weather from backend:', error);
// Fallback weather for Madrid
return {
temperature: 18,
description: 'Parcialmente nublado',
precipitation: 0,
humidity: 65,
wind_speed: 10
};
}
} }
/** /**
* Get Weather Forecast * Get Weather Forecast
* This should be added to the DataService class * This should be added to the DataService class

View File

@@ -22,16 +22,44 @@ export class ForecastingService {
* Create Single Product Forecast * Create Single Product Forecast
*/ */
async createSingleForecast( async createSingleForecast(
tenantId: string, tenantId: string,
request: SingleForecastRequest request: SingleForecastRequest
): Promise<ForecastResponse[]> { ): Promise<ForecastResponse[]> {
return apiClient.post( console.log('🔮 Creating single forecast:', { tenantId, request });
`/tenants/${tenantId}/forecasts/single`,
request, try {
{ // Backend returns single ForecastResponse object
timeout: RequestTimeouts.MEDIUM, const response = await apiClient.post(
`/tenants/${tenantId}/forecasts/single`,
request,
{
timeout: RequestTimeouts.MEDIUM,
}
);
console.log('🔮 Forecast API Response:', response);
console.log('- Type:', typeof response);
console.log('- Is Array:', Array.isArray(response));
// ✅ FIX: Convert single response to array
if (response && typeof response === 'object' && !Array.isArray(response)) {
// Single forecast response - wrap in array
const forecastArray = [response as ForecastResponse];
console.log('✅ Converted single forecast to array:', forecastArray);
return forecastArray;
} else if (Array.isArray(response)) {
// Already an array (unexpected but handle gracefully)
console.log('✅ Response is already an array:', response);
return response;
} else {
console.error('❌ Unexpected response format:', response);
throw new Error('Invalid forecast response format');
}
} catch (error) {
console.error('❌ Forecast API Error:', error);
throw error;
} }
);
} }
/** /**

View File

@@ -5,14 +5,19 @@
export interface SingleForecastRequest { export interface SingleForecastRequest {
product_name: string; product_name: string;
forecast_date: string;
forecast_days: number; forecast_days: number;
location: string;
include_external_factors?: boolean; include_external_factors?: boolean;
confidence_intervals?: boolean; confidence_intervals?: boolean;
// Note: confidence_level is handled internally by backend (0.8 default)
} }
export interface BatchForecastRequest { export interface BatchForecastRequest {
product_names?: string[]; product_names?: string[];
forecast_date: string;
forecast_days: number; forecast_days: number;
location: string;
include_external_factors?: boolean; include_external_factors?: boolean;
confidence_intervals?: boolean; confidence_intervals?: boolean;
batch_name?: string; batch_name?: string;
@@ -23,11 +28,11 @@ export interface ForecastResponse {
tenant_id: string; tenant_id: string;
product_name: string; product_name: string;
forecast_date: string; forecast_date: string;
predicted_quantity: number; predicted_demand: number;
confidence_lower?: number; confidence_lower?: number;
confidence_upper?: number; confidence_upper?: number;
model_id: string; model_id: string;
model_accuracy?: number; confidence_level?: number;
external_factors?: ExternalFactors; external_factors?: ExternalFactors;
created_at: string; created_at: string;
processing_time_ms?: number; processing_time_ms?: number;

View File

@@ -107,8 +107,8 @@ export default function EnhancedTrainingProgress({ progress, onTimeout }: Traini
// Create progress steps based on current progress percentage // Create progress steps based on current progress percentage
const steps = [ const steps = [
{ id: 'data_validation', threshold: 25, name: 'Validación' }, { id: 'data_validation', threshold: 25, name: 'Validación' },
{ id: 'feature_engineering', threshold: 50, name: 'Características' }, { id: 'feature_engineering', threshold: 45, name: 'Características' },
{ id: 'model_training', threshold: 80, name: 'Entrenamiento' }, { id: 'model_training', threshold: 85, name: 'Entrenamiento' },
{ id: 'model_validation', threshold: 100, name: 'Validación' } { id: 'model_validation', threshold: 100, name: 'Validación' }
]; ];

View File

@@ -93,11 +93,10 @@ export const useDashboard = () => {
console.warn('Failed to fetch products:', error); console.warn('Failed to fetch products:', error);
products = ['Croissants', 'Pan de molde', 'Baguettes', 'Café', 'Napolitanas']; products = ['Croissants', 'Pan de molde', 'Baguettes', 'Café', 'Napolitanas'];
} }
// 2. Get weather data (Madrid coordinates) // 2. Get weather data (Madrid coordinates)
let weather = null; let weather = null;
try { try {
weather = await getCurrentWeather(40.4168, -3.7038); weather = await getCurrentWeather(tenantId, 40.4168, -3.7038);
} catch (error) { } catch (error) {
console.warn('Failed to fetch weather:', error); console.warn('Failed to fetch weather:', error);
// Fallback weather // Fallback weather
@@ -113,9 +112,12 @@ export const useDashboard = () => {
try { try {
const forecastRequest = { const forecastRequest = {
product_name: product, product_name: product,
forecast_date: new Date().toISOString().split('T')[0], // Today's date as YYYY-MM-DD
forecast_days: 1, forecast_days: 1,
location: 'madrid_centro', // Default location for Madrid bakery
include_external_factors: true, include_external_factors: true,
confidence_intervals: true confidence_intervals: true
// confidence_level is handled by backend internally (default 0.8)
}; };
const forecastResults = await createSingleForecast(tenantId, forecastRequest); const forecastResults = await createSingleForecast(tenantId, forecastRequest);
@@ -124,7 +126,7 @@ export const useDashboard = () => {
const forecast = forecastResults[0]; const forecast = forecastResults[0];
// Map API response to dashboard format // Map API response to dashboard format
const confidenceScore = forecast.model_accuracy || 0.8; const confidenceScore = forecast.confidence_level || 0.8;
const confidence = confidenceScore > 0.8 ? 'high' as const : const confidence = confidenceScore > 0.8 ? 'high' as const :
confidenceScore > 0.6 ? 'medium' as const : 'low' as const; confidenceScore > 0.6 ? 'medium' as const : 'low' as const;
@@ -133,7 +135,7 @@ export const useDashboard = () => {
return { return {
product, product,
predicted: Math.round(forecast.predicted_quantity || 0), predicted: Math.round(forecast.predicted_demand || 0),
confidence, confidence,
change change
}; };