import React, { useEffect, useRef } from 'react'; import { MarkerView, PointAnnotation } from '@maplibre/maplibre-react-native'; import { View, StyleSheet, Image, Animated, Platform, Text } from 'react-native'; import { usePOIsStore } from '../storages/pois'; import { POI } from '../types'; interface POIAnnotationProps { /** * Called when a POI annotation is pressed * @param poiId - The ID of the pressed POI */ onPOIPress?: (poiId: number) => void; } const OpenedPOIs: React.FC = ({ onPOIPress }) => { const openedPOIs = usePOIsStore((state) => state.openedPOIs); return ( <> {openedPOIs.map((poi) => ( Platform.select({ default: , android: , }) ))} ); }; /** * Android Marker * Needs MarkerView in order to properly display the image */ const AndroidMarker: React.FC<{ poi: POI }> = ({ poi }) => { const imageUrl = poi.media_url || poi.image_url; return ( ); }; /** * iOS/Default Marker * Uses PointAnnotation as it's most efficient and use animated.view to animate the marker */ const AnimatedMarker: React.FC<{ poi: POI }> = ({ poi }) => { const scaleY = useRef(new Animated.Value(0.7)).current; const opacity = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.parallel([ Animated.timing(scaleY, { toValue: 1, duration: 300, useNativeDriver: true, }), Animated.timing(opacity, { toValue: 1, duration: 200, useNativeDriver: true, }), ]).start(); }, []); const imageUrl = poi.media_url || poi.image_url; return ( ); }; const styles = StyleSheet.create({ markerContainer: { alignItems: 'center', position: 'relative', transformOrigin: 'bottom', top: -25, // Not working in Android width: 42, height: 60, }, imageContainer: { width: 40, height: 40, borderRadius: 20, backgroundColor: 'white', padding: 2, // Creates white border effect elevation: 5, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, }, image: { width: '100%', height: '100%', borderRadius: 18, // Slightly less than container to show white border }, arrow: { width: 0, height: 0, backgroundColor: 'transparent', borderStyle: 'solid', borderLeftWidth: 8, borderRightWidth: 8, borderTopWidth: 10, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: 'white', // Negative margin to overlap with container for seamless look marginTop: -2, }, }); export default OpenedPOIs;