feat: Update remaining settings cards with new UX design patterns

Applied consistent design patterns to operational settings cards using SettingSection, SettingRow, and Toggle components for improved user experience.

## Updated Cards

### ProcurementSettingsCard
- Replaced checkboxes with toggle switches for all boolean settings
- Added progressive disclosure for auto-approval threshold settings
- Grouped smart procurement options with consistent toggle rows
- Added helpful descriptions and tooltips
- Better visual hierarchy with icons and sections

### ProductionSettingsCard
- Converted quality check and schedule optimization to toggles
- Progressive disclosure for quality parameters (only shown when enabled)
- Improved section organization with clearer headings
- Better responsive grid layouts

### POSSettingsCard
- Replaced sync checkboxes with toggle switches
- Cleaner layout with SettingRow components
- Enhanced info box with dark mode support
- Better visual feedback for sync settings

### SupplierSettingsCard
- Wrapped in SettingSection for consistency
- Better organized performance thresholds
- Enhanced info box styling with dark mode
- Clearer visual hierarchy

### OrderSettingsCard
- Converted discount and delivery toggles
- Progressive disclosure not needed but consistent layout applied
- Better organized sections with icons
- Enhanced info box with business rules explanation

## Key Improvements

-  Toggle switches instead of checkboxes for binary settings
-  Progressive disclosure hides complexity until needed
-  Consistent SettingSection wrapping for all cards
-  Dark mode support for info boxes
-  Help text and tooltips for better guidance
-  Responsive layouts optimized for mobile and desktop
-  Icons for visual recognition
-  Unified design language across all operational settings

All cards now follow the same design patterns established in the bakery and user settings redesign.
This commit is contained in:
Claude
2025-11-14 06:40:55 +00:00
parent a5200bbc94
commit e82c2d1e44
5 changed files with 348 additions and 411 deletions

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { ShoppingBag, Tag, Clock, TrendingUp, MapPin } from 'lucide-react'; import { ShoppingBag, Tag, Clock, TrendingUp, MapPin, Info } from 'lucide-react';
import { Card, Input } from '../../../../../components/ui'; import { Input, SettingSection, SettingRow } from '../../../../../components/ui';
import type { OrderSettings } from '../../../../../api/types/settings'; import type { OrderSettings } from '../../../../../api/types/settings';
interface OrderSettingsCardProps { interface OrderSettingsCardProps {
@@ -23,22 +23,24 @@ const OrderSettingsCard: React.FC<OrderSettingsCardProps> = ({
onChange({ ...settings, [field]: value }); onChange({ ...settings, [field]: value });
}; };
return ( const handleToggleChange = (field: keyof OrderSettings) => (checked: boolean) => {
<Card className="p-6"> onChange({ ...settings, [field]: checked });
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-6 flex items-center"> };
<ShoppingBag className="w-5 h-5 mr-2 text-[var(--color-primary)]" />
Pedidos y Reglas de Negocio
</h3>
<div className="space-y-6"> return (
<SettingSection
title="Pedidos y Reglas de Negocio"
description="Configure order discounts, pricing rules, and delivery settings"
icon={<ShoppingBag className="w-5 h-5" />}
>
<div className="divide-y divide-[var(--border-primary)]">
{/* Discount & Pricing */} {/* Discount & Pricing */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<Tag className="w-4 h-4 mr-2" /> <Tag className="w-4 h-4 mr-2" />
Descuentos y Precios Descuentos y Precios
</h4> </h4>
<div className="space-y-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Descuento Máximo (%)" label="Descuento Máximo (%)"
@@ -49,50 +51,40 @@ const OrderSettingsCard: React.FC<OrderSettingsCardProps> = ({
max={100} max={100}
step={1} step={1}
placeholder="50.0" placeholder="50.0"
helperText="Porcentaje máximo de descuento permitido en pedidos" helperText="Porcentaje máximo de descuento permitido"
/> />
</div> </div>
</div>
<div className="space-y-3"> <SettingRow
<div className="flex items-center gap-2"> label="Habilitar descuentos en pedidos"
<input description="Allow discounts to be applied to orders"
type="checkbox" icon={<Tag className="w-4 h-4" />}
id="discount_enabled" type="toggle"
checked={settings.discount_enabled} checked={settings.discount_enabled}
onChange={handleChange('discount_enabled')} onToggle={handleToggleChange('discount_enabled')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="When enabled, discounts can be applied within the maximum limit"
/> />
<label htmlFor="discount_enabled" className="text-sm text-[var(--text-secondary)]">
Habilitar descuentos en pedidos
</label>
</div>
<div className="flex items-center gap-2"> <SettingRow
<input label="Habilitar precios dinámicos"
type="checkbox" description="Automatically adjust prices based on demand and inventory"
id="dynamic_pricing_enabled" icon={<TrendingUp className="w-4 h-4" />}
type="toggle"
checked={settings.dynamic_pricing_enabled} checked={settings.dynamic_pricing_enabled}
onChange={handleChange('dynamic_pricing_enabled')} onToggle={handleToggleChange('dynamic_pricing_enabled')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="AI-powered dynamic pricing based on market conditions"
/> />
<label htmlFor="dynamic_pricing_enabled" className="text-sm text-[var(--text-secondary)]">
Habilitar precios dinámicos
</label>
</div>
</div>
</div>
</div>
{/* Delivery Settings */} {/* Delivery Settings */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<MapPin className="w-4 h-4 mr-2" /> <MapPin className="w-4 h-4 mr-2" />
Configuración de Entrega Configuración de Entrega
</h4> </h4>
<div className="space-y-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Ventana de Entrega Predeterminada (horas)" label="Ventana de Entrega Predeterminada (horas)"
@@ -103,38 +95,34 @@ const OrderSettingsCard: React.FC<OrderSettingsCardProps> = ({
max={168} max={168}
step={1} step={1}
placeholder="48" placeholder="48"
helperText="Tiempo predeterminado para la entrega de pedidos" helperText="Tiempo predeterminado para entrega"
/> />
</div> </div>
</div>
<div className="flex items-center gap-2"> <SettingRow
<input label="Habilitar seguimiento de entregas"
type="checkbox" description="Allow customers to track their deliveries in real-time"
id="delivery_tracking_enabled" icon={<MapPin className="w-4 h-4" />}
type="toggle"
checked={settings.delivery_tracking_enabled} checked={settings.delivery_tracking_enabled}
onChange={handleChange('delivery_tracking_enabled')} onToggle={handleToggleChange('delivery_tracking_enabled')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="Enables real-time delivery tracking for customers"
/> />
<label htmlFor="delivery_tracking_enabled" className="text-sm text-[var(--text-secondary)]">
Habilitar seguimiento de entregas
</label>
</div>
</div>
</div>
{/* Info Box */} {/* Info Box */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4"> <div className="p-4 sm:p-6 bg-blue-50 dark:bg-blue-900/20">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<TrendingUp className="w-5 h-5 text-blue-600 mt-0.5" /> <Info className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
<div className="flex-1"> <div className="flex-1">
<h5 className="text-sm font-semibold text-blue-900 mb-1"> <h5 className="text-sm font-semibold text-blue-900 dark:text-blue-100 mb-1">
Reglas de Negocio Reglas de Negocio
</h5> </h5>
<p className="text-xs text-blue-700 mb-2"> <p className="text-xs text-blue-700 dark:text-blue-300 mb-2">
Estos ajustes controlan las reglas de negocio que se aplican a los pedidos. Estos ajustes controlan las reglas de negocio que se aplican a los pedidos.
</p> </p>
<ul className="text-xs text-blue-700 space-y-1 list-disc list-inside"> <ul className="text-xs text-blue-700 dark:text-blue-300 space-y-1 list-disc list-inside">
<li><strong>Precios dinámicos:</strong> Ajusta automáticamente los precios según demanda, inventario y otros factores</li> <li><strong>Precios dinámicos:</strong> Ajusta automáticamente los precios según demanda, inventario y otros factores</li>
<li><strong>Descuentos:</strong> Permite aplicar descuentos a productos y pedidos dentro del límite establecido</li> <li><strong>Descuentos:</strong> Permite aplicar descuentos a productos y pedidos dentro del límite establecido</li>
<li><strong>Seguimiento de entregas:</strong> Permite a los clientes rastrear sus pedidos en tiempo real</li> <li><strong>Seguimiento de entregas:</strong> Permite a los clientes rastrear sus pedidos en tiempo real</li>
@@ -143,7 +131,7 @@ const OrderSettingsCard: React.FC<OrderSettingsCardProps> = ({
</div> </div>
</div> </div>
</div> </div>
</Card> </SettingSection>
); );
}; };

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Smartphone, RefreshCw, Clock } from 'lucide-react'; import { Smartphone, RefreshCw, Clock, Info } from 'lucide-react';
import { Card, Input } from '../../../../../components/ui'; import { Input, SettingSection, SettingRow } from '../../../../../components/ui';
import type { POSSettings } from '../../../../../api/types/settings'; import type { POSSettings } from '../../../../../api/types/settings';
interface POSSettingsCardProps { interface POSSettingsCardProps {
@@ -23,21 +23,24 @@ const POSSettingsCard: React.FC<POSSettingsCardProps> = ({
onChange({ ...settings, [field]: value }); onChange({ ...settings, [field]: value });
}; };
return ( const handleToggleChange = (field: keyof POSSettings) => (checked: boolean) => {
<Card className="p-6"> onChange({ ...settings, [field]: checked });
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-6 flex items-center"> };
<Smartphone className="w-5 h-5 mr-2 text-[var(--color-primary)]" />
Punto de Venta (POS)
</h3>
<div className="space-y-6"> return (
<SettingSection
title="Punto de Venta (POS)"
description="Configure POS system sync settings and integration options"
icon={<Smartphone className="w-5 h-5" />}
>
<div className="divide-y divide-[var(--border-primary)]">
{/* Sync Settings */} {/* Sync Settings */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<RefreshCw className="w-4 h-4 mr-2" /> <RefreshCw className="w-4 h-4 mr-2" />
Sincronización Sincronización
</h4> </h4>
<div className="space-y-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Intervalo de Sincronización (minutos)" label="Intervalo de Sincronización (minutos)"
@@ -48,54 +51,47 @@ const POSSettingsCard: React.FC<POSSettingsCardProps> = ({
max={60} max={60}
step={1} step={1}
placeholder="5" placeholder="5"
helperText="Frecuencia con la que se sincroniza el POS con el sistema central" helperText="Frecuencia con la que se sincroniza el POS"
/> />
</div>
</div>
<div className="space-y-3"> {/* Auto-sync Options */}
<div className="flex items-center gap-2"> <SettingRow
<input label="Sincronización automática de productos"
type="checkbox" description="Automatically sync product changes to POS terminals"
id="auto_sync_products" icon={<RefreshCw className="w-4 h-4" />}
type="toggle"
checked={settings.auto_sync_products} checked={settings.auto_sync_products}
onChange={handleChange('auto_sync_products')} onToggle={handleToggleChange('auto_sync_products')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="When enabled, product updates are immediately pushed to POS"
/> />
<label htmlFor="auto_sync_products" className="text-sm text-[var(--text-secondary)]">
Sincronización automática de productos
</label>
</div>
<div className="flex items-center gap-2"> <SettingRow
<input label="Sincronización automática de transacciones"
type="checkbox" description="Automatically sync transactions from POS terminals"
id="auto_sync_transactions" icon={<RefreshCw className="w-4 h-4" />}
type="toggle"
checked={settings.auto_sync_transactions} checked={settings.auto_sync_transactions}
onChange={handleChange('auto_sync_transactions')} onToggle={handleToggleChange('auto_sync_transactions')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="When enabled, sales are automatically synced from POS"
/> />
<label htmlFor="auto_sync_transactions" className="text-sm text-[var(--text-secondary)]">
Sincronización automática de transacciones
</label>
</div>
</div>
</div>
</div>
{/* Info Box */} {/* Info Box */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4"> <div className="p-4 sm:p-6 bg-blue-50 dark:bg-blue-900/20">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<Smartphone className="w-5 h-5 text-blue-600 mt-0.5" /> <Info className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
<div className="flex-1"> <div className="flex-1">
<h5 className="text-sm font-semibold text-blue-900 mb-1"> <h5 className="text-sm font-semibold text-blue-900 dark:text-blue-100 mb-1">
Integración POS Integración POS
</h5> </h5>
<p className="text-xs text-blue-700 mb-2"> <p className="text-xs text-blue-700 dark:text-blue-300 mb-2">
Estos ajustes controlan cómo se sincroniza la información entre el sistema central Estos ajustes controlan cómo se sincroniza la información entre el sistema central
y los terminales de punto de venta. y los terminales de punto de venta.
</p> </p>
<ul className="text-xs text-blue-700 space-y-1 list-disc list-inside"> <ul className="text-xs text-blue-700 dark:text-blue-300 space-y-1 list-disc list-inside">
<li>Un intervalo más corto mantiene los datos más actualizados pero consume más recursos</li> <li>Un intervalo más corto mantiene los datos más actualizados pero consume más recursos</li>
<li>La sincronización automática garantiza que los cambios se reflejen inmediatamente</li> <li>La sincronización automática garantiza que los cambios se reflejen inmediatamente</li>
<li>Desactivar la sincronización automática requiere sincronización manual</li> <li>Desactivar la sincronización automática requiere sincronización manual</li>
@@ -104,7 +100,7 @@ const POSSettingsCard: React.FC<POSSettingsCardProps> = ({
</div> </div>
</div> </div>
</div> </div>
</Card> </SettingSection>
); );
}; };

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { ShoppingCart, TrendingUp, Clock, AlertTriangle, Brain } from 'lucide-react'; import { ShoppingCart, TrendingUp, Clock, AlertTriangle, Brain } from 'lucide-react';
import { Card, Input } from '../../../../../components/ui'; import { Input, SettingSection, SettingRow } from '../../../../../components/ui';
import type { ProcurementSettings } from '../../../../../api/types/settings'; import type { ProcurementSettings } from '../../../../../api/types/settings';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@@ -26,41 +26,43 @@ const ProcurementSettingsCard: React.FC<ProcurementSettingsCardProps> = ({
onChange({ ...settings, [field]: value }); onChange({ ...settings, [field]: value });
}; };
const handleToggleChange = (field: keyof ProcurementSettings) => (checked: boolean) => {
onChange({ ...settings, [field]: checked });
};
return ( return (
<Card className="p-6"> <SettingSection
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-6 flex items-center"> title={t('procurement.title')}
<ShoppingCart className="w-5 h-5 mr-2 text-[var(--color-primary)]" /> description="Configure automatic approval rules, planning parameters, and smart procurement options"
{t('procurement.title')} icon={<ShoppingCart className="w-5 h-5" />}
</h3> >
<div className="divide-y divide-[var(--border-primary)]">
<div className="space-y-6">
{/* Auto-Approval Settings */} {/* Auto-Approval Settings */}
<div> <div className="divide-y divide-[var(--border-primary)]">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <SettingRow
<TrendingUp className="w-4 h-4 mr-2" /> label={t('procurement.auto_approve_enabled')}
{t('procurement.auto_approval')} description="Automatically approve purchase orders that meet criteria"
</h4> icon={<TrendingUp className="w-4 h-4" />}
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6"> type="toggle"
<div className="flex items-center gap-2 md:col-span-2 xl:col-span-3">
<input
type="checkbox"
id="auto_approve_enabled"
checked={settings.auto_approve_enabled} checked={settings.auto_approve_enabled}
onChange={handleChange('auto_approve_enabled')} onToggle={handleToggleChange('auto_approve_enabled')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="When enabled, POs below threshold with good suppliers are auto-approved"
/> />
<label htmlFor="auto_approve_enabled" className="text-sm text-[var(--text-secondary)]">
{t('procurement.auto_approve_enabled')}
</label>
</div>
{settings.auto_approve_enabled && (
<>
<div className="p-4 sm:p-6 bg-[var(--bg-secondary)]">
<h5 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
Auto-Approval Thresholds
</h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label={t('procurement.auto_approve_threshold')} label={t('procurement.auto_approve_threshold')}
value={settings.auto_approve_threshold_eur} value={settings.auto_approve_threshold_eur}
onChange={handleChange('auto_approve_threshold_eur')} onChange={handleChange('auto_approve_threshold_eur')}
disabled={disabled || !settings.auto_approve_enabled} disabled={disabled}
min={0} min={0}
max={10000} max={10000}
step={50} step={50}
@@ -72,50 +74,43 @@ const ProcurementSettingsCard: React.FC<ProcurementSettingsCardProps> = ({
label={t('procurement.min_supplier_score')} label={t('procurement.min_supplier_score')}
value={settings.auto_approve_min_supplier_score} value={settings.auto_approve_min_supplier_score}
onChange={handleChange('auto_approve_min_supplier_score')} onChange={handleChange('auto_approve_min_supplier_score')}
disabled={disabled || !settings.auto_approve_enabled} disabled={disabled}
min={0} min={0}
max={1} max={1}
step={0.01} step={0.01}
placeholder="0.80" placeholder="0.80"
/> />
</div>
</div>
<div className="flex items-center gap-2"> <SettingRow
<input label={t('procurement.require_approval_new_suppliers')}
type="checkbox" description="Always require manual approval for new suppliers"
id="require_approval_new_suppliers" type="toggle"
checked={settings.require_approval_new_suppliers} checked={settings.require_approval_new_suppliers}
onChange={handleChange('require_approval_new_suppliers')} onToggle={handleToggleChange('require_approval_new_suppliers')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]"
/> />
<label htmlFor="require_approval_new_suppliers" className="text-sm text-[var(--text-secondary)]">
{t('procurement.require_approval_new_suppliers')}
</label>
</div>
<div className="flex items-center gap-2"> <SettingRow
<input label={t('procurement.require_approval_critical_items')}
type="checkbox" description="Always require manual approval for critical items"
id="require_approval_critical_items" type="toggle"
checked={settings.require_approval_critical_items} checked={settings.require_approval_critical_items}
onChange={handleChange('require_approval_critical_items')} onToggle={handleToggleChange('require_approval_critical_items')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]"
/> />
<label htmlFor="require_approval_critical_items" className="text-sm text-[var(--text-secondary)]"> </>
{t('procurement.require_approval_critical_items')} )}
</label>
</div>
</div>
</div> </div>
{/* Planning & Forecasting */} {/* Planning & Forecasting */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<Clock className="w-4 h-4 mr-2" /> <Clock className="w-4 h-4 mr-2" />
{t('procurement.planning')} {t('procurement.planning')}
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
<Input <Input
type="number" type="number"
label={t('procurement.lead_time_days')} label={t('procurement.lead_time_days')}
@@ -155,12 +150,12 @@ const ProcurementSettingsCard: React.FC<ProcurementSettingsCardProps> = ({
</div> </div>
{/* Approval Workflow */} {/* Approval Workflow */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<AlertTriangle className="w-4 h-4 mr-2" /> <AlertTriangle className="w-4 h-4 mr-2" />
{t('procurement.workflow')} {t('procurement.workflow')}
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label={t('procurement.approval_reminder_hours')} label={t('procurement.approval_reminder_hours')}
@@ -187,111 +182,70 @@ const ProcurementSettingsCard: React.FC<ProcurementSettingsCardProps> = ({
</div> </div>
</div> </div>
{/* Smart Procurement Calculation */} {/* Smart Procurement Options */}
<div className="border-t border-[var(--border-primary)] pt-6"> <div className="divide-y divide-[var(--border-primary)]">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-2 flex items-center">
<Brain className="w-4 h-4 mr-2" /> <Brain className="w-4 h-4 mr-2" />
{t('procurement.smart_procurement')} {t('procurement.smart_procurement')}
</h4> </h4>
<div className="space-y-3 pl-6"> <p className="text-xs text-[var(--text-tertiary)] mb-4">
<div className="flex items-start gap-2"> Intelligent rules for optimizing procurement decisions
<input </p>
type="checkbox" </div>
id="use_reorder_rules"
<SettingRow
label={t('procurement.use_reorder_rules')}
description={t('procurement.use_reorder_rules_desc')}
type="toggle"
checked={settings.use_reorder_rules} checked={settings.use_reorder_rules}
onChange={handleChange('use_reorder_rules')} onToggle={handleToggleChange('use_reorder_rules')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)] mt-0.5" helpText="Automatically calculate when to reorder based on usage patterns"
/> />
<div className="flex flex-col">
<label htmlFor="use_reorder_rules" className="text-sm font-medium text-[var(--text-secondary)]">
{t('procurement.use_reorder_rules')}
</label>
<span className="text-xs text-[var(--text-tertiary)] mt-0.5">
{t('procurement.use_reorder_rules_desc')}
</span>
</div>
</div>
<div className="flex items-start gap-2"> <SettingRow
<input label={t('procurement.economic_rounding')}
type="checkbox" description={t('procurement.economic_rounding_desc')}
id="economic_rounding" type="toggle"
checked={settings.economic_rounding} checked={settings.economic_rounding}
onChange={handleChange('economic_rounding')} onToggle={handleToggleChange('economic_rounding')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)] mt-0.5" helpText="Round order quantities to economical batch sizes"
/> />
<div className="flex flex-col">
<label htmlFor="economic_rounding" className="text-sm font-medium text-[var(--text-secondary)]">
{t('procurement.economic_rounding')}
</label>
<span className="text-xs text-[var(--text-tertiary)] mt-0.5">
{t('procurement.economic_rounding_desc')}
</span>
</div>
</div>
<div className="flex items-start gap-2"> <SettingRow
<input label={t('procurement.respect_storage_limits')}
type="checkbox" description={t('procurement.respect_storage_limits_desc')}
id="respect_storage_limits" type="toggle"
checked={settings.respect_storage_limits} checked={settings.respect_storage_limits}
onChange={handleChange('respect_storage_limits')} onToggle={handleToggleChange('respect_storage_limits')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)] mt-0.5" helpText="Ensure orders don't exceed available storage capacity"
/> />
<div className="flex flex-col">
<label htmlFor="respect_storage_limits" className="text-sm font-medium text-[var(--text-secondary)]">
{t('procurement.respect_storage_limits')}
</label>
<span className="text-xs text-[var(--text-tertiary)] mt-0.5">
{t('procurement.respect_storage_limits_desc')}
</span>
</div>
</div>
<div className="flex items-start gap-2"> <SettingRow
<input label={t('procurement.use_supplier_minimums')}
type="checkbox" description={t('procurement.use_supplier_minimums_desc')}
id="use_supplier_minimums" type="toggle"
checked={settings.use_supplier_minimums} checked={settings.use_supplier_minimums}
onChange={handleChange('use_supplier_minimums')} onToggle={handleToggleChange('use_supplier_minimums')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)] mt-0.5" helpText="Respect minimum order quantities set by suppliers"
/> />
<div className="flex flex-col">
<label htmlFor="use_supplier_minimums" className="text-sm font-medium text-[var(--text-secondary)]">
{t('procurement.use_supplier_minimums')}
</label>
<span className="text-xs text-[var(--text-tertiary)] mt-0.5">
{t('procurement.use_supplier_minimums_desc')}
</span>
</div>
</div>
<div className="flex items-start gap-2"> <SettingRow
<input label={t('procurement.optimize_price_tiers')}
type="checkbox" description={t('procurement.optimize_price_tiers_desc')}
id="optimize_price_tiers" type="toggle"
checked={settings.optimize_price_tiers} checked={settings.optimize_price_tiers}
onChange={handleChange('optimize_price_tiers')} onToggle={handleToggleChange('optimize_price_tiers')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)] mt-0.5" helpText="Automatically optimize order quantities to get best price tiers"
/> />
<div className="flex flex-col">
<label htmlFor="optimize_price_tiers" className="text-sm font-medium text-[var(--text-secondary)]">
{t('procurement.optimize_price_tiers')}
</label>
<span className="text-xs text-[var(--text-tertiary)] mt-0.5">
{t('procurement.optimize_price_tiers_desc')}
</span>
</div> </div>
</div> </div>
</div> </SettingSection>
</div>
</div>
</Card>
); );
}; };

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Factory, Calendar, TrendingUp, Clock, DollarSign } from 'lucide-react'; import { Factory, Calendar, TrendingUp, Clock, DollarSign } from 'lucide-react';
import { Card, Input } from '../../../../../components/ui'; import { Input, SettingSection, SettingRow } from '../../../../../components/ui';
import type { ProductionSettings } from '../../../../../api/types/settings'; import type { ProductionSettings } from '../../../../../api/types/settings';
interface ProductionSettingsCardProps { interface ProductionSettingsCardProps {
@@ -23,21 +23,24 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
onChange({ ...settings, [field]: value }); onChange({ ...settings, [field]: value });
}; };
return ( const handleToggleChange = (field: keyof ProductionSettings) => (checked: boolean) => {
<Card className="p-6"> onChange({ ...settings, [field]: checked });
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-6 flex items-center"> };
<Factory className="w-5 h-5 mr-2 text-[var(--color-primary)]" />
Producción
</h3>
<div className="space-y-6"> return (
<SettingSection
title="Producción"
description="Configure production planning, batch sizes, quality control, and cost settings"
icon={<Factory className="w-5 h-5" />}
>
<div className="divide-y divide-[var(--border-primary)]">
{/* Planning & Batch Size */} {/* Planning & Batch Size */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<Calendar className="w-4 h-4 mr-2" /> <Calendar className="w-4 h-4 mr-2" />
Planificación y Lotes Planificación y Lotes
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
<Input <Input
type="number" type="number"
label="Horizonte de Planificación (días)" label="Horizonte de Planificación (días)"
@@ -85,30 +88,29 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
step={1} step={1}
placeholder="10.0" placeholder="10.0"
/> />
</div>
</div>
<div className="flex items-center gap-2 md:col-span-2 xl:col-span-2"> {/* Schedule Optimization */}
<input <div className="divide-y divide-[var(--border-primary)]">
type="checkbox" <SettingRow
id="schedule_optimization_enabled" label="Optimización de Horarios"
description="Enable intelligent schedule optimization for production batches"
type="toggle"
checked={settings.schedule_optimization_enabled} checked={settings.schedule_optimization_enabled}
onChange={handleChange('schedule_optimization_enabled')} onToggle={handleToggleChange('schedule_optimization_enabled')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="Uses AI to optimize production schedules based on capacity and demand"
/> />
<label htmlFor="schedule_optimization_enabled" className="text-sm text-[var(--text-secondary)]">
Habilitar optimización de horarios
</label>
</div>
</div>
</div> </div>
{/* Capacity & Working Hours */} {/* Capacity & Working Hours */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<Clock className="w-4 h-4 mr-2" /> <Clock className="w-4 h-4 mr-2" />
Capacidad y Jornada Laboral Capacidad y Jornada Laboral
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
<Input <Input
type="number" type="number"
label="Horas de Trabajo por Día" label="Horas de Trabajo por Día"
@@ -160,33 +162,30 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
</div> </div>
{/* Quality Control */} {/* Quality Control */}
<div> <div className="divide-y divide-[var(--border-primary)]">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <SettingRow
<TrendingUp className="w-4 h-4 mr-2" /> label="Verificación de Calidad"
Control de Calidad description="Enable quality checks for production batches"
</h4> icon={<TrendingUp className="w-4 h-4" />}
<div className="space-y-4 pl-6"> type="toggle"
<div className="flex items-center gap-2">
<input
type="checkbox"
id="quality_check_enabled"
checked={settings.quality_check_enabled} checked={settings.quality_check_enabled}
onChange={handleChange('quality_check_enabled')} onToggle={handleToggleChange('quality_check_enabled')}
disabled={disabled} disabled={disabled}
className="rounded border-[var(--border-primary)]" helpText="When enabled, production batches require quality verification"
/> />
<label htmlFor="quality_check_enabled" className="text-sm text-[var(--text-secondary)]">
Habilitar verificación de calidad
</label>
</div>
{settings.quality_check_enabled && (
<div className="p-4 sm:p-6 bg-[var(--bg-secondary)]">
<h5 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
Parámetros de Calidad
</h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Rendimiento Mínimo (%)" label="Rendimiento Mínimo (%)"
value={settings.minimum_yield_percentage} value={settings.minimum_yield_percentage}
onChange={handleChange('minimum_yield_percentage')} onChange={handleChange('minimum_yield_percentage')}
disabled={disabled || !settings.quality_check_enabled} disabled={disabled}
min={50} min={50}
max={100} max={100}
step={1} step={1}
@@ -198,7 +197,7 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
label="Umbral de Puntuación de Calidad (0-10)" label="Umbral de Puntuación de Calidad (0-10)"
value={settings.quality_score_threshold} value={settings.quality_score_threshold}
onChange={handleChange('quality_score_threshold')} onChange={handleChange('quality_score_threshold')}
disabled={disabled || !settings.quality_check_enabled} disabled={disabled}
min={0} min={0}
max={10} max={10}
step={0.1} step={0.1}
@@ -206,15 +205,16 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
/> />
</div> </div>
</div> </div>
)}
</div> </div>
{/* Time Buffers */} {/* Time Buffers */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<Clock className="w-4 h-4 mr-2" /> <Clock className="w-4 h-4 mr-2" />
Tiempos de Preparación Tiempos de Preparación
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Tiempo de Preparación (minutos)" label="Tiempo de Preparación (minutos)"
@@ -242,12 +242,12 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
</div> </div>
{/* Cost Settings */} {/* Cost Settings */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<DollarSign className="w-4 h-4 mr-2" /> <DollarSign className="w-4 h-4 mr-2" />
Costes Costes
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Coste Laboral por Hora (EUR)" label="Coste Laboral por Hora (EUR)"
@@ -274,7 +274,7 @@ const ProductionSettingsCard: React.FC<ProductionSettingsCardProps> = ({
</div> </div>
</div> </div>
</div> </div>
</Card> </SettingSection>
); );
}; };

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Truck, Calendar, TrendingUp, AlertTriangle, DollarSign } from 'lucide-react'; import { Truck, Calendar, TrendingUp, AlertTriangle, Info } from 'lucide-react';
import { Card, Input } from '../../../../../components/ui'; import { Input, SettingSection } from '../../../../../components/ui';
import type { SupplierSettings } from '../../../../../api/types/settings'; import type { SupplierSettings } from '../../../../../api/types/settings';
interface SupplierSettingsCardProps { interface SupplierSettingsCardProps {
@@ -22,20 +22,19 @@ const SupplierSettingsCard: React.FC<SupplierSettingsCardProps> = ({
}; };
return ( return (
<Card className="p-6"> <SettingSection
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-6 flex items-center"> title="Gestión de Proveedores"
<Truck className="w-5 h-5 mr-2 text-[var(--color-primary)]" /> description="Configure supplier performance thresholds and default terms"
Gestión de Proveedores icon={<Truck className="w-5 h-5" />}
</h3> >
<div className="divide-y divide-[var(--border-primary)]">
<div className="space-y-6">
{/* Default Terms */} {/* Default Terms */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<Calendar className="w-4 h-4 mr-2" /> <Calendar className="w-4 h-4 mr-2" />
Términos Predeterminados Términos Predeterminados
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Plazo de Pago Predeterminado (días)" label="Plazo de Pago Predeterminado (días)"
@@ -63,12 +62,12 @@ const SupplierSettingsCard: React.FC<SupplierSettingsCardProps> = ({
</div> </div>
{/* Performance Thresholds - Delivery */} {/* Performance Thresholds - Delivery */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<TrendingUp className="w-4 h-4 mr-2" /> <TrendingUp className="w-4 h-4 mr-2" />
Umbrales de Rendimiento - Entregas Umbrales de Rendimiento - Entregas
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Tasa de Entrega Excelente (%)" label="Tasa de Entrega Excelente (%)"
@@ -96,12 +95,12 @@ const SupplierSettingsCard: React.FC<SupplierSettingsCardProps> = ({
</div> </div>
{/* Performance Thresholds - Quality */} {/* Performance Thresholds - Quality */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<TrendingUp className="w-4 h-4 mr-2" /> <TrendingUp className="w-4 h-4 mr-2" />
Umbrales de Rendimiento - Calidad Umbrales de Rendimiento - Calidad
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input <Input
type="number" type="number"
label="Tasa de Calidad Excelente (%)" label="Tasa de Calidad Excelente (%)"
@@ -129,12 +128,12 @@ const SupplierSettingsCard: React.FC<SupplierSettingsCardProps> = ({
</div> </div>
{/* Critical Alerts */} {/* Critical Alerts */}
<div> <div className="p-4 sm:p-6">
<h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center"> <h4 className="text-sm font-semibold text-[var(--text-secondary)] mb-4 flex items-center">
<AlertTriangle className="w-4 h-4 mr-2" /> <AlertTriangle className="w-4 h-4 mr-2" />
Alertas Críticas Alertas Críticas
</h4> </h4>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 pl-6"> <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
<Input <Input
type="number" type="number"
label="Retraso de Entrega Crítico (horas)" label="Retraso de Entrega Crítico (horas)"
@@ -174,14 +173,14 @@ const SupplierSettingsCard: React.FC<SupplierSettingsCardProps> = ({
</div> </div>
{/* Info Box */} {/* Info Box */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4"> <div className="p-4 sm:p-6 bg-blue-50 dark:bg-blue-900/20">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<TrendingUp className="w-5 h-5 text-blue-600 mt-0.5" /> <Info className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
<div className="flex-1"> <div className="flex-1">
<h5 className="text-sm font-semibold text-blue-900 mb-1"> <h5 className="text-sm font-semibold text-blue-900 dark:text-blue-100 mb-1">
Evaluación de Proveedores Evaluación de Proveedores
</h5> </h5>
<p className="text-xs text-blue-700"> <p className="text-xs text-blue-700 dark:text-blue-300">
Estos umbrales se utilizan para evaluar automáticamente el rendimiento de los proveedores. Estos umbrales se utilizan para evaluar automáticamente el rendimiento de los proveedores.
Los proveedores con rendimiento por debajo de los umbrales "buenos" recibirán alertas automáticas. Los proveedores con rendimiento por debajo de los umbrales "buenos" recibirán alertas automáticas.
</p> </p>
@@ -189,7 +188,7 @@ const SupplierSettingsCard: React.FC<SupplierSettingsCardProps> = ({
</div> </div>
</div> </div>
</div> </div>
</Card> </SettingSection>
); );
}; };