Fix: Improve table layout functionality

This commit is contained in:
gpt-engineer-app[bot]
2025-10-10 23:32:17 +00:00
parent 73f9b1ab95
commit b1030222f6
8 changed files with 867 additions and 2 deletions

View File

@@ -34,6 +34,7 @@ import Invoices from "./pages/dashboard/Invoices";
import InvoiceDetail from "./pages/dashboard/InvoiceDetail"; import InvoiceDetail from "./pages/dashboard/InvoiceDetail";
import HotelManagement from "./pages/dashboard/HotelManagement"; import HotelManagement from "./pages/dashboard/HotelManagement";
import RestaurantPOS from "./pages/dashboard/RestaurantPOS"; import RestaurantPOS from "./pages/dashboard/RestaurantPOS";
import Personalization from "./pages/dashboard/Personalization";
import NotFound from "./pages/NotFound"; import NotFound from "./pages/NotFound";
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@@ -255,6 +256,13 @@ const AppRouter = () => (
</DashboardLayout> </DashboardLayout>
</ProtectedRoute> </ProtectedRoute>
} /> } />
<Route path="/dashboard/personalization" element={
<ProtectedRoute>
<DashboardLayout>
<Personalization />
</DashboardLayout>
</ProtectedRoute>
} />
{/* Catch-all route */} {/* Catch-all route */}
<Route path="*" element={<NotFound />} /> <Route path="*" element={<NotFound />} />

View File

@@ -38,7 +38,8 @@ import {
ChevronDown, ChevronDown,
ChevronRight, ChevronRight,
Hotel, Hotel,
UtensilsCrossed UtensilsCrossed,
Brain
} from 'lucide-react'; } from 'lucide-react';
const DashboardLayout = ({ children }: { children: React.ReactNode }) => { const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
@@ -63,6 +64,7 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
{ icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager' }, { icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager' },
{ icon: Hotel, label: 'Hotel Management', path: '/dashboard/hotel-management' }, { icon: Hotel, label: 'Hotel Management', path: '/dashboard/hotel-management' },
{ icon: UtensilsCrossed, label: 'Restaurant POS', path: '/dashboard/restaurant-pos' }, { icon: UtensilsCrossed, label: 'Restaurant POS', path: '/dashboard/restaurant-pos' },
{ icon: Brain, label: 'Personalization', path: '/dashboard/personalization' },
{ icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' }, { icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' },
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' }, { icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
]; ];

View File

