Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,19 @@
.animate-modal-content {
animation: modal-slide-up 0.3s ease-out;
}

/* Smart banner slide-down */
@keyframes slide-down {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}

.animate-slide-down {
animation: slide-down 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
49 changes: 42 additions & 7 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import { useState, useEffect } from "react";
import Link from "next/link";

import AedDetailModal from "@/components/AedDetailModal";
import {
AppDownloadPrompt,
AppDownloadSection,
AppSmartBanner,
useAppDownloadPrompt,
} from "@/components/AppDownloadBanner";
import { useAnalytics } from "@/hooks/useAnalytics";
import type { Aed } from "@/types/aed";

Expand Down Expand Up @@ -77,6 +83,8 @@ export default function Home() {
trackButtonClick,
} = useAnalytics();

const appPrompt = useAppDownloadPrompt();

// Debounce for address search
const searchAddressSuggestions = async (query: string) => {
if (query.length < 3) {
Expand Down Expand Up @@ -136,6 +144,8 @@ export default function Home() {
setNearbyAeds(nearbyData.data);
if (nearbyData.data.length === 0) {
setError("No se encontraron DEAs cerca de esta ubicación en un radio de 10 km.");
} else {
appPrompt.trigger("search_results", 2000);
}
} else {
throw new Error(nearbyData.message || "Error al buscar DEAs");
Expand Down Expand Up @@ -196,6 +206,7 @@ export default function Home() {
});

trackGeolocationRequest("success");
appPrompt.trigger("geolocation", 3000);
const { latitude, longitude } = position.coords;
setSearchLocation({ lat: latitude, lng: longitude });

Expand Down Expand Up @@ -318,6 +329,17 @@ export default function Home() {

return (
<>
{/* Smart App Banner for mobile users */}
<AppSmartBanner />

{/* Contextual App Download Prompt */}
<AppDownloadPrompt
visible={appPrompt.visible}
context={appPrompt.context}
platform={appPrompt.platform}
onDismiss={appPrompt.dismiss}
/>

{/* Fullscreen Map Section */}
<div className="relative w-full h-[calc(100vh-56px)]">
<MapView
Expand All @@ -327,8 +349,10 @@ export default function Home() {
onAddressChange={handleAddressChange}
/>

{/* Search Controls Overlay - Desktop: Top Left, Mobile: Top */}
<div className="absolute top-4 left-4 right-4 z-[1000] pointer-events-none">
{/* Search Controls Overlay - Desktop: Top Left, Mobile: Top (hidden when modal open) */}
<div
className={`absolute top-4 left-4 right-4 z-[1000] pointer-events-none ${modalOpen ? "hidden" : ""}`}
>
<div className="max-w-md pointer-events-auto">
{/* Search Box */}
<div className="bg-white rounded-xl shadow-2xl overflow-hidden">
Expand Down Expand Up @@ -419,8 +443,10 @@ export default function Home() {
</div>
</div>

{/* Geolocation Button - Mobile: Bottom Center */}
<div className="md:hidden absolute bottom-24 left-1/2 transform -translate-x-1/2 z-[1000]">
{/* Geolocation Button - Mobile: Bottom Center (hidden when modal open) */}
<div
className={`md:hidden absolute bottom-24 left-1/2 transform -translate-x-1/2 z-[1000] ${modalOpen ? "hidden" : ""}`}
>
<button
onClick={handleFindNearestByGeolocation}
disabled={loading}
Expand Down Expand Up @@ -518,8 +544,8 @@ export default function Home() {
</>
)}

{/* Scroll Down Indicator - Hide when showing results */}
{!showResults && (
{/* Scroll Down Indicator - Hide when showing results or modal open */}
{!showResults && !modalOpen && (
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 z-[999] pointer-events-none">
<div className="flex flex-col items-center gap-2 text-white drop-shadow-lg">
<span className="text-sm font-medium bg-black/50 px-3 py-1 rounded-full backdrop-blur-sm">
Expand All @@ -531,7 +557,13 @@ export default function Home() {
)}

{/* Detail Modal */}
<AedDetailModal aed={selectedAed} isOpen={modalOpen} onClose={handleCloseModal} />
<AedDetailModal
aed={selectedAed}
isOpen={modalOpen}
onClose={handleCloseModal}
onDirectionsClick={() => appPrompt.trigger("directions")}
onViewDuration={() => appPrompt.trigger("dea_detail")}
/>
</div>

{/* Info Section - After the map */}
Expand Down Expand Up @@ -614,6 +646,9 @@ export default function Home() {
</div>
</section>

{/* App Download Banner */}
<AppDownloadSection />

{/* Stats Section */}
<section className="max-w-4xl mx-auto">
<div className="bg-gradient-to-r from-blue-600 to-blue-700 rounded-2xl p-8 shadow-2xl text-white">
Expand Down
23 changes: 20 additions & 3 deletions src/components/AedDetailModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,17 @@ interface AedDetailModalProps {
aed: Aed | null;
isOpen: boolean;
onClose: () => void;
onDirectionsClick?: () => void;
onViewDuration?: () => void;
}

export default function AedDetailModal({ aed, isOpen, onClose }: AedDetailModalProps) {
export default function AedDetailModal({
aed,
isOpen,
onClose,
onDirectionsClick,
onViewDuration,
}: AedDetailModalProps) {
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
const { trackDeaImageView, trackDeaPhoneClick, trackExternalLink, trackButtonClick } =
useAnalytics();
Expand All @@ -31,6 +39,14 @@ export default function AedDetailModal({ aed, isOpen, onClose }: AedDetailModalP
setSelectedImageIndex(0);
}, [aed?.id]);

// Trigger app download prompt after viewing for 5 seconds
const aedId = aed?.id;
useEffect(() => {
if (!isOpen || !aedId || !onViewDuration) return;
const timer = setTimeout(onViewDuration, 5000);
return () => clearTimeout(timer);
}, [isOpen, aedId, onViewDuration]);

const handleImageChange = useCallback(
(index: number) => {
if (aed) {
Expand All @@ -57,8 +73,9 @@ export default function AedDetailModal({ aed, isOpen, onClose }: AedDetailModalP
"Cómo llegar",
"dea_modal"
);
onDirectionsClick?.();
}
}, [aed, trackExternalLink]);
}, [aed, trackExternalLink, onDirectionsClick]);

const handleEmailClick = useCallback(
(_email: string) => {
Expand All @@ -82,7 +99,7 @@ export default function AedDetailModal({ aed, isOpen, onClose }: AedDetailModalP

return (
<div
className="fixed inset-0 z-50 flex items-center justify-center p-4"
className="fixed inset-0 z-[1500] flex items-center justify-center p-4"
style={{
background:
"radial-gradient(circle at center, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.9) 100%)",
Expand Down
Loading
Loading