Support multiple languages
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -10,6 +10,7 @@ const OnboardingPage: React.FC = () => {
|
||||
headerProps={{
|
||||
showThemeToggle: true,
|
||||
showAuthButtons: false,
|
||||
showLanguageSelector: true,
|
||||
variant: "minimal"
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -37,6 +37,7 @@ const LoginPage: React.FC = () => {
|
||||
headerProps={{
|
||||
showThemeToggle: true,
|
||||
showAuthButtons: false,
|
||||
showLanguageSelector: true,
|
||||
variant: "minimal"
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -21,6 +21,7 @@ const RegisterPage: React.FC = () => {
|
||||
headerProps={{
|
||||
showThemeToggle: true,
|
||||
showAuthButtons: false,
|
||||
showLanguageSelector: true,
|
||||
variant: "minimal"
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user