From 71ef3f206cf95327f4acaa8c50342dadb8440b9b Mon Sep 17 00:00:00 2001 From: JAlan Date: Sun, 15 Feb 2026 14:20:48 -0600 Subject: [PATCH 1/9] stash changes --- utils/api-hooks.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/utils/api-hooks.ts b/utils/api-hooks.ts index 6af435d..75e32f9 100644 --- a/utils/api-hooks.ts +++ b/utils/api-hooks.ts @@ -16,6 +16,15 @@ export const queryKeys = { profile: (id: number) => ["profile", id] as const, }; + +// get route between two points +// export function getRoute() { +// return useQuery({ + +// }); +// } + + // fetch all POIs export function usePOIs() { return useQuery({ From bfa2fd8b487ec6ddaa28016ddb81d9a74d333d82 Mon Sep 17 00:00:00 2001 From: JAlan Date: Sun, 22 Feb 2026 14:19:49 -0600 Subject: [PATCH 2/9] update gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c8152d6..81ccf27 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ android .DS_Store # Temporary files created by Metro to check the health of the file watcher -.metro-health-check* \ No newline at end of file +.metro-health-check* + +pnpm-lock.yaml From 4614f1c5265d9d95642beedeed9c1ebe0c9f9c92 Mon Sep 17 00:00:00 2001 From: JAlan Date: Sun, 22 Feb 2026 15:57:43 -0600 Subject: [PATCH 3/9] add openroute endpoint --- utils/api-client.ts | 23 +++++++++++++++++++++++ utils/api-hooks.ts | 15 +++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/utils/api-client.ts b/utils/api-client.ts index 45472d7..c87a54b 100644 --- a/utils/api-client.ts +++ b/utils/api-client.ts @@ -47,6 +47,29 @@ class ApiClient { return await response.text(); } + + async getRoute(pointData: string) { + const FEATURE_URL = "https://api.openrouteservice.org/v2/directions/wheelchair"; + const TOKEN = process.env.OPENROUTE_API_KEY || ""; + + let res = await fetch( + FEATURE_URL, + { + method: "post", + headers: { + 'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8', + 'Authorization': TOKEN, + 'Content-Type': 'application/json; charset=utf-8' + }, + body: pointData + } + ); + if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`); + const json = await res.json(); + return json; + } + + // Get profile by ID async getProfile(id: number) { return this.request(`/profiles?id=${id}`); diff --git a/utils/api-hooks.ts b/utils/api-hooks.ts index 75e32f9..47e2e42 100644 --- a/utils/api-hooks.ts +++ b/utils/api-hooks.ts @@ -14,15 +14,18 @@ export const queryKeys = { avoidanceArea: (id: string) => ["avoidanceArea", id] as const, avoidanceAreaReports: (id: string) => ["avoidanceAreaReports", id] as const, profile: (id: number) => ["profile", id] as const, + routes: ["routes"] as const, }; -// get route between two points -// export function getRoute() { -// return useQuery({ - -// }); -// } +// get route between 2+ points +export function getRoute(pointData: string) { + // TODO implement caching later + return useQuery({ + queryKey: queryKeys.routes, + queryFn: () => apiClient.getRoute(pointData), + }); +} // fetch all POIs From f20ab9e2065907d870280b458f4db55e542bf60f Mon Sep 17 00:00:00 2001 From: JAlan Date: Thu, 26 Feb 2026 00:27:24 -0600 Subject: [PATCH 4/9] add openroute api request formatting --- utils/api-client.ts | 14 ++++++++++++-- utils/api-hooks.ts | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/utils/api-client.ts b/utils/api-client.ts index c87a54b..953d4ee 100644 --- a/utils/api-client.ts +++ b/utils/api-client.ts @@ -48,7 +48,7 @@ class ApiClient { } - async getRoute(pointData: string) { + async getRoute(waypoints: any[], avoiding: any[]) { const FEATURE_URL = "https://api.openrouteservice.org/v2/directions/wheelchair"; const TOKEN = process.env.OPENROUTE_API_KEY || ""; @@ -61,7 +61,17 @@ class ApiClient { 'Authorization': TOKEN, 'Content-Type': 'application/json; charset=utf-8' }, - body: pointData + body: JSON.stringify( + {"coordinates":JSON.stringify(waypoints), + "options":{ + "avoid_polygons":{ + "type":"MultiPolygon", + "coordinates":JSON.stringify(avoiding) + } + } + } + ) + } ); if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`); diff --git a/utils/api-hooks.ts b/utils/api-hooks.ts index 47e2e42..3fda421 100644 --- a/utils/api-hooks.ts +++ b/utils/api-hooks.ts @@ -19,11 +19,11 @@ export const queryKeys = { // get route between 2+ points -export function getRoute(pointData: string) { +export function getRoute(waypoints: any[], avoiding: any[]) { // TODO implement caching later return useQuery({ queryKey: queryKeys.routes, - queryFn: () => apiClient.getRoute(pointData), + queryFn: () => apiClient.getRoute(waypoints, avoiding), }); } From 61cb1b4446c16bd30b1eac39649294ca2a0843f3 Mon Sep 17 00:00:00 2001 From: JAlan Date: Thu, 26 Feb 2026 01:44:11 -0600 Subject: [PATCH 5/9] add working openroute api code --- app/(tabs)/index.tsx | 12 +++++++----- utils/api-client.ts | 10 +++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index bf004ef..76659d7 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -17,6 +17,7 @@ import { useAvoidanceAreas, useConstructionAreas, useInsertAvoidanceArea, + getRoute } from "~/utils/api-hooks"; import useMapIcons from "~/utils/useMapIcons"; @@ -55,6 +56,7 @@ export default function Home() { const { data: constructionAreas } = useConstructionAreas(); const { data: POIs } = usePOIs(); const { mutateAsync: insertAvoidanceArea } = useInsertAvoidanceArea(); + // getRoute([[-97.733785,30.282635],[-97.733731,30.285145]], [[[-97.734269,30.284691],[-97.733454,30.284654],[-97.733669,30.283366],[-97.734708,30.283932],[-97.734269,30.284691]]]); const testGooglePlaces = async () => { console.log("Testing Google Places..."); @@ -71,6 +73,7 @@ export default function Home() { testGooglePlaces(); }, []); + const getMapIcon = useCallback( (poiType: any, metadata: any) => { switch (poiType) { @@ -125,6 +128,7 @@ export default function Home() { // Handle avoidance area click const handleAvoidanceAreaPress = (polygonId: string) => { + if (polygonId[0] == 'C') return; // construction areas if (isReportMode) return; avoidanceAreaBottomSheetRef.current?.present({ id: polygonId }); }; @@ -133,8 +137,6 @@ export default function Home() { const handlePOIPress = (poi: any) => { if (isReportMode) return; poiBottomSheetRef.current?.present({ poi }); - if (polygonId[0] == 'C') return; // construction areas - bottomSheetRef.current?.present({ id: polygonId }); }; const polygons = useMemo( @@ -184,8 +186,8 @@ export default function Home() { const markers = useMemo( () => { if (POIs && !isReportMode) { - console.log("Pois"); - console.log(POIs); + // console.log("Pois"); + // console.log(POIs); } const poiMarkers = !isReportMode && zoomLevel >= MIN_ZOOM_FOR_POIS @@ -199,7 +201,7 @@ export default function Home() { icon: getMapIcon(poi.poi_type, poi.metadata) || undefined, }; // 📝 ADDED CONSOLE LOGGING HERE - console.log(`POI Marker for ID ${marker.id}:`, marker); + // console.log(`POI Marker for ID ${marker.id}:`, marker); return marker; }) : []; diff --git a/utils/api-client.ts b/utils/api-client.ts index e2c0486..e04a110 100644 --- a/utils/api-client.ts +++ b/utils/api-client.ts @@ -50,7 +50,9 @@ class ApiClient { async getRoute(waypoints: any[], avoiding: any[]) { const FEATURE_URL = "https://api.openrouteservice.org/v2/directions/wheelchair"; - const TOKEN = process.env.OPENROUTE_API_KEY || ""; + const TOKEN = process.env.EXPO_PUBLIC_OPENROUTE_KEY || ""; + + // multipoly format reference: https://en.wikipedia.org/wiki/GeoJSON let res = await fetch( FEATURE_URL, @@ -62,11 +64,11 @@ class ApiClient { 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify( - {"coordinates":JSON.stringify(waypoints), + {"coordinates":waypoints, "options":{ "avoid_polygons":{ "type":"MultiPolygon", - "coordinates":JSON.stringify(avoiding) + "coordinates":avoiding.map((poly) => [poly]) } } } @@ -74,8 +76,10 @@ class ApiClient { } ); + console.log(res); if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`); const json = await res.json(); + console.log(json); return json; } From f61617082c4d9d1dacf01f72f972d18b41e42087 Mon Sep 17 00:00:00 2001 From: JAlan Date: Thu, 5 Mar 2026 18:27:07 -0600 Subject: [PATCH 6/9] add working routing code to Get Directions --- app/(tabs)/index.tsx | 28 ++++++++++++++++++++++++++-- components/POIBottomSheet.tsx | 11 +++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 76659d7..68d151e 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -4,7 +4,7 @@ import * as turf from "@turf/turf"; import { Stack } from "expo-router"; import { useCallback, useMemo, useRef, useState, useEffect } from "react"; import { View } from "react-native"; -import MapView, { Polygon, Marker, LatLng } from "react-native-maps"; +import MapView, { Polygon, Marker, LatLng, Polyline } from "react-native-maps"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import Toast from "react-native-toast-message"; @@ -45,6 +45,7 @@ export default function Home() { const [clickedPoint, setClickedPoint] = useState(null); const [reportStep, setReportStep] = useState(0); const [zoomLevel, setZoomLevel] = useState(15); + const [Route, setRoute] = useState([]); // Minimum zoom level to show POIs (higher = more zoomed in) const MIN_ZOOM_FOR_POIS = 16; @@ -230,6 +231,18 @@ export default function Home() { [POIs, aaPointsReport, mapIcons, getMapIcon, isReportMode, clickedPoint, zoomLevel], ); + + const getDirections = (target: any[]) => { + const UT_TOWER = [-97.73942, 30.28614]; + // let res = getRoute([UT_TOWER, target], + // polygons.map((poly) => [poly.coordinates.map((coord: any) => [coord.longitude, coord.latitude])]) + // ) + console.log(polygons) + + // console.log(res); + } + + const handleSelectLocation = async (location: { id: string; name: string; @@ -306,7 +319,7 @@ export default function Home() { {/* POI Bottom Sheet */} - + {/* Location Details Bottom Sheet */} @@ -343,6 +356,17 @@ export default function Home() { /> ))} + {/* Render Polylines */} + {(Route.length !== 0) && ( + + )} + {/* Render markers */} {markers.map((marker) => ( ; allPOIs: any[]; + getDirections: (target: any[]) => void; } interface POIContentProps { poi: any; allPOIs: any[]; + getDirections: (target: any[]) => void; } -const POIContent = ({ poi, allPOIs }: POIContentProps) => { +const POIContent = ({ poi, allPOIs, getDirections }: POIContentProps) => { const mapIcons = useMapIcons(); const [selectedEntrance, setSelectedEntrance] = useState(""); const [hours, setHours] = useState("Loading..."); @@ -294,7 +296,8 @@ const POIContent = ({ poi, allPOIs }: POIContentProps) => { backgroundColor: "#BF5700", height: 41.32, paddingHorizontal: 8, borderRadius: 9.31, alignItems: "center", flexDirection: "row", justifyContent: "center", marginBottom: 8, - }}> + }} + onPress={() => getDirections(poi.location_geojson.coordinates)}> Get Directions @@ -304,7 +307,7 @@ const POIContent = ({ poi, allPOIs }: POIContentProps) => { ); }; -const POIBottomSheet = ({ ref, allPOIs }: POIBottomSheetProps) => { +const POIBottomSheet = ({ ref, allPOIs, getDirections }: POIBottomSheetProps) => { const bottomTabBarHeight = useBottomTabBarHeight(); return ( @@ -319,7 +322,7 @@ const POIBottomSheet = ({ ref, allPOIs }: POIBottomSheetProps) => { > {({ data }) => { if (!data?.poi) return null; - return ; + return ; }} ); From e47779a4b60fadc3f0e57b50a60fa78b51bd3878 Mon Sep 17 00:00:00 2001 From: JAlan Date: Sun, 8 Mar 2026 15:35:50 -0500 Subject: [PATCH 7/9] add working routing --- app/(tabs)/index.tsx | 31 ++++++++++++++++++-------- utils/api-hooks.ts | 10 +++------ utils/decode_polyline.ts | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 utils/decode_polyline.ts diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 68d151e..6751096 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -28,6 +28,7 @@ import { type LocationDetailsBottomSheetRef, } from "~/components/LocationDetailsBottomSheet"; import { searchPlaces, getPlaceDetails } from "~/utils/googlePlaces"; +import decode from "~/utils/decode_polyline"; export default function Home() { // hooks @@ -45,7 +46,7 @@ export default function Home() { const [clickedPoint, setClickedPoint] = useState(null); const [reportStep, setReportStep] = useState(0); const [zoomLevel, setZoomLevel] = useState(15); - const [Route, setRoute] = useState([]); + const [Route, setRoute] = useState(null); // Minimum zoom level to show POIs (higher = more zoomed in) const MIN_ZOOM_FOR_POIS = 16; @@ -234,10 +235,22 @@ export default function Home() { const getDirections = (target: any[]) => { const UT_TOWER = [-97.73942, 30.28614]; - // let res = getRoute([UT_TOWER, target], - // polygons.map((poly) => [poly.coordinates.map((coord: any) => [coord.longitude, coord.latitude])]) - // ) - console.log(polygons) + let res = getRoute([UT_TOWER, target.slice(0, 2)], + polygons.map((poly) => poly.coordinates.map((coord: any) => [coord.longitude, coord.latitude])) + ) + + // console.log(decode({value: res.routes.geometry})); + res.then((result) => { + // console.log(decode(result.routes[0].geometry)); + setRoute(decode(result.routes[0].geometry).map( + (coord) => ({ + latitude: coord[1], + longitude: coord[0] + }) + )); + }); + // console.log(target.slice(0, 2)); + // console.log(polygons.map((poly) => poly.coordinates.map((coord: any) => [coord.longitude, coord.latitude]))) // console.log(res); } @@ -357,13 +370,13 @@ export default function Home() { ))} {/* Render Polylines */} - {(Route.length !== 0) && ( + {(Route !== null) && ( )} diff --git a/utils/api-hooks.ts b/utils/api-hooks.ts index 615c053..2e2fb73 100644 --- a/utils/api-hooks.ts +++ b/utils/api-hooks.ts @@ -1,6 +1,6 @@ // TanStack Query hooks for the Hono backend import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"; -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient, UseQueryResult } from "@tanstack/react-query"; import { Polygon } from "geojson"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import Toast from "react-native-toast-message"; @@ -15,17 +15,13 @@ export const queryKeys = { avoidanceArea: (id: string) => ["avoidanceArea", id] as const, avoidanceAreaReports: (id: string) => ["avoidanceAreaReports", id] as const, profile: (id: number) => ["profile", id] as const, - routes: ["routes"] as const, }; // get route between 2+ points -export function getRoute(waypoints: any[], avoiding: any[]) { +export async function getRoute(waypoints: any[], avoiding: any[]) { // TODO implement caching later - return useQuery({ - queryKey: queryKeys.routes, - queryFn: () => apiClient.getRoute(waypoints, avoiding), - }); + return await apiClient.getRoute(waypoints, avoiding) } diff --git a/utils/decode_polyline.ts b/utils/decode_polyline.ts new file mode 100644 index 0000000..9a821aa --- /dev/null +++ b/utils/decode_polyline.ts @@ -0,0 +1,48 @@ +// Source - https://stackoverflow.com/q/40694161 +// Posted by Neil Simpson +// Retrieved 2026-03-08, License - CC BY-SA 3.0 + +export default function decode( value: any ) { + + var values = decode.integers( value ) + var points = [] + + for( var i = 0; i < values.length; i += 2 ) { + points.push([ + ( values[ i + 1 ] += ( values[ i - 1 ] || 0 ) ) / 1e5, + ( values[ i + 0 ] += ( values[ i - 2 ] || 0 ) ) / 1e5, + ]) + } + + return points + +} + +decode.sign = function( value: any ) { + return value & 1 ? ~( value >>> 1 ) : ( value >>> 1 ) +} + +decode.integers = function( value: any ) { + + var values = [] + var byte = 0 + var current = 0 + var bits = 0 + + for( var i = 0; i < value.length; i++ ) { + + byte = value.charCodeAt( i ) - 63 + current = current | (( byte & 0x1F ) << bits ) + bits = bits + 5 + + if( byte < 0x20 ) { + values.push( decode.sign( current ) ) + current = 0 + bits = 0 + } + + } + + return values + +} From 4630e9d1516b6ebcb4582ac50333831c9a11fc28 Mon Sep 17 00:00:00 2001 From: JAlan Date: Tue, 10 Mar 2026 13:07:19 -0500 Subject: [PATCH 8/9] add preliminary routing ui --- components/RouteBottomSheet.tsx | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 components/RouteBottomSheet.tsx diff --git a/components/RouteBottomSheet.tsx b/components/RouteBottomSheet.tsx new file mode 100644 index 0000000..6dc9796 --- /dev/null +++ b/components/RouteBottomSheet.tsx @@ -0,0 +1,49 @@ +import { BottomSheetModal } from "@gorhom/bottom-sheet"; +import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"; +import { ForwardedRef } from "react"; + +import colors from "~/types/colors"; + + +interface RouteContentProps { + route: any; +} + +const RouteContent = ({ route } : RouteContentProps) => { + return ( + <> + ) +} + + + +interface RouteBottomSheetProps { + ref: ForwardedRef; +} + +interface RouteData { + route: any; +} + +const RouteBottomSheet = ({ ref }: RouteBottomSheetProps) => { + const bottomTabBarHeight = useBottomTabBarHeight(); + + return ( + + ref={ref} + bottomInset={bottomTabBarHeight} + backgroundStyle={{ borderRadius: 32 }} + enableDynamicSizing={false} + snapPoints={["50%"]} + handleIndicatorStyle={{ backgroundColor: colors.theme.majorgridline, width: 80 }} + enableContentPanningGesture={false} + > + {({ data }) => { + if (!data?.route) return null; + return ; + }} + + ); +}; + +export default RouteBottomSheet; \ No newline at end of file From 8f23af97659baf2ac3014e68745677a1302e7949 Mon Sep 17 00:00:00 2001 From: JAlan Date: Sun, 29 Mar 2026 15:56:30 -0500 Subject: [PATCH 9/9] start ui --- app/(tabs)/index.tsx | 3 +++ components/{RouteBottomSheet.tsx => RouteOverlaySheet.tsx} | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) rename components/{RouteBottomSheet.tsx => RouteOverlaySheet.tsx} (88%) diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 6751096..03465fc 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -334,6 +334,9 @@ export default function Home() { {/* POI Bottom Sheet */} + {/* Routing Mode Overlay */} + {/* */} + {/* Location Details Bottom Sheet */} diff --git a/components/RouteBottomSheet.tsx b/components/RouteOverlaySheet.tsx similarity index 88% rename from components/RouteBottomSheet.tsx rename to components/RouteOverlaySheet.tsx index 6dc9796..ce12c13 100644 --- a/components/RouteBottomSheet.tsx +++ b/components/RouteOverlaySheet.tsx @@ -17,7 +17,7 @@ const RouteContent = ({ route } : RouteContentProps) => { -interface RouteBottomSheetProps { +interface RouteOverlaySheetProps { ref: ForwardedRef; } @@ -25,7 +25,7 @@ interface RouteData { route: any; } -const RouteBottomSheet = ({ ref }: RouteBottomSheetProps) => { +const RouteOverlaySheet = ({ ref }: RouteOverlaySheetProps) => { const bottomTabBarHeight = useBottomTabBarHeight(); return ( @@ -46,4 +46,4 @@ const RouteBottomSheet = ({ ref }: RouteBottomSheetProps) => { ); }; -export default RouteBottomSheet; \ No newline at end of file +export default RouteOverlaySheet; \ No newline at end of file