Implement Tourist Guide System

This commit is contained in:
gpt-engineer-app[bot]
2025-10-11 15:54:12 +00:00
parent 9ac041c74d
commit 1b16a9a584
5 changed files with 823 additions and 0 deletions

View File

@@ -56,6 +56,8 @@ import PolReports from "./pages/dashboard/politur/Reports";
import GuideDashboard from "./pages/dashboard/guides/GuideDashboard"; import GuideDashboard from "./pages/dashboard/guides/GuideDashboard";
import ItineraryBuilder from "./pages/dashboard/guides/ItineraryBuilder"; import ItineraryBuilder from "./pages/dashboard/guides/ItineraryBuilder";
import ContentLibrary from "./pages/dashboard/guides/ContentLibrary"; import ContentLibrary from "./pages/dashboard/guides/ContentLibrary";
// Tourist App
import TouristApp from "./pages/TouristApp";
// Commerce pages (for retail stores) // Commerce pages (for retail stores)
import CommerceStore from "./pages/dashboard/commerce/Store"; import CommerceStore from "./pages/dashboard/commerce/Store";
import CommercePOS from "./pages/dashboard/commerce/POSTerminal"; import CommercePOS from "./pages/dashboard/commerce/POSTerminal";
@@ -182,6 +184,11 @@ const AppRouter = () => (
<OrderConfirmation /> <OrderConfirmation />
</FrontendLayout> </FrontendLayout>
} /> } />
<Route path="/tourist-app" element={
<FrontendLayout>
<TouristApp />
</FrontendLayout>
} />
{/* Protected Dashboard Routes */} {/* Protected Dashboard Routes */}
<Route path="/dashboard" element={ <Route path="/dashboard" element={

View File

@@ -0,0 +1,187 @@
import React, { useState } from 'react';
import { Camera, Info, Volume2, X } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { useToast } from '@/hooks/use-toast';
const ARViewer = () => {
const [isARActive, setIsARActive] = useState(false);
const [detectedMonument, setDetectedMonument] = useState<string | null>(null);
const { toast } = useToast();
const startAR = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'environment' }
});
setIsARActive(true);
// Simulate monument detection after 2 seconds
setTimeout(() => {
setDetectedMonument('Catedral Primada de América');
toast({
title: "Monumento Detectado",
description: "Catedral Primada de América (1514)",
});
}, 2000);
} catch (error) {
toast({
title: "Error",
description: "No se pudo acceder a la cámara. Por favor verifica los permisos.",
variant: "destructive"
});
}
};
const stopAR = () => {
setIsARActive(false);
setDetectedMonument(null);
};
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h3 className="font-semibold text-lg">Realidad Aumentada</h3>
<p className="text-sm text-gray-600">Apunta tu cámara a monumentos para más información</p>
</div>
</div>
{!isARActive ? (
<div className="aspect-video bg-gradient-to-br from-blue-100 to-purple-100 rounded-lg flex flex-col items-center justify-center p-8 text-center">
<Camera className="w-20 h-20 text-blue-600 mb-4" />
<h4 className="text-xl font-semibold mb-2">Experiencia AR</h4>
<p className="text-gray-600 mb-6 max-w-md">
Descubre la historia de los monumentos apuntando tu cámara.
La IA reconocerá automáticamente los lugares históricos.
</p>
<Button size="lg" onClick={startAR}>
<Camera className="w-5 h-5 mr-2" />
Activar Cámara AR
</Button>
</div>
) : (
<div className="relative">
{/* Camera View Simulation */}
<div className="aspect-video bg-gradient-to-br from-gray-800 to-gray-600 rounded-lg overflow-hidden relative">
{/* Simulated camera feed */}
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-center text-white">
<Camera className="w-16 h-16 mx-auto mb-4 animate-pulse" />
<p className="text-lg">Vista de Cámara Activa</p>
<p className="text-sm opacity-75">Apunta a un monumento</p>
</div>
</div>
{/* AR Overlay */}
{detectedMonument && (
<div className="absolute inset-0 pointer-events-none">
{/* Detection Frame */}
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-64 border-4 border-green-500 rounded-lg">
<div className="absolute top-0 left-0 w-8 h-8 border-t-4 border-l-4 border-green-500"></div>
<div className="absolute top-0 right-0 w-8 h-8 border-t-4 border-r-4 border-green-500"></div>
<div className="absolute bottom-0 left-0 w-8 h-8 border-b-4 border-l-4 border-green-500"></div>
<div className="absolute bottom-0 right-0 w-8 h-8 border-b-4 border-r-4 border-green-500"></div>
</div>
</div>
)}
{/* Close Button */}
<button
onClick={stopAR}
className="absolute top-4 right-4 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-colors z-10"
>
<X className="w-6 h-6" />
</button>
{/* Recording Indicator */}
<div className="absolute top-4 left-4 flex items-center gap-2 bg-red-500 text-white px-3 py-1 rounded-full text-sm z-10">
<div className="w-2 h-2 bg-white rounded-full animate-pulse"></div>
AR Activo
</div>
</div>
{/* Information Overlay */}
{detectedMonument && (
<Card className="mt-4 p-4 animate-fade-in">
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-2">
<div className="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
<Info className="w-6 h-6 text-green-600" />
</div>
<div>
<h4 className="font-semibold">{detectedMonument}</h4>
<p className="text-sm text-gray-600">Monumento Histórico</p>
</div>
</div>
<Button size="sm" variant="outline">
<Volume2 className="w-4 h-4 mr-1" />
Audio
</Button>
</div>
<div className="space-y-2 text-sm">
<p className="text-gray-700">
Primera catedral de América, construcción iniciada en 1514.
Combina elementos góticos y barrocos. Declarada Patrimonio de la Humanidad por la UNESCO.
</p>
<div className="flex gap-2 pt-2">
<Button size="sm" variant="outline" className="flex-1">
Ver más información
</Button>
<Button size="sm" className="flex-1">
Reservar Tour
</Button>
</div>
</div>
</Card>
)}
</div>
)}
{/* Features Info */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
<Card className="p-4">
<div className="flex items-start gap-3">
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center flex-shrink-0">
<Camera className="w-6 h-6 text-purple-600" />
</div>
<div>
<h5 className="font-semibold text-sm mb-1">Reconocimiento IA</h5>
<p className="text-xs text-gray-600">Identifica monumentos automáticamente</p>
</div>
</div>
</Card>
<Card className="p-4">
<div className="flex items-start gap-3">
<div className="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center flex-shrink-0">
<Info className="w-6 h-6 text-blue-600" />
</div>
<div>
<h5 className="font-semibold text-sm mb-1">Info Histórica</h5>
<p className="text-xs text-gray-600">Datos e historia en tiempo real</p>
</div>
</div>
</Card>
<Card className="p-4">
<div className="flex items-start gap-3">
<div className="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center flex-shrink-0">
<Volume2 className="w-6 h-6 text-green-600" />
</div>
<div>
<h5 className="font-semibold text-sm mb-1">Audio Guías</h5>
<p className="text-xs text-gray-600">Narración profesional</p>
</div>
</div>
</Card>
</div>
</div>
);
};
export default ARViewer;

