diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 62eb234..bf36063 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.7.1",
+ "@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.1",
"@fortawesome/react-fontawesome": "^0.2.2",
"@testing-library/jest-dom": "^5.17.0",
@@ -2462,6 +2463,25 @@
"node": ">=6"
}
},
+ "node_modules/@fortawesome/free-regular-svg-icons": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz",
+ "integrity": "sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.7.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-regular-svg-icons/node_modules/@fortawesome/fontawesome-common-types": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
+ "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/@fortawesome/free-solid-svg-icons": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 3a1a78a..36584df 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -5,6 +5,7 @@
"type": "module",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.7.1",
+ "@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.1",
"@fortawesome/react-fontawesome": "^0.2.2",
"@testing-library/jest-dom": "^5.17.0",
diff --git a/frontend/src/ProtectedRoute.js b/frontend/src/ProtectedRoute.js
new file mode 100644
index 0000000..4430747
--- /dev/null
+++ b/frontend/src/ProtectedRoute.js
@@ -0,0 +1,26 @@
+import React, { useEffect, useState } from 'react';
+import { Navigate } from 'react-router-dom';
+import axiosClient from '../axiosClient.js';
+
+export default function ProtectedRoute({ children }) {
+ const [isAuthorized, setIsAuthorized] = useState(null);
+
+ useEffect(() => {
+ const checkAuthorization = async () => {
+ try {
+ const response = await axiosClient.get('/getCurrentUser', {
+ headers: { Authorization: `Bearer ${localStorage.getItem('authToken')}` },
+ });
+ const user = response.data.user;
+ setIsAuthorized(user.isAdmin === 1);
+ } catch (error) {
+ console.error('Błąd podczas sprawdzania uprawnień:', error);
+ setIsAuthorized(false);
+ }
+ };
+
+ checkAuthorization();
+ }, []);
+
+ return isAuthorized ? children : ;
+}
diff --git a/frontend/src/components/Footer.js b/frontend/src/components/Footer.js
index 0ecde75..3d28214 100644
--- a/frontend/src/components/Footer.js
+++ b/frontend/src/components/Footer.js
@@ -1,10 +1,14 @@
-import '../index.css'
-import React from 'react'
+import '../index.css';
+import React from 'react';
export default function Footer() {
return (
- © 2024 Legnica Kebab City Tour. Wszelkie prawa zastrzeżone.
+
+
+ ©kibolAPP
+ 2024 Legnica Kebab City Tour. Wszelkie prawa zastrzeżone.
+
- )
+ );
}
diff --git a/frontend/src/components/KebabsList.js b/frontend/src/components/KebabsList.js
new file mode 100644
index 0000000..c4eac44
--- /dev/null
+++ b/frontend/src/components/KebabsList.js
@@ -0,0 +1,211 @@
+import React, { useState, useEffect, useRef } from 'react';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faArrowDown, faHeart as solidHeart } from '@fortawesome/free-solid-svg-icons';
+import { faHeart as regularHeart } from '@fortawesome/free-regular-svg-icons';
+import axiosClient from '../axiosClient.js';
+
+const daysTranslations = {
+ monday: 'Poniedziałek',
+ tuesday: 'Wtorek',
+ wednesday: 'Środa',
+ thursday: 'Czwartek',
+ friday: 'Piątek',
+ saturday: 'Sobota',
+ sunday: 'Niedziela',
+};
+
+const dayOrder = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
+
+const translateStatus = (status) => {
+ const statusMap = {
+ exists: 'Istnieje',
+ closed: 'Zamknięty',
+ planned: 'Planowany',
+ };
+ return statusMap[status] || 'Nieznany';
+ };
+
+ export default function KebabsList({ kebabs, activeKebabIndex }) {
+ const [openIndex, setOpenIndex] = useState(null);
+ const [favorites, setFavorites] = useState([]);
+ const [sortedKebabs, setSortedKebabs] = useState([]);
+ const [userId, setUserId] = useState(null);
+ const kebabRefs = useRef([]);
+
+ useEffect(() => {
+ if (activeKebabIndex !== null) {
+ setOpenIndex(activeKebabIndex);
+ if (kebabRefs.current[activeKebabIndex]) {
+ kebabRefs.current[activeKebabIndex].scrollIntoView({
+ behavior: 'smooth',
+ block: 'center',
+ });
+ }
+ }
+ }, [activeKebabIndex]);
+
+ useEffect(() => {
+ const fetchUser = async () => {
+ try {
+ const response = await axiosClient.get('/getCurrentUser', {
+ headers: { Authorization: `Bearer ${localStorage.getItem('authToken')}` },
+ });
+ const user = response.data.user;
+ setUserId(user.id);
+ setFavorites(user.favorites ? JSON.parse(user.favorites) : []);
+ } catch (error) {
+ console.error('Błąd pobierania danych użytkownika:', error);
+ }
+ };
+
+ fetchUser();
+ }, []);
+
+ useEffect(() => {
+ const sortKebabs = () => {
+ const favoriteKebabs = kebabs.filter((kebab) => favorites.includes(kebab.id));
+ const nonFavoriteKebabs = kebabs.filter((kebab) => !favorites.includes(kebab.id));
+ setSortedKebabs([...favoriteKebabs, ...nonFavoriteKebabs]);
+ };
+
+ sortKebabs();
+ }, [favorites, kebabs]);
+
+ const toggleDetails = (index) => {
+ setOpenIndex(openIndex === index ? null : index);
+ };
+
+ const handleFavoriteToggle = async (kebabId) => {
+ try {
+ if (favorites.includes(kebabId)) {
+ await axiosClient.post(
+ '/remfav',
+ { user_id: userId, kebab_id: kebabId },
+ {
+ headers: { Authorization: `Bearer ${localStorage.getItem('authToken')}` },
+ }
+ );
+ setFavorites((prev) => prev.filter((id) => id !== kebabId));
+ } else {
+ await axiosClient.post(
+ '/addfav',
+ { user_id: userId, kebab_id: kebabId },
+ {
+ headers: { Authorization: `Bearer ${localStorage.getItem('authToken')}` },
+ }
+ );
+ setFavorites((prev) => [...prev, kebabId]);
+ }
+ } catch (error) {
+ console.error('Błąd przy przełączaniu ulubionych:', error);
+ }
+ };
+
+ return (
+
diff --git a/frontend/src/components/ProtectedRoute.js b/frontend/src/components/ProtectedRoute.js
new file mode 100644
index 0000000..9e26069
--- /dev/null
+++ b/frontend/src/components/ProtectedRoute.js
@@ -0,0 +1,30 @@
+import React, { useEffect, useState } from 'react';
+import { Navigate } from 'react-router-dom';
+import axiosClient from '../axiosClient.js';
+
+export default function ProtectedRoute({ children }) {
+ const [isAuthorized, setIsAuthorized] = useState(null);
+
+ useEffect(() => {
+ const checkAuthorization = async () => {
+ try {
+ const response = await axiosClient.get('/getCurrentUser', {
+ headers: { Authorization: `Bearer ${localStorage.getItem('authToken')}` },
+ });
+ const user = response.data.user;
+ setIsAuthorized(user.isAdmin === 1);
+ } catch (error) {
+ console.error('Błąd podczas sprawdzania uprawnień:', error);
+ setIsAuthorized(false);
+ }
+ };
+
+ checkAuthorization();
+ }, []);
+
+ if (isAuthorized === null) {
+ return
Ładowanie...
;
+ }
+
+ return isAuthorized ? children :
;
+}
diff --git a/frontend/src/components/SearchPanel.js b/frontend/src/components/SearchPanel.js
new file mode 100644
index 0000000..a8f77f4
--- /dev/null
+++ b/frontend/src/components/SearchPanel.js
@@ -0,0 +1,256 @@
+import React, { useState } from 'react';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faArrowDown } from '@fortawesome/free-solid-svg-icons';
+
+export default function SearchPanel({ kebabs, onSearch }) {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [sortOrder, setSortOrder] = useState('asc');
+ const [isFilterOpen, setIsFilterOpen] = useState(false);
+ const [showOpenNow, setShowOpenNow] = useState(false);
+ const [selectedSauces, setSelectedSauces] = useState([]);
+ const [selectedMeats, setSelectedMeats] = useState([]);
+ const [selectedOrderingOptions, setSelectedOrderingOptions] = useState([]);
+
+ const allSauces = Array.from(
+ new Set(kebabs.flatMap((kebab) => kebab.sauces || []))
+ );
+
+ const allMeats = Array.from(
+ new Set(kebabs.flatMap((kebab) => kebab.meats || []))
+ );
+
+ const allOrderingOptions = Array.from(
+ new Set(kebabs.flatMap((kebab) => kebab.ordering_options || []))
+ );
+
+ const getCurrentTimeDetails = () => {
+ const now = new Date();
+ const currentHour = now.getHours();
+ const currentMinute = now.getMinutes();
+ const currentTime = currentHour + currentMinute / 60;
+ const currentDay = now.toLocaleString('en-US', { weekday: 'long' }).toLowerCase();
+ return { currentTime, currentDay };
+ };
+
+ const isOpenNow = (kebab) => {
+ const { currentTime, currentDay } = getCurrentTimeDetails();
+
+ if (!kebab.opening_hours || !kebab.opening_hours[currentDay]) {
+ return false;
+ }
+
+ const [opening, closing] = kebab.opening_hours[currentDay]
+ .split('-')
+ .map((time) => {
+ const [hour, minute] = time.split(':').map(Number);
+ return hour + minute / 60;
+ });
+
+ return currentTime >= opening && currentTime < closing;
+ };
+
+ const handleSearchChange = (e) => {
+ const query = e.target.value;
+ setSearchQuery(query);
+ applyFilters(query, selectedSauces, selectedMeats, showOpenNow, sortOrder);
+ };
+
+ const handleSortChange = (order) => {
+ setSortOrder(order);
+ applyFilters(searchQuery, selectedSauces, selectedMeats, showOpenNow, order);
+ };
+
+ const handleSauceToggle = (sauce) => {
+ const updatedSauces = selectedSauces.includes(sauce)
+ ? selectedSauces.filter((s) => s !== sauce)
+ : [...selectedSauces, sauce];
+
+ setSelectedSauces(updatedSauces);
+ applyFilters(searchQuery, updatedSauces, selectedMeats, showOpenNow, sortOrder);
+ };
+
+ const handleMeatToggle = (meat) => {
+ const updatedMeats = selectedMeats.includes(meat)
+ ? selectedMeats.filter((m) => m !== meat)
+ : [...selectedMeats, meat];
+
+ setSelectedMeats(updatedMeats);
+ applyFilters(searchQuery, selectedSauces, updatedMeats, showOpenNow, sortOrder);
+ };
+
+ const handleOrderingOptionToggle = (option) => {
+ const updatedOptions = selectedOrderingOptions.includes(option)
+ ? selectedOrderingOptions.filter((o) => o !== option)
+ : [...selectedOrderingOptions, option];
+
+ setSelectedOrderingOptions(updatedOptions);
+ applyFilters(searchQuery, selectedSauces, selectedMeats, showOpenNow, sortOrder, updatedOptions);
+ };
+
+ const toggleOpenNow = () => {
+ const updatedShowOpenNow = !showOpenNow;
+ setShowOpenNow(updatedShowOpenNow);
+ applyFilters(searchQuery, selectedSauces, selectedMeats, updatedShowOpenNow, sortOrder);
+ };
+
+ const applyFilters = (query, sauces, meats, openNow, order, orderingOptions = []) => {
+ let filteredKebabs = kebabs;
+
+ if (query) {
+ filteredKebabs = filteredKebabs.filter((kebab) =>
+ kebab.name.toLowerCase().includes(query.toLowerCase())
+ );
+ }
+
+ if (sauces.length > 0) {
+ filteredKebabs = filteredKebabs.filter((kebab) =>
+ sauces.every((sauce) => kebab.sauces?.includes(sauce))
+ );
+ }
+
+ if (meats.length > 0) {
+ filteredKebabs = filteredKebabs.filter((kebab) =>
+ meats.every((meat) => kebab.meats?.includes(meat))
+ );
+ }
+
+ if (orderingOptions.length > 0) {
+ filteredKebabs = filteredKebabs.filter((kebab) =>
+ orderingOptions.every((option) => kebab.ordering_options?.includes(option))
+ );
+ }
+
+ if (openNow) {
+ filteredKebabs = filteredKebabs.filter(isOpenNow);
+ }
+
+ filteredKebabs = filteredKebabs.sort((a, b) => {
+ if (order === 'asc') {
+ return a.name.localeCompare(b.name);
+ }
+ return b.name.localeCompare(a.name);
+ });
+
+ onSearch(filteredKebabs);
+ };
+
+ return (
+
+
+
Sortowanie po nazwie:
+
+ handleSortChange('asc')}
+ className={`flex-1 p-2 text-center rounded ${
+ sortOrder === 'asc'
+ ? 'bg-green-500 text-white'
+ : 'bg-gray-300 text-gray-700'
+ }`}
+ >
+ Rosnąco ↑
+
+ handleSortChange('desc')}
+ className={`flex-1 p-2 text-center rounded ${
+ sortOrder === 'desc'
+ ? 'bg-green-500 text-white'
+ : 'bg-gray-300 text-gray-700'
+ }`}
+ >
+ Malejąco ↓
+
+
+
+ {/* Filtrowanie */}
+
setIsFilterOpen(!isFilterOpen)}
+ >
+ Filtrowanie
+
+
+
+
+
+
+ Aktualnie otwarte
+
+
+ {/* Sosy */}
+
+
Sosy:
+
+ {allSauces.map((sauce) => (
+
+ handleSauceToggle(sauce)}
+ className="w-4 h-4"
+ />
+ {sauce}
+
+ ))}
+
+
+
+ {/* Mięsa */}
+
+
Mięsa:
+
+ {allMeats.map((meat) => (
+
+ handleMeatToggle(meat)}
+ className="w-4 h-4"
+ />
+ {meat}
+
+ ))}
+
+
+
+ {/* Opcje zamówienia */}
+
+
Opcje zamówienia:
+
+ {allOrderingOptions.map((option) => (
+
+ handleOrderingOptionToggle(option)}
+ className="w-4 h-4"
+ />
+ {option}
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/img/kebab_icon.png b/frontend/src/img/kebab_icon.png
new file mode 100644
index 0000000..c0d0290
Binary files /dev/null and b/frontend/src/img/kebab_icon.png differ
diff --git a/frontend/src/pages/AdminPanel.js b/frontend/src/pages/AdminPanel.js
index ea00602..075b1f0 100644
--- a/frontend/src/pages/AdminPanel.js
+++ b/frontend/src/pages/AdminPanel.js
@@ -169,48 +169,34 @@ export default function AdminPanel() {
const kebabId = selectedKebab?.id;
const openKebabModal = (kebab) => {
- const parsedOpeningHours =
- typeof kebab.opening_hours === "string"
- ? JSON.parse(kebab.opening_hours || "{}")
- : kebab.opening_hours || {};
-
- setSelectedKebab({
- ...kebab,
- logo: kebab.logo,
- opening_hours: parsedOpeningHours,
- ordering_options: Array.isArray(kebab.ordering_options)
- ? kebab.ordering_options
- : JSON.parse(kebab.ordering_options || "[]"),
- sauces: Array.isArray(kebab.sauces)
- ? kebab.sauces
- : JSON.parse(kebab.sauces || "[]"),
- pages: Array.isArray(kebab.pages)
- ? kebab.pages
- : JSON.parse(kebab.pages || "[]"),
- });
-
- setInitialKebab({
- ...kebab,
- opening_hours: parsedOpeningHours,
- ordering_options: Array.isArray(kebab.ordering_options)
- ? kebab.ordering_options
- : JSON.parse(kebab.ordering_options || "[]"),
- sauces: Array.isArray(kebab.sauces)
- ? kebab.sauces
- : JSON.parse(kebab.sauces || "[]"),
- pages: Array.isArray(kebab.pages)
- ? kebab.pages
- : JSON.parse(kebab.pages || "[]"),
- });
-
- setLocalSauces(Array.isArray(kebab.sauces) ? kebab.sauces : JSON.parse(kebab.sauces || "[]"));
- setLocalMeats([...kebab.meats]);
- setLocalStatus(kebab.status || "exists");
- setLocalOpeningHours(parsedOpeningHours);
- setLocalLogo(null);
- setLocalOrderingOptions(Array.isArray(kebab.ordering_options) ? [...kebab.ordering_options] : []);
- setLocalPages([...kebab.pages]);
- setIsKebabModalOpen(true);
+ setSelectedKebab({
+ ...kebab,
+ opening_hours: kebab.opening_hours || {},
+ ordering_options: Array.isArray(kebab.ordering_options)
+ ? kebab.ordering_options
+ : [],
+ sauces: Array.isArray(kebab.sauces) ? kebab.sauces : [],
+ pages: kebab.pages || {},
+ });
+
+ setInitialKebab({
+ ...kebab,
+ opening_hours: kebab.opening_hours || {},
+ ordering_options: Array.isArray(kebab.ordering_options)
+ ? kebab.ordering_options
+ : [],
+ sauces: Array.isArray(kebab.sauces) ? kebab.sauces : [],
+ pages: kebab.pages || {},
+ });
+
+ setLocalSauces(Array.isArray(kebab.sauces) ? kebab.sauces : []);
+ setLocalMeats([...kebab.meats]);
+ setLocalStatus(kebab.status || "exists");
+ setLocalOpeningHours(kebab.opening_hours || {});
+ setLocalLogo(null);
+ setLocalOrderingOptions(Array.isArray(kebab.ordering_options) ? kebab.ordering_options : []);
+ setLocalPages(kebab.pages || {});
+ setIsKebabModalOpen(true);
};
const handleLogoChange = (file) => {
@@ -848,7 +834,7 @@ export default function AdminPanel() {
setSelectedKebab({
...selectedKebab,
@@ -868,7 +854,7 @@ export default function AdminPanel() {
setSelectedKebab({
...selectedKebab,
diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js
index 0b70d40..e81c555 100644
--- a/frontend/src/pages/Home.js
+++ b/frontend/src/pages/Home.js
@@ -1,27 +1,73 @@
-import '../index.css'
-import kebab_logo from '../img/kebab_logo.png'
-import { useNavigate } from 'react-router-dom'
-import Footer from '../components/Footer.js'
-import { useEffect, useState } from 'react'
-import 'react-toastify/dist/ReactToastify.css'
-import { toast, ToastContainer } from 'react-toastify'
+import '../index.css';
+import kebab_logo from '../img/kebab_logo.png';
+import { useNavigate } from 'react-router-dom';
+import Footer from '../components/Footer.js';
+import { useEffect, useState } from 'react';
+import 'react-toastify/dist/ReactToastify.css';
+import { toast, ToastContainer } from 'react-toastify';
+import axiosClient from '../axiosClient.js';
export default function Home() {
- const navigate = useNavigate()
- const [isLoggedIn, setIsLoggedIn] = useState(false)
+ const navigate = useNavigate();
+ const [isLoggedIn, setIsLoggedIn] = useState(false);
+ const [isAdmin, setIsAdmin] = useState(false);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [suggestion, setSuggestion] = useState('');
useEffect(() => {
- const token = localStorage.getItem('authToken')
+ const token = localStorage.getItem('authToken');
if (token) {
- setIsLoggedIn(true)
+ setIsLoggedIn(true);
+
+ axiosClient
+ .get('/getCurrentUser', {
+ headers: { Authorization: `Bearer ${token}` },
+ })
+ .then((response) => {
+ const user = response.data.user;
+ setIsAdmin(user.isAdmin === 1);
+ })
+ .catch((error) => {
+ console.error('Błąd pobierania danych użytkownika:', error);
+ });
}
- }, [])
+ }, []);
const handleLogout = () => {
- localStorage.removeItem('authToken')
- setIsLoggedIn(false)
- toast.success('Wylogowano pomyślnie!', { autoClose: 2000 })
- }
+ localStorage.removeItem('authToken');
+ setIsLoggedIn(false);
+ setIsAdmin(false);
+ toast.success('Wylogowano pomyślnie!', { autoClose: 2000 });
+ };
+
+ const handleSuggestionSubmit = async () => {
+ const token = localStorage.getItem('authToken');
+ if (!suggestion.trim()) {
+ toast.error('Proszę wpisać treść sugestii.');
+ return;
+ }
+
+ try {
+ const userResponse = await axiosClient.get('/getCurrentUser', {
+ headers: { Authorization: `Bearer ${token}` },
+ });
+
+ const user = userResponse.data.user?.name || 'Anonimowy użytkownik';
+
+ await axiosClient.post(
+ '/suggestions',
+ { user, contents: suggestion },
+ { headers: { Authorization: `Bearer ${token}` } }
+ );
+
+ toast.success('Sugestia została wysłana!');
+ setIsModalOpen(false);
+ setSuggestion('');
+ } catch (error) {
+ toast.error('Nie udało się wysłać sugestii. Spróbuj ponownie później.');
+ console.error('Błąd podczas wysyłania sugestii:', error);
+ }
+ };
return (
@@ -35,8 +81,7 @@ export default function Home() {
LEGNICA KEBAB CITY TOUR
- Legnica Kebab City Tour jest to aplikacja oraz witryna internetowa służąca pomocą w odnalezieniu lokalizacji wszystkich dostępnych, w planach oraz zamkniętych punktów gastronomicznych serwujących słynne Kebaby. Poniższe przyciski pokierują Cię dalej. Wybierz przycisk "Mapa" aby bezpośrednio odnaleźć Kebaby rozsiane po Legnicy. Możesz też utworzyć konto lub zalogować się aby dodać Twojego ulubionego Kebaba do zakładki "Ulubione", dzięki czemu łatwiej go odnajdziesz!!
-
+ Legnica Kebab City Tour jest to aplikacja oraz witryna internetowa służąca pomocą w odnalezieniu lokalizacji wszystkich dostępnych, w planach oraz zamkniętych punktów gastronomicznych serwujących słynne Kebaby. Poniższe przyciski pokierują Cię dalej. Wybierz przycisk "Mapa" aby bezpośrednio odnaleźć Kebaby rozsiane po Legnicy. Możesz też utworzyć konto lub zalogować się aby na mapie dodać Twojego ulubionego Kebaba, dzięki czemu łatwiej go odnajdziesz!! Dodatkowo po zalogowaniu pojawi się przycisk "Sugestia", nie krępuj się i zostaw nam swoją opinię!
{isLoggedIn ? (
-
- WYLOGUJ
-
+ <>
+
+ WYLOGUJ
+
+ setIsModalOpen(true)}
+ >
+ SUGESTIA
+
+ {isAdmin && (
+ navigate('/admin')}
+ >
+ ADMIN PANEL
+
+ )}
+ >
) : (
+
+ {/* Sugestia Panel */}
+ {isModalOpen && (
+
+ )}
- )
+ );
}
diff --git a/frontend/src/pages/Map.js b/frontend/src/pages/Map.js
index 517ce57..1dfd0ff 100644
--- a/frontend/src/pages/Map.js
+++ b/frontend/src/pages/Map.js
@@ -1,41 +1,121 @@
-import React from 'react'
-import '../index.css'
-import Header from '../components/Header.js'
-import { MapContainer, TileLayer } from 'react-leaflet'
-import 'leaflet/dist/leaflet.css'
-import Footer from '../components/Footer.js'
+import React, { useState, useEffect } from 'react';
+import '../index.css';
+import Header from '../components/Header.js';
+import Footer from '../components/Footer.js';
+import KebabsList from '../components/KebabsList.js';
+import SearchPanel from '../components/SearchPanel.js';
+import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
+import L from 'leaflet';
+import 'leaflet/dist/leaflet.css';
+import axiosClient from '../axiosClient.js';
+import kebab_icon from '../img/kebab_icon.png';
+import { toast, ToastContainer } from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
export default function Map() {
const legnicaBounds = [
- [51.165803, 16.148615],
- [51.232924, 16.177626],
- [51.202710, 16.245260],
- ]
+ [51.158, 16.114],
+ [51.242, 16.260],
+ ];
+
+ const [kebabs, setKebabs] = useState([]);
+ const [filteredKebabs, setFilteredKebabs] = useState([]);
+ const [activeKebabIndex, setActiveKebabIndex] = useState(null);
+
+ useEffect(() => {
+ axiosClient
+ .get('/kebabs')
+ .then((response) => {
+ setKebabs(response.data);
+ setFilteredKebabs(response.data);
+ console.log('Pobrane kebaby:', response.data);
+ })
+ .catch((error) => {
+ console.error('Błąd pobierania kebabów:', error);
+ toast.error('Błąd pobrania szczegółów kebabów z serwera. Odśwież stronę lub skontaktuj się z administratorem.');
+ });
+ }, []);
+
+ const kebabIcon = new L.Icon({
+ iconUrl: kebab_icon,
+ iconSize: [30, 30],
+ iconAnchor: [15, 30],
+ popupAnchor: [0, -30],
+ });
+
+ const handleSearch = (filtered) => {
+ setFilteredKebabs(filtered);
+ };
+
+ const scrollToKebab = (index) => {
+ setActiveKebabIndex(index);
+
+ setTimeout(() => {
+ const kebabElement = document.getElementById(`kebab-${index}`);
+ if (kebabElement) {
+ const rect = kebabElement.getBoundingClientRect();
+ const offset = window.scrollY + rect.top - 150;
+ window.scrollTo({
+ top: offset,
+ behavior: 'smooth',
+ });
+ }
+ }, 0);
+ };
return (
-
-
+
+
+ {filteredKebabs.map((kebab, index) => (
+
+
+ {kebab.name}
+ {kebab.address}
+ scrollToKebab(index)}
+ >
+ Szczegóły
+
+
+
+ ))}
-
- )
+ );
}
diff --git a/frontend/src/router.js b/frontend/src/router.js
index 17d2a32..d5bfa20 100644
--- a/frontend/src/router.js
+++ b/frontend/src/router.js
@@ -1,9 +1,10 @@
-import React from 'react'
-import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
-import Home from './pages/Home.js'
-import Map from './pages/Map.js'
-import AuthPage from './pages/AuthPage.js'
-import AdminPanel from './pages/AdminPanel.js'
+import React from 'react';
+import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
+import Home from './pages/Home.js';
+import Map from './pages/Map.js';
+import AuthPage from './pages/AuthPage.js';
+import AdminPanel from './pages/AdminPanel.js';
+import ProtectedRoute from './components/ProtectedRoute.js';
const AppRouter = () => (
@@ -11,9 +12,16 @@ const AppRouter = () => (
} />
} />
} />
- } />
+
+
+
+ }
+ />
-)
+);
-export default AppRouter
+export default AppRouter;