From fb19ec60b266188ecbca2c925d82c8c5326ac0ab Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Thu, 26 Feb 2026 17:53:23 +0800 Subject: [PATCH 1/2] Fix Maps iOS Project - HIPMIBadungConnect.xcodeproj/project.pbxproj Maps & Location Screens - screens/Maps/MapsView2.tsx - screens/Portofolio/BusinessLocationSection.tsx New Map Components - components/Map/MapsV2Custom.tsx - components/Map/SelectLocationMap.tsx ### No Issue --- .../project.pbxproj | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj b/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj index 2e5951a..fa94b4c 100644 --- a/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj +++ b/ios/HIPMIBadungConnect.xcodeproj/project.pbxproj @@ -155,6 +155,14 @@ B6436A881D9B484CB6D18085 /* Remove signature files (Xcode workaround) */, 2BAE9DA9D4244A23B39651C7 /* Remove signature files (Xcode workaround) */, 81D5244C04C44C06AD9AE152 /* Remove signature files (Xcode workaround) */, + 806E7861EC0045A8A1F95D2D /* Remove signature files (Xcode workaround) */, + 4B22761083094691A59ABFF6 /* Remove signature files (Xcode workaround) */, + B68271891C364FB0B1E59DC4 /* Remove signature files (Xcode workaround) */, + A38A95E05F7448A8922DE72A /* Remove signature files (Xcode workaround) */, + 6692ADBCD8384D8EA2D9A355 /* Remove signature files (Xcode workaround) */, + 5A6E1555841A4B9D9D246E71 /* Remove signature files (Xcode workaround) */, + 0B4282049A4A4293821DF904 /* Remove signature files (Xcode workaround) */, + CCCF75FD0B87410193A6B7DB /* Remove signature files (Xcode workaround) */, ); buildRules = ( ); @@ -491,6 +499,142 @@ rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; "; }; + 806E7861EC0045A8A1F95D2D /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 4B22761083094691A59ABFF6 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + B68271891C364FB0B1E59DC4 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + A38A95E05F7448A8922DE72A /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 6692ADBCD8384D8EA2D9A355 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 5A6E1555841A4B9D9D246E71 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + 0B4282049A4A4293821DF904 /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; + CCCF75FD0B87410193A6B7DB /* Remove signature files (Xcode workaround) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + name = "Remove signature files (Xcode workaround)"; + inputPaths = ( + ); + outputPaths = ( + ); + shellPath = /bin/sh; + shellScript = " + echo \"Remove signature files (Xcode workaround)\"; + rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\"; + "; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ -- 2.49.1 From 67070bb2f100547076d9a5c69f7309a651c48b77 Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Thu, 26 Feb 2026 18:04:45 +0800 Subject: [PATCH 2/2] Fix Maps iOS Project - HIPMIBadungConnect.xcodeproj/project.pbxproj Maps & Location Screens - screens/Maps/MapsView2.tsx - screens/Portofolio/BusinessLocationSection.tsx New Map Components - components/Map/MapsV2Custom.tsx - components/Map/SelectLocationMap.tsx ### No Issue --- components/Map/MapsV2Custom.tsx | 542 ++++++++++++++++++ components/Map/SelectLocationMap.tsx | 272 +++++++++ screens/Maps/MapsView2.tsx | 117 ++-- .../Portofolio/BusinessLocationSection.tsx | 70 ++- 4 files changed, 901 insertions(+), 100 deletions(-) create mode 100644 components/Map/MapsV2Custom.tsx create mode 100644 components/Map/SelectLocationMap.tsx diff --git a/components/Map/MapsV2Custom.tsx b/components/Map/MapsV2Custom.tsx new file mode 100644 index 0000000..09cefee --- /dev/null +++ b/components/Map/MapsV2Custom.tsx @@ -0,0 +1,542 @@ +import { ReactNode, useCallback, useMemo, useState, useEffect } from "react"; +import { + Image, + StyleSheet, + View, + ViewStyle, + StyleProp, + Animated, + Easing, +} from "react-native"; + +import API_IMAGE from "@/constants/api-storage"; +import { MainColor } from "@/constants/color-palet"; +import { + Camera, + MapView, + PointAnnotation, +} from "@maplibre/maplibre-react-native"; + +// Style peta default +const DEFAULT_MAP_STYLE = "https://tiles.openfreemap.org/styles/liberty"; + +// Region default (Bali, Indonesia) +const DEFAULT_REGION = { + latitude: -8.737109, + longitude: 115.1756897, + latitudeDelta: 0.1, + longitudeDelta: 0.1, +}; + +// Zoom level default +const DEFAULT_ZOOM_LEVEL = 12; + +// Ukuran marker default +const DEFAULT_MARKER_SIZE = 30; + +/** + * Interface data marker untuk MapsV2Custom + */ +export interface MapMarker { + id: string; + coordinate: [number, number]; // [longitude, latitude] + imageId?: string; + imageUrl?: string; + onSelected?: () => void; + [key: string]: any; // Izinkan properti custom tambahan +} + +/** + * Interface region untuk positioning kamera + */ +export interface Region { + latitude: number; + longitude: number; + latitudeDelta: number; + longitudeDelta: number; +} + +/** + * Props untuk komponen MapsV2Custom + */ +export interface MapsV2CustomProps { + /** URL style peta custom (default: liberty style) */ + mapStyle?: string; + + /** Override style container */ + style?: StyleProp; + + /** Override style MapView */ + mapViewStyle?: StyleProp; + + /** Region awal kamera */ + initialRegion?: Region; + + /** Zoom level awal (default: 12) */ + zoomLevel?: number; + + /** + * Data marker - mendukung single marker atau array of markers + * @example + * // Single marker + * markers={{ id: "1", coordinate: [115.175, -8.737], imageId: "abc" }} + * + * @example + * // Multiple markers + * markers={[ + * { id: "1", coordinate: [115.175, -8.737], imageId: "abc" }, + * { id: "2", coordinate: [115.180, -8.740], imageId: "xyz" } + * ]} + */ + markers?: MapMarker | MapMarker[]; + + /** Custom renderer marker */ + renderMarker?: (marker: MapMarker) => ReactNode; + + /** Callback ketika marker ditekan */ + onMarkerPress?: (marker: MapMarker) => void; + + /** Gunakan style marker image default (default: true jika markers disediakan) */ + showDefaultMarkers?: boolean; + + /** Ukuran untuk marker default (default: 30) */ + markerSize?: number; + + /** Warna border untuk marker default */ + markerBorderColor?: string; + + /** Children tambahan untuk MapView (custom overlays, dll.) */ + children?: ReactNode; + + /** Handler untuk tekan pada peta */ + onMapPress?: (coordinates: [number, number]) => void; + + /** Test identifier */ + testID?: string; + + /** Props tambahan untuk Camera */ + cameraProps?: Partial, "centerCoordinate" | "zoomLevel">>; + + /** Props tambahan untuk MapView */ + mapViewProps?: Partial>; + + /** Props tambahan untuk PointAnnotation */ + annotationProps?: Partial<{ + id: string; + title?: string; + snippet?: string; + selected?: boolean; + draggable?: boolean; + coordinate: number[]; + anchor?: { x: number; y: number }; + onSelected?: (payload: any) => void; + onDeselected?: (payload: any) => void; + onDragStart?: (payload: any) => void; + onDragEnd?: (payload: any) => void; + onDrag?: (payload: any) => void; + style?: StyleProp; + }>; +} + +/** + * Normalisasi markers ke array - mendukung single marker atau array + */ +function normalizeMarkers(markers: MapMarker | MapMarker[] | undefined): MapMarker[] { + if (!markers) return []; + return Array.isArray(markers) ? markers : [markers]; +} + +/** + * Validasi marker memiliki props yang required (hanya development mode) + */ +function validateMarker(marker: MapMarker, index: number): boolean { + if (!marker.id) { + console.warn(`[MapsV2Custom] Marker pada index ${index} tidak memiliki prop 'id' yang required`); + return false; + } + if (!marker.coordinate || !Array.isArray(marker.coordinate) || marker.coordinate.length !== 2) { + console.warn(`[MapsV2Custom] Marker pada index ${index} tidak memiliki prop 'coordinate' yang required. Format yang diharapkan: [longitude, latitude]`); + return false; + } + return true; +} + +/** + * Komponen skeleton untuk loading state dengan shimmer animation + */ +function SkeletonMarker({ + size = DEFAULT_MARKER_SIZE, + borderColor = MainColor.darkblue, + loadingColor = "#C5C5C5", +}: { + size?: number; + borderColor?: string; + loadingColor?: string; +}) { + const shimmerAnim = useMemo(() => new Animated.Value(0), []); + + useEffect(() => { + const animation = Animated.loop( + Animated.sequence([ + Animated.timing(shimmerAnim, { + toValue: 1, + duration: 800, + easing: Easing.inOut(Easing.ease), + useNativeDriver: true, + }), + Animated.timing(shimmerAnim, { + toValue: 0, + duration: 800, + easing: Easing.inOut(Easing.ease), + useNativeDriver: true, + }), + ]) + ); + + animation.start(); + + return () => animation.stop(); + }, [shimmerAnim]); + + const shimmerOpacity = shimmerAnim.interpolate({ + inputRange: [0, 1], + outputRange: [0.3, 0.7], + }); + + return ( + + + + ); +} + +/** + * Komponen fallback untuk error state + */ +function FallbackMarker({ + size = DEFAULT_MARKER_SIZE, + borderColor = MainColor.darkblue, + iconColor = MainColor.darkblue, +}: { + size?: number; + borderColor?: string; + iconColor?: string; +}) { + return ( + + + + + + ); +} + +/** + * Props untuk DefaultMarker component + */ +export interface DefaultMarkerProps { + /** ID file image dari API */ + imageId?: string; + /** URL image langsung */ + imageUrl?: string; + /** Ukuran marker (default: 30) */ + size?: number; + /** Warna border marker (default: darkblue) */ + borderColor?: string; + /** Warna skeleton loading (default: gray) */ + loadingColor?: string; + /** Warna icon fallback (default: darkblue) */ + fallbackIconColor?: string; +} + +/** + * Komponen marker default dengan image, border, shadows, loading skeleton, dan error fallback + */ +export function DefaultMarker({ + imageId, + imageUrl, + size = DEFAULT_MARKER_SIZE, + borderColor = MainColor.darkblue, + loadingColor = MainColor.white_gray, + fallbackIconColor = MainColor.darkblue, +}: DefaultMarkerProps) { + const [hasError, setHasError] = useState(false); + const uri = imageId ? API_IMAGE.GET({ fileId: imageId }) : imageUrl; + + // Debug log untuk development + if (__DEV__ && uri) { + console.log("[DefaultMarker] Image URI:", uri); + } + + const handleError = useCallback((error: any) => { + console.log("[DefaultMarker] Image error:", error?.nativeEvent?.error || error); + setHasError(true); + }, []); + + const handleLoad = useCallback(() => { + console.log("[DefaultMarker] Image loaded successfully"); + }, []); + + // Jika tidak ada URI atau error, tampilkan fallback + if (!uri || hasError) { + return ( + + ); + } + + // Render image dengan placeholder (defaultSource) untuk loading state + return ( + + + + ); +} + +/** + * Komponen Map yang reusable dan customizable menggunakan Mapbox/MapLibre + * + * Mendukung single marker, multiple markers, atau empty state. + * + * @example + * // Single marker + * + * + * @example + * // Multiple markers + * + * + * @example + * // Peta dengan custom style dan custom markers + * + * + * @example + * // Dengan custom marker renderer + * } + * /> + * + * @example + * // Peta kosong (tanpa markers) + * + */ +export function MapsV2Custom({ + mapStyle = DEFAULT_MAP_STYLE, + style = styles.container, + mapViewStyle = styles.map, + initialRegion = DEFAULT_REGION, + zoomLevel = DEFAULT_ZOOM_LEVEL, + markers, + renderMarker, + onMarkerPress, + showDefaultMarkers = true, + markerSize = DEFAULT_MARKER_SIZE, + markerBorderColor = MainColor.darkblue, + children, + onMapPress, + testID, + cameraProps, + mapViewProps, + annotationProps, +}: MapsV2CustomProps) { + // Normalisasi markers ke array (mendukung single atau multiple) + const normalizedMarkers = useMemo( + () => { + const arr = normalizeMarkers(markers); + // Filter marker yang invalid + return arr.filter((marker) => { + if (!marker.id) { + console.warn("[MapsV2Custom] Marker tanpa id akan diabaikan"); + return false; + } + if (!marker.coordinate || marker.coordinate.length !== 2) { + console.warn("[MapsV2Custom] Marker tanpa coordinate valid akan diabaikan"); + return false; + } + return true; + }); + }, + [markers] + ); + + // Validasi markers dalam development mode + useMemo(() => { + if (__DEV__) { + normalizedMarkers.forEach((marker, index) => { + validateMarker(marker, index); + }); + } + }, [normalizedMarkers]); + + const handleMarkerSelected = useCallback( + (marker: MapMarker) => { + if (marker.onSelected) { + marker.onSelected(); + } + if (onMarkerPress) { + onMarkerPress(marker); + } + }, + [onMarkerPress] + ); + + const renderMarkerComponent = useCallback( + (marker: MapMarker): ReactNode => { + if (renderMarker) { + return renderMarker(marker); + } + + if (showDefaultMarkers) { + return ( + + ); + } + + return null; + }, + [renderMarker, showDefaultMarkers, markerSize, markerBorderColor] + ); + + return ( + + + + + {normalizedMarkers.map((marker) => ( + handleMarkerSelected(marker)} + {...annotationProps} + > + {renderMarkerComponent(marker) as any} + + ))} + + {children} + + + ); +} + +const styles = StyleSheet.create({ + container: { flex: 1 }, + map: { flex: 1 }, + markerContainer: { + overflow: "hidden", + borderWidth: 1, + elevation: 4, + shadowColor: "#000", + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.3, + shadowRadius: 3, + }, + markerImage: { + width: "100%", + height: "100%", + }, + skeletonShimmer: { + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + borderRadius: 999, + }, + fallbackIcon: { + width: "60%", + height: "60%", + borderRadius: 999, + borderWidth: 2, + justifyContent: "center", + alignItems: "center", + }, + fallbackIconInner: { + width: "40%", + height: "40%", + borderRadius: 999, + }, +}); diff --git a/components/Map/SelectLocationMap.tsx b/components/Map/SelectLocationMap.tsx new file mode 100644 index 0000000..8eb16c2 --- /dev/null +++ b/components/Map/SelectLocationMap.tsx @@ -0,0 +1,272 @@ +import React, { useState, useCallback, useRef } from "react"; +import { + View, + Text, + StyleSheet, + TouchableOpacity, + ActivityIndicator, +} from "react-native"; +import { + MapView, + Camera, + PointAnnotation, + MarkerView, +} from "@maplibre/maplibre-react-native"; +import * as Location from "expo-location"; +import { useFocusEffect, useRouter } from "expo-router"; + +const MAP_STYLE = "https://tiles.openfreemap.org/styles/liberty"; + +type Coordinate = { + latitude: number; + longitude: number; +}; + +export default function SelectLocationMap() { + const router = useRouter(); + const annotationRef = useRef(null); + + const [selectedCoord, setSelectedCoord] = useState(null); + const [address, setAddress] = useState(""); + const [isLoadingAddress, setIsLoadingAddress] = useState(false); + const [cameraCenter, setCameraCenter] = useState<[number, number]>([ + 106.8272, -6.1751, + ]); + + const reverseGeocode = async (coord: Coordinate): Promise => { + try { + const { status } = await Location.getForegroundPermissionsAsync(); + if (status !== "granted") { + await Location.requestForegroundPermissionsAsync(); + } + + const results = await Location.reverseGeocodeAsync({ + latitude: coord.latitude, + longitude: coord.longitude, + }); + + if (!results || results.length === 0) return "Alamat tidak ditemukan"; + + const loc = results[0]; + const parts = [ + loc.street, + loc.district, + loc.subregion, + loc.city, + loc.region, + loc.country, + ].filter(Boolean); + + return parts.length > 0 ? parts.join(", ") : "Alamat tidak ditemukan"; + } catch (error: any) { + console.log("reverseGeocode error:", error?.message || error); + return "Gagal mengambil alamat"; + } + }; + + const handleMapPress = useCallback(async (event: any) => { + try { + const coordinates = event?.geometry?.coordinates; + if (!coordinates) return; + + const [longitude, latitude] = coordinates; + if (!longitude || !latitude) return; + + const coord: Coordinate = { latitude, longitude }; + + // ✅ Update state koordinat, BUKAN ganti key + setSelectedCoord(coord); + setCameraCenter([longitude, latitude]); + setAddress(""); + setIsLoadingAddress(true); + + const resolvedAddress = await reverseGeocode(coord); + setAddress(resolvedAddress); + setIsLoadingAddress(false); + + // ✅ Refresh annotation tanpa unmount + annotationRef.current?.refresh?.(); + } catch (error: any) { + console.log("handleMapPress error:", error?.message || error); + setIsLoadingAddress(false); + } + }, []); + + const handleConfirm = () => { + if (!selectedCoord) return; + router.navigate({ + pathname: "/maps/create", + params: { + latitude: String(selectedCoord.latitude), + longitude: String(selectedCoord.longitude), + address, + }, + }); + }; + + // Sembunyikan marker sebelum halaman unmount + useFocusEffect( + useCallback(() => { + return () => { + // Cleanup saat leave — sembunyikan marker dulu sebelum unmount + setSelectedCoord(null); + }; + }, []), + ); + + return ( + + + + + {/* ✅ Key statis — tidak pernah berubah, tidak unmount/remount */} + {selectedCoord && ( + + + + + + )} + + + {/* Bottom Sheet */} + + {!selectedCoord ? ( + + Tap pada peta untuk memilih lokasi + + ) : ( + <> + + + Latitude + + {selectedCoord.latitude.toFixed(6)} + + + + + Longitude + + {selectedCoord.longitude.toFixed(6)} + + + + + + Alamat + {isLoadingAddress ? ( + + ) : ( + + {address || "-"} + + )} + + + + Konfirmasi Lokasi + + + )} + + + ); +} + +const styles = StyleSheet.create({ + container: { flex: 1 }, + map: { flex: 1 }, + pin: { + width: 28, + height: 28, + borderRadius: 100, + backgroundColor: "#0a1f44", + justifyContent: "center", + alignItems: "center", + borderWidth: 2, + borderColor: "#fff", + }, + pinDot: { + width: 8, + height: 8, + borderRadius: 100, + backgroundColor: "#fff", + }, + bottomSheet: { + backgroundColor: "#fff", + paddingHorizontal: 20, + paddingVertical: 20, + paddingBottom: 32, + borderTopLeftRadius: 20, + borderTopRightRadius: 20, + elevation: 10, + shadowColor: "#000", + shadowOffset: { width: 0, height: -3 }, + shadowOpacity: 0.1, + shadowRadius: 6, + minHeight: 140, + justifyContent: "center", + }, + hintText: { + textAlign: "center", + color: "#888", + fontSize: 14, + }, + coordRow: { + flexDirection: "row", + marginBottom: 12, + }, + coordItem: { flex: 1 }, + dividerVertical: { + width: 1, + backgroundColor: "#e0e0e0", + marginHorizontal: 12, + }, + coordLabel: { + fontSize: 11, + color: "#888", + marginBottom: 2, + }, + coordValue: { + fontSize: 14, + fontWeight: "600", + color: "#0a1f44", + }, + addressContainer: { marginBottom: 16 }, + addressText: { + fontSize: 13, + color: "#333", + lineHeight: 18, + }, + confirmButton: { + backgroundColor: "#0a1f44", + borderRadius: 12, + paddingVertical: 14, + alignItems: "center", + }, + confirmButtonDisabled: { + backgroundColor: "#aaa", + }, + confirmButtonText: { + color: "#fff", + fontWeight: "700", + fontSize: 15, + }, +}); diff --git a/screens/Maps/MapsView2.tsx b/screens/Maps/MapsView2.tsx index a21f522..f0c0872 100644 --- a/screens/Maps/MapsView2.tsx +++ b/screens/Maps/MapsView2.tsx @@ -1,19 +1,13 @@ import { useCallback, useState } from "react"; -import { Image, StyleSheet, View } from "react-native"; -// Cek versi >= 10.x gunakan ini -import API_IMAGE from "@/constants/api-storage"; -import { MainColor } from "@/constants/color-palet"; import { apiMapsGetAll } from "@/service/api-client/api-maps"; -import { - Camera, - MapView, - PointAnnotation, -} from "@maplibre/maplibre-react-native"; import { useFocusEffect } from "expo-router"; -import DrawerMaps from "./DrawerMaps"; -const MAP_STYLE = "https://tiles.openfreemap.org/styles/liberty"; +import { ViewWrapper } from "@/components"; +import { MapMarker, MapsV2Custom } from "@/components/Map/MapsV2Custom"; + +import DrawerMaps from "./DrawerMaps"; +import { StyleSheet } from "react-native"; interface TypeMaps { id: string; @@ -40,14 +34,6 @@ interface TypeMaps { }; } -const defaultRegion = { - latitude: -8.737109, - longitude: 115.1756897, - latitudeDelta: 0.1, - longitudeDelta: 0.1, - height: 300, -}; - export default function MapsView2() { const [list, setList] = useState(null); const [loadList, setLoadList] = useState(false); @@ -76,7 +62,6 @@ export default function MapsView2() { const response = await apiMapsGetAll(); if (response.success) { - // console.log("[RESPONSE]", JSON.stringify(response.data, null, 2)); setList(response.data); } } catch (error) { @@ -86,53 +71,31 @@ export default function MapsView2() { } }; + const markers: MapMarker[] = list?.map((item) => ({ + id: item.id, + coordinate: [item.longitude, item.latitude] as [number, number], + imageId: item.Portofolio.logoId, + onSelected: () => { + setOpenDrawer(true); + setSelected({ + id: item.id, + bidangBisnis: item.Portofolio.MasterBidangBisnis.name, + nomorTelepon: item.Portofolio.tlpn, + alamatBisnis: item.Portofolio.alamatKantor, + namePin: item.namePin, + imageId: item.imageId, + portofolioId: item.Portofolio.id, + latitude: item.latitude, + longitude: item.longitude, + }); + }, + })) || []; + return ( <> - - - - - {list?.map((item: TypeMaps) => { - const imageUrl = API_IMAGE.GET({ fileId: item.Portofolio.logoId }); - - return ( - { - setOpenDrawer(true); - setSelected({ - id: item?.id, - bidangBisnis: item?.Portofolio?.MasterBidangBisnis?.name, - nomorTelepon: item?.Portofolio?.tlpn, - alamatBisnis: item?.Portofolio?.alamatKantor, - namePin: item?.namePin, - imageId: item?.imageId, - portofolioId: item?.Portofolio?.id, - latitude: item?.latitude, - longitude: item?.longitude, - }); - }} - > - - - console.log("Image error:", e.nativeEvent.error) - } // Tangkap error image - /> - - - ); - })} - - + + + void; }) { + console.log("data", data); + + // Buat marker hanya jika data lengkap + const markers = + data?.latitude && data?.longitude + ? [ + { + id: data.id || "location-marker", + coordinate: [data.longitude, data.latitude] as [number, number], + imageId, + onSelected: () => { + setOpenDrawerLocation(true); + }, + }, + ] + : []; + return ( <> @@ -30,18 +53,33 @@ export default function Portofolio_BusinessLocation({ Lokasi bisnis belum ditambahkan ) : ( - { - setOpenDrawerLocation(true); - }} - /> + + + )} ); } + +const styles = StyleSheet.create({ + mapContainer: { + width: "100%", + height: 250, + borderRadius: 8, + overflow: "hidden", + marginTop: 8, + }, +}); -- 2.49.1