View File

@@ -0,0 +1,149 @@
import React, { useState } from 'react';
import { AlertCircle, Phone, X, MapPin } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { useToast } from '@/hooks/use-toast';
const EmergencyButton = () => {
const [showDialog, setShowDialog] = useState(false);
const [emergencyType, setEmergencyType] = useState<string | null>(null);
const { toast } = useToast();
const emergencyTypes = [
{ id: 'medical', label: 'Emergencia Médica', icon: '🏥', color: 'bg-red-500' },
{ id: 'security', label: 'Seguridad', icon: '🚨', color: 'bg-orange-500' },
{ id: 'accident', label: 'Accidente', icon: '🚗', color: 'bg-yellow-500' },
{ id: 'other', label: 'Otra Emergencia', icon: '⚠️', color: 'bg-gray-500' }
];
const sendEmergencyAlert = (type: string) => {
// Get user location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords;
toast({
title: "¡Alerta Enviada!",
description: "POLITUR ha sido notificado de tu emergencia. Te contactarán pronto.",
});
// In production, this would send to the backend
console.log('Emergency Alert:', {
type,
location: { lat: latitude, lng: longitude },
timestamp: new Date().toISOString()
});
setShowDialog(false);
setEmergencyType(null);
},
(error) => {
toast({
title: "Error de Ubicación",
description: "No se pudo obtener tu ubicación. Por favor activa el GPS.",
variant: "destructive"
});
}
);
}
};
return (
<>
{/* Floating Emergency Button */}
<button
onClick={() => setShowDialog(true)}
className="fixed bottom-24 right-6 z-50 w-16 h-16 bg-red-500 hover:bg-red-600 text-white rounded-full shadow-2xl flex items-center justify-center transition-all hover:scale-110 animate-pulse"
aria-label="Botón de Emergencia"
>
<AlertCircle className="w-8 h-8" />
</button>
{/* Emergency Dialog */}
<Dialog open={showDialog} onOpenChange={setShowDialog}>
<DialogContent className="max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-red-600">
<AlertCircle className="w-6 h-6" />
Emergencia
</DialogTitle>
</DialogHeader>
{!emergencyType ? (
<div className="space-y-4">
<p className="text-gray-600">Selecciona el tipo de emergencia:</p>
<div className="grid grid-cols-2 gap-3">
{emergencyTypes.map((type) => (
<button
key={type.id}
onClick={() => setEmergencyType(type.id)}
className={`${type.color} text-white p-4 rounded-lg hover:opacity-90 transition-all hover:scale-105 flex flex-col items-center gap-2`}
>
<span className="text-3xl">{type.icon}</span>
<span className="text-sm font-medium text-center">{type.label}</span>
</button>
))}
</div>
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mt-4">
<div className="flex items-start gap-3">
<Phone className="w-5 h-5 text-blue-600 flex-shrink-0 mt-0.5" />
<div className="text-sm">
<p className="font-semibold text-blue-900 mb-1">Números de Emergencia:</p>
<p className="text-blue-800">POLITUR: *911</p>
<p className="text-blue-800">Emergencias: 911</p>
</div>
</div>
</div>
</div>
) : (
<div className="space-y-4">
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
<p className="text-sm text-red-800 mb-3">
Estás a punto de enviar una alerta de emergencia a POLITUR.
Tu ubicación actual será compartida.
</p>
<div className="flex items-center gap-2 text-sm text-red-700">
<MapPin className="w-4 h-4" />
<span>Compartiendo ubicación GPS...</span>
</div>
</div>
<div className="flex gap-3">
<Button
variant="outline"
className="flex-1"
onClick={() => setEmergencyType(null)}
>
Cancelar
</Button>
<Button
className="flex-1 bg-red-500 hover:bg-red-600"
onClick={() => sendEmergencyAlert(emergencyType)}
>
<AlertCircle className="w-4 h-4 mr-2" />
Enviar Alerta
</Button>
</div>
<div className="text-center">
<Button
variant="link"
className="text-blue-600"
onClick={() => window.location.href = 'tel:*911'}
>
<Phone className="w-4 h-4 mr-2" />
Llamar a POLITUR (*911)
</Button>
</div>
</div>
)}
</DialogContent>
</Dialog>
</>
);
};
export default EmergencyButton;

