Skip to content

Commit

Permalink
feat: #56 Location Map
Browse files Browse the repository at this point in the history
  • Loading branch information
bkrowka committed Apr 23, 2024
1 parent 44d7e1f commit d5a52fa
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 23 deletions.
52 changes: 52 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@
},
"dependencies": {
"axios": "^1.6.8",
"leaflet": "^1.9.4",
"leaflet-defaulticon-compatibility": "^0.1.2",
"next": "^14.1.3",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.0.1",
"react-leaflet": "^4.2.1",
"react-multi-carousel": "^2.8.5",
"react-query": "^3.39.3"
},
"devDependencies": {
"@types/leaflet": "^1.9.12",
"@types/node": "20.11.30",
"@types/react": "18.2.70",
"@types/react-dom": "^18",
Expand Down
Binary file added public/marker-icon-2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/marker-shadow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions src/components/common/Input/LocationMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React, { useState, useEffect, Dispatch, SetStateAction } from "react";
import { useMapEvents, useMap } from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import dynamic from "next/dynamic";
import axios from "axios";

const MapContainer = dynamic(
() => import("react-leaflet").then((mod) => mod.MapContainer),
{
ssr: false,
}
);

const TileLayer = dynamic(
() => import("react-leaflet").then((mod) => mod.TileLayer),
{
ssr: false,
}
);

const Marker = dynamic(
() => import("react-leaflet").then((mod) => mod.Marker),
{
ssr: false,
}
);

const Popup = dynamic(() => import("react-leaflet").then((mod) => mod.Popup), {
ssr: false,
});

export function LocationMap({
locX,
setLocX,
locY,
setLocY,
locName,
setLocName,
}: {
locX: number;
setLocX: Dispatch<SetStateAction<number>>;
locY: number;
setLocY: Dispatch<SetStateAction<number>>;
locName: string;
setLocName: Dispatch<SetStateAction<string>>;
}) {
const [position, setPosition] = useState<L.LatLng | null>(null);

useEffect(() => {
import("leaflet").then((L) => {
if (locX === 0 && locY === 0) {
setPosition(null);
} else {
setPosition(new L.LatLng(locX, locY));
}
});
}, [locX, locY]);

const MyMapEvents: React.FC = () => {
const map = useMap();

useEffect(() => {
if (position !== null) {
map.setView(position, map.getZoom());
}
}, [position, map]);

useMapEvents({
click(e) {
const { lat, lng } = e.latlng;
setPosition(e.latlng);
setLocX(lat);
setLocY(lng);
console.log(`Wybrane współrzędne: ${lat}, ${lng}`);
axios
.get(
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json`
)
.then((response) => {
const address = response.data.address;
const streetNumber = address.house_number || "";
const streetName = address.road || "";
const city = address.city || address.town || address.village || "";
const name = streetNumber
? `${streetName} ${streetNumber}, ${city}`
: `${streetName}, ${city}`;

setLocName(name);
console.log(`Nazwa miejsca: ${locName}`);
})
.catch((error) => {
console.error("Błąd pobierania nazwy miejsca:", error);
});
},
});

return position ? (
<Marker position={position}>
<Popup>Wybrana lokalizacja: {locName}</Popup>
</Marker>
) : null;
};

return (
<MapContainer
center={[50.04370714836096, 22.00386841259957]}
zoom={15}
className="w-full h-96 rounded"
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
<MyMapEvents />
</MapContainer>
);
}
33 changes: 10 additions & 23 deletions src/components/myconference/AddConferenceInputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {addNewConference, AddNewConferenceData} from "@/hooks/conference";
import {uploadFile, FileResponseData} from "@/hooks/file";
import APIImageComponent from "@/hooks/imageAPI";
import {MdOutlineDeleteForever} from "react-icons/md";

import { LocationMap } from "../common/Input/LocationMap";

export default function AddConferenceInputs() {
const [name, setName] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [startDateTime, setStartDateTime] = useState<string>("");
const [locX, setLocX] = useState<number>(0);
const [locY, setLocY] = useState<number>(0);
const [place, setPlace] = useState<string>("");
const [participantsLimit, setParticipantsLimit] = useState<string>("");
const [format, setFormat] = useState<string>("STATIONARY");
Expand Down Expand Up @@ -73,8 +75,8 @@ export default function AddConferenceInputs() {
logoId: imageId,
tagsIds: [],
location: {
locX: 0,
locY: 0,
locX: locX,
locY: locY,
name: place,
},
participantsLimit: parseInt(participantsLimit, 10),
Expand All @@ -84,7 +86,7 @@ export default function AddConferenceInputs() {

const handleAddConference = async () => {

console.log(newConference);
// console.log(newConference);

if (!name || !description || !startDateTime || !participantsLimit.trim() || imageId === 0 || !place) {
console.error("Wszystkie pola muszą być wypełnione");
Expand All @@ -100,6 +102,7 @@ export default function AddConferenceInputs() {
}

try {
console.log(newConference);
const result = await addNewConference(newConference);
if(result !== "Brak autoryzacji użytkownika" && result !== "Nie jesteś organizatorem" && result !== "Wystąpił błąd podczas dodawania konferencji"){
setName("");
Expand Down Expand Up @@ -228,25 +231,9 @@ export default function AddConferenceInputs() {
</div>
</div>

<div className="relative">
<SingleFormInput
type="text"
id="place"
name="place"
placeholder=" "
value={place}
onChange={(e) => {
const value = e.target.value;
const isValid = /^[\w\s\/\d\WąęłńóśźżĄĘŁŃÓŚŹŻ]*$/i.test(value);

if (isValid) {
setPlace(value);
}
}}
/>
<label htmlFor="place" className="absolute left-0 -top-4 text-xs text-darkblue font-bold cursor-text peer-placeholder-shown:top-1 peer-placeholder-shown:text-base peer-placeholder-shown:font-normal peer-placeholder-shown:text-blue peer-focus:text-xs peer-focus:-top-4 peer-focus:text-darkblue font-sans peer-focus:font-bold transition-all">
Miejsce konferencji
</label>
<div>
<h1 className="text-xs text-darkblue font-bold font-sans">Miejsce konferencji:</h1>
<LocationMap locX={locX} setLocX={setLocX} locY={locY} setLocY={setLocY} locName={place} setLocName={setPlace}/>
</div>

<div className="relative">
Expand Down

0 comments on commit d5a52fa

Please sign in to comment.