@@ -0,0 +1,181 @@
import { useState } from 'react';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Brain, Star, MapPin, TrendingUp, ThumbsUp, ThumbsDown } from 'lucide-react';
import { toast } from 'sonner';
interface Recommendation {
id: string;
userId: string;
userName: string;
type: 'destination' | 'activity' | 'restaurant' | 'hotel';
item: string;
confidence: number;
reason: string;
matchScore: number;
}
const AIRecommendations = () => {
const [recommendations] = useState<Recommendation[]>([
{
id: '1',
userId: 'user_123',
userName: 'María García',
type: 'destination',
item: 'Barcelona, España',
confidence: 95,
reason: 'Basado en historial de viajes a ciudades culturales',
matchScore: 95
},
{
id: '2',
userId: 'user_123',
userName: 'María García',
type: 'activity',
item: 'Tour Gastronómico Sagrada Familia',
confidence: 88,
reason: 'Usuario interesado en gastronomía y arquitectura',
matchScore: 88
},
{
id: '3',
userId: 'user_456',
userName: 'Carlos López',
type: 'hotel',
item: 'Hotel Boutique Centro Histórico',
confidence: 92,
reason: 'Prefiere alojamientos boutique en zonas céntricas',
matchScore: 92
},
{
id: '4',
userId: 'user_789',
userName: 'Ana Martínez',
type: 'restaurant',
item: 'Restaurante Vegetariano "Green Life"',
confidence: 90,
reason: 'Historial de preferencias vegetarianas y sostenibles',
matchScore: 90
}
]);
const getTypeIcon = (type: Recommendation['type']) => {
switch (type) {
case 'destination': return MapPin;
case 'activity': return Star;
case 'restaurant': return Star;
case 'hotel': return MapPin;
default: return Star;
}
};
const getTypeLabel = (type: Recommendation['type']) => {
switch (type) {
case 'destination': return 'Destino';
case 'activity': return 'Actividad';
case 'restaurant': return 'Restaurante';
case 'hotel': return 'Hotel';
default: return type;
}
};
const getConfidenceColor = (confidence: number) => {
if (confidence >= 90) return 'bg-green-500';
if (confidence >= 75) return 'bg-yellow-500';
return 'bg-orange-500';
};
const handleFeedback = (recId: string, positive: boolean) => {
toast.success(positive ? 'Feedback positivo registrado' : 'Feedback negativo registrado');
};
return (
<div className="space-y-6">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Brain className="h-4 w-4" />
<span>Motor de IA analizando {recommendations.length} recomendaciones activas</span>
</div>
<div className="grid gap-4 md:grid-cols-2">
{recommendations.map((rec) => {
const Icon = getTypeIcon(rec.type);
return (
<Card key={rec.id}>
<CardContent className="p-4">
<div className="space-y-3">
<div className="flex justify-between items-start">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Icon className="h-4 w-4 text-primary" />
<Badge variant="outline">{getTypeLabel(rec.type)}</Badge>
</div>
<h4 className="font-semibold">{rec.item}</h4>
<p className="text-xs text-muted-foreground mt-1">
Para: {rec.userName}
</p>
</div>
<div className="text-right">
<div className="flex items-center gap-1">
<div className={`w-2 h-2 rounded-full ${getConfidenceColor(rec.confidence)}`}></div>
<span className="text-sm font-medium">{rec.confidence}%</span>
</div>
<span className="text-xs text-muted-foreground">confianza</span>
</div>
</div>
<div className="p-3 bg-muted rounded-lg">
<div className="flex items-start gap-2">
<Brain className="h-4 w-4 text-primary mt-0.5" />
<div className="flex-1">
<div className="text-xs font-medium mb-1">Razón de la recomendación:</div>
<div className="text-xs text-muted-foreground">{rec.reason}</div>
</div>
</div>
</div>
<div className="flex items-center justify-between pt-2">
<div className="flex items-center gap-1">
<TrendingUp className="h-3 w-3 text-muted-foreground" />
<span className="text-xs text-muted-foreground">
Match Score: {rec.matchScore}%
</span>
</div>
<div className="flex gap-1">
<Button
size="sm"
variant="ghost"
className="h-7 w-7 p-0"
onClick={() => handleFeedback(rec.id, true)}
>
<ThumbsUp className="h-3 w-3" />
</Button>
<Button
size="sm"
variant="ghost"
className="h-7 w-7 p-0"
onClick={() => handleFeedback(rec.id, false)}
>
<ThumbsDown className="h-3 w-3" />
</Button>
</div>
</div>
</div>
</CardContent>
</Card>
);
})}
</div>
{recommendations.length === 0 && (
<div className="text-center py-12 text-muted-foreground">
<Brain className="h-12 w-12 mx-auto mb-4 opacity-50" />
<p>No hay recomendaciones activas</p>
</div>
)}
</div>
);
};
export default AIRecommendations;

View File