View File

@@ -0,0 +1,225 @@
import React, { useEffect, useRef, useState } from 'react';
import { MapPin, Navigation, Layers } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useToast } from '@/hooks/use-toast';
interface Attraction {
id: string;
name: string;
category: string;
distance: string;
rating: number;
}
interface InteractiveMapProps {
attractions: Attraction[];
}
const InteractiveMap: React.FC<InteractiveMapProps> = ({ attractions }) => {
const mapContainer = useRef<HTMLDivElement>(null);
const [userLocation, setUserLocation] = useState<{ lat: number; lng: number } | null>(null);
const { toast } = useToast();
useEffect(() => {
// Get user location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
setUserLocation({
lat: position.coords.latitude,
lng: position.coords.longitude
});
toast({
title: "Ubicación Obtenida",
description: "Mostrando atracciones cerca de ti",
});
},
(error) => {
console.error('Error getting location:', error);
}
);
}
if (!mapContainer.current) return;
// Simulated interactive map
const canvas = document.createElement('canvas');
canvas.width = mapContainer.current.clientWidth;
canvas.height = 500;
canvas.style.width = '100%';
canvas.style.height = '500px';
canvas.style.borderRadius = '8px';
const ctx = canvas.getContext('2d');
if (!ctx) return;
// Draw map background
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, '#e8f4f8');
gradient.addColorStop(1, '#b8d4e0');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw grid
ctx.strokeStyle = '#d0e8f0';
ctx.lineWidth = 1;
for (let i = 0; i < canvas.width; i += 40) {
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, canvas.height);
ctx.stroke();
}
for (let i = 0; i < canvas.height; i += 40) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(canvas.width, i);
ctx.stroke();
}
// Draw title
ctx.fillStyle = '#333';
ctx.font = 'bold 20px Arial';
ctx.textAlign = 'center';
ctx.fillText('Mapa Interactivo', canvas.width / 2, 30);
ctx.font = '14px Arial';
ctx.fillStyle = '#666';
ctx.fillText('(Integración con Mapbox + IA próximamente)', canvas.width / 2, 55);
// Draw user location (center)
if (userLocation) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// User marker
ctx.fillStyle = '#3b82f6';
ctx.beginPath();
ctx.arc(centerX, centerY, 12, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.stroke();
// Pulse effect
ctx.strokeStyle = '#3b82f6';
ctx.lineWidth = 2;
ctx.globalAlpha = 0.3;
ctx.beginPath();
ctx.arc(centerX, centerY, 20, 0, Math.PI * 2);
ctx.stroke();
ctx.globalAlpha = 1;
ctx.fillStyle = '#333';
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'center';
ctx.fillText('Tu ubicación', centerX, centerY + 35);
}
// Draw attraction markers
attractions.forEach((attraction, index) => {
const angle = (index / attractions.length) * Math.PI * 2;
const radius = 120;
const x = canvas.width / 2 + Math.cos(angle) * radius;
const y = canvas.height / 2 + Math.sin(angle) * radius;
// Marker
ctx.fillStyle = '#ef4444';
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 2;
ctx.stroke();
// Label background
const labelWidth = ctx.measureText(attraction.name).width + 16;
ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';
ctx.fillRect(x - labelWidth / 2, y - 35, labelWidth, 24);
ctx.strokeStyle = '#ddd';
ctx.lineWidth = 1;
ctx.strokeRect(x - labelWidth / 2, y - 35, labelWidth, 24);
// Label text
ctx.fillStyle = '#333';
ctx.font = '11px Arial';
ctx.textAlign = 'center';
ctx.fillText(attraction.name, x, y - 18);
});
mapContainer.current.innerHTML = '';
mapContainer.current.appendChild(canvas);
// Add click handler
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
const x = (e.clientX - rect.left) * (canvas.width / rect.width);
const y = (e.clientY - rect.top) * (canvas.height / rect.height);
attractions.forEach((attraction, index) => {
const angle = (index / attractions.length) * Math.PI * 2;
const radius = 120;
const markerX = canvas.width / 2 + Math.cos(angle) * radius;
const markerY = canvas.height / 2 + Math.sin(angle) * radius;
const distance = Math.sqrt(Math.pow(x - markerX, 2) + Math.pow(y - markerY, 2));
if (distance < 15) {
toast({
title: attraction.name,
description: `${attraction.category} - ${attraction.distance}`,
});
}
});
});
canvas.style.cursor = 'pointer';
}, [attractions, userLocation, toast]);
const centerOnUser = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
setUserLocation({
lat: position.coords.latitude,
lng: position.coords.longitude
});
toast({
title: "Centrando Mapa",
description: "Mostrando tu ubicación actual",
});
}
);
}
};
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="font-semibold text-lg">Explora Cerca de Ti</h3>
<div className="flex gap-2">
<Button size="sm" variant="outline" onClick={centerOnUser}>
<Navigation className="w-4 h-4 mr-2" />
Mi Ubicación
</Button>
<Button size="sm" variant="outline">
<Layers className="w-4 h-4 mr-2" />
Capas
</Button>
</div>
</div>
<div ref={mapContainer} className="w-full h-[500px] rounded-lg overflow-hidden bg-gray-100">
{/* Map will be rendered here */}
</div>
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
<p className="text-sm text-blue-800">
💡 <strong>Funciones IA próximamente:</strong> Reconocimiento automático de monumentos con la cámara,
navegación guiada por voz, y recomendaciones personalizadas basadas en tus preferencias.
</p>
</div>
</div>
);
};
export default InteractiveMap;

255
src/pages/TouristApp.tsx Normal file
View File

@@ -0,0 +1,255 @@
import React, { useState } from 'react';
import { MapPin, Camera, ShoppingBag, Calendar, User, Search, AlertCircle, Navigation, Star } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Badge } from '@/components/ui/badge';
import InteractiveMap from '@/components/tourist/InteractiveMap';
import EmergencyButton from '@/components/tourist/EmergencyButton';
import ARViewer from '@/components/tourist/ARViewer';
interface Attraction {
id: string;
name: string;
category: string;
distance: string;
rating: number;
image: string;
price?: number;
}
const TouristApp = () => {
const [activeTab, setActiveTab] = useState<'explore' | 'map' | 'ar' | 'bookings' | 'shop'>('explore');
const [searchQuery, setSearchQuery] = useState('');
const attractions: Attraction[] = [
{
id: '1',
name: 'Zona Colonial',
category: 'Histórico',
distance: '2.3 km',
rating: 4.8,
image: '🏛️',
price: 25
},
{
id: '2',
name: 'Catedral Primada',
category: 'Monumento',
distance: '2.5 km',
rating: 4.9,
image: '⛪',
price: 15
},
{
id: '3',
name: 'Alcázar de Colón',
category: 'Museo',
distance: '2.8 km',
rating: 4.7,
image: '🏰',
price: 20
}
];
const quickActions = [
{ icon: Calendar, label: 'Reservar Hotel', color: 'bg-blue-500' },
{ icon: User, label: 'Contratar Guía', color: 'bg-purple-500' },
{ icon: Navigation, label: 'Taxi', color: 'bg-yellow-500' },
{ icon: ShoppingBag, label: 'Souvenirs', color: 'bg-green-500' }
];
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<div className="bg-gradient-to-r from-primary to-orange-600 text-white p-6 pb-24">
<div className="max-w-4xl mx-auto">
<div className="flex items-center justify-between mb-6">
<h1 className="text-2xl font-bold">Explora República Dominicana</h1>
<Button variant="ghost" size="icon" className="text-white">
<User className="w-6 h-6" />
</Button>
</div>
{/* Search Bar */}
<div className="relative">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<Input
placeholder="Buscar atracciones, restaurantes..."
className="pl-12 bg-white text-gray-900 border-0"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
</div>
</div>
{/* Emergency Button - Always Visible */}
<EmergencyButton />
<div className="max-w-4xl mx-auto -mt-16 px-4 pb-24">
{/* Quick Actions */}
<Card className="mb-6">
<CardContent className="p-4">
<div className="grid grid-cols-4 gap-3">
{quickActions.map((action, index) => (
<button
key={index}
className="flex flex-col items-center gap-2 p-3 rounded-lg hover:bg-gray-50 transition-colors"
>
<div className={`${action.color} w-12 h-12 rounded-full flex items-center justify-center`}>
<action.icon className="w-6 h-6 text-white" />
</div>
<span className="text-xs text-center font-medium">{action.label}</span>
</button>
))}
</div>
</CardContent>
</Card>
{/* Content Area */}
{activeTab === 'explore' && (
<div className="space-y-4">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-bold">Cerca de ti</h2>
<Button variant="outline" size="sm">
<MapPin className="w-4 h-4 mr-2" />
Ver en mapa
</Button>
</div>
{attractions.map((attraction) => (
<Card key={attraction.id} className="overflow-hidden hover:shadow-lg transition-shadow cursor-pointer">
<CardContent className="p-0">
<div className="flex">
<div className="w-32 h-32 bg-gray-200 flex items-center justify-center text-6xl">
{attraction.image}
</div>
<div className="flex-1 p-4">
<div className="flex items-start justify-between mb-2">
<div>
<h3 className="font-semibold text-lg mb-1">{attraction.name}</h3>
<Badge variant="secondary">{attraction.category}</Badge>
</div>
<div className="text-right">
<div className="flex items-center gap-1 mb-1">
<Star className="w-4 h-4 fill-yellow-400 text-yellow-400" />
<span className="font-semibold">{attraction.rating}</span>
</div>
<span className="text-sm text-gray-600">{attraction.distance}</span>
</div>
</div>
<div className="flex items-center justify-between mt-3">
<span className="text-lg font-bold text-primary">${attraction.price}</span>
<div className="flex gap-2">
<Button size="sm" variant="outline">
<Camera className="w-4 h-4 mr-1" />
Ver AR
</Button>
<Button size="sm">
Reservar
</Button>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
)}
{activeTab === 'map' && (
<Card>
<CardContent className="p-4">
<InteractiveMap attractions={attractions} />
</CardContent>
</Card>
)}
{activeTab === 'ar' && (
<Card>
<CardContent className="p-4">
<ARViewer />
</CardContent>
</Card>
)}
{activeTab === 'bookings' && (
<div className="text-center py-12">
<Calendar className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-xl font-semibold mb-2">Mis Reservas</h3>
<p className="text-gray-600">No tienes reservas activas</p>
<Button className="mt-4">Explorar Actividades</Button>
</div>
)}
{activeTab === 'shop' && (
<div className="text-center py-12">
<ShoppingBag className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-xl font-semibold mb-2">Tienda de Souvenirs</h3>
<p className="text-gray-600">Descubre productos locales</p>
<Button className="mt-4">Ver Productos</Button>
</div>
)}
</div>
{/* Bottom Navigation */}
<div className="fixed bottom-0 left-0 right-0 bg-white border-t shadow-lg">
<div className="max-w-4xl mx-auto grid grid-cols-5 gap-1 p-2">
<button
onClick={() => setActiveTab('explore')}
className={`flex flex-col items-center gap-1 py-2 rounded-lg transition-colors ${
activeTab === 'explore' ? 'text-primary bg-primary/10' : 'text-gray-600'
}`}
>
<Search className="w-5 h-5" />
<span className="text-xs font-medium">Explorar</span>
</button>
<button
onClick={() => setActiveTab('map')}
className={`flex flex-col items-center gap-1 py-2 rounded-lg transition-colors ${
activeTab === 'map' ? 'text-primary bg-primary/10' : 'text-gray-600'
}`}
>
<MapPin className="w-5 h-5" />
<span className="text-xs font-medium">Mapa</span>
</button>
<button
onClick={() => setActiveTab('ar')}
className={`flex flex-col items-center gap-1 py-2 rounded-lg transition-colors ${
activeTab === 'ar' ? 'text-primary bg-primary/10' : 'text-gray-600'
}`}
>
<Camera className="w-5 h-5" />
<span className="text-xs font-medium">AR</span>
</button>
<button
onClick={() => setActiveTab('bookings')}
className={`flex flex-col items-center gap-1 py-2 rounded-lg transition-colors ${
activeTab === 'bookings' ? 'text-primary bg-primary/10' : 'text-gray-600'
}`}
>
<Calendar className="w-5 h-5" />
<span className="text-xs font-medium">Reservas</span>
</button>
<button
onClick={() => setActiveTab('shop')}
className={`flex flex-col items-center gap-1 py-2 rounded-lg transition-colors ${
activeTab === 'shop' ? 'text-primary bg-primary/10' : 'text-gray-600'
}`}
>
<ShoppingBag className="w-5 h-5" />
<span className="text-xs font-medium">Tienda</span>
</button>
</div>
</div>
</div>
);
};
export default TouristApp;