Add traslations

This commit is contained in:
Urtzi Alfaro
2025-12-25 18:35:37 +01:00
parent 82567b8701
commit b95b86ee2c
18 changed files with 516 additions and 52 deletions

View File

@@ -58,7 +58,7 @@ export const CompletionStep: React.FC<CompletionStepProps> = ({
{/* Success Message */}
<div className="space-y-5 animate-slide-up">
<h1 className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-[var(--color-primary)] via-[var(--color-success)] to-[var(--color-primary)] bg-clip-text text-transparent animate-shimmer" style={{ backgroundSize: '200% auto' }}>
<h1 className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-[var(--color-primary)] via-[var(--color-success)] to-[var(--color-primary)] bg-clip-text text-transparent" style={{ backgroundSize: '200% auto' }}>
{t('onboarding:completion.congratulations', '¡Felicidades! Tu Sistema Está Listo')}
</h1>
<p className="text-lg md:text-xl text-[var(--text-secondary)] max-w-3xl mx-auto leading-relaxed">

View File

@@ -57,27 +57,30 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
// Merge existing stock from backend on mount
useEffect(() => {
if (stockData?.items && products.length > 0) {
console.log('🔄 Merging backend stock data into initial stock entry state...', { itemsCount: stockData.items.length });
if (!stockData?.items || products.length === 0) return;
let hasChanges = false;
const updatedProducts = products.map(p => {
const existingStock = stockData?.items?.find(s => s.ingredient_id === p.id);
if (existingStock && p.initialStock !== existingStock.current_quantity) {
hasChanges = true;
return {
...p,
initialStock: existingStock.current_quantity
};
}
return p;
});
console.log('🔄 Merging backend stock data into initial stock entry state...', { itemsCount: stockData.items.length });
if (hasChanges) {
setProducts(updatedProducts);
let hasChanges = false;
const updatedProducts = products.map(p => {
const existingStock = stockData.items.find(s => s.ingredient_id === p.id);
// Only merge if user hasn't entered value yet
if (existingStock && p.initialStock === undefined) {
hasChanges = true;
return {
...p,
initialStock: existingStock.current_quantity
};
}
return p;
});
if (hasChanges) {
setProducts(updatedProducts);
onUpdate?.({ productsWithStock: updatedProducts });
}
}, [stockData, products]); // Run when stock data changes or products list is initialized
}, [stockData]); // Only depend on stockData to avoid infinite loop
const ingredients = products.filter(p => p.type === 'ingredient');
const finishedProducts = products.filter(p => p.type === 'finished_product');

View File

@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '../../../ui/Button';
import { useCurrentTenant } from '../../../../stores/tenant.store';
import { useCreateIngredient, useIngredients } from '../../../../api/hooks/inventory';
import { useCreateIngredient, useBulkCreateIngredients, useIngredients } from '../../../../api/hooks/inventory';
import { useImportSalesData } from '../../../../api/hooks/sales';
import type { ProductSuggestionResponse, IngredientCreate } from '../../../../api/types/inventory';
import { ProductType, UnitOfMeasure, IngredientCategory, ProductCategory } from '../../../../api/types/inventory';
@@ -140,6 +140,7 @@ export const InventoryReviewStep: React.FC<InventoryReviewStepProps> = ({
// API hooks
const createIngredientMutation = useCreateIngredient();
const bulkCreateIngredientsMutation = useBulkCreateIngredients();
const importSalesMutation = useImportSalesData();
const { data: existingIngredients } = useIngredients(tenantId);
@@ -333,26 +334,61 @@ export const InventoryReviewStep: React.FC<InventoryReviewStepProps> = ({
console.log(`📦 Inventory processing: ${itemsToCreate.length} to create, ${existingMatches.length} already exist.`);
// STEP 1: Create new inventory items in parallel
const createPromises = itemsToCreate.map((item, index) => {
const ingredientData: IngredientCreate = {
name: item.name,
product_type: item.product_type,
category: item.category,
unit_of_measure: item.unit_of_measure as UnitOfMeasure,
};
// STEP 1: Create new inventory items using bulk API (with fallback to individual creates)
let newlyCreatedIngredients: any[] = [];
return createIngredientMutation.mutateAsync({
tenantId,
ingredientData,
}).catch(error => {
console.error(`❌ Failed to create ingredient "${item.name}":`, error);
throw error;
});
});
if (itemsToCreate.length > 0) {
try {
// Try bulk creation first (more efficient)
const ingredientsData: IngredientCreate[] = itemsToCreate.map(item => ({
name: item.name,
product_type: item.product_type,
category: item.category,
unit_of_measure: item.unit_of_measure as UnitOfMeasure,
}));
const newlyCreatedIngredients = await Promise.all(createPromises);
console.log('✅ New inventory items created successfully');
const bulkResult = await bulkCreateIngredientsMutation.mutateAsync({
tenantId,
ingredients: ingredientsData,
});
// Extract successfully created ingredients
newlyCreatedIngredients = bulkResult.results
.filter(r => r.success && r.ingredient)
.map(r => r.ingredient!);
console.log(`✅ Bulk creation: ${bulkResult.total_created}/${bulkResult.total_requested} items created successfully`);
// Log any failures
if (bulkResult.total_failed > 0) {
const failures = bulkResult.results.filter(r => !r.success);
console.warn(`⚠️ ${bulkResult.total_failed} items failed:`, failures.map(f => f.error));
}
} catch (bulkError) {
console.warn('⚠️ Bulk create failed, falling back to individual creates:', bulkError);
// Fallback: Create items individually in parallel
const createPromises = itemsToCreate.map((item, index) => {
const ingredientData: IngredientCreate = {
name: item.name,
product_type: item.product_type,
category: item.category,
unit_of_measure: item.unit_of_measure as UnitOfMeasure,
};
return createIngredientMutation.mutateAsync({
tenantId,
ingredientData,
}).catch(error => {
console.error(`❌ Failed to create ingredient "${item.name}":`, error);
throw error;
});
});
newlyCreatedIngredients = await Promise.all(createPromises);
console.log('✅ Fallback: New inventory items created successfully via individual requests');
}
}
// STEP 2: Import sales data (only if file was uploaded)
let salesImported = false;
@@ -467,10 +503,10 @@ export const InventoryReviewStep: React.FC<InventoryReviewStepProps> = ({
<span className="text-3xl group-hover:scale-110 transition-transform">{template.icon}</span>
<div className="flex-1 min-w-0">
<h4 className="font-medium text-[var(--text-primary)] mb-1">
{template.name}
{t(`setup_wizard:inventory.templates.${template.id}`, template.name)}
</h4>
<p className="text-xs text-[var(--text-secondary)] mb-2">
{template.description}
{t(`setup_wizard:inventory.templates.${template.id}-desc`, template.description)}
</p>
<p className="text-xs text-purple-600 dark:text-purple-400 font-medium">
{template.items.length} {t('inventory:templates.items', 'ingredientes')}