Fix new services implementation 11
This commit is contained in:
@@ -15,6 +15,7 @@ import ForecastPage from './pages/forecast/ForecastPage';
|
||||
import OrdersPage from './pages/orders/OrdersPage';
|
||||
import InventoryPage from './pages/inventory/InventoryPage';
|
||||
import SalesPage from './pages/sales/SalesPage';
|
||||
import RecipesPage from './pages/recipes/RecipesPage';
|
||||
import SettingsPage from './pages/settings/SettingsPage';
|
||||
import Layout from './components/layout/Layout';
|
||||
|
||||
@@ -31,7 +32,7 @@ import './i18n';
|
||||
// Global styles
|
||||
import './styles/globals.css';
|
||||
|
||||
type CurrentPage = 'landing' | 'login' | 'register' | 'onboarding' | 'dashboard' | 'reports' | 'orders' | 'production' | 'inventory' | 'sales' | 'settings';
|
||||
type CurrentPage = 'landing' | 'login' | 'register' | 'onboarding' | 'dashboard' | 'reports' | 'orders' | 'production' | 'inventory' | 'recipes' | 'sales' | 'settings';
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
@@ -295,6 +296,8 @@ const App: React.FC = () => {
|
||||
return <ProductionPage />;
|
||||
case 'inventory':
|
||||
return <InventoryPage />;
|
||||
case 'recipes':
|
||||
return <RecipesPage />;
|
||||
case 'sales':
|
||||
return <SalesPage />;
|
||||
case 'settings':
|
||||
@@ -305,6 +308,7 @@ const App: React.FC = () => {
|
||||
onNavigateToReports={() => navigateTo('reports')}
|
||||
onNavigateToProduction={() => navigateTo('production')}
|
||||
onNavigateToInventory={() => navigateTo('inventory')}
|
||||
onNavigateToRecipes={() => navigateTo('recipes')}
|
||||
onNavigateToSales={() => navigateTo('sales')}
|
||||
/>;
|
||||
}
|
||||
|
||||
@@ -304,9 +304,11 @@ private buildURL(endpoint: string): string {
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
console.log('🔍 Raw responseData from fetch:', responseData);
|
||||
|
||||
// Apply response interceptors
|
||||
const processedResponse = await this.applyResponseInterceptors(responseData);
|
||||
console.log('🔍 processedResponse after interceptors:', processedResponse);
|
||||
|
||||
return processedResponse;
|
||||
});
|
||||
@@ -335,9 +337,14 @@ private buildURL(endpoint: string): string {
|
||||
|
||||
// Handle both wrapped and unwrapped responses
|
||||
// If result has a 'data' property, return it; otherwise return the result itself
|
||||
console.log('🔍 Final result before return:', result);
|
||||
console.log('🔍 Result has data property?', result && typeof result === 'object' && 'data' in result);
|
||||
|
||||
if (result && typeof result === 'object' && 'data' in result) {
|
||||
console.log('🔍 Returning result.data:', result.data);
|
||||
return result.data as T;
|
||||
}
|
||||
console.log('🔍 Returning raw result:', result);
|
||||
return result as T;
|
||||
} catch (error) {
|
||||
// Record error metrics
|
||||
|
||||
@@ -550,27 +550,46 @@ export class InventoryService {
|
||||
const response = await apiClient.get(`/tenants/${tenantId}/ingredients`, {
|
||||
params: {
|
||||
limit: 100,
|
||||
product_type: 'finished_product' // Only get finished products, not raw ingredients
|
||||
product_type: 'finished_product'
|
||||
},
|
||||
});
|
||||
|
||||
console.log('🔍 Inventory Products API Response:', response);
|
||||
console.log('🔍 Raw response data:', response.data);
|
||||
console.log('🔍 Response status:', response.status);
|
||||
console.log('🔍 Response headers:', response.headers);
|
||||
console.log('🔍 Full response object keys:', Object.keys(response || {}));
|
||||
console.log('🔍 Response data type:', typeof response);
|
||||
console.log('🔍 Response data constructor:', response?.constructor?.name);
|
||||
|
||||
// Check if response.data exists and what type it is
|
||||
if (response && 'data' in response) {
|
||||
console.log('🔍 Response.data exists:', typeof response.data);
|
||||
console.log('🔍 Response.data keys:', Object.keys(response.data || {}));
|
||||
console.log('🔍 Response.data constructor:', response.data?.constructor?.name);
|
||||
}
|
||||
|
||||
let productsArray: any[] = [];
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
productsArray = response;
|
||||
} else if (response && typeof response === 'object') {
|
||||
// Check response.data first (typical API client behavior)
|
||||
const dataToProcess = response?.data || response;
|
||||
|
||||
if (Array.isArray(dataToProcess)) {
|
||||
productsArray = dataToProcess;
|
||||
console.log('✅ Found array data with', productsArray.length, 'items');
|
||||
} else if (dataToProcess && typeof dataToProcess === 'object') {
|
||||
// Handle different response formats
|
||||
const keys = Object.keys(response);
|
||||
const keys = Object.keys(dataToProcess);
|
||||
if (keys.length > 0 && keys.every(key => !isNaN(Number(key)))) {
|
||||
productsArray = Object.values(response);
|
||||
productsArray = Object.values(dataToProcess);
|
||||
console.log('✅ Found object with numeric keys, converted to array with', productsArray.length, 'items');
|
||||
} else {
|
||||
console.warn('⚠️ Response is object but not with numeric keys:', response);
|
||||
console.warn('⚠️ Response is object but not with numeric keys:', dataToProcess);
|
||||
console.warn('⚠️ Object keys:', keys);
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ Response is not array or object:', response);
|
||||
console.warn('⚠️ Response data is not array or object:', dataToProcess);
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -593,8 +612,19 @@ export class InventoryService {
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to fetch inventory products:', error);
|
||||
console.error('❌ Error details:', {
|
||||
message: error instanceof Error ? error.message : 'Unknown error',
|
||||
response: (error as any)?.response,
|
||||
status: (error as any)?.response?.status,
|
||||
data: (error as any)?.response?.data
|
||||
});
|
||||
|
||||
// Return empty array on error - let dashboard handle fallback
|
||||
// If it's an authentication error, throw it to trigger auth flow
|
||||
if ((error as any)?.response?.status === 401) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Return empty array on other errors - let dashboard handle fallback
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ export interface ProductInfo {
|
||||
sales_count?: number;
|
||||
total_quantity?: number;
|
||||
last_sale_date?: string;
|
||||
// Additional inventory fields
|
||||
current_stock?: number;
|
||||
unit?: string;
|
||||
cost_per_unit?: number;
|
||||
}
|
||||
|
||||
export interface SalesData {
|
||||
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
ChevronDown,
|
||||
ChefHat,
|
||||
Warehouse,
|
||||
ShoppingCart
|
||||
ShoppingCart,
|
||||
BookOpen
|
||||
} from 'lucide-react';
|
||||
|
||||
interface LayoutProps {
|
||||
@@ -44,6 +45,7 @@ const Layout: React.FC<LayoutProps> = ({
|
||||
{ id: 'dashboard', label: 'Inicio', icon: Home, href: '/dashboard' },
|
||||
{ id: 'orders', label: 'Pedidos', icon: Package, href: '/orders' },
|
||||
{ id: 'production', label: 'Producción', icon: ChefHat, href: '/production' },
|
||||
{ id: 'recipes', label: 'Recetas', icon: BookOpen, href: '/recipes' },
|
||||
{ id: 'inventory', label: 'Inventario', icon: Warehouse, href: '/inventory' },
|
||||
{ id: 'sales', label: 'Ventas', icon: ShoppingCart, href: '/sales' },
|
||||
{ id: 'reports', label: 'Informes', icon: TrendingUp, href: '/reports' },
|
||||
|
||||
@@ -224,6 +224,7 @@ export const useDashboard = () => {
|
||||
|
||||
return {
|
||||
...dashboardData,
|
||||
tenantId,
|
||||
isLoading: isLoading || salesLoading || inventoryLoading || externalLoading || forecastLoading,
|
||||
error: error || salesError || inventoryError || externalError || forecastError,
|
||||
reload: () => tenantId ? loadDashboardData(tenantId) : Promise.resolve(),
|
||||
|
||||
@@ -32,13 +32,16 @@ const SUPPLIERS: Record<string, string> = {
|
||||
'Bolsas papel': 'Distribuciones Madrid',
|
||||
};
|
||||
|
||||
export const useOrderSuggestions = () => {
|
||||
export const useOrderSuggestions = (providedTenantId?: string | null) => {
|
||||
const [dailyOrders, setDailyOrders] = useState<DailyOrderItem[]>([]);
|
||||
const [weeklyOrders, setWeeklyOrders] = useState<WeeklyOrderItem[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const { tenantId, isLoading: tenantLoading, error: tenantError } = useTenantId();
|
||||
const { tenantId: hookTenantId, isLoading: tenantLoading, error: tenantError } = useTenantId();
|
||||
|
||||
// Use provided tenant ID if available, otherwise use hook tenant ID
|
||||
const tenantId = providedTenantId !== undefined ? providedTenantId : hookTenantId;
|
||||
|
||||
console.log('🏢 OrderSuggestions: Tenant info:', { tenantId, tenantLoading, tenantError });
|
||||
const {
|
||||
@@ -65,43 +68,32 @@ export const useOrderSuggestions = () => {
|
||||
console.log('📊 OrderSuggestions: Generating daily suggestions for tenant:', tenantId);
|
||||
|
||||
// Get products list from backend
|
||||
let products: string[] = [];
|
||||
try {
|
||||
products = await getProductsList(tenantId);
|
||||
console.log('📋 OrderSuggestions: Products list:', products);
|
||||
} catch (error) {
|
||||
console.error('❌ OrderSuggestions: Failed to get products list:', error);
|
||||
throw error;
|
||||
}
|
||||
const productsList = await getProductsList(tenantId);
|
||||
const products = productsList.map(p => p.name);
|
||||
console.log('📋 OrderSuggestions: Products list:', products);
|
||||
|
||||
// Filter for daily bakery products (case insensitive)
|
||||
const dailyProductKeywords = ['pan', 'baguette', 'croissant', 'magdalena'];
|
||||
const dailyProducts = products.filter(p =>
|
||||
['Pan de Molde', 'Baguettes', 'Croissants', 'Magdalenas'].includes(p)
|
||||
dailyProductKeywords.some(keyword =>
|
||||
p.toLowerCase().includes(keyword.toLowerCase())
|
||||
)
|
||||
);
|
||||
console.log('🥖 OrderSuggestions: Daily products:', dailyProducts);
|
||||
|
||||
// Get quick forecasts for these products
|
||||
let quickForecasts: any[] = [];
|
||||
try {
|
||||
quickForecasts = await getQuickForecasts(tenantId);
|
||||
console.log('🔮 OrderSuggestions: Quick forecasts:', quickForecasts);
|
||||
} catch (error) {
|
||||
console.error('❌ OrderSuggestions: Failed to get quick forecasts:', error);
|
||||
throw error;
|
||||
}
|
||||
const quickForecasts = await getQuickForecasts(tenantId);
|
||||
console.log('🔮 OrderSuggestions: Quick forecasts:', quickForecasts);
|
||||
|
||||
// Get weather data to determine urgency
|
||||
let weather: any = null;
|
||||
try {
|
||||
weather = await getCurrentWeather(tenantId, 40.4168, -3.7038);
|
||||
console.log('🌤️ OrderSuggestions: Weather data:', weather);
|
||||
} catch (error) {
|
||||
console.error('❌ OrderSuggestions: Failed to get current weather:', error);
|
||||
throw error;
|
||||
}
|
||||
const weather = await getCurrentWeather(tenantId, 40.4168, -3.7038);
|
||||
console.log('🌤️ OrderSuggestions: Weather data:', weather);
|
||||
|
||||
const suggestions: DailyOrderItem[] = [];
|
||||
console.log('🔄 OrderSuggestions: Processing daily products:', dailyProducts);
|
||||
|
||||
for (const product of dailyProducts) {
|
||||
console.log('🔄 OrderSuggestions: Processing product:', product);
|
||||
// Find forecast for this product
|
||||
const forecast = quickForecasts.find(f =>
|
||||
f.product_name === product || f.inventory_product_id === product
|
||||
@@ -145,14 +137,15 @@ export const useOrderSuggestions = () => {
|
||||
};
|
||||
|
||||
suggestions.push(orderItem);
|
||||
console.log('➕ OrderSuggestions: Added daily suggestion:', orderItem);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🎯 OrderSuggestions: Final daily suggestions:', suggestions);
|
||||
return suggestions;
|
||||
} catch (error) {
|
||||
console.error('❌ OrderSuggestions: Error generating daily suggestions, using fallback:', error);
|
||||
// Return mock data as fallback
|
||||
return getMockDailyOrders();
|
||||
console.error('❌ OrderSuggestions: Error in generateDailyOrderSuggestions:', error);
|
||||
return [];
|
||||
}
|
||||
}, [tenantId, getProductsList, getQuickForecasts, getCurrentWeather]);
|
||||
|
||||
@@ -160,21 +153,14 @@ export const useOrderSuggestions = () => {
|
||||
const generateWeeklyOrderSuggestions = useCallback(async (): Promise<WeeklyOrderItem[]> => {
|
||||
if (!tenantId) return [];
|
||||
|
||||
try {
|
||||
console.log('📊 OrderSuggestions: Generating weekly suggestions for tenant:', tenantId);
|
||||
console.log('📊 OrderSuggestions: Generating weekly suggestions for tenant:', tenantId);
|
||||
|
||||
// Get sales analytics for the past month
|
||||
const endDate = new Date().toISOString();
|
||||
const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
||||
|
||||
let analytics: any = null;
|
||||
try {
|
||||
analytics = await getSalesAnalytics(tenantId, startDate, endDate);
|
||||
console.log('📈 OrderSuggestions: Sales analytics:', analytics);
|
||||
} catch (error) {
|
||||
console.error('❌ OrderSuggestions: Failed to get sales analytics:', error);
|
||||
throw error;
|
||||
}
|
||||
const analytics = await getSalesAnalytics(tenantId, startDate, endDate);
|
||||
console.log('📈 OrderSuggestions: Sales analytics:', analytics);
|
||||
|
||||
// Weekly products (ingredients and supplies)
|
||||
const weeklyProducts = [
|
||||
@@ -221,11 +207,6 @@ export const useOrderSuggestions = () => {
|
||||
}
|
||||
|
||||
return suggestions.sort((a, b) => a.stockDays - b.stockDays); // Sort by urgency
|
||||
} catch (error) {
|
||||
console.error('❌ OrderSuggestions: Error generating weekly suggestions, using fallback:', error);
|
||||
// Return mock data as fallback
|
||||
return getMockWeeklyOrders();
|
||||
}
|
||||
}, [tenantId, getSalesAnalytics]);
|
||||
|
||||
// Load order suggestions
|
||||
@@ -233,10 +214,7 @@ export const useOrderSuggestions = () => {
|
||||
console.log('🔍 OrderSuggestions: loadOrderSuggestions called, tenantId:', tenantId);
|
||||
|
||||
if (!tenantId) {
|
||||
console.log('❌ OrderSuggestions: No tenantId available, loading mock data');
|
||||
// Load mock data when tenant ID is not available
|
||||
setDailyOrders(getMockDailyOrders());
|
||||
setWeeklyOrders(getMockWeeklyOrders());
|
||||
console.log('❌ OrderSuggestions: No tenantId available, skipping load');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -245,15 +223,21 @@ export const useOrderSuggestions = () => {
|
||||
|
||||
try {
|
||||
console.log('📊 OrderSuggestions: Starting to generate suggestions...');
|
||||
console.log('📊 OrderSuggestions: About to call generateDailyOrderSuggestions');
|
||||
|
||||
const [daily, weekly] = await Promise.all([
|
||||
generateDailyOrderSuggestions(),
|
||||
generateWeeklyOrderSuggestions()
|
||||
]);
|
||||
const dailyPromise = generateDailyOrderSuggestions();
|
||||
console.log('📊 OrderSuggestions: About to call generateWeeklyOrderSuggestions');
|
||||
|
||||
const weeklyPromise = generateWeeklyOrderSuggestions();
|
||||
console.log('📊 OrderSuggestions: Waiting for both promises to resolve...');
|
||||
|
||||
const [daily, weekly] = await Promise.all([dailyPromise, weeklyPromise]);
|
||||
|
||||
console.log('✅ OrderSuggestions: Generated suggestions:', {
|
||||
dailyCount: daily.length,
|
||||
weeklyCount: weekly.length
|
||||
weeklyCount: weekly.length,
|
||||
dailyData: daily,
|
||||
weeklyData: weekly
|
||||
});
|
||||
|
||||
setDailyOrders(daily);
|
||||
@@ -268,9 +252,13 @@ export const useOrderSuggestions = () => {
|
||||
|
||||
// Load on mount and when tenant changes
|
||||
useEffect(() => {
|
||||
console.log('🔄 OrderSuggestions: useEffect triggered, tenantId:', tenantId);
|
||||
loadOrderSuggestions();
|
||||
}, [loadOrderSuggestions]);
|
||||
console.log('🔄 OrderSuggestions: useEffect triggered, tenantId:', tenantId, 'tenantLoading:', tenantLoading);
|
||||
|
||||
// Only load if we have a tenantId or if tenant loading is complete
|
||||
if (tenantId || !tenantLoading) {
|
||||
loadOrderSuggestions();
|
||||
}
|
||||
}, [tenantId, tenantLoading, loadOrderSuggestions]);
|
||||
|
||||
return {
|
||||
dailyOrders,
|
||||
|
||||
@@ -15,15 +15,22 @@ interface DashboardPageProps {
|
||||
onNavigateToOrders?: () => void;
|
||||
onNavigateToReports?: () => void;
|
||||
onNavigateToProduction?: () => void;
|
||||
onNavigateToInventory?: () => void;
|
||||
onNavigateToRecipes?: () => void;
|
||||
onNavigateToSales?: () => void;
|
||||
}
|
||||
|
||||
const DashboardPage: React.FC<DashboardPageProps> = ({
|
||||
onNavigateToOrders,
|
||||
onNavigateToReports,
|
||||
onNavigateToProduction
|
||||
onNavigateToProduction,
|
||||
onNavigateToInventory,
|
||||
onNavigateToRecipes,
|
||||
onNavigateToSales
|
||||
}) => {
|
||||
const {
|
||||
weather,
|
||||
tenantId,
|
||||
isLoading,
|
||||
error,
|
||||
reload,
|
||||
@@ -31,13 +38,13 @@ const DashboardPage: React.FC<DashboardPageProps> = ({
|
||||
metrics
|
||||
} = useDashboard();
|
||||
|
||||
// Use real API data for order suggestions
|
||||
// Use real API data for order suggestions - pass tenantId from dashboard
|
||||
const {
|
||||
dailyOrders: realDailyOrders,
|
||||
weeklyOrders: realWeeklyOrders,
|
||||
isLoading: ordersLoading,
|
||||
error: ordersError
|
||||
} = useOrderSuggestions();
|
||||
} = useOrderSuggestions(tenantId);
|
||||
|
||||
// Debug order suggestions
|
||||
console.log('📈 Dashboard: OrderSuggestions data:', {
|
||||
|
||||
Reference in New Issue
Block a user