Skip to content

Commit

Permalink
added pan to marker button
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmistica0 committed Nov 16, 2023
1 parent c3cc310 commit c2ffc3a
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 117 deletions.
6 changes: 3 additions & 3 deletions src/components/api/geocode-search.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Position } from "../context/MapContext";
import { Coordinates } from "../context/MapContext.types";

const buildQuery = (query: string, location: Position) => {
const buildQuery = (query: string, location: Coordinates) => {
const base_url = "https://api.mapbox.com/geocoding/v5/mapbox.places/"
const with_bias = `${base_url}${query}.json?country=US&proximity=${location.lng},${location.lat}&access_token=${process.env.NEXT_PUBLIC_MAPBOX_API_KEY}`
const without_bias = `${base_url}${query}.json?country=US&access_token=${process.env.NEXT_PUBLIC_MAPBOX_API_KEY}`
return location.lat !== 0 && location.lng !==0 ? with_bias : without_bias
};

const getResults = async function(query: string, location: Position) {
const getResults = async function(query: string, location: Coordinates) {
if (query === "") {
return {
response: {
Expand Down
121 changes: 76 additions & 45 deletions src/components/context/MapContext.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,62 @@
"use client"

import { useTheme } from "next-themes";
import { createContext, useContext, useEffect, useState } from "react";
import { createContext, useContext, useEffect, useRef, useState } from "react";
import { MapContextType, MapTypes, Coordinates, CatchData } from "./MapContext.types";
import { MapRef } from "react-map-gl";
import randomLocation from "random-location";
import { v4 as uuidv4 } from 'uuid';
import fishImage from '@/assets/fish.jpg'
import fishIcon from '@/assets/fish-icon.png'

enum MapTypes {
DEFAULT = 'mapbox://styles/mapbox/streets-v9',
DARK = 'mapbox://styles/johnmistica0/clousxn6q00mk01ntbw5n323k',
LIGHT = 'mapbox://styles/johnmistica0/clout1ex200me01pef84yfwie',
TERRAIN = 'mapbox://styles/johnmistica0/clout3ozt00mn01qj3xqs3p7h',
SATELLITE = 'mapbox://styles/johnmistica0/clout47fo00ml01nth9h736up'
}

export interface Position {
lat: number;
lng: number;
}
export const getMapStyle = (value: string, theme: string | undefined) => {
if (value === 'map') {
if (theme === 'dark') {
return MapTypes.DARK
} else if (theme === 'light') {
return MapTypes.LIGHT

export interface MapContextType {
position: Position;
setPosition: (newPosition: Position) => void;
currentLocation: Position;
setCurrentLocation: (newCurrentLocation: Position) => void;
mapStyle: string;
setThemeMapStyle: (newThemeMapStyle: string) => void;
} else if (theme === 'system') {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return MapTypes.DARK
} else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
return MapTypes.LIGHT
}
}
} else if (value === 'satellite') {
return MapTypes.SATELLITE
} else if (value === 'terrain') {
return MapTypes.TERRAIN
}
return MapTypes.DEFAULT
}

const MapContext = createContext<MapContextType | null>(null);

export function MapContextWrapper({ children }: any) {
const { theme } = useTheme()
const [position, setPosition] = useState<Position>({ lat: 30.425803, lng: -97.934957 })
const [currentLocation, setCurrentLocation] = useState<Position>({ lat: 0, lng: 0 })
const [mapPosition, setMapPosition] = useState<Coordinates>({ lat: 30.425803, lng: -97.934957 })
const [userLocation, setUserLocation] = useState<Coordinates>({ lat: 0, lng: 0 })
const [markerData, setMarkerData] = useState<CatchData[]>([])
const [mapStyle, setMapStyle] = useState<string>(MapTypes.DEFAULT)
const mapRef = useRef<MapRef>()

const setThemeMapStyle = (value: string) => {
if (value === 'map') {
if (theme === 'dark') {
setMapStyle(MapTypes.DARK)
} else if (theme === 'light') {
setMapStyle(MapTypes.LIGHT)

} else if (theme === 'system') {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
setMapStyle(MapTypes.DARK)
} else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
setMapStyle(MapTypes.LIGHT)
}
}
} else if (value === 'satellite') {
setMapStyle(MapTypes.SATELLITE)
} else if (value === 'terrain') {
setMapStyle(MapTypes.TERRAIN)
}
}
const getRandomCoordinate = (lat: number, lng: number) => randomLocation.randomCirclePoint({ latitude: lat, longitude: lng }, 2500)

useEffect(() => {
setThemeMapStyle('map')
setMapStyle(getMapStyle('map', theme))
}, [theme])

useEffect(() => {
mapRef?.current?.flyTo({ center: [mapPosition.lng, mapPosition.lat] })
}, [mapPosition])

useEffect(() => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords
setCurrentLocation({ lat: latitude, lng: longitude })
setUserLocation({ lat: latitude, lng: longitude })
},
(err) => {
console.error(err)
Expand All @@ -72,8 +65,46 @@ export function MapContextWrapper({ children }: any) {
}
}, []);

useEffect(() => {
if (userLocation.lat !== 0 && userLocation.lng !== 0) {
setMarkerData(Array.from({ length: 20 }, () => {
const { longitude, latitude } = getRandomCoordinate(userLocation.lat, userLocation.lng)
return {
id: uuidv4(),
coordinates: { lng: longitude, lat: latitude },
location: "Lake Travis, TX",
species: "Largemouth Bass",
image: fishImage,
icon: fishIcon,
lure: "Crankbait",
weight: "3 lb 5oz",
username: "john_mistica",
date: "Dec 2, 2021"
} as CatchData
}))
mapRef?.current?.setCenter([userLocation.lng, userLocation.lat])
mapRef?.current?.setZoom(15)
} else {
setMarkerData(Array.from({ length: 20 }, () => {
const { longitude, latitude } = getRandomCoordinate(mapPosition.lat, mapPosition.lng)
return {
id: uuidv4(),
coordinates: { lng: longitude, lat: latitude },
location: "Lake Travis, TX",
species: "Largemouth Bass",
image: fishImage,
icon: fishIcon,
lure: "Crankbait",
weight: "3 Ib 5oz",
username: "john_mistica",
date: "Dec 2, 2021"
} as CatchData
}))
}
}, [userLocation]);

return (
<MapContext.Provider value={{ position, setPosition, currentLocation, setCurrentLocation, mapStyle, setThemeMapStyle } as MapContextType}>
<MapContext.Provider value={{ mapPosition, setMapPosition, userLocation, setUserLocation, mapStyle, setMapStyle, markerData, setMarkerData, mapRef } as MapContextType}>
{children}
</MapContext.Provider>
);
Expand Down
41 changes: 41 additions & 0 deletions src/components/context/MapContext.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { StaticImageData } from "next/image";
import { RefObject } from "react";
import { MapRef } from "react-map-gl";

export enum MapTypes {
DEFAULT = 'mapbox://styles/mapbox/streets-v9',
DARK = 'mapbox://styles/johnmistica0/clousxn6q00mk01ntbw5n323k',
LIGHT = 'mapbox://styles/johnmistica0/clout1ex200me01pef84yfwie',
TERRAIN = 'mapbox://styles/johnmistica0/clout3ozt00mn01qj3xqs3p7h',
SATELLITE = 'mapbox://styles/johnmistica0/clout47fo00ml01nth9h736up'
}

export interface Coordinates {
lat: number;
lng: number;
}

export interface MapContextType {
mapPosition: Coordinates;
setMapPosition: (newMapPosition: Coordinates) => void;
userLocation: Coordinates;
setUserLocation: (newCurrentLocation: Coordinates) => void;
mapStyle: string;
setMapStyle: (newMapStyle: string) => void;
markerData: CatchData[];
setMarkerData: (newMarkerData: CatchData[]) => void;
mapRef: RefObject<MapRef>;
}

export interface CatchData {
id: string;
coordinates: Coordinates;
location: string;
species: string;
image: StaticImageData;
icon: StaticImageData;
lure: string;
weight: string;
username: string;
date: string;
}
43 changes: 27 additions & 16 deletions src/components/explore/CatchCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@ import {
CardHeader,
} from "@/components/ui/card"
import { CalendarDays } from "lucide-react"
import { TbWeight } from "react-icons/tb"
import { TbRoute, TbWeight, TbMapPin2 } from "react-icons/tb"
import { GiFishingLure } from "react-icons/gi"
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"
import fishImage from '@/assets/fish.jpg'
import fishIcon from '@/assets/fish-icon.png'
import Image from "next/image"
import { Button } from "../ui/button"
import { FaSearchLocation } from "react-icons/fa"
import { CatchData } from "../context/MapContext.types"
import { useMapContext } from "../context/MapContext"

interface CatchCardProps {
data: CatchData
}

export default function CatchCard({ data }: CatchCardProps) {
const { mapRef } = useMapContext()

const gotoMarkerLocation = () => {
mapRef?.current?.flyTo({ center: [data.coordinates.lng, data.coordinates.lat], zoom: 18 })
}

export default function CatchCard() {
return (
<Card className="w-full mb-3">
<CardHeader>
Expand All @@ -26,39 +35,41 @@ export default function CatchCard() {
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<h4 className="text-sm font-semibold">john_mistica</h4>
<h2 className="text-xs">Lake Travis, TX</h2>
<h4 className="text-sm font-semibold">{data.username}</h4>
<h2 className="text-xs">{data.location}</h2>
</div>
</div>
<Button variant="ghost" size="icon">
<FaSearchLocation className="w-5 h-5" />
</Button>
<div>
<Button variant="ghost_secondary" size="icon" onClick={gotoMarkerLocation}>
<TbMapPin2 className="w-5 h-5" />
</Button>
</div>
</div>
</CardHeader>
<CardContent>
<div className="space-y-3">
<Image src={fishImage} alt='fish' className="rounded-md" priority={true} />
<Image src={data.image} alt='fish' className="rounded-md" priority={true} />
<span className="flex flex-row justify-between items-center">
<h1 className="text-lg font-semibold">Largemouth Bass</h1>
<Image src={fishIcon} alt='fish' className="h-auto w-[50px]" priority={false}/>
<h1 className="text-lg font-semibold">{data.species}</h1>
<Image src={data.icon} alt='fish' className="h-auto w-[50px]" priority={false} />
</span>
<div className="flex flex-row justify-between w-full">
<div className="flex items-center">
<GiFishingLure className="mr-2 h-4 w-4 opacity-70" />
<span className="text-xs text-muted-foreground">
Crankbait
{data.lure}
</span>
</div>
<div className="flex items-center">
<TbWeight className="mr-2 h-4 w-4 opacity-70" />
<span className="text-xs text-muted-foreground">
3 Ib 5 oz
{data.weight}
</span>
</div>
<div className="flex items-center">
<CalendarDays className="mr-2 h-4 w-4 opacity-70" />
<span className="text-xs text-muted-foreground">
Dec 2, 2021
{data.date}
</span>
</div>
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/components/explore/CatchFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import { ImShrink2 } from "react-icons/im";
import { BiArrowToLeft } from "react-icons/bi";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
import { cn } from "@/lib/utils";
import { useMapContext } from "../context/MapContext";
import { CatchData } from "../context/MapContext.types";

export default function CatchFeed() {
const { markerData } = useMapContext()

return (
<div className="flex flex-col p-5 space-y-3 h-full items-center">
Expand Down Expand Up @@ -55,7 +58,9 @@ export default function CatchFeed() {
</div>
<span className="flex flex-grow h-96">
<ScrollArea className="rounded-md h-full w-full">
{Array.from({ length: 8 }, (_, index) => <CatchCard key={index} />)}
{markerData.map((data: CatchData) => {
return <CatchCard key={data.id} data={data}/>
})}
</ScrollArea>
</span>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/explore/CatchMarker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { useState } from "react";
export default function CatchMarker({ location }: any) {
const [focus, setFocus] = useState(false)
return (
<span onMouseEnter={() => setFocus(true)} onMouseLeave={() => {setTimeout(() => {setFocus(false)}, 500)}}>
<Marker longitude={location.lng} latitude={location.lat} anchor="center" style={{ cursor: 'default', zIndex: `${focus ? '100' : '0'}` }}>
<CatchMarkerCard open={open}>
<span>
<Marker longitude={location.lng} latitude={location.lat} anchor="center" style={{ cursor: 'default', zIndex: `${focus ? '1' : '0'}` }}>
<CatchMarkerCard open={open} setFocus={setFocus}>
<span className="relative flex h-4 w-4">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full h-5 w-5 bg-red-500"></span>
Expand Down
4 changes: 2 additions & 2 deletions src/components/explore/CatchMarkerCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { GiFishingLure } from "react-icons/gi"
import Image from "next/image"
import fishIcon from '@/assets/fish-icon.png'

export default function CatcherMarkerCard({ children }: any) {
export default function CatcherMarkerCard({ children, setFocus }: any) {

return (
<HoverCard>
<HoverCard onOpenChange={setFocus}>
<HoverCardTrigger asChild>
{children}
</HoverCardTrigger>
Expand Down
Loading

0 comments on commit c2ffc3a

Please sign in to comment.