281 lines
9.9 KiB
TypeScript
281 lines
9.9 KiB
TypeScript
|
|
import React from 'react';
|
||
|
|
import { Package, AlertCircle, Thermometer, Clock } from 'lucide-react';
|
||
|
|
import { Card, Input } from '../../../../../components/ui';
|
||
|
|
import type { InventorySettings } from '../../../../../api/types/settings';
|
||
|
|
|
||
|
|
interface InventorySettingsCardProps {
|
||
|
|
settings: InventorySettings;
|
||
|
|
onChange: (settings: InventorySettings) => void;
|
||
|
|
disabled?: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
const InventorySettingsCard: React.FC<InventorySettingsCardProps> = ({
|
||
|
|
settings,
|
||
|
|
onChange,
|
||
|
|
disabled = false,
|
||
|
|
}) => {
|
||
|
|
const handleChange = (field: keyof InventorySettings) => (
|
||
|
|
e: React.ChangeEvent<HTMLInputElement>
|
||
|
|
) => {
|
||
|
|
const value = e.target.type === 'checkbox' ? e.target.checked :
|
||
|
|
e.target.type === 'number' ? parseFloat(e.target.value) :
|
||
|
|
e.target.value;
|
||
|
|
onChange({ ...settings, [field]: value });
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card className="p-6">
|
||
|
|
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-6 flex items-center">
|
||
|
|
<Package className="w-5 h-5 mr-2 text-[var(--color-primary)]" />
|
||
|
|
Gestión de Inventario
|
||
|
|
</h3>
|
||
|
|
|
||
|
|
<div className="space-y-6">
|
||
|
|
{/* Stock Management */}
|
||
|
|
<div>
|
||
|
|
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
|
||
|
|
<Package className="w-4 h-4 mr-2" />
|
||
|
|
Control de Stock
|
||
|
|
</h4>
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6">
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Umbral de Stock Bajo"
|
||
|
|
value={settings.low_stock_threshold}
|
||
|
|
onChange={handleChange('low_stock_threshold')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={1000}
|
||
|
|
step={1}
|
||
|
|
placeholder="10"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Punto de Reorden"
|
||
|
|
value={settings.reorder_point}
|
||
|
|
onChange={handleChange('reorder_point')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={1000}
|
||
|
|
step={1}
|
||
|
|
placeholder="20"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Cantidad de Reorden"
|
||
|
|
value={settings.reorder_quantity}
|
||
|
|
onChange={handleChange('reorder_quantity')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={1000}
|
||
|
|
step={1}
|
||
|
|
placeholder="50"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Expiration Management */}
|
||
|
|
<div>
|
||
|
|
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
|
||
|
|
<Clock className="w-4 h-4 mr-2" />
|
||
|
|
Gestión de Caducidad
|
||
|
|
</h4>
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6">
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Días para 'Próximo a Caducar'"
|
||
|
|
value={settings.expiring_soon_days}
|
||
|
|
onChange={handleChange('expiring_soon_days')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={30}
|
||
|
|
step={1}
|
||
|
|
placeholder="7"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Días para Alerta de Caducidad"
|
||
|
|
value={settings.expiration_warning_days}
|
||
|
|
onChange={handleChange('expiration_warning_days')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={14}
|
||
|
|
step={1}
|
||
|
|
placeholder="3"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Umbral de Calidad (0-10)"
|
||
|
|
value={settings.quality_score_threshold}
|
||
|
|
onChange={handleChange('quality_score_threshold')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={0}
|
||
|
|
max={10}
|
||
|
|
step={0.1}
|
||
|
|
placeholder="8.0"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Temperature Monitoring */}
|
||
|
|
<div>
|
||
|
|
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
|
||
|
|
<Thermometer className="w-4 h-4 mr-2" />
|
||
|
|
Monitorización de Temperatura
|
||
|
|
</h4>
|
||
|
|
<div className="space-y-4 pl-6">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<input
|
||
|
|
type="checkbox"
|
||
|
|
id="temperature_monitoring_enabled"
|
||
|
|
checked={settings.temperature_monitoring_enabled}
|
||
|
|
onChange={handleChange('temperature_monitoring_enabled')}
|
||
|
|
disabled={disabled}
|
||
|
|
className="rounded border-[var(--border-primary)]"
|
||
|
|
/>
|
||
|
|
<label htmlFor="temperature_monitoring_enabled" className="text-sm text-[var(--text-secondary)]">
|
||
|
|
Habilitar monitorización de temperatura
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{settings.temperature_monitoring_enabled && (
|
||
|
|
<>
|
||
|
|
{/* Refrigeration */}
|
||
|
|
<div>
|
||
|
|
<label className="block text-xs font-medium text-[var(--text-tertiary)] mb-2">
|
||
|
|
Refrigeración (°C)
|
||
|
|
</label>
|
||
|
|
<div className="grid grid-cols-2 gap-4">
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Temperatura Mínima"
|
||
|
|
value={settings.refrigeration_temp_min}
|
||
|
|
onChange={handleChange('refrigeration_temp_min')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={-5}
|
||
|
|
max={10}
|
||
|
|
step={0.5}
|
||
|
|
placeholder="1.0"
|
||
|
|
/>
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Temperatura Máxima"
|
||
|
|
value={settings.refrigeration_temp_max}
|
||
|
|
onChange={handleChange('refrigeration_temp_max')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={-5}
|
||
|
|
max={10}
|
||
|
|
step={0.5}
|
||
|
|
placeholder="4.0"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Freezer */}
|
||
|
|
<div>
|
||
|
|
<label className="block text-xs font-medium text-[var(--text-tertiary)] mb-2">
|
||
|
|
Congelador (°C)
|
||
|
|
</label>
|
||
|
|
<div className="grid grid-cols-2 gap-4">
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Temperatura Mínima"
|
||
|
|
value={settings.freezer_temp_min}
|
||
|
|
onChange={handleChange('freezer_temp_min')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={-30}
|
||
|
|
max={0}
|
||
|
|
step={1}
|
||
|
|
placeholder="-20.0"
|
||
|
|
/>
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Temperatura Máxima"
|
||
|
|
value={settings.freezer_temp_max}
|
||
|
|
onChange={handleChange('freezer_temp_max')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={-30}
|
||
|
|
max={0}
|
||
|
|
step={1}
|
||
|
|
placeholder="-15.0"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Room Temperature */}
|
||
|
|
<div>
|
||
|
|
<label className="block text-xs font-medium text-[var(--text-tertiary)] mb-2">
|
||
|
|
Temperatura Ambiente (°C)
|
||
|
|
</label>
|
||
|
|
<div className="grid grid-cols-2 gap-4">
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Temperatura Mínima"
|
||
|
|
value={settings.room_temp_min}
|
||
|
|
onChange={handleChange('room_temp_min')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={10}
|
||
|
|
max={35}
|
||
|
|
step={1}
|
||
|
|
placeholder="18.0"
|
||
|
|
/>
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Temperatura Máxima"
|
||
|
|
value={settings.room_temp_max}
|
||
|
|
onChange={handleChange('room_temp_max')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={10}
|
||
|
|
max={35}
|
||
|
|
step={1}
|
||
|
|
placeholder="25.0"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Alert Timing */}
|
||
|
|
<div>
|
||
|
|
<h5 className="text-xs font-medium text-[var(--text-tertiary)] mb-2 flex items-center">
|
||
|
|
<AlertCircle className="w-3 h-3 mr-1" />
|
||
|
|
Alertas de Desviación
|
||
|
|
</h5>
|
||
|
|
<div className="grid grid-cols-2 gap-4">
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Desviación Normal (minutos)"
|
||
|
|
value={settings.temp_deviation_alert_minutes}
|
||
|
|
onChange={handleChange('temp_deviation_alert_minutes')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={60}
|
||
|
|
step={1}
|
||
|
|
placeholder="15"
|
||
|
|
/>
|
||
|
|
<Input
|
||
|
|
type="number"
|
||
|
|
label="Desviación Crítica (minutos)"
|
||
|
|
value={settings.critical_temp_deviation_minutes}
|
||
|
|
onChange={handleChange('critical_temp_deviation_minutes')}
|
||
|
|
disabled={disabled}
|
||
|
|
min={1}
|
||
|
|
max={30}
|
||
|
|
step={1}
|
||
|
|
placeholder="5"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default InventorySettingsCard;
|