feat: Redesign bakery and user settings pages with improved UX
Implemented a comprehensive redesign of the settings pages using Jobs To Be Done (JTBD) methodology to improve user experience, visual appeal, and discoverability. ## New Components - **SettingRow**: Reusable component for consistent setting layouts with support for toggles, inputs, selects, and custom content - **SettingSection**: Collapsible section component for grouping related settings with consistent styling ## Page Redesigns ### BakerySettingsPage - Redesigned information tab with better visual hierarchy using SettingSection components - Improved business hours UI with clearer day-by-day layout - Enhanced header with gradient bakery icon and status indicators - Consistent spacing and responsive design improvements - Better visual feedback for unsaved changes ### NewProfileSettingsPage - Unified design with bakery settings page - Improved personal information section with SettingSection - Better security section layout with collapsible password change form - Enhanced privacy & data management UI - Consistent icon usage and visual hierarchy ### InventorySettingsCard - Replaced checkbox with toggle switch for temperature monitoring - Progressive disclosure: temperature settings only shown when enabled - Better visual separation between setting groups - Improved responsive grid layouts - Added helpful descriptions and tooltips ## Key Improvements 1. **Visual Consistency**: Both bakery and user settings now use the same design patterns and components 2. **Scannability**: Icons, badges, and clear visual hierarchy make settings easier to scan 3. **Progressive Disclosure**: Complex settings (like temperature monitoring) only show when relevant 4. **Toggle Switches**: Binary settings use toggles instead of checkboxes for better visual feedback 5. **Responsive Design**: Improved mobile and desktop layouts with better touch targets 6. **Accessibility**: Proper ARIA labels, help text, and keyboard navigation support ## JTBD Analysis Applied - Main job: "Quickly find, understand, and change settings without mistakes" - Sub-jobs addressed: - Discovery & navigation (visual grouping, icons, clear labels) - Configuration & adjustment (toggles, inline editing, validation) - Validation & confidence (help text, descriptions, visual feedback) This redesign maintains backward compatibility while significantly improving the user experience for managing bakery and personal settings.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Package, AlertCircle, Thermometer, Clock } from 'lucide-react';
|
||||
import { Card, Input } from '../../../../../components/ui';
|
||||
import { Card, Input, SettingSection, SettingRow } from '../../../../../components/ui';
|
||||
import type { InventorySettings } from '../../../../../api/types/settings';
|
||||
|
||||
interface InventorySettingsCardProps {
|
||||
@@ -23,21 +23,24 @@ const InventorySettingsCard: React.FC<InventorySettingsCardProps> = ({
|
||||
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>
|
||||
const handleToggleChange = (field: keyof InventorySettings) => (checked: boolean) => {
|
||||
onChange({ ...settings, [field]: checked });
|
||||
};
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* Stock Management */}
|
||||
<div>
|
||||
return (
|
||||
<SettingSection
|
||||
title="Gestión de Inventario"
|
||||
description="Configure stock management, expiration tracking, and temperature monitoring"
|
||||
icon={<Package className="w-5 h-5" />}
|
||||
>
|
||||
<div className="divide-y divide-[var(--border-primary)]">
|
||||
{/* Stock Management Section */}
|
||||
<div className="p-4 sm:p-6">
|
||||
<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">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
<Input
|
||||
type="number"
|
||||
label="Umbral de Stock Bajo"
|
||||
@@ -76,13 +79,13 @@ const InventorySettingsCard: React.FC<InventorySettingsCardProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expiration Management */}
|
||||
<div>
|
||||
{/* Expiration Management Section */}
|
||||
<div className="p-4 sm:p-6">
|
||||
<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">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
<Input
|
||||
type="number"
|
||||
label="Días para 'Próximo a Caducar'"
|
||||
@@ -121,159 +124,150 @@ const InventorySettingsCard: React.FC<InventorySettingsCardProps> = ({
|
||||
</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>
|
||||
{/* Temperature Monitoring Section */}
|
||||
<div className="divide-y divide-[var(--border-primary)]">
|
||||
<SettingRow
|
||||
label="Monitorización de Temperatura"
|
||||
description="Enable temperature tracking for inventory items"
|
||||
icon={<Thermometer className="w-4 h-4" />}
|
||||
type="toggle"
|
||||
checked={settings.temperature_monitoring_enabled}
|
||||
onToggle={handleToggleChange('temperature_monitoring_enabled')}
|
||||
disabled={disabled}
|
||||
helpText="When enabled, system will monitor and alert on temperature deviations"
|
||||
/>
|
||||
|
||||
{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>
|
||||
{settings.temperature_monitoring_enabled && (
|
||||
<>
|
||||
{/* Refrigeration Settings */}
|
||||
<div className="p-4 sm:p-6 bg-[var(--bg-secondary)]">
|
||||
<h5 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
|
||||
Refrigeración (°C)
|
||||
</h5>
|
||||
<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>
|
||||
{/* Freezer Settings */}
|
||||
<div className="p-4 sm:p-6 bg-[var(--bg-secondary)]">
|
||||
<h5 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
|
||||
Congelador (°C)
|
||||
</h5>
|
||||
<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>
|
||||
{/* Room Temperature Settings */}
|
||||
<div className="p-4 sm:p-6 bg-[var(--bg-secondary)]">
|
||||
<h5 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
|
||||
Temperatura Ambiente (°C)
|
||||
</h5>
|
||||
<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>
|
||||
{/* Alert Timing */}
|
||||
<div className="p-4 sm:p-6 bg-[var(--bg-secondary)]">
|
||||
<h5 className="text-sm font-medium text-[var(--text-secondary)] mb-4 flex items-center">
|
||||
<AlertCircle className="w-4 h-4 mr-2" />
|
||||
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>
|
||||
</SettingSection>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user