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
* 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 {
setIsLoading(true);
setError(null);
const weather = await dataService.getCurrentWeather(lat, lon);
const weather = await dataService.getCurrentWeather(tenantId, lat, lon);
return weather;
} catch (error) {

View File

@@ -185,29 +185,148 @@ export class DataService {
* This should be added to the DataService class
*/
async getProductsList(tenantId: string): Promise<string[]> {
try {
const response = await apiClient.get(`/tenants/${tenantId}/sales/products`);
// Extract product names from the response
return response.map((product: any) =>
product.name || product.product_name || product
).filter(Boolean);
console.log('🔍 Products API Response Analysis:');
console.log('- Type:', typeof response);
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
* 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;
description: string;
precipitation: number;
humidity?: number;
wind_speed?: number;
}> {
return apiClient.get(`/data/weather/current`, {
params: { lat, lon }
});
try {
// ✅ 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

View File

@@ -25,13 +25,41 @@ export class ForecastingService {
tenantId: string,
request: SingleForecastRequest
): Promise<ForecastResponse[]> {
return apiClient.post(
console.log('🔮 Creating single forecast:', { tenantId, request });
try {
// Backend returns single ForecastResponse object
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 {
product_name: string;
forecast_date: string;
forecast_days: number;
location: string;
include_external_factors?: boolean;
confidence_intervals?: boolean;
// Note: confidence_level is handled internally by backend (0.8 default)
}
export interface BatchForecastRequest {
product_names?: string[];
forecast_date: string;
forecast_days: number;
location: string;
include_external_factors?: boolean;
confidence_intervals?: boolean;
batch_name?: string;
@@ -23,11 +28,11 @@ export interface ForecastResponse {
tenant_id: string;
product_name: string;
forecast_date: string;
predicted_quantity: number;
predicted_demand: number;
confidence_lower?: number;
confidence_upper?: number;
model_id: string;
model_accuracy?: number;
confidence_level?: number;
external_factors?: ExternalFactors;
created_at: string;
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
const steps = [
{ id: 'data_validation', threshold: 25, name: 'Validación' },
{ id: 'feature_engineering', threshold: 50, name: 'Características' },
{ id: 'model_training', threshold: 80, name: 'Entrenamiento' },
{ id: 'feature_engineering', threshold: 45, name: 'Características' },
{ id: 'model_training', threshold: 85, name: 'Entrenamiento' },
{ id: 'model_validation', threshold: 100, name: 'Validación' }
];

View File

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