Create the frontend receipes page to use real API 2

This commit is contained in:
Urtzi Alfaro
2025-09-20 08:24:03 +02:00
parent d18c64ce6e
commit 66ef2121a1
6 changed files with 177 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Plus, Clock, Package, Eye, Edit, CheckCircle, AlertCircle, Timer, Users, Loader, Euro } from 'lucide-react';
import { Button, Input, Card, Badge, StatsGrid, StatusCard, getStatusColor, StatusModal } from '../../../../components/ui';
import { Button, Input, Card, Badge, StatsGrid, StatusCard, getStatusColor, StatusModal, Tabs } from '../../../../components/ui';
import { formatters } from '../../../../components/ui/Stats/StatsPresets';
import { PageHeader } from '../../../../components/layout';
import {
@@ -302,31 +302,18 @@ const OrdersPage: React.FC = () => {
]}
/>
{/* Tabs - Mobile-friendly */}
<Card className="p-1">
<div className="flex space-x-1">
<button
onClick={() => setActiveTab('orders')}
className={`flex-1 sm:flex-none px-3 sm:px-4 py-3 sm:py-2 rounded-md text-sm font-medium transition-colors ${
activeTab === 'orders'
? 'bg-[var(--color-primary)] text-white'
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-secondary)]'
}`}
>
Pedidos
</button>
<button
onClick={() => setActiveTab('customers')}
className={`flex-1 sm:flex-none px-3 sm:px-4 py-3 sm:py-2 rounded-md text-sm font-medium transition-colors ${
activeTab === 'customers'
? 'bg-[var(--color-primary)] text-white'
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-secondary)]'
}`}
>
Clientes
</button>
</div>
</Card>
{/* Tabs */}
<Tabs
items={[
{ id: 'orders', label: 'Pedidos' },
{ id: 'customers', label: 'Clientes' }
]}
activeTab={activeTab}
onTabChange={(tabId) => setActiveTab(tabId as 'orders' | 'customers')}
fullWidth={true}
variant="pills"
size="md"
/>
{/* Stats Grid */}
<StatsGrid

View File

@@ -6,7 +6,7 @@ import { formatters } from '../../../../components/ui/Stats/StatsPresets';
import { PageHeader } from '../../../../components/layout';
import { useRecipes, useRecipeStatistics, useCreateRecipe, useUpdateRecipe, useDeleteRecipe } from '../../../../api/hooks/recipes';
import { useCurrentTenant } from '../../../../stores/tenant.store';
import type { RecipeResponse, RecipeCreate } from '../../../../api/types/recipes';
import type { RecipeResponse, RecipeCreate, MeasurementUnit } from '../../../../api/types/recipes';
import { CreateRecipeModal } from '../../../../components/domain/recipes';
const RecipesPage: React.FC = () => {
@@ -201,6 +201,12 @@ const RecipesPage: React.FC = () => {
cook_time_minutes: typeof editedRecipe.cook_time_minutes === 'string'
? parseInt(editedRecipe.cook_time_minutes.toString())
: editedRecipe.cook_time_minutes,
// Ensure yield_unit is properly typed
yield_unit: editedRecipe.yield_unit ? editedRecipe.yield_unit as MeasurementUnit : undefined,
// Convert difficulty level to number if needed
difficulty_level: typeof editedRecipe.difficulty_level === 'string'
? parseInt(editedRecipe.difficulty_level.toString())
: editedRecipe.difficulty_level,
};
await updateRecipeMutation.mutateAsync({
@@ -423,31 +429,28 @@ const RecipesPage: React.FC = () => {
`${recipe.ingredients?.length || 0} ingredientes principales`
]}
actions={[
// Primary action - View recipe details
{
label: 'Ver',
label: 'Ver Detalles',
icon: Eye,
variant: 'outline',
variant: 'primary',
priority: 'primary',
onClick: () => {
setSelectedRecipe(recipe);
setModalMode('view');
setShowForm(true);
}
},
// Secondary action - Edit recipe
{
label: 'Editar',
icon: Edit,
variant: 'outline',
priority: 'secondary',
onClick: () => {
setSelectedRecipe(recipe);
setModalMode('edit');
setShowForm(true);
}
},
{
label: 'Producir',
icon: ChefHat,
variant: 'primary',
onClick: () => console.log('Produce recipe', recipe.id)
}
]}
/>
@@ -483,45 +486,20 @@ const RecipesPage: React.FC = () => {
setEditedRecipe({});
}}
mode={modalMode}
onModeChange={setModalMode}
onModeChange={(newMode) => {
setModalMode(newMode);
if (newMode === 'view') {
setEditedRecipe({});
}
}}
title={selectedRecipe.name}
subtitle={selectedRecipe.description || ''}
statusIndicator={getRecipeStatusConfig(selectedRecipe)}
size="xl"
sections={getModalSections()}
onFieldChange={handleFieldChange}
actions={modalMode === 'edit' ? [
{
label: 'Guardar',
icon: ChefHat,
variant: 'primary',
onClick: handleSaveRecipe,
disabled: updateRecipeMutation.isPending
},
{
label: 'Cancelar',
variant: 'outline',
onClick: () => {
setModalMode('view');
setEditedRecipe({});
}
}
] : [
{
label: 'Producir',
icon: ChefHat,
variant: 'primary',
onClick: () => {
console.log('Producing recipe:', selectedRecipe.id);
setShowForm(false);
setSelectedRecipe(null);
}
}
]}
onEdit={() => {
setModalMode('edit');
setEditedRecipe({});
}}
showDefaultActions={true}
onSave={handleSaveRecipe}
/>
)}