11"use client" ;
22
33import { Button } from "@/components/ui/button" ;
4- import { Locate , Plus , Minus , ArrowUpCircle } from "lucide-react" ;
4+ import {
5+ Locate ,
6+ Plus ,
7+ Minus ,
8+ ArrowUpCircle ,
9+ EyeOff ,
10+ ImageIcon ,
11+ SatelliteIcon ,
12+ MapIcon ,
13+ } from "lucide-react" ;
514import mapboxgl , { LngLatLike } from "mapbox-gl" ;
615import React , { useRef , useEffect , useState } from "react" ;
716import "mapbox-gl/dist/mapbox-gl.css" ;
@@ -10,6 +19,7 @@ import MapboxDraw from "@mapbox/mapbox-gl-draw";
1019import { inspect } from "@/api/inspect" ;
1120import { toast } from "sonner" ;
1221import { summon } from "@/api/summon" ;
22+ import { SummonDialog } from "@/components/summon-dialog" ;
1323
1424const INITIAL_CENTER : { lng : number ; lat : number } = {
1525 lng : - 88.23556018270287 ,
@@ -27,29 +37,37 @@ export function MapView() {
2737 lat : number ;
2838 } | null > ( null ) ;
2939 const [ center , setCenter ] = useState < { lng : number ; lat : number } > (
30- INITIAL_CENTER
40+ INITIAL_CENTER ,
3141 ) ;
3242 const [ boundingBox , setBoundingBox ] = useState < LngLatLike [ ] > ( [ ] ) ;
3343 const [ zoom , setZoom ] = useState ( INITIAL_ZOOM ) ;
3444 const [ pitch , _ ] = useState ( INITIAL_PITCH ) ;
35-
45+ const [ satelliteMode , setSatelliteMode ] = useState ( false ) ;
3646 const [ isSummoning , setIsSummoning ] = useState ( false ) ;
3747
48+ const streetStyle = "mapbox://styles/mapbox/standard" ;
49+ const satelliteStyle = "mapbox://styles/mapbox/satellite-v9" ;
3850 const mapboxToken = process . env . NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN ;
3951
4052 const handleSummon = async ( ) => {
41- toast . info ( `Summoning to ${ userLocation ?. lat } ${ userLocation ?. lng } ` )
53+ toast . info (
54+ `Summon to ${ userLocation ?. lat } ${ userLocation ?. lng } was placed into queue.` ,
55+ {
56+ description :
57+ "Summoning will begin shortly (as soon as GEM will pick up the event)" ,
58+ } ,
59+ ) ;
4260 setIsSummoning ( true ) ;
4361 const coords = userLocation ? userLocation : center ;
4462
45- const summonReq = await summon ( coords . lng , coords . lat ) ;
63+ const summonReq = await summon ( coords . lng , coords . lat ) ;
4664
47- if ( ! summonReq . ok ) {
48- const errorData = await summonReq . json ( ) ;
49- console . error ( "Summon error:" , errorData . detail || errorData ) ;
50- setIsSummoning ( false ) ;
51- return ;
52- }
65+ if ( ! summonReq . ok ) {
66+ const errorData = await summonReq . json ( ) ;
67+ console . error ( "Summon error:" , errorData . detail || errorData ) ;
68+ setIsSummoning ( false ) ;
69+ return ;
70+ }
5371 } ;
5472
5573 const handleZoomIn = ( ) => {
@@ -59,6 +77,13 @@ export function MapView() {
5977 mapRef . current ?. zoomOut ( ) ;
6078 } ;
6179
80+ const toggleStyle = ( ) => {
81+ if ( ! mapRef . current ) return ;
82+ const newMode = ! satelliteMode ;
83+ setSatelliteMode ( newMode ) ;
84+ mapRef . current . setStyle ( newMode ? satelliteStyle : streetStyle ) ;
85+ } ;
86+
6287 useEffect ( ( ) => {
6388 if ( mapboxToken ) {
6489 mapboxgl . accessToken = mapboxToken ;
@@ -73,8 +98,8 @@ export function MapView() {
7398 // style: "mapbox://styles/mapbox/satellite-v9",
7499 maxBounds : [
75100 [ - 88.2368 , 40.0925 ] , // Southwest coordinates
76- [ - 88.2346 , 40.0935 ] // Northeast coordinates
77- ]
101+ [ - 88.2346 , 40.0935 ] , // Northeast coordinates
102+ ] ,
78103 } ) ;
79104
80105 const draw = new MapboxDraw ( {
@@ -131,17 +156,17 @@ export function MapView() {
131156 }
132157
133158 const marker = new mapboxgl . Marker ( {
134- draggable : true
159+ draggable : true ,
135160 } )
136- . setLngLat ( INITIAL_CENTER )
137- . addTo ( mapRef . current ) ;
161+ . setLngLat ( INITIAL_CENTER )
162+ . addTo ( mapRef . current ) ;
138163
139164 function onDragEnd ( ) {
140165 const lngLat = marker . getLngLat ( ) ;
141- setUserLocation ( { lat : lngLat . lat , lng : lngLat . lng } )
166+ setUserLocation ( { lat : lngLat . lat , lng : lngLat . lng } ) ;
142167 }
143168
144- marker . on ( ' dragend' , onDragEnd ) ;
169+ marker . on ( " dragend" , onDragEnd ) ;
145170
146171 mapRef . current . on ( "move" , ( ) => {
147172 // get the current center coordinates and zoom level from the map
@@ -166,58 +191,73 @@ export function MapView() {
166191
167192 return (
168193 < div className = "relative w-full h-full bg-neutral-800 flex items-center justify-center" >
194+ < SummonDialog />
169195 < div id = "map-container" ref = { mapContainerRef } />
170196 < div className = "absolute top-6 left-6 bg-neutral-900/50 p-2 rounded-sm md:text-base text-xs md:max-w-none max-w-[200px]" >
171197 Longitude: { center . lng . toFixed ( 4 ) } | Latitude: { center . lat . toFixed ( 4 ) } |
172198 Zoom: { zoom . toFixed ( 2 ) }
173199 </ div >
174200
175201 { /* Map controls */ }
176- < div className = "absolute bottom-6 right-6 flex flex-col gap-2" >
177- < Button
178- variant = "secondary"
179- size = "icon"
180- className = "rounded-full bg-neutral-900 hover:bg-neutral-800"
181- onClick = { handleZoomIn }
182- >
183- < Plus
184- className = "h-5 w-5"
185- onClick = { ( ) => setZoom ( Math . min ( zoom + 1 , 20 ) ) }
186- />
187- </ Button >
188- < Button
189- variant = "secondary"
190- size = "icon"
191- className = "rounded-full bg-neutral-900 hover:bg-neutral-800"
192- onClick = { handleZoomOut }
193- >
194- < Minus
195- className = "h-5 w-5"
196- onClick = { ( ) => setZoom ( Math . max ( zoom - 1 , 10 ) ) }
197- />
198- </ Button >
199- </ div >
200-
201- < div className = "absolute bottom-6 left-6 flex gap-2" >
202- < Button
203- variant = "secondary"
204- className = "rounded-
202+ < div className = "absolute bottom-6 flex sm:flex-row flex-col-reverse gap-4 justify-between w-full px-6 sm:items-end" >
203+ < div className = "flex flex-col sm:flex-row gap-2" >
204+ < Button
205+ variant = "secondary"
206+ className = "rounded-
205207 full bg-neutral-900 hover:bg-neutral-800"
206- onClick = { handleSummon }
207- disabled = { isSummoning || ! userLocation }
208- >
209- < Locate className = "h-5 w-5 mr-2" />
210- { isSummoning ? "Summoning..." : " Summon My Car" }
211- </ Button >
212- < Button
213- variant = "secondary"
214- className = "rounded-
208+ onClick = { handleSummon }
209+ disabled = { ! userLocation }
210+ >
211+ < Locate className = "h-5 w-5 mr-2" />
212+ Summon My Car
213+ </ Button >
214+ < Button
215+ variant = "secondary"
216+ className = "rounded-
215217 full bg-neutral-900 hover:bg-neutral-800"
216- onClick = { ( ) => inspect ( boundingBox ) }
217- >
218- < ArrowUpCircle className = "h-5 w-5 mr-2" />
219- < span > Inspect Region</ span >
220- </ Button >
218+ onClick = { ( ) => inspect ( boundingBox ) }
219+ >
220+ < ArrowUpCircle className = "h-5 w-5 mr-2" />
221+ < span > Inspect Region</ span >
222+ </ Button >
223+ </ div >
224+
225+ < div className = "flex sm:flex-col gap-2" >
226+ < Button
227+ variant = "secondary"
228+ size = "icon"
229+ className = "rounded-full bg-neutral-900 hover:bg-neutral-800"
230+ onClick = { toggleStyle }
231+ >
232+ { satelliteMode ? (
233+ < SatelliteIcon className = "h-5 w-5" />
234+ ) : (
235+ < MapIcon className = "h-5 w-5" />
236+ ) }
237+ </ Button >
238+ < Button
239+ variant = "secondary"
240+ size = "icon"
241+ className = "rounded-full bg-neutral-900 hover:bg-neutral-800"
242+ onClick = { handleZoomIn }
243+ >
244+ < Plus
245+ className = "h-5 w-5"
246+ onClick = { ( ) => setZoom ( Math . min ( zoom + 1 , 20 ) ) }
247+ />
248+ </ Button >
249+ < Button
250+ variant = "secondary"
251+ size = "icon"
252+ className = "rounded-full bg-neutral-900 hover:bg-neutral-800"
253+ onClick = { handleZoomOut }
254+ >
255+ < Minus
256+ className = "h-5 w-5"
257+ onClick = { ( ) => setZoom ( Math . max ( zoom - 1 , 10 ) ) }
258+ />
259+ </ Button >
260+ </ div >
221261 </ div >
222262 </ div >
223263 ) ;
0 commit comments