Skip to content

Commit ffaeecb

Browse files
Installed map featuring in bookshop page
1 parent 613c3f3 commit ffaeecb

File tree

8 files changed

+296
-728
lines changed

8 files changed

+296
-728
lines changed

package-lock.json

Lines changed: 204 additions & 727 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"i18next-resources-to-backend": "^1.2.1",
3030
"mongodb": "^6.9.0",
3131
"next": "^14.2.15",
32+
"ol": "^10.2.0",
3233
"react": "18.3.1",
3334
"react-cookie": "^7.2.2",
3435
"react-dom": "18.3.1",
@@ -72,4 +73,4 @@
7273
"minimumChangeThreshold": 0,
7374
"showDetails": true
7475
}
75-
}
76+
}

src/api/map/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { MapCoordinates, MapResponse } from 'src/types/map'
2+
3+
4+
export const getMapCoordinates = async (address: string): Promise<MapCoordinates> => {
5+
const response = await fetch(
6+
`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(address)}&format=json`
7+
)
8+
const data: MapResponse[] = await response.json()
9+
console.log('data', data)
10+
11+
return [parseFloat(data[0].lon), parseFloat(data[0].lat)]
12+
}

src/app/[locale]/bookshops/[bookshopId]/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { isImageSecure } from 'helpers/utils/isImageSecure'
77
import type { Metadata } from 'next'
88
import { notFound } from 'next/navigation'
99
import { getBookshop } from 'src/api/bookshop'
10+
import { getMapCoordinates } from 'src/api/map'
11+
import { GeoMap } from 'src/components/geo-map'
1012
import { SafeImage } from 'src/components/safe-image'
1113
import type { ComponentParams } from 'types/component'
1214
import type { I18nLocale } from 'types/i18n'
@@ -53,6 +55,8 @@ export default async function BookshopPage(
5355
notFound()
5456
}
5557

58+
const bookshopCoordinates = await getMapCoordinates(bookshop.address)
59+
5660
let bookshopMeta: BookshopMeta
5761
try {
5862
bookshopMeta = bookshop.site ? await fetchedMeta(bookshop.site) : null
@@ -76,6 +80,10 @@ export default async function BookshopPage(
7680
</a>
7781
</section>
7882

83+
<section className={styles.uaplace_section}>
84+
<GeoMap address={bookshop.address} coordinates={bookshopCoordinates}/>
85+
</section>
86+
7987
{bookshop.site && (
8088
<section className={styles.uabookshop_section}>
8189
<h4>{t('form.website')}</h4>

src/components/geo-map/geo-map.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use client'
2+
3+
import { Map, View } from 'ol'
4+
import { Tile as TileLayer } from 'ol/layer'
5+
import 'ol/ol.css'
6+
import { fromLonLat } from 'ol/proj'
7+
import { OSM } from 'ol/source'
8+
import type { FC } from 'react'
9+
import { useEffect, useRef } from 'react'
10+
import { MAP_ZOOM_LEVEL } from 'src/helpers/config/map'
11+
import type { MapCoordinates } from 'src/types/map'
12+
13+
14+
type GeoMapProps = {
15+
address: string
16+
coordinates: MapCoordinates
17+
}
18+
19+
export const GeoMap: FC<GeoMapProps> = ({ coordinates }) => {
20+
const mapContainerRef = useRef<HTMLDivElement>(null)
21+
const mapRef = useRef<Map | null>(null)
22+
23+
useEffect(() => {
24+
if (coordinates !== null) {
25+
const centerCoordinates = fromLonLat(coordinates)
26+
27+
if (mapContainerRef.current && !mapRef.current) {
28+
mapRef.current = new Map({
29+
layers: [new TileLayer({ source: new OSM() })],
30+
view: new View({
31+
center: centerCoordinates,
32+
zoom: MAP_ZOOM_LEVEL,
33+
}),
34+
target: mapContainerRef.current,
35+
})
36+
} else if (mapRef.current) {
37+
mapRef.current.getView().setCenter(centerCoordinates)
38+
}
39+
}
40+
}, [coordinates])
41+
42+
useEffect(() => {
43+
return () => {
44+
if (mapRef.current) {
45+
console.log('unmount')
46+
mapRef.current.setTarget(undefined)
47+
mapRef.current = null
48+
}
49+
}
50+
}, [])
51+
52+
if (coordinates === null) {
53+
return null
54+
}
55+
56+
return (
57+
<div
58+
ref={mapContainerRef}
59+
style={{ width: '100%', height: '400px', position: 'relative' }}
60+
/>
61+
)
62+
}

src/components/geo-map/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './geo-map'

src/helpers/config/map.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MAP_ZOOM_LEVEL = 19

src/types/map.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type MapResponse = {
2+
lat: string
3+
lon: string
4+
}
5+
6+
export type MapCoordinates = [number, number]

0 commit comments

Comments
 (0)