- Added bg-[var(--bg-primary)] and text-[var(--text-primary)] CSS variables - Fixes white background + white text issue in dark mode - Applied to all input, select, and textarea elements across 8 wizards Wizards fixed: - InventoryWizard - CustomerWizard - SupplierWizard - RecipeWizard - EquipmentWizard - QualityTemplateWizard - TeamMemberWizard - CustomerOrderWizard (SalesEntryWizard was already fixed in previous commit) This completes the dark mode UI improvements (High Priority item). All form inputs now properly support dark mode with correct contrast.
150 lines
6.3 KiB
TypeScript
150 lines
6.3 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { WizardStep, WizardStepProps } from '../../../ui/WizardModal/WizardModal';
|
|
import { Wrench, CheckCircle2, Loader2 } from 'lucide-react';
|
|
import { useTenant } from '../../../../stores/tenant.store';
|
|
import { equipmentService } from '../../../../api/services/equipment';
|
|
import { showToast } from '../../../../utils/toast';
|
|
|
|
interface WizardDataProps extends WizardStepProps {
|
|
data: Record<string, any>;
|
|
onDataChange: (data: Record<string, any>) => void;
|
|
}
|
|
|
|
const EquipmentDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange, onComplete }) => {
|
|
const { currentTenant } = useTenant();
|
|
const [equipmentData, setEquipmentData] = useState({
|
|
type: data.type || 'oven',
|
|
brand: data.brand || '',
|
|
model: data.model || '',
|
|
location: data.location || '',
|
|
purchaseDate: data.purchaseDate || '',
|
|
status: data.status || 'active',
|
|
});
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const handleSave = async () => {
|
|
if (!currentTenant?.id) {
|
|
setError('No se pudo obtener información del tenant');
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const equipmentCreateData: any = {
|
|
name: `${equipmentData.type} - ${equipmentData.brand || 'Sin marca'}`,
|
|
type: equipmentData.type,
|
|
model: equipmentData.brand,
|
|
serialNumber: equipmentData.model,
|
|
location: equipmentData.location,
|
|
status: equipmentData.status,
|
|
installDate: equipmentData.purchaseDate || new Date().toISOString().split('T')[0],
|
|
lastMaintenance: new Date().toISOString().split('T')[0],
|
|
nextMaintenance: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
|
|
maintenanceInterval: 30,
|
|
is_active: true
|
|
};
|
|
|
|
await equipmentService.createEquipment(currentTenant.id, equipmentCreateData);
|
|
|
|
showToast.success('Equipo creado exitosamente');
|
|
onDataChange({ ...data, ...equipmentData });
|
|
onComplete();
|
|
} catch (err: any) {
|
|
console.error('Error creating equipment:', err);
|
|
const errorMessage = err.response?.data?.detail || 'Error al crear el equipo';
|
|
setError(errorMessage);
|
|
showToast.error(errorMessage);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="text-center pb-4 border-b border-[var(--border-primary)]">
|
|
<Wrench className="w-12 h-12 mx-auto mb-3 text-[var(--color-primary)]" />
|
|
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-2">Equipo de Panadería</h3>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className="p-3 bg-red-50 border border-red-200 rounded-lg text-red-700 text-sm">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">Tipo de Equipo *</label>
|
|
<select
|
|
value={equipmentData.type}
|
|
onChange={(e) => setEquipmentData({ ...equipmentData, type: e.target.value })}
|
|
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
|
>
|
|
<option value="oven">Horno</option>
|
|
<option value="mixer">Amasadora</option>
|
|
<option value="proofer">Fermentadora</option>
|
|
<option value="refrigerator">Refrigerador</option>
|
|
<option value="other">Otro</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">Marca/Modelo</label>
|
|
<input
|
|
type="text"
|
|
value={equipmentData.brand}
|
|
onChange={(e) => setEquipmentData({ ...equipmentData, brand: e.target.value })}
|
|
placeholder="Ej: Rational SCC 101"
|
|
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">Ubicación</label>
|
|
<input
|
|
type="text"
|
|
value={equipmentData.location}
|
|
onChange={(e) => setEquipmentData({ ...equipmentData, location: e.target.value })}
|
|
placeholder="Ej: Cocina principal"
|
|
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">Fecha de Compra</label>
|
|
<input
|
|
type="date"
|
|
value={equipmentData.purchaseDate}
|
|
onChange={(e) => setEquipmentData({ ...equipmentData, purchaseDate: e.target.value })}
|
|
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-end pt-4 border-t border-[var(--border-primary)]">
|
|
<button
|
|
onClick={handleSave}
|
|
disabled={loading}
|
|
className="px-8 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 font-semibold inline-flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{loading ? (
|
|
<>
|
|
<Loader2 className="w-5 h-5 animate-spin" />
|
|
Guardando...
|
|
</>
|
|
) : (
|
|
<>
|
|
<CheckCircle2 className="w-5 h-5" />
|
|
Agregar Equipo
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const EquipmentWizardSteps = (data: Record<string, any>, setData: (data: Record<string, any>) => void): WizardStep[] => [
|
|
{ id: 'equipment-details', title: 'Detalles del Equipo', description: 'Tipo, modelo, ubicación', component: (props) => <EquipmentDetailsStep {...props} data={data} onDataChange={setData} /> },
|
|
];
|