@@ -0,0 +1,180 @@
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { TrendingUp, Eye, MousePointer, Clock, MapPin } from 'lucide-react';
const BehaviorAnalytics = () => {
const behaviorData = {
topDestinations: [
{ name: 'Barcelona', views: 1250, bookings: 85 },
{ name: 'Madrid', views: 1120, bookings: 72 },
{ name: 'Valencia', views: 890, bookings: 58 },
{ name: 'Sevilla', views: 780, bookings: 45 }
],
userJourney: [
{ step: 'Landing Page', users: 1000, dropoff: 0 },
{ step: 'Búsqueda', users: 850, dropoff: 15 },
{ step: 'Detalle', users: 680, dropoff: 20 },
{ step: 'Reserva', users: 425, dropoff: 37.5 },
{ step: 'Pago', users: 340, dropoff: 20 }
],
peakHours: [
{ hour: '09:00', activity: 45 },
{ hour: '12:00', activity: 78 },
{ hour: '15:00', activity: 65 },
{ hour: '18:00', activity: 92 },
{ hour: '21:00', activity: 58 }
]
};
return (
<div className="space-y-6">
<div className="grid gap-6 md:grid-cols-2">
{/* Top Destinations */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<MapPin className="h-5 w-5" />
Destinos Más Vistos
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{behaviorData.topDestinations.map((dest, idx) => (
<div key={idx} className="space-y-1">
<div className="flex justify-between items-center">
<span className="font-medium">{dest.name}</span>
<Badge variant="secondary">{dest.views} vistas</Badge>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 h-2 bg-muted rounded-full overflow-hidden">
<div
className="h-full bg-primary"
style={{ width: `${(dest.bookings / dest.views) * 100}%` }}
></div>
</div>
<span className="text-xs text-muted-foreground">
{dest.bookings} reservas
</span>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* User Journey Funnel */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<TrendingUp className="h-5 w-5" />
Embudo de Conversión
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{behaviorData.userJourney.map((step, idx) => (
<div key={idx} className="space-y-1">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">{step.step}</span>
<div className="flex items-center gap-2">
<span className="text-sm">{step.users} usuarios</span>
{step.dropoff > 0 && (
<Badge variant="outline" className="text-xs">
-{step.dropoff}%
</Badge>
)}
</div>
</div>
<div className="flex-1 h-2 bg-muted rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-green-500 to-blue-500"
style={{ width: `${(step.users / 1000) * 100}%` }}
></div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
{/* Peak Activity Hours */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<Clock className="h-5 w-5" />
Horas de Mayor Actividad
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex justify-between items-end h-40 gap-4">
{behaviorData.peakHours.map((hour, idx) => (
<div key={idx} className="flex-1 flex flex-col items-center gap-2">
<div className="w-full flex items-end justify-center h-32">
<div
className="w-full bg-primary rounded-t-lg transition-all hover:bg-primary/80"
style={{ height: `${hour.activity}%` }}
></div>
</div>
<div className="text-xs text-muted-foreground">{hour.hour}</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* Quick Stats */}
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<Eye className="h-8 w-8 text-blue-500" />
<div>
<div className="text-2xl font-bold">4,890</div>
<div className="text-xs text-muted-foreground">Páginas vistas</div>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<MousePointer className="h-8 w-8 text-green-500" />
<div>
<div className="text-2xl font-bold">68%</div>
<div className="text-xs text-muted-foreground">Click-through rate</div>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<Clock className="h-8 w-8 text-purple-500" />
<div>
<div className="text-2xl font-bold">4:32</div>
<div className="text-xs text-muted-foreground">Tiempo promedio</div>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<TrendingUp className="h-8 w-8 text-orange-500" />
<div>
<div className="text-2xl font-bold">34%</div>
<div className="text-xs text-muted-foreground">Tasa conversión</div>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
);
};
export default BehaviorAnalytics;

View File

@@ -0,0 +1,179 @@
import { useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Users, Plus, Target, TrendingUp } from 'lucide-react';
import { toast } from 'sonner';
interface Segment {
id: string;
name: string;
description: string;
userCount: number;
criteria: string[];
conversionRate: number;
avgSpending: number;
}
const SegmentManagement = () => {
const [segments] = useState<Segment[]>([
{
id: '1',
name: 'Viajeros Culturales',
description: 'Usuarios interesados en historia, arte y cultura',
userCount: 450,
criteria: ['Visita museos', 'Busca tours culturales', 'Presupuesto medio-alto'],
conversionRate: 42,
avgSpending: 850
},
{
id: '2',
name: 'Amantes de la Playa',
description: 'Prefieren destinos costeros y actividades acuáticas',
userCount: 380,
criteria: ['Busca playas', 'Reserva resorts', 'Temporada verano'],
conversionRate: 38,
avgSpending: 720
},
{
id: '3',
name: 'Aventureros',
description: 'Buscan experiencias de aventura y naturaleza',
userCount: 290,
criteria: ['Actividades outdoor', 'Deportes extremos', 'Ecoturismo'],
conversionRate: 45,
avgSpending: 950
},
{
id: '4',
name: 'Gastronómicos',
description: 'Viajeros enfocados en experiencias culinarias',
userCount: 320,
criteria: ['Tours gastronómicos', 'Restaurantes gourmet', 'Cocina local'],
conversionRate: 48,
avgSpending: 1100
}
]);
const createSegment = () => {
toast.success('Segmento creado correctamente');
};
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<div>
<h3 className="text-lg font-semibold">Segmentos Activos</h3>
<p className="text-sm text-muted-foreground">
{segments.length} segmentos de usuarios configurados
</p>
</div>
<Dialog>
<DialogTrigger asChild>
<Button className="gap-2">
<Plus className="h-4 w-4" />
Nuevo Segmento
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Crear Nuevo Segmento</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label htmlFor="segment-name">Nombre del Segmento</Label>
<Input id="segment-name" placeholder="Ej: Viajeros de Lujo" />
</div>
<div>
<Label htmlFor="segment-desc">Descripción</Label>
<Input id="segment-desc" placeholder="Descripción del segmento" />
</div>
<div>
<Label htmlFor="segment-criteria">Criterios (separados por coma)</Label>
<Input
id="segment-criteria"
placeholder="Alta capacidad de gasto, Hoteles 5 estrellas, ..."
/>
</div>
<Button onClick={createSegment} className="w-full">
Crear Segmento
</Button>
</div>
</DialogContent>
</Dialog>
</div>
<div className="grid gap-4 md:grid-cols-2">
{segments.map((segment) => (
<Card key={segment.id}>
<CardHeader>
<div className="flex justify-between items-start">
<div className="flex-1">
<CardTitle className="flex items-center gap-2 text-lg">
<Target className="h-5 w-5 text-primary" />
{segment.name}
</CardTitle>
<p className="text-sm text-muted-foreground mt-1">
{segment.description}
</p>
</div>
</div>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between p-3 bg-muted rounded-lg">
<div className="flex items-center gap-2">
<Users className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">Usuarios</span>
</div>
<span className="text-2xl font-bold">{segment.userCount}</span>
</div>
<div className="space-y-2">
<div className="text-sm font-medium">Criterios de segmentación:</div>
<div className="flex flex-wrap gap-1">
{segment.criteria.map((criterion, idx) => (
<Badge key={idx} variant="outline">{criterion}</Badge>
))}
</div>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="p-3 bg-green-50 rounded-lg">
<div className="flex items-center gap-1 mb-1">
<TrendingUp className="h-3 w-3 text-green-600" />
<span className="text-xs text-green-600">Conversión</span>
</div>
<div className="text-xl font-bold text-green-700">
{segment.conversionRate}%
</div>
</div>
<div className="p-3 bg-blue-50 rounded-lg">
<div className="flex items-center gap-1 mb-1">
<span className="text-xs text-blue-600">Gasto Promedio</span>
</div>
<div className="text-xl font-bold text-blue-700">
{segment.avgSpending}
</div>
</div>
</div>
<div className="flex gap-2 pt-2">
<Button variant="outline" size="sm" className="flex-1">
Ver Usuarios
</Button>
<Button variant="outline" size="sm" className="flex-1">
Editar
</Button>
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
};
export default SegmentManagement;

View File

@@ -0,0 +1,154 @@
import { useState } from 'react';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { Label } from '@/components/ui/label';
import { User, Heart, Tag, Bell } from 'lucide-react';
interface UserProfile {
id: string;
name: string;
email: string;
preferences: {
destinations: string[];
activities: string[];
budget: string;
travelStyle: string;
};
notifications: {
email: boolean;
push: boolean;
sms: boolean;
};
interests: string[];
}
const UserPreferences = () => {
const [users] = useState<UserProfile[]>([
{
id: '1',
name: 'María García',
email: 'maria@example.com',
preferences: {
destinations: ['Europa', 'Asia'],
activities: ['Cultura', 'Gastronomía', 'Historia'],
budget: 'Medio-Alto',
travelStyle: 'Cultural'
},
notifications: {
email: true,
push: true,
sms: false
},
interests: ['Arte', 'Museos', 'Cocina Local', 'Arquitectura']
},
{
id: '2',
name: 'Carlos López',
email: 'carlos@example.com',
preferences: {
destinations: ['Caribe', 'Mediterráneo'],
activities: ['Playa', 'Deportes', 'Relax'],
budget: 'Alto',
travelStyle: 'Lujo'
},
notifications: {
email: true,
push: false,
sms: true
},
interests: ['Golf', 'Spa', 'Gastronomía Gourmet', 'Vinos']
}
]);
return (
<div className="space-y-6">
<div className="grid gap-4 md:grid-cols-2">
{users.map((user) => (
<Card key={user.id}>
<CardContent className="p-4">
<div className="space-y-4">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center">
<User className="h-5 w-5 text-primary" />
</div>
<div>
<h4 className="font-semibold">{user.name}</h4>
<p className="text-xs text-muted-foreground">{user.email}</p>
</div>
</div>
</div>
<div className="space-y-3">
<div>
<div className="flex items-center gap-2 mb-2">
<Heart className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">Destinos Favoritos</span>
</div>
<div className="flex flex-wrap gap-1">
{user.preferences.destinations.map((dest, idx) => (
<Badge key={idx} variant="secondary">{dest}</Badge>
))}
</div>
</div>
<div>
<div className="flex items-center gap-2 mb-2">
<Tag className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">Intereses</span>
</div>
<div className="flex flex-wrap gap-1">
{user.interests.map((interest, idx) => (
<Badge key={idx} variant="outline">{interest}</Badge>
))}
</div>
</div>
<div className="grid grid-cols-2 gap-3 text-sm">
<div>
<span className="text-muted-foreground">Presupuesto:</span>
<div className="font-medium">{user.preferences.budget}</div>
</div>
<div>
<span className="text-muted-foreground">Estilo:</span>
<div className="font-medium">{user.preferences.travelStyle}</div>
</div>
</div>
<div className="pt-3 border-t">
<div className="flex items-center gap-2 mb-3">
<Bell className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">Notificaciones</span>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label htmlFor={`email-${user.id}`} className="text-xs">Email</Label>
<Switch id={`email-${user.id}`} checked={user.notifications.email} />
</div>
<div className="flex items-center justify-between">
<Label htmlFor={`push-${user.id}`} className="text-xs">Push</Label>
<Switch id={`push-${user.id}`} checked={user.notifications.push} />
</div>
<div className="flex items-center justify-between">
<Label htmlFor={`sms-${user.id}`} className="text-xs">SMS</Label>
<Switch id={`sms-${user.id}`} checked={user.notifications.sms} />
</div>
</div>
</div>
</div>
<Button variant="outline" className="w-full" size="sm">
Editar Preferencias
</Button>
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
};
export default UserPreferences;

View File

@@ -151,7 +151,22 @@ const TableConfiguration = () => {
{tables.map((table) => ( {tables.map((table) => (
<div <div
key={table.id} key={table.id}
className="absolute cursor-pointer hover:scale-110 transition-transform" className="absolute cursor-move hover:scale-110 transition-transform"
draggable
onDragStart={(e) => {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('tableId', table.id);
}}
onDragEnd={(e) => {
const rect = e.currentTarget.parentElement?.getBoundingClientRect();
if (rect) {
const x = Math.max(0, Math.min(e.clientX - rect.left - 40, rect.width - 80));
const y = Math.max(0, Math.min(e.clientY - rect.top - 40, rect.height - 80));
setTables(tables.map(t =>
t.id === table.id ? { ...t, position: { x, y } } : t
));
}
}}
style={{ style={{
left: `${table.position.x}px`, left: `${table.position.x}px`,
top: `${table.position.y}px` top: `${table.position.y}px`

View File

@@ -0,0 +1,146 @@
import { useState } from 'react';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Target, Brain, TrendingUp, Users } from 'lucide-react';
import UserPreferences from '@/components/personalization/UserPreferences';
import AIRecommendations from '@/components/personalization/AIRecommendations';
import BehaviorAnalytics from '@/components/personalization/BehaviorAnalytics';
import SegmentManagement from '@/components/personalization/SegmentManagement';
const Personalization = () => {
const [totalUsers] = useState(1250);
const [activeSegments] = useState(8);
const [recommendationAccuracy] = useState(87);
const [engagement] = useState(72);
return (
<div className="container mx-auto p-6 space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold flex items-center gap-2">
<Target className="h-8 w-8 text-primary" />
Personalización con IA
</h1>
<p className="text-muted-foreground mt-1">
Recomendaciones inteligentes y segmentación de usuarios
</p>
</div>
</div>
{/* Stats Overview */}
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Usuarios Activos</CardTitle>
<Users className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalUsers.toLocaleString()}</div>
<p className="text-xs text-muted-foreground">perfiles analizados</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Segmentos</CardTitle>
<Target className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{activeSegments}</div>
<p className="text-xs text-muted-foreground">grupos activos</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Precisión IA</CardTitle>
<Brain className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{recommendationAccuracy}%</div>
<p className="text-xs text-muted-foreground">accuracy de recomendaciones</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Engagement</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{engagement}%</div>
<p className="text-xs text-muted-foreground">tasa de interacción</p>
</CardContent>
</Card>
</div>
{/* Main Content */}
<Tabs defaultValue="recommendations" className="space-y-4">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="recommendations">Recomendaciones</TabsTrigger>
<TabsTrigger value="preferences">Preferencias</TabsTrigger>
<TabsTrigger value="analytics">Analytics</TabsTrigger>
<TabsTrigger value="segments">Segmentos</TabsTrigger>
</TabsList>
<TabsContent value="recommendations" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Recomendaciones con IA</CardTitle>
<CardDescription>
Sistema de recomendaciones personalizadas basado en comportamiento
</CardDescription>
</CardHeader>
<CardContent>
<AIRecommendations />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="preferences" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Preferencias de Usuario</CardTitle>
<CardDescription>
Gestiona las preferencias y configuraciones de personalización
</CardDescription>
</CardHeader>
<CardContent>
<UserPreferences />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="analytics" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Análisis de Comportamiento</CardTitle>
<CardDescription>
Insights sobre patrones de uso y preferencias de usuarios
</CardDescription>
</CardHeader>
<CardContent>
<BehaviorAnalytics />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="segments" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Gestión de Segmentos</CardTitle>
<CardDescription>
Crea y gestiona segmentos de usuarios para campañas dirigidas
</CardDescription>
</CardHeader>
<CardContent>
<SegmentManagement />
</CardContent>
</Card>
</TabsContent>
</Tabs>
</div>
);
};
export default Personalization;