feat: restore and integrate AppDownloadBanner under Top-Bar
This commit is contained in:
Vendored
+2
-2
@@ -21,7 +21,7 @@
|
||||
<meta name="twitter:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
|
||||
<meta name="twitter:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
|
||||
<meta name="twitter:image" content="https://yotrip.labz.io.vn/background.avif" />
|
||||
<script type="module" crossorigin src="/assets/index-BYlJbgKh.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CnmnZivz.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Cyuzqnbw.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-others-VIU5qAPG.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-editor-DOXkNaRS.js">
|
||||
@@ -30,7 +30,7 @@
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-pdf-IjT8x9OX.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/vendor-maps-CcXJxNtP.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/vendor-react-CuSj0z1j.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BO3HsKs5.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-w726aohe.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { X, Download } from 'lucide-react';
|
||||
import { BACKEND_URL } from '@/utils/backendEndpoint';
|
||||
|
||||
export const AppDownloadBanner: React.FC = () => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
// Force APK download relative to backend endpoint
|
||||
const APK_DOWNLOAD_URL = `${BACKEND_URL}/downloads/yotrip-latest.apk`;
|
||||
|
||||
useEffect(() => {
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
const isAndroidBrowser = userAgent.includes('android') &&
|
||||
!window.location.origin.includes('capacitor://') &&
|
||||
!window.location.origin.includes('localhost:80');
|
||||
const isBannerDismissed = localStorage.getItem('yotrip_apk_banner_dismissed') === 'true';
|
||||
|
||||
// Target condition match: User is on Android mobile browser and hasn't closed it yet
|
||||
if (isAndroidBrowser && !isBannerDismissed) {
|
||||
setIsVisible(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleDismiss = () => {
|
||||
localStorage.setItem('yotrip_apk_banner_dismissed', 'true');
|
||||
setIsVisible(false);
|
||||
};
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="w-full bg-gradient-to-r from-blue-900 to-indigo-950 border-b border-blue-800 px-4 py-2.5 flex items-center justify-between text-white text-[11px] font-medium z-40 relative shrink-0">
|
||||
<div className="flex items-center gap-2.5 flex-1 min-w-0">
|
||||
<div className="p-1 bg-blue-500/20 rounded-lg text-blue-400 shrink-0">
|
||||
<Download className="w-3.5 h-3.5" />
|
||||
</div>
|
||||
<p className="truncate text-slate-200">
|
||||
Trải nghiệm mượt mà hơn với ứng dụng <span className="text-white font-bold">YoTrip cho Android</span>!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 ml-2 shrink-0">
|
||||
<a
|
||||
href={APK_DOWNLOAD_URL}
|
||||
download="yotrip.apk"
|
||||
className="bg-blue-600 hover:bg-blue-500 px-3 py-1 rounded-xl font-bold text-white transition-all shadow-sm active:scale-95 text-[10px]"
|
||||
>
|
||||
Tải APK
|
||||
</a>
|
||||
|
||||
<button
|
||||
onClick={handleDismiss}
|
||||
className="p-1 hover:bg-slate-800 rounded text-slate-400 hover:text-slate-200 transition-colors"
|
||||
title="Đóng thông báo"
|
||||
>
|
||||
<X className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -20,6 +20,7 @@ import { MyToursModal } from '../components/modals/MyToursModal';
|
||||
import { PhotoGalleryModal as MyPhotosModal } from '../components/modals/PhotoGalleryModal';
|
||||
import { LiveChatModal } from '../components/modals/LiveChatModal';
|
||||
import { FriendsManagerModal } from '../components/modals/FriendsManagerModal';
|
||||
import { AppDownloadBanner } from '../components/layout/AppDownloadBanner';
|
||||
|
||||
// Fix lỗi icon mặc định của Leaflet
|
||||
const DefaultIcon = L.icon({
|
||||
@@ -654,8 +655,11 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onLoginSuccess,
|
||||
}, [publicPhotos]);
|
||||
|
||||
return (
|
||||
<div className="h-dvh w-full relative overflow-hidden">
|
||||
{/* Top Bar Container - Chứa tất cả các nút điều hướng phía trên */}
|
||||
<div className="h-dvh w-full flex flex-col overflow-hidden bg-slate-950">
|
||||
<AppDownloadBanner />
|
||||
|
||||
<div className="flex-1 w-full relative min-h-0">
|
||||
{/* Top Bar Container - Chứa tất cả các nút điều hướng phía trên */}
|
||||
<div className="absolute top-[calc(1rem+env(safe-area-inset-top,0px))] left-4 right-4 z-[1002] flex items-center justify-between pointer-events-none">
|
||||
{/* Nhóm bên trái: Quay lại và Thông tin vị trí */}
|
||||
<div className="flex items-center gap-3 pointer-events-auto">
|
||||
@@ -1125,6 +1129,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour, onLoginSuccess,
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Admin Modal */}
|
||||
<UserManagementModal isOpen={isAdminModalOpen} onClose={() => setIsAdminModalOpen(false)} />
|
||||
|
||||
@@ -9,6 +9,7 @@ import { MyToursModal } from '../components/modals/MyToursModal';
|
||||
import { PhotoGalleryModal as MyPhotosModal } from '../components/modals/PhotoGalleryModal';
|
||||
import { LiveChatModal } from '../components/modals/LiveChatModal';
|
||||
import { FriendsManagerModal } from '../components/modals/FriendsManagerModal';
|
||||
import { AppDownloadBanner } from '../components/layout/AppDownloadBanner';
|
||||
import { useNotification } from '@/hooks/useNotification';
|
||||
import { processImageModeration } from '../hooks/useImageModeration';
|
||||
import { useTranslation } from '../hooks/useTranslation';
|
||||
@@ -343,7 +344,10 @@ export const LandingPage: React.FC<LandingPageProps> = ({
|
||||
|
||||
|
||||
return (
|
||||
<div className="h-dvh w-full overflow-hidden font-sans bg-[var(--background)] relative">
|
||||
<div className="h-dvh w-full flex flex-col overflow-hidden font-sans bg-[var(--background)]">
|
||||
<AppDownloadBanner />
|
||||
|
||||
<div className="flex-1 w-full relative min-h-0">
|
||||
{/* Background Image with Horizontal Panning */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
{/* Active image for panning */}
|
||||
@@ -655,6 +659,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Login Modal Component */}
|
||||
<LoginModal
|
||||
|
||||
Reference in New Issue
Block a user