feat: add Jordan 3D topographic platform, Siro Map cinematic orbit studio, sun-shadow simulation, and sovereign intelligence security gating

This commit is contained in:
Hamza-Ayed
2026-09-19 12:34:26 +03:00
parent 91e9e71ce4
commit 0bf13824c9
180 changed files with 245224 additions and 704 deletions
+179 -3
View File
@@ -4,6 +4,9 @@ import { Navigation, Compass, Activity, BarChart3, MapPin, Eye, Shield, Gauge, C
import { decodePolyline } from './utils/polyline';
import WeatherPanel from './components/WeatherPanel';
import { LineOfSightTool } from './components/LineOfSightTool';
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') || '';
@@ -30,6 +33,14 @@ function App() {
const [weatherCity, setWeatherCity] = useState<any>(null);
const [weatherAlerts, setWeatherAlerts] = useState<any[]>([]);
// Tourism & Heritage State
const [tourismMode, setTourismMode] = useState(true);
const [heritageLandmarks, setHeritageLandmarks] = useState<HeritageLandmarkData[]>([]);
const [selectedLandmark, setSelectedLandmark] = useState<HeritageLandmarkData | null>(null);
const [showContributeModal, setShowContributeModal] = useState(false);
const [contributeTargetLandmark, setContributeTargetLandmark] = useState<HeritageLandmarkData | null>(null);
const [showGuidesPanel, setShowGuidesPanel] = useState(false);
// Geocoding State
const [searchQuery, setSearchQuery] = useState('');
const [searchResults, setSearchResults] = useState<any[]>([]);
@@ -40,6 +51,36 @@ function App() {
const [originText, setOriginText] = useState('31.9539, 35.9106');
const [destText, setDestText] = useState('32.0608, 36.1032');
const fetchHeritageLandmarks = async () => {
try {
const apiUrl = (import.meta as any).env.VITE_API_URL || '/api';
const res = await fetch(`${apiUrl}/v1/heritage/landmarks`, {
headers: { 'x-api-key': DEFAULT_API_KEY }
});
if (res.ok) {
const data = await res.json();
setHeritageLandmarks(Array.isArray(data) ? data : []);
}
} catch (e) {
console.error('Failed to fetch heritage landmarks', e);
}
};
useEffect(() => {
fetchHeritageLandmarks();
}, []);
const handleNavigateToGate = (lat: number, lng: number, name: string) => {
setDestText(`${lat.toFixed(5)}, ${lng.toFixed(5)}`);
if (map) {
const center = map.getCenter();
setOriginText(`${center.lat.toFixed(5)}, ${center.lng.toFixed(5)}`);
}
setTimeout(() => {
calculateRoute();
}, 150);
};
const regions = [
{
name: 'Syria',
@@ -59,6 +100,15 @@ function App() {
defaultOrigin: '31.9539, 35.9106', // Amman
defaultDest: '32.0608, 36.1032' // Zarqa
},
{
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: 'مصر',
@@ -112,12 +162,24 @@ function App() {
headers: { 'x-api-key': DEFAULT_API_KEY }
});
const data = await response.json();
let results = data.results || [];
setSearchResults(data.results || []);
// If no local results within 50km, fall back to nationwide/global search
if (results.length === 0) {
const fallbackRes = await fetch(`${apiUrl}/geocoding/search?q=${encodeURIComponent(searchQuery)}`, {
headers: { 'x-api-key': DEFAULT_API_KEY }
});
const fallbackData = await fallbackRes.json();
if (fallbackData.results && fallbackData.results.length > 0) {
results = fallbackData.results;
}
}
setSearchResults(results);
setShowResults(true);
if (data.results && data.results.length > 0 && map) {
const place = data.results[0];
if (results && results.length > 0 && map) {
const place = results[0];
const placeLng = parseFloat(place.longitude);
const placeLat = parseFloat(place.latitude);
if (!isNaN(placeLat) && !isNaN(placeLng)) {
@@ -277,6 +339,76 @@ function App() {
<h1>{currentRegion} Maps SaaS</h1>
<p style={{ color: 'var(--text-muted)', fontSize: '0.8rem' }}>Intaleq Mobility & Maps Cloud</p>
{/* Siro Tourism & Heritage Mode Toggle */}
<div style={{ display: 'flex', gap: '8px', margin: '14px 0 6px' }}>
<button
onClick={() => setTourismMode(!tourismMode)}
style={{
flex: 1.2,
padding: '10px 8px',
borderRadius: '10px',
border: tourismMode ? '1.5px solid #d4af37' : '1px solid var(--glass-border)',
background: tourismMode
? 'linear-gradient(135deg, rgba(181, 146, 71, 0.3) 0%, rgba(212, 175, 55, 0.15) 100%)'
: 'rgba(255,255,255,0.04)',
color: tourismMode ? '#fef08a' : '#e2e8f0',
fontWeight: 800,
fontSize: '0.78rem',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '6px',
transition: 'all 0.2s',
boxShadow: tourismMode ? '0 4px 14px rgba(212, 175, 55, 0.25)' : 'none',
}}
>
<span>🏛️</span>
<span>{tourismMode ? 'الخريطة السياحية (مفعلة)' : 'النمط السياحي والآثار'}</span>
</button>
<button
onClick={() => setShowGuidesPanel(true)}
style={{
flex: 0.8,
padding: '10px 8px',
borderRadius: '10px',
border: '1px solid var(--glass-border)',
background: 'rgba(255,255,255,0.04)',
color: '#38bdf8',
fontWeight: 700,
fontSize: '0.78rem',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '4px',
}}
title="مجتمع المرشدين وطابور المراجعة"
>
<span>🌟</span>
<span>المرشدين</span>
</button>
</div>
{tourismMode && (
<div style={{
background: 'rgba(181, 146, 71, 0.1)',
border: '1px solid rgba(181, 146, 71, 0.3)',
borderRadius: '10px',
padding: '8px 10px',
fontSize: '0.75rem',
color: '#fef08a',
marginBottom: '10px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}>
<span>✨ معالم التراث والآثار ({heritageLandmarks.length})</span>
<span style={{ fontSize: '0.7rem', color: '#cbd5e1' }}>انقر لأي معلم لمشاهدة البوابات</span>
</div>
)}
{/* Region Selector */}
<div className="region-selector" style={{ display: 'flex', gap: '8px', margin: '15px 0' }}>
{regions.map(r => (
@@ -621,8 +753,52 @@ function App() {
losActive={showLOS}
losPointA={losPointA}
losPointB={losPointB}
tourismMode={tourismMode}
heritageLandmarks={heritageLandmarks}
selectedLandmark={selectedLandmark}
onSelectLandmark={setSelectedLandmark}
/>
{/* Interactive Landmark Card */}
{selectedLandmark && (
<LandmarkCard
landmark={selectedLandmark}
onClose={() => setSelectedLandmark(null)}
onNavigateToGate={handleNavigateToGate}
onOpenContribute={(lm) => {
setContributeTargetLandmark(lm);
setShowContributeModal(true);
}}
/>
)}
{/* Field Contributor Submission Modal */}
{showContributeModal && (
<SubmitContributionModal
landmark={contributeTargetLandmark}
mapCenter={map ? map.getCenter() : undefined}
apiKey={DEFAULT_API_KEY}
onClose={() => {
setShowContributeModal(false);
setContributeTargetLandmark(null);
}}
onSuccess={() => {
fetchHeritageLandmarks();
}}
/>
)}
{/* Community Guides & Moderation Slide-Over */}
{showGuidesPanel && (
<GuidesModerationPanel
apiKey={DEFAULT_API_KEY}
onClose={() => setShowGuidesPanel(false)}
onContributionApproved={() => {
fetchHeritageLandmarks();
}}
/>
)}
{/* Tactical Line of Sight Tool Overlay */}
<LineOfSightTool
active={showLOS}