Support multiple languages

This commit is contained in:
Urtzi Alfaro
2025-09-25 12:14:46 +02:00
parent 6d4090f825
commit f02a980c87
66 changed files with 3274 additions and 333 deletions

View File

@@ -1,9 +1,11 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Calendar, Activity, Filter, Download, Eye, BarChart3 } from 'lucide-react';
import { Button, Card, Badge } from '../../../../components/ui';
import { PageHeader } from '../../../../components/layout';
const EventsPage: React.FC = () => {
const { t } = useTranslation();
const [selectedPeriod, setSelectedPeriod] = useState('week');
const [selectedCategory, setSelectedCategory] = useState('all');
@@ -145,8 +147,8 @@ const EventsPage: React.FC = () => {
return (
<div className="p-6 space-y-6">
<PageHeader
title="Registro de Eventos"
description="Seguimiento de todas las actividades y eventos del sistema"
title={t('events:title', 'Registro de Eventos')}
description={t('events:description', 'Seguimiento de todas las actividades y eventos del sistema')}
action={
<div className="flex space-x-2">
<Button variant="outline">

View File

@@ -1,9 +1,11 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Users, Clock, TrendingUp, MapPin, Calendar, BarChart3, Download, Filter } from 'lucide-react';
import { Button, Card, Badge } from '../../../../components/ui';
import { PageHeader } from '../../../../components/layout';
const TrafficPage: React.FC = () => {
const { t } = useTranslation();
const [selectedPeriod, setSelectedPeriod] = useState('week');
const [selectedMetric, setSelectedMetric] = useState('visitors');
@@ -99,8 +101,8 @@ const TrafficPage: React.FC = () => {
return (
<div className="p-6 space-y-6">
<PageHeader
title="Análisis de Tráfico"
description="Monitorea los patrones de visitas y flujo de clientes"
title={t('traffic:title', 'Análisis de Tráfico')}
description={t('traffic:description', 'Monitorea los patrones de visitas y flujo de clientes')}
action={
<div className="flex space-x-2">
<Button variant="outline">

View File

@@ -1,9 +1,11 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Cloud, Sun, CloudRain, Thermometer, Wind, Droplets, Calendar, TrendingUp } from 'lucide-react';
import { Button, Card, Badge } from '../../../../components/ui';
import { PageHeader } from '../../../../components/layout';
const WeatherPage: React.FC = () => {
const { t } = useTranslation();
const [selectedPeriod, setSelectedPeriod] = useState('week');
const currentWeather = {
@@ -14,13 +16,13 @@ const WeatherPage: React.FC = () => {
pressure: 1013,
uvIndex: 4,
visibility: 10,
description: 'Parcialmente nublado'
description: t('weather:conditions.partly_cloudy', 'Parcialmente nublado')
};
const forecast = [
{
date: '2024-01-27',
day: 'Sábado',
day: t('weather:days.saturday', 'Sábado'),
condition: 'sunny',
tempMax: 22,
tempMin: 12,
@@ -28,11 +30,11 @@ const WeatherPage: React.FC = () => {
precipitation: 0,
wind: 8,
impact: 'high-demand',
recommendation: 'Incrementar producción de helados y bebidas frías'
recommendation: t('weather:recommendations.increase_ice_cream', 'Incrementar producción de helados y bebidas frías')
},
{
date: '2024-01-28',
day: 'Domingo',
day: t('weather:days.sunday', 'Domingo'),
condition: 'partly-cloudy',
tempMax: 19,
tempMin: 11,
@@ -40,11 +42,11 @@ const WeatherPage: React.FC = () => {
precipitation: 20,
wind: 15,
impact: 'normal',
recommendation: 'Producción estándar'
recommendation: t('weather:recommendations.standard_production', 'Producción estándar')
},
{
date: '2024-01-29',
day: 'Lunes',
day: t('weather:days.monday', 'Lunes'),
condition: 'rainy',
tempMax: 15,
tempMin: 8,
@@ -52,11 +54,11 @@ const WeatherPage: React.FC = () => {
precipitation: 80,
wind: 22,
impact: 'comfort-food',
recommendation: 'Aumentar sopas, chocolates calientes y pan recién horneado'
recommendation: t('weather:recommendations.comfort_foods', 'Aumentar sopas, chocolates calientes y pan recién horneado')
},
{
date: '2024-01-30',
day: 'Martes',
day: t('weather:days.tuesday', 'Martes'),
condition: 'cloudy',
tempMax: 16,
tempMin: 9,
@@ -64,11 +66,11 @@ const WeatherPage: React.FC = () => {
precipitation: 40,
wind: 18,
impact: 'moderate',
recommendation: 'Enfoque en productos de interior'
recommendation: t('weather:recommendations.indoor_focus', 'Enfoque en productos de interior')
},
{
date: '2024-01-31',
day: 'Miércoles',
day: t('weather:days.wednesday', 'Miércoles'),
condition: 'sunny',
tempMax: 24,
tempMin: 14,
@@ -76,44 +78,44 @@ const WeatherPage: React.FC = () => {
precipitation: 0,
wind: 10,
impact: 'high-demand',
recommendation: 'Incrementar productos frescos y ensaladas'
recommendation: t('weather:recommendations.fresh_products', 'Incrementar productos frescos y ensaladas')
}
];
const weatherImpacts = [
{
condition: 'Día Soleado',
condition: t('weather:impacts.sunny_day.condition', 'Día Soleado'),
icon: Sun,
impact: 'Aumento del 25% en bebidas frías',
impact: t('weather:impacts.sunny_day.impact', 'Aumento del 25% en bebidas frías'),
recommendations: [
'Incrementar producción de helados',
'Más bebidas refrescantes',
'Ensaladas y productos frescos',
'Horario extendido de terraza'
t('weather:impacts.sunny_day.recommendations.0', 'Incrementar producción de helados'),
t('weather:impacts.sunny_day.recommendations.1', 'Más bebidas refrescantes'),
t('weather:impacts.sunny_day.recommendations.2', 'Ensaladas y productos frescos'),
t('weather:impacts.sunny_day.recommendations.3', 'Horario extendido de terraza')
],
color: 'yellow'
},
{
condition: 'Día Lluvioso',
condition: t('weather:impacts.rainy_day.condition', 'Día Lluvioso'),
icon: CloudRain,
impact: 'Aumento del 40% en productos calientes',
impact: t('weather:impacts.rainy_day.impact', 'Aumento del 40% en productos calientes'),
recommendations: [
'Más sopas y caldos',
'Chocolates calientes',
'Pan recién horneado',
'Productos de repostería'
t('weather:impacts.rainy_day.recommendations.0', 'Más sopas y caldos'),
t('weather:impacts.rainy_day.recommendations.1', 'Chocolates calientes'),
t('weather:impacts.rainy_day.recommendations.2', 'Pan recién horneado'),
t('weather:impacts.rainy_day.recommendations.3', 'Productos de repostería')
],
color: 'blue'
},
{
condition: 'Frío Intenso',
condition: t('weather:impacts.cold_day.condition', 'Frío Intenso'),
icon: Thermometer,
impact: 'Preferencia por comida reconfortante',
impact: t('weather:impacts.cold_day.impact', 'Preferencia por comida reconfortante'),
recommendations: [
'Aumentar productos horneados',
'Bebidas calientes especiales',
'Productos energéticos',
'Promociones de interior'
t('weather:impacts.cold_day.recommendations.0', 'Aumentar productos horneados'),
t('weather:impacts.cold_day.recommendations.1', 'Bebidas calientes especiales'),
t('weather:impacts.cold_day.recommendations.2', 'Productos energéticos'),
t('weather:impacts.cold_day.recommendations.3', 'Promociones de interior')
],
color: 'purple'
}
@@ -183,10 +185,10 @@ const WeatherPage: React.FC = () => {
const getConditionLabel = (condition: string) => {
switch (condition) {
case 'sunny': return 'Soleado';
case 'partly-cloudy': return 'Parcialmente nublado';
case 'cloudy': return 'Nublado';
case 'rainy': return 'Lluvioso';
case 'sunny': return t('weather:conditions.sunny', 'Soleado');
case 'partly-cloudy': return t('weather:conditions.partly_cloudy', 'Parcialmente nublado');
case 'cloudy': return t('weather:conditions.cloudy', 'Nublado');
case 'rainy': return t('weather:conditions.rainy', 'Lluvioso');
default: return condition;
}
};
@@ -203,10 +205,10 @@ const WeatherPage: React.FC = () => {
const getImpactLabel = (impact: string) => {
switch (impact) {
case 'high-demand': return 'Alta Demanda';
case 'comfort-food': return 'Comida Reconfortante';
case 'moderate': return 'Demanda Moderada';
case 'normal': return 'Demanda Normal';
case 'high-demand': return t('weather:impact.high_demand', 'Alta Demanda');
case 'comfort-food': return t('weather:impact.comfort_food', 'Comida Reconfortante');
case 'moderate': return t('weather:impact.moderate', 'Demanda Moderada');
case 'normal': return t('weather:impact.normal', 'Demanda Normal');
default: return impact;
}
};
@@ -214,13 +216,13 @@ const WeatherPage: React.FC = () => {
return (
<div className="p-6 space-y-6">
<PageHeader
title="Datos Meteorológicos"
description="Integra información del clima para optimizar la producción y ventas"
title={t('weather:title', 'Datos Meteorológicos')}
description={t('weather:description', 'Integra información del clima para optimizar la producción y ventas')}
/>
{/* Current Weather */}
<Card className="p-6">
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">Condiciones Actuales</h3>
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">{t('weather:current.title', 'Condiciones Actuales')}</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="flex items-center space-x-4">
{getWeatherIcon(currentWeather.condition)}
@@ -233,28 +235,28 @@ const WeatherPage: React.FC = () => {
<div className="space-y-2">
<div className="flex items-center space-x-2">
<Droplets className="w-4 h-4 text-blue-500" />
<span className="text-sm text-[var(--text-secondary)]">Humedad: {currentWeather.humidity}%</span>
<span className="text-sm text-[var(--text-secondary)]">{t('weather:current.humidity', 'Humedad')}: {currentWeather.humidity}%</span>
</div>
<div className="flex items-center space-x-2">
<Wind className="w-4 h-4 text-[var(--text-tertiary)]" />
<span className="text-sm text-[var(--text-secondary)]">Viento: {currentWeather.windSpeed} km/h</span>
<span className="text-sm text-[var(--text-secondary)]">{t('weather:current.wind', 'Viento')}: {currentWeather.windSpeed} km/h</span>
</div>
</div>
<div className="space-y-2">
<div className="text-sm text-[var(--text-secondary)]">
<span className="font-medium">Presión:</span> {currentWeather.pressure} hPa
<span className="font-medium">{t('weather:current.pressure', 'Presión')}:</span> {currentWeather.pressure} hPa
</div>
<div className="text-sm text-[var(--text-secondary)]">
<span className="font-medium">UV:</span> {currentWeather.uvIndex}
<span className="font-medium">{t('weather:current.uv', 'UV')}:</span> {currentWeather.uvIndex}
</div>
</div>
<div className="space-y-2">
<div className="text-sm text-[var(--text-secondary)]">
<span className="font-medium">Visibilidad:</span> {currentWeather.visibility} km
<span className="font-medium">{t('weather:current.visibility', 'Visibilidad')}:</span> {currentWeather.visibility} km
</div>
<Badge variant="blue">Condiciones favorables</Badge>
<Badge variant="blue">{t('weather:current.favorable_conditions', 'Condiciones favorables')}</Badge>
</div>
</div>
</Card>
@@ -262,14 +264,14 @@ const WeatherPage: React.FC = () => {
{/* Weather Forecast */}
<Card className="p-6">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-[var(--text-primary)]">Pronóstico Extendido</h3>
<h3 className="text-lg font-semibold text-[var(--text-primary)]">{t('weather:forecast.title', 'Pronóstico Extendido')}</h3>
<select
value={selectedPeriod}
onChange={(e) => setSelectedPeriod(e.target.value)}
className="px-3 py-2 border border-[var(--border-secondary)] rounded-md text-sm"
>
<option value="week">Próxima Semana</option>
<option value="month">Próximo Mes</option>
<option value="week">{t('weather:forecast.next_week', 'Próxima Semana')}</option>
<option value="month">{t('weather:forecast.next_month', 'Próximo Mes')}</option>
</select>
</div>
@@ -294,15 +296,15 @@ const WeatherPage: React.FC = () => {
<div className="space-y-2 text-xs text-[var(--text-secondary)]">
<div className="flex justify-between">
<span>Humedad:</span>
<span>{t('weather:current.humidity', 'Humedad')}:</span>
<span>{day.humidity}%</span>
</div>
<div className="flex justify-between">
<span>Lluvia:</span>
<span>{t('weather:forecast.rain', 'Lluvia')}:</span>
<span>{day.precipitation}%</span>
</div>
<div className="flex justify-between">
<span>Viento:</span>
<span>{t('weather:current.wind', 'Viento')}:</span>
<span>{day.wind} km/h</span>
</div>
</div>
@@ -324,7 +326,7 @@ const WeatherPage: React.FC = () => {
{/* Weather Impact Analysis */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="p-6">
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">Impacto del Clima</h3>
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">{t('weather:impact.title', 'Impacto del Clima')}</h3>
<div className="space-y-4">
{weatherImpacts.map((impact, index) => (
<div key={index} className="border rounded-lg p-4">
@@ -339,7 +341,7 @@ const WeatherPage: React.FC = () => {
</div>
<div className="ml-10">
<p className="text-sm font-medium text-[var(--text-secondary)] mb-2">Recomendaciones:</p>
<p className="text-sm font-medium text-[var(--text-secondary)] mb-2">{t('weather:impact.recommendations', 'Recomendaciones')}:</p>
<ul className="text-sm text-[var(--text-secondary)] space-y-1">
{impact.recommendations.map((rec, idx) => (
<li key={idx} className="flex items-center">
@@ -356,7 +358,7 @@ const WeatherPage: React.FC = () => {
{/* Seasonal Trends */}
<Card className="p-6">
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">Tendencias Estacionales</h3>
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">{t('weather:seasonal.title', 'Tendencias Estacionales')}</h3>
<div className="space-y-4">
{seasonalTrends.map((season, index) => (
<div key={index} className="border rounded-lg p-4">
@@ -395,7 +397,7 @@ const WeatherPage: React.FC = () => {
{/* Weather Alerts */}
<Card className="p-6">
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">Alertas Meteorológicas</h3>
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-4">{t('weather:alerts.title', 'Alertas Meteorológicas')}</h3>
<div className="space-y-3">
<div className="flex items-center p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
<Sun className="w-5 h-5 text-yellow-600 mr-3" />

View File

@@ -1,9 +1,11 @@
import React from 'react';
import { Outlet, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { PageHeader } from '../../../components/layout/PageHeader/PageHeader';
import { Database, Package, ShoppingCart, Truck, Settings, Users, MessageSquare } from 'lucide-react';
const DatabasePage: React.FC = () => {
const { t } = useTranslation();
const location = useLocation();
const isParentRoute = location.pathname === '/app/database';
@@ -14,8 +16,8 @@ const DatabasePage: React.FC = () => {
return (
<div className="p-6 space-y-6">
<PageHeader
title="Mi Panadería"
description="Consulta y gestiona toda la información de tu panadería"
title={t('database:title', 'Mi Panadería')}
description={t('database:subtitle', 'Consulta y gestiona toda la información de tu panadería')}
/>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -24,9 +26,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-blue-100 rounded-lg">
<Package className="w-6 h-6 text-blue-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Recetas</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.recipes.title', 'Recetas')}</h3>
</div>
<p className="text-gray-600">Gestiona las recetas de tus productos</p>
<p className="text-gray-600">{t('database:sections.recipes.description', 'Gestiona las recetas de tus productos')}</p>
</div>
<div className="bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-shadow cursor-pointer">
@@ -34,9 +36,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-green-100 rounded-lg">
<ShoppingCart className="w-6 h-6 text-green-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Pedidos</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.orders.title', 'Pedidos')}</h3>
</div>
<p className="text-gray-600">Consulta el estado de todos los pedidos</p>
<p className="text-gray-600">{t('database:sections.orders.description', 'Consulta el estado de todos los pedidos')}</p>
</div>
@@ -45,9 +47,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-yellow-100 rounded-lg">
<Truck className="w-6 h-6 text-yellow-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Proveedores</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.suppliers.title', 'Proveedores')}</h3>
</div>
<p className="text-gray-600">Gestiona tus proveedores</p>
<p className="text-gray-600">{t('database:sections.suppliers.description', 'Gestiona tus proveedores')}</p>
</div>
<div className="bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-shadow cursor-pointer">
@@ -55,9 +57,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-red-100 rounded-lg">
<Database className="w-6 h-6 text-red-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Inventario</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.inventory.title', 'Inventario')}</h3>
</div>
<p className="text-gray-600">Estado actual del inventario</p>
<p className="text-gray-600">{t('database:sections.inventory.description', 'Estado actual del inventario')}</p>
</div>
<div className="bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-shadow cursor-pointer">
@@ -65,9 +67,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-indigo-100 rounded-lg">
<Settings className="w-6 h-6 text-indigo-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Configuración de Panadería</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.bakery_config.title', 'Configuración de Panadería')}</h3>
</div>
<p className="text-gray-600">Configuración general de tu panadería</p>
<p className="text-gray-600">{t('database:sections.bakery_config.description', 'Configuración general de tu panadería')}</p>
</div>
<div className="bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-shadow cursor-pointer">
@@ -75,9 +77,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-orange-100 rounded-lg">
<Users className="w-6 h-6 text-orange-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Gestión de Equipo</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.team_management.title', 'Gestión de Equipo')}</h3>
</div>
<p className="text-gray-600">Administra tu equipo de trabajo</p>
<p className="text-gray-600">{t('database:sections.team_management.description', 'Administra tu equipo de trabajo')}</p>
</div>
<div className="bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-shadow cursor-pointer">
@@ -85,9 +87,9 @@ const DatabasePage: React.FC = () => {
<div className="p-2 bg-teal-100 rounded-lg">
<MessageSquare className="w-6 h-6 text-teal-600" />
</div>
<h3 className="text-lg font-semibold text-gray-900">Preferencias de Comunicación</h3>
<h3 className="text-lg font-semibold text-gray-900">{t('database:sections.communication_preferences.title', 'Preferencias de Comunicación')}</h3>
</div>
<p className="text-gray-600">Configura notificaciones y comunicaciones</p>
<p className="text-gray-600">{t('database:sections.communication_preferences.description', 'Configura notificaciones y comunicaciones')}</p>
</div>
</div>
</div>

View File

@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { PageHeader } from '../../../../components/layout';
import { Button } from '../../../../components/ui/Button';
import { Card, CardHeader, CardBody } from '../../../../components/ui/Card';
@@ -25,6 +26,7 @@ import {
} from 'lucide-react';
const OrganizationsPage: React.FC = () => {
const { t } = useTranslation(['settings']);
const navigate = useNavigate();
const user = useAuthUser();
const { currentTenant, availableTenants, switchTenant } = useTenant();
@@ -77,8 +79,8 @@ const OrganizationsPage: React.FC = () => {
return (
<div className="space-y-6 p-4 sm:p-6">
<PageHeader
title="Mis Organizaciones"
description="Gestiona tus panaderías y negocios"
title={t('settings:organization.title', 'Mis Organizaciones')}
description={t('settings:organization.description', 'Gestiona tus panaderías y negocios')}
actions={
<Button
onClick={handleAddNewOrganization}

View File

@@ -29,7 +29,7 @@ interface PasswordData {
const ProfilePage: React.FC = () => {
const user = useAuthUser();
const { t } = useTranslation('auth');
const { t } = useTranslation(['settings', 'auth']);
const { addToast } = useToast();
const { data: profile, isLoading: profileLoading, error: profileError } = useAuthProfile();
@@ -405,7 +405,7 @@ const ProfilePage: React.FC = () => {
)}
<div className="flex items-center gap-2 mt-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="text-sm text-text-tertiary">En línea</span>
<span className="text-sm text-text-tertiary">{t('settings:profile.online', 'En línea')}</span>
</div>
</div>
<div className="flex gap-2">
@@ -416,7 +416,7 @@ const ProfilePage: React.FC = () => {
className="flex items-center gap-2"
>
<User className="w-4 h-4" />
Editar Perfil
{t('settings:profile.edit_profile', 'Editar Perfil')}
</Button>
)}
<Button
@@ -425,7 +425,7 @@ const ProfilePage: React.FC = () => {
className="flex items-center gap-2"
>
<Lock className="w-4 h-4" />
Cambiar Contraseña
{t('settings:profile.change_password', 'Cambiar Contraseña')}
</Button>
</div>
</div>
@@ -435,11 +435,11 @@ const ProfilePage: React.FC = () => {
{/* Profile Form */}
{activeTab === 'profile' && (
<Card className="p-6">
<h2 className="text-lg font-semibold mb-4">Información Personal</h2>
<h2 className="text-lg font-semibold mb-4">{t('settings:profile.personal_info', 'Información Personal')}</h2>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
<Input
label="Nombre"
label={t('settings:profile.fields.first_name', 'Nombre')}
value={profileData.first_name}
onChange={handleInputChange('first_name')}
error={errors.first_name}
@@ -448,7 +448,7 @@ const ProfilePage: React.FC = () => {
/>
<Input
label="Apellidos"
label={t('settings:profile.fields.last_name', 'Apellidos')}
value={profileData.last_name}
onChange={handleInputChange('last_name')}
error={errors.last_name}
@@ -457,7 +457,7 @@ const ProfilePage: React.FC = () => {
<Input
type="email"
label="Correo Electrónico"
label={t('settings:profile.fields.email', 'Correo Electrónico')}
value={profileData.email}
onChange={handleInputChange('email')}
error={errors.email}
@@ -467,7 +467,7 @@ const ProfilePage: React.FC = () => {
<Input
type="tel"
label="Teléfono"
label={t('settings:profile.fields.phone', 'Teléfono')}
value={profileData.phone}
onChange={handleInputChange('phone')}
error={errors.phone}

View File

@@ -1,4 +1,5 @@
import React, { useState, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Users, Plus, Search, Shield, Trash2, Crown, UserCheck } from 'lucide-react';
import { Button, Card, Input, StatusCard, getStatusColor, StatsGrid } from '../../../../components/ui';
import AddTeamMemberModal from '../../../../components/domain/team/AddTeamMemberModal';
@@ -11,6 +12,7 @@ import { useToast } from '../../../../hooks/ui/useToast';
import { TENANT_ROLES } from '../../../../types/roles';
const TeamPage: React.FC = () => {
const { t } = useTranslation(['settings']);
const { addToast } = useToast();
const currentUser = useAuthUser();
const currentTenant = useCurrentTenant();
@@ -299,8 +301,8 @@ const TeamPage: React.FC = () => {
return (
<div className="p-6 space-y-6">
<PageHeader
title="Gestión de Equipo"
description="Administra los miembros del equipo, roles y permisos"
title={t('settings:team.title', 'Gestión de Equipo')}
description={t('settings:team.description', 'Administra los miembros del equipo, roles y permisos')}
actions={
canManageTeam ? [{
id: 'add-member',

View File

@@ -10,6 +10,7 @@ const OnboardingPage: React.FC = () => {
headerProps={{
showThemeToggle: true,
showAuthButtons: false,
showLanguageSelector: true,
variant: "minimal"
}}
>

View File

@@ -1,5 +1,6 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Button } from '../../components/ui';
import { PublicLayout } from '../../components/layout';
import {
@@ -23,6 +24,8 @@ import {
} from 'lucide-react';
const LandingPage: React.FC = () => {
const { t } = useTranslation();
const scrollToSection = (sectionId: string) => {
const element = document.getElementById(sectionId);
if (element) {
@@ -37,12 +40,13 @@ const LandingPage: React.FC = () => {
headerProps={{
showThemeToggle: true,
showAuthButtons: true,
showLanguageSelector: true,
variant: "default",
navigationItems: [
{ id: 'features', label: 'Características', href: '#features' },
{ id: 'benefits', label: 'Beneficios', href: '#benefits' },
{ id: 'pricing', label: 'Precios', href: '#pricing' },
{ id: 'testimonials', label: 'Testimonios', href: '#testimonials' }
{ id: 'features', label: t('landing:navigation.features', 'Características'), href: '#features' },
{ id: 'benefits', label: t('landing:navigation.benefits', 'Beneficios'), href: '#benefits' },
{ id: 'pricing', label: t('landing:navigation.pricing', 'Precios'), href: '#pricing' },
{ id: 'testimonials', label: t('landing:navigation.testimonials', 'Testimonios'), href: '#testimonials' }
]
}}
>
@@ -54,24 +58,23 @@ const LandingPage: React.FC = () => {
<div className="mb-6">
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-[var(--color-primary)]/10 text-[var(--color-primary)]">
<Zap className="w-4 h-4 mr-2" />
IA Avanzada para Panaderías
{t('landing:hero.badge', 'IA Avanzada para Panaderías')}
</span>
</div>
<h1 className="text-4xl tracking-tight font-extrabold text-[var(--text-primary)] sm:text-5xl lg:text-7xl">
<span className="block">Revoluciona tu</span>
<span className="block text-[var(--color-primary)]">Panadería con IA</span>
<span className="block">{t('landing:hero.title_line1', 'Revoluciona tu')}</span>
<span className="block text-[var(--color-primary)]">{t('landing:hero.title_line2', 'Panadería con IA')}</span>
</h1>
<p className="mt-6 max-w-3xl mx-auto text-lg text-[var(--text-secondary)] sm:text-xl">
Optimiza automáticamente tu producción, reduce desperdicios hasta un 35%,
predice demanda con precisión del 92% y aumenta tus ventas con inteligencia artificial.
{t('landing:hero.subtitle', 'Optimiza automáticamente tu producción, reduce desperdicios hasta un 35%, predice demanda con precisión del 92% y aumenta tus ventas con inteligencia artificial.')}
</p>
<div className="mt-10 flex flex-col sm:flex-row gap-4 justify-center">
<Link to="/register">
<Button size="lg" className="px-8 py-4 text-lg font-semibold bg-[var(--color-primary)] hover:bg-[var(--color-primary-dark)] text-white shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200">
Comenzar Gratis 14 Días
{t('landing:hero.cta_primary', 'Comenzar Gratis 14 Días')}
<ArrowRight className="ml-2 w-5 h-5" />
</Button>
</Link>
@@ -82,22 +85,22 @@ const LandingPage: React.FC = () => {
onClick={() => scrollToSection('demo')}
>
<Play className="mr-2 w-5 h-5" />
Ver Demo en Vivo
{t('landing:hero.cta_secondary', 'Ver Demo en Vivo')}
</Button>
</div>
<div className="mt-12 flex items-center justify-center space-x-6 text-sm text-[var(--text-tertiary)]">
<div className="flex items-center">
<Check className="w-4 h-4 text-green-500 mr-2" />
Sin tarjeta de crédito
{t('landing:hero.features.no_credit_card', 'Sin tarjeta de crédito')}
</div>
<div className="flex items-center">
<Check className="w-4 h-4 text-green-500 mr-2" />
Configuración en 5 minutos
{t('landing:hero.features.quick_setup', 'Configuración en 5 minutos')}
</div>
<div className="flex items-center">
<Check className="w-4 h-4 text-green-500 mr-2" />
Soporte 24/7 en español
{t('landing:hero.features.support_24_7', 'Soporte 24/7 en español')}
</div>
</div>
</div>

View File

@@ -37,6 +37,7 @@ const LoginPage: React.FC = () => {
headerProps={{
showThemeToggle: true,
showAuthButtons: false,
showLanguageSelector: true,
variant: "minimal"
}}
>

View File

@@ -21,6 +21,7 @@ const RegisterPage: React.FC = () => {
headerProps={{
showThemeToggle: true,
showAuthButtons: false,
showLanguageSelector: true,
variant: "minimal"
}}
>