fix: remove landing page nav tab and prevent crowdsource contribution modal from auto-opening on tourism map
This commit is contained in:
+45
-45
@@ -8,7 +8,7 @@ import { LandmarkCard, HeritageLandmarkData } from './components/LandmarkCard';
|
||||
import { SubmitContributionModal } from './components/SubmitContributionModal';
|
||||
import { GuidesModerationPanel } from './components/GuidesModerationPanel';
|
||||
|
||||
const DEFAULT_API_KEY = (import.meta as any).env.VITE_API_KEY || localStorage.getItem('intaleq_api_key') || '';
|
||||
const DEFAULT_API_KEY = (import.meta as any).env.VITE_API_KEY || localStorage.getItem('intaleq_api_key') || localStorage.getItem('map_admin_key');
|
||||
|
||||
function App() {
|
||||
const [map, setMap] = useState<any>(null);
|
||||
@@ -19,7 +19,7 @@ function App() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [routeLoading, setRouteLoading] = useState(false);
|
||||
const [routeError, setRouteError] = useState('');
|
||||
|
||||
|
||||
// Layer Toggles
|
||||
const [show3D, setShow3D] = useState(false);
|
||||
const [showPOIs, setShowPOIs] = useState(true);
|
||||
@@ -87,38 +87,38 @@ function App() {
|
||||
};
|
||||
|
||||
const regions = [
|
||||
{
|
||||
name: 'Syria',
|
||||
name_ar: 'سوريا',
|
||||
center: [36.29, 33.51],
|
||||
zoom: 11,
|
||||
{
|
||||
name: 'Syria',
|
||||
name_ar: 'سوريا',
|
||||
center: [36.29, 33.51],
|
||||
zoom: 11,
|
||||
flag: '🇸🇾',
|
||||
defaultOrigin: '33.5138, 36.2765', // Damascus
|
||||
defaultDest: '36.2021, 37.1343' // Aleppo
|
||||
},
|
||||
{
|
||||
name: 'Jordan',
|
||||
name_ar: 'الأردن',
|
||||
center: [35.91, 31.95],
|
||||
zoom: 11,
|
||||
{
|
||||
name: 'Jordan',
|
||||
name_ar: 'الأردن',
|
||||
center: [35.91, 31.95],
|
||||
zoom: 11,
|
||||
flag: '🇯🇴',
|
||||
defaultOrigin: '31.9539, 35.9106', // Amman
|
||||
defaultDest: '32.0608, 36.1032' // Zarqa
|
||||
},
|
||||
{
|
||||
name: 'Iraq',
|
||||
name_ar: 'العراق',
|
||||
center: [44.3661, 33.3152],
|
||||
zoom: 11,
|
||||
{
|
||||
name: 'Iraq',
|
||||
name_ar: 'العراق',
|
||||
center: [44.3661, 33.3152],
|
||||
zoom: 11,
|
||||
flag: '🇮🇶',
|
||||
defaultOrigin: '33.3152, 44.3661', // Baghdad
|
||||
defaultDest: '32.0000, 44.4000' // Karbala / Babil
|
||||
},
|
||||
{
|
||||
name: 'Egypt',
|
||||
name_ar: 'مصر',
|
||||
center: [31.23, 30.04],
|
||||
zoom: 10,
|
||||
{
|
||||
name: 'Egypt',
|
||||
name_ar: 'مصر',
|
||||
center: [31.23, 30.04],
|
||||
zoom: 10,
|
||||
flag: '🇪🇬',
|
||||
defaultOrigin: '30.0444, 31.2357', // Cairo
|
||||
defaultDest: '31.2001, 29.9187' // Alexandria
|
||||
@@ -447,12 +447,12 @@ function App() {
|
||||
<div className="input-group">
|
||||
<label><MapPin size={14} style={{ marginRight: 5 }} /> Search Places / البحث في الأماكن</label>
|
||||
<div style={{ display: 'flex', gap: '5px' }}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search city, street, cafe..."
|
||||
value={searchQuery}
|
||||
onChange={e => setSearchQuery(e.target.value)}
|
||||
onKeyDown={e => e.key === 'Enter' && handleSearch()}
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search city, street, cafe..."
|
||||
value={searchQuery}
|
||||
onChange={e => setSearchQuery(e.target.value)}
|
||||
onKeyDown={e => e.key === 'Enter' && handleSearch()}
|
||||
/>
|
||||
<button className="btn" style={{ width: 'auto', marginTop: 0, padding: '10px 15px' }} onClick={handleSearch} disabled={loading}>
|
||||
{loading ? '...' : 'Go'}
|
||||
@@ -464,9 +464,9 @@ function App() {
|
||||
{searchResults.map((res) => (
|
||||
<div
|
||||
key={res.id || Math.random()}
|
||||
onClick={() => {
|
||||
const rLng = parseFloat(res.longitude);
|
||||
const rLat = parseFloat(res.latitude);
|
||||
onClick={() => {
|
||||
const rLng = parseFloat(res.longitude);
|
||||
const rLat = parseFloat(res.latitude);
|
||||
if (!isNaN(rLat) && !isNaN(rLng)) {
|
||||
map?.flyTo({ center: [rLng, rLat], zoom: 16, duration: 1500 });
|
||||
}
|
||||
@@ -498,21 +498,21 @@ function App() {
|
||||
{/* Route Calculation */}
|
||||
<div className="input-group">
|
||||
<label><Navigation size={14} style={{ marginRight: 5 }} /> Origin / نقطة الانطلاق</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="lat, lng"
|
||||
value={originText}
|
||||
onChange={e => setOriginText(e.target.value)}
|
||||
<input
|
||||
type="text"
|
||||
placeholder="lat, lng"
|
||||
value={originText}
|
||||
onChange={e => setOriginText(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="input-group">
|
||||
<label><Compass size={14} style={{ marginRight: 5 }} /> Destination / الوجهة</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="lat, lng"
|
||||
value={destText}
|
||||
onChange={e => setDestText(e.target.value)}
|
||||
<input
|
||||
type="text"
|
||||
placeholder="lat, lng"
|
||||
value={destText}
|
||||
onChange={e => setDestText(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -705,16 +705,16 @@ function App() {
|
||||
border: showLOS ? '1px solid rgba(99, 102, 241, 0.4)' : '1px solid transparent'
|
||||
}}>
|
||||
<label style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px', fontWeight: showLOS ? 700 : 400 }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showLOS}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showLOS}
|
||||
onChange={(e) => {
|
||||
setShowLOS(e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
setLosPointA(null);
|
||||
setLosPointB(null);
|
||||
}
|
||||
}}
|
||||
}}
|
||||
/>
|
||||
🎯 Tactical LOS / تبادل الرؤية العسكري
|
||||
</label>
|
||||
|
||||
@@ -3,7 +3,9 @@ import { X, Send, MapPin, CheckCircle2, AlertCircle, Sparkles, Shield } from 'lu
|
||||
import { HeritageLandmarkData } from './LandmarkCard';
|
||||
|
||||
interface SubmitContributionModalProps {
|
||||
isOpen?: boolean;
|
||||
landmark?: HeritageLandmarkData | null;
|
||||
initialLandmark?: HeritageLandmarkData | null;
|
||||
mapCenter?: { lat: number; lng: number };
|
||||
apiKey?: string;
|
||||
onClose: () => void;
|
||||
@@ -11,21 +13,46 @@ interface SubmitContributionModalProps {
|
||||
}
|
||||
|
||||
export const SubmitContributionModal: React.FC<SubmitContributionModalProps> = ({
|
||||
isOpen = false,
|
||||
landmark,
|
||||
initialLandmark,
|
||||
mapCenter,
|
||||
apiKey = '',
|
||||
onClose,
|
||||
onSuccess,
|
||||
}) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
const targetLandmark = landmark || initialLandmark;
|
||||
const [displayName, setDisplayName] = useState('المرشد الميداني (حمزة)');
|
||||
const [contributionType, setContributionType] = useState('CONFIRM_GATE');
|
||||
const [lat, setLat] = useState(landmark?.coordinates.access_gate?.lat ?? mapCenter?.lat ?? 31.9539);
|
||||
const [lng, setLng] = useState(landmark?.coordinates.access_gate?.lng ?? mapCenter?.lng ?? 35.9106);
|
||||
const [lat, setLat] = useState(targetLandmark?.coordinates.access_gate?.lat ?? mapCenter?.lat ?? 31.9539);
|
||||
const [lng, setLng] = useState(targetLandmark?.coordinates.access_gate?.lng ?? mapCenter?.lng ?? 35.9106);
|
||||
const [notes, setNotes] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [onClose]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (targetLandmark?.coordinates.access_gate) {
|
||||
setLat(targetLandmark.coordinates.access_gate.lat);
|
||||
setLng(targetLandmark.coordinates.access_gate.lng);
|
||||
} else if (mapCenter) {
|
||||
setLat(mapCenter.lat);
|
||||
setLng(mapCenter.lng);
|
||||
}
|
||||
}, [targetLandmark, mapCenter]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
@@ -38,8 +65,8 @@ export const SubmitContributionModal: React.FC<SubmitContributionModalProps> = (
|
||||
displayName: displayName.trim(),
|
||||
contributionType,
|
||||
targetTable: 'heritage.landmarks',
|
||||
targetId: landmark?.id ?? null,
|
||||
placeName: landmark?.name_ar || 'معلم أثري ميداني',
|
||||
targetId: targetLandmark?.id ?? null,
|
||||
placeName: targetLandmark?.name_ar || 'معلم أثري ميداني',
|
||||
lat: parseFloat(lat as any),
|
||||
lng: parseFloat(lng as any),
|
||||
suggestedData: {
|
||||
@@ -75,6 +102,7 @@ export const SubmitContributionModal: React.FC<SubmitContributionModalProps> = (
|
||||
return (
|
||||
<div
|
||||
dir="rtl"
|
||||
onClick={onClose}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
@@ -89,6 +117,7 @@ export const SubmitContributionModal: React.FC<SubmitContributionModalProps> = (
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: '520px',
|
||||
@@ -134,7 +163,7 @@ export const SubmitContributionModal: React.FC<SubmitContributionModalProps> = (
|
||||
<Sparkles size={16} /> شبكة المساهمين والمرشدين المحليين
|
||||
</div>
|
||||
<h2 style={{ margin: 0, fontSize: '20px', fontWeight: 800 }}>
|
||||
{landmark ? `اقتراح وتوثيق: ${landmark.name_ar}` : 'إضافة وتوثيق بوابة سياحية جديدة'}
|
||||
{targetLandmark ? `اقتراح وتوثيق: ${targetLandmark.name_ar}` : 'إضافة وتوثيق بوابة سياحية جديدة'}
|
||||
</h2>
|
||||
<p style={{ margin: '6px 0 0', fontSize: '13px', color: '#94a3b8' }}>
|
||||
تخضع المساهمات لطابور المراجعة المعتمد قبل نشرها للجمهور وتمنحك نقاط المرشد الموثوق.
|
||||
@@ -315,29 +344,48 @@ export const SubmitContributionModal: React.FC<SubmitContributionModalProps> = (
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
style={{
|
||||
width: '100%',
|
||||
background: 'linear-gradient(135deg, #0b2547 0%, #153e75 100%)',
|
||||
color: '#ffffff',
|
||||
border: 'none',
|
||||
borderRadius: '12px',
|
||||
padding: '14px',
|
||||
fontSize: '15px',
|
||||
fontWeight: 800,
|
||||
cursor: loading ? 'wait' : 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '8px',
|
||||
boxShadow: '0 4px 14px rgba(11, 37, 71, 0.25)',
|
||||
}}
|
||||
>
|
||||
{loading ? 'جارٍ الإرسال والتسجيل...' : <><Send size={16} /> إرسال المساهمة لطابور الاعتماد</>}
|
||||
</button>
|
||||
{/* Submit & Cancel Buttons */}
|
||||
<div style={{ display: 'flex', gap: '10px', marginTop: '10px' }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
style={{
|
||||
flex: 1,
|
||||
background: 'rgba(241, 245, 249, 0.9)',
|
||||
color: '#475569',
|
||||
border: '1px solid #cbd5e1',
|
||||
borderRadius: '12px',
|
||||
padding: '13px',
|
||||
fontSize: '14px',
|
||||
fontWeight: 700,
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
إلغاء
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
style={{
|
||||
flex: 2,
|
||||
background: 'linear-gradient(135deg, #0b2547 0%, #153e75 100%)',
|
||||
color: '#ffffff',
|
||||
border: 'none',
|
||||
borderRadius: '12px',
|
||||
padding: '13px',
|
||||
fontSize: '14px',
|
||||
fontWeight: 800,
|
||||
cursor: loading ? 'wait' : 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '8px',
|
||||
boxShadow: '0 4px 14px rgba(11, 37, 71, 0.25)',
|
||||
}}
|
||||
>
|
||||
{loading ? 'جارٍ الإرسال والتسجيل...' : <><Send size={16} /> إرسال المساهمة لطابور الاعتماد</>}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+137
-7
@@ -25,7 +25,6 @@ try {
|
||||
|
||||
// Lightweight hash router with Sovereign Executive Styling
|
||||
const NAV = [
|
||||
{ hash: '#landing', label: 'Landing Page (صفحة الهبوط)', icon: '🚀' },
|
||||
{ hash: '#map', label: 'الخريطة والملاحة الشاملة', icon: '🗺️' },
|
||||
{ hash: '#terrain3d', label: 'الخريطة ثلاثية الأبعاد والتضاريس', icon: '🏔️' },
|
||||
{ hash: '#tourism', label: 'الخريطة السياحية والتراثية', icon: '🏛️' },
|
||||
@@ -37,13 +36,33 @@ const NAV = [
|
||||
function MasterHeader({ hash }: { hash: string }) {
|
||||
const currentHash = hash || '#map'
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
const [showAdminModal, setShowAdminModal] = useState(false);
|
||||
const [adminKey, setAdminKey] = useState(() => {
|
||||
return (import.meta as any).env.VITE_ADMIN_API_KEY || (import.meta as any).env.VITE_API_KEY || localStorage.getItem('map_admin_key') || localStorage.getItem('intaleq_api_key') || '';
|
||||
});
|
||||
const [keyInput, setKeyInput] = useState(adminKey);
|
||||
const [savedSuccess, setSavedSuccess] = useState(false);
|
||||
|
||||
const saveAdminKey = (newKey: string) => {
|
||||
const trimmed = newKey.trim();
|
||||
localStorage.setItem('map_admin_key', trimmed);
|
||||
localStorage.setItem('intaleq_api_key', trimmed);
|
||||
sessionStorage.setItem('tactical_api_key', trimmed);
|
||||
setAdminKey(trimmed);
|
||||
setSavedSuccess(true);
|
||||
setTimeout(() => {
|
||||
setSavedSuccess(false);
|
||||
setShowAdminModal(false);
|
||||
window.location.reload();
|
||||
}, 800);
|
||||
};
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
if (!document.fullscreenElement) {
|
||||
document.documentElement.requestFullscreen().catch(() => {});
|
||||
document.documentElement.requestFullscreen().catch(() => { });
|
||||
setIsFullscreen(true);
|
||||
} else {
|
||||
document.exitFullscreen().catch(() => {});
|
||||
document.exitFullscreen().catch(() => { });
|
||||
setIsFullscreen(false);
|
||||
}
|
||||
};
|
||||
@@ -149,8 +168,29 @@ function MasterHeader({ hash }: { hash: string }) {
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* Left Section: Live Sovereign Telemetry & Fullscreen */}
|
||||
{/* Left Section: Admin Key Clearance & Telemetry & Fullscreen */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
<button
|
||||
onClick={() => setShowAdminModal(true)}
|
||||
title="تصريح المشرف الرسمي (Admin Clearance)"
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
background: 'rgba(234, 179, 8, 0.12)',
|
||||
border: '1px solid rgba(234, 179, 8, 0.35)',
|
||||
color: '#facc15',
|
||||
padding: '4px 10px',
|
||||
borderRadius: 8,
|
||||
fontSize: '0.72rem',
|
||||
fontWeight: 700,
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<span>🛡️</span>
|
||||
<span>تصريح المشرف (Admin)</span>
|
||||
</button>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -194,6 +234,99 @@ function MasterHeader({ hash }: { hash: string }) {
|
||||
<span>{isFullscreen ? '🗗' : '🗖'}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Admin Key Clearance Modal */}
|
||||
{showAdminModal && (
|
||||
<div style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
background: 'rgba(0, 0, 0, 0.75)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
zIndex: 100000,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
direction: 'rtl'
|
||||
}}>
|
||||
<div style={{
|
||||
background: '#0d1527',
|
||||
border: '1px solid rgba(234, 179, 8, 0.4)',
|
||||
borderRadius: 16,
|
||||
padding: '24px 28px',
|
||||
width: 480,
|
||||
maxWidth: '90vw',
|
||||
boxShadow: '0 20px 50px rgba(0,0,0,0.6)',
|
||||
color: '#fff'
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12 }}>
|
||||
<span style={{ fontSize: 24 }}>🛡️</span>
|
||||
<h3 style={{ margin: 0, fontSize: '1.1rem', fontWeight: 800 }}>تصريح المشرف الرسمي (Admin Clearance)</h3>
|
||||
</div>
|
||||
<p style={{ fontSize: '0.85rem', color: '#94a3b8', margin: '0 0 16px 0', lineHeight: 1.6 }}>
|
||||
يُستخدم هذا المفتاح للوصول إلى المنظومة التكتيكية وتدقيق الطرق الذكي وكافة ميزات المنصة السيادية بصلاحيات المشرف الكاملة.
|
||||
</p>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<label style={{ display: 'block', fontSize: '0.78rem', color: '#cbd5e1', marginBottom: 6, fontWeight: 700 }}>
|
||||
مفتاح الـ API الرسمي للمشرف (Admin API Key):
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={keyInput}
|
||||
onChange={(e) => setKeyInput(e.target.value)}
|
||||
placeholder="أدخل مفتاح الـ Admin هنا..."
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 14px',
|
||||
borderRadius: 8,
|
||||
border: '1px solid rgba(255, 255, 255, 0.15)',
|
||||
background: 'rgba(255, 255, 255, 0.05)',
|
||||
color: '#facc15',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '0.9rem',
|
||||
outline: 'none',
|
||||
boxSizing: 'border-box'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{savedSuccess && (
|
||||
<div style={{ color: '#4ade80', fontSize: '0.82rem', marginBottom: 12, fontWeight: 700 }}>
|
||||
✅ تم حفظ وتفعيل مفتاح المشرف بنجاح! جاري التحديث...
|
||||
</div>
|
||||
)}
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
|
||||
<button
|
||||
onClick={() => setShowAdminModal(false)}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
borderRadius: 8,
|
||||
border: '1px solid rgba(255, 255, 255, 0.15)',
|
||||
background: 'transparent',
|
||||
color: '#94a3b8',
|
||||
cursor: 'pointer',
|
||||
fontWeight: 600
|
||||
}}
|
||||
>
|
||||
إلغاء
|
||||
</button>
|
||||
<button
|
||||
onClick={() => saveAdminKey(keyInput)}
|
||||
style={{
|
||||
padding: '8px 20px',
|
||||
borderRadius: 8,
|
||||
border: 'none',
|
||||
background: 'linear-gradient(135deg, #eab308, #ca8a04)',
|
||||
color: '#000',
|
||||
fontWeight: 800,
|
||||
cursor: 'pointer',
|
||||
boxShadow: '0 2px 10px rgba(234, 179, 8, 0.4)'
|
||||
}}
|
||||
>
|
||||
تفعيل وحفظ المفتاح
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
)
|
||||
}
|
||||
@@ -261,9 +394,6 @@ function Root() {
|
||||
return window.location.hash;
|
||||
}
|
||||
const p = window.location.pathname.toLowerCase();
|
||||
if (p.includes('landing')) {
|
||||
return '#landing';
|
||||
}
|
||||
if (p.includes('tourism') || p.includes('heritage') || p.includes('tourist') || window.location.href.includes('سياح')) {
|
||||
return '#tourism';
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ export const TourismMapView: React.FC = () => {
|
||||
startLat = fallbackHub[1];
|
||||
}
|
||||
|
||||
const SOVEREIGN_MAP_API_KEY = 'zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX';
|
||||
const SOVEREIGN_MAP_API_KEY = (import.meta as any).env.VITE_API_KEY || (import.meta as any).env.VITE_ADMIN_API_KEY || localStorage.getItem('map_admin_key') || localStorage.getItem('intaleq_api_key') || '';
|
||||
const queryParams = `fromLat=${startLat}&fromLng=${startLng}&toLat=${lat}&toLng=${lng}&profile=car&steps=true&locale=ar&key=${SOVEREIGN_MAP_API_KEY}`;
|
||||
|
||||
const isServerEnv = window.location.hostname.includes('intaleqapp.com') || window.location.port === '3201' || window.location.port === '3204';
|
||||
@@ -1000,12 +1000,18 @@ export const TourismMapView: React.FC = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 7. Crowdsourcing Contribution Modal */}
|
||||
<SubmitContributionModal
|
||||
isOpen={isContributeOpen}
|
||||
onClose={() => setIsContributeOpen(false)}
|
||||
initialLandmark={contributeTarget}
|
||||
/>
|
||||
{/* 7. Crowdsourcing Contribution Modal (Only open on user action) */}
|
||||
{isContributeOpen && (
|
||||
<SubmitContributionModal
|
||||
isOpen={isContributeOpen}
|
||||
onClose={() => {
|
||||
setIsContributeOpen(false);
|
||||
setContributeTarget(undefined);
|
||||
}}
|
||||
initialLandmark={contributeTarget}
|
||||
mapCenter={mapInstance ? { lat: mapInstance.getCenter().lat, lng: mapInstance.getCenter().lng } : undefined}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 8. Sovereign In-App Navigation HUD */}
|
||||
{activeNav && (
|
||||
|
||||
Reference in New Issue
Block a user