From a67ba72305705866ba361bab1cd44e6aff9c273a Mon Sep 17 00:00:00 2001 From: pro028 Date: Fri, 2 May 2025 16:49:52 +0200 Subject: [PATCH] Now filtering based on type of waste searched for --- frontend/sortify/README.md | 2 +- .../sortify/app/context/searchContext.tsx | 25 +++++++++ frontend/sortify/app/layout.tsx | 15 ++--- .../sortify/app/{mainContent.tsx => page.tsx} | 8 ++- .../dropDownMeny/dropDownMenu.module.css | 0 .../dropDownMeny/dropDownMenu.tsx | 0 .../footer/footer.module.css | 0 .../footer/footer.tsx | 0 .../header/header.module.css | 0 .../header/header.tsx | 4 +- .../component/map.js => components/map.jsx} | 55 ++++++++++++++++--- .../searchbar/searchbar.module.css | 0 .../searchbar/searchbar.tsx | 27 +++++---- .../signup/signup.module.css | 0 .../signup/signup.tsx | 0 15 files changed, 102 insertions(+), 34 deletions(-) create mode 100644 frontend/sortify/app/context/searchContext.tsx rename frontend/sortify/app/{mainContent.tsx => page.tsx} (51%) rename frontend/sortify/{app/component => components}/dropDownMeny/dropDownMenu.module.css (100%) rename frontend/sortify/{app/component => components}/dropDownMeny/dropDownMenu.tsx (100%) rename frontend/sortify/{app/component => components}/footer/footer.module.css (100%) rename frontend/sortify/{app/component => components}/footer/footer.tsx (100%) rename frontend/sortify/{app/component => components}/header/header.module.css (100%) rename frontend/sortify/{app/component => components}/header/header.tsx (90%) rename frontend/sortify/{app/component/map.js => components/map.jsx} (80%) rename frontend/sortify/{app/component => components}/searchbar/searchbar.module.css (100%) rename frontend/sortify/{app/component => components}/searchbar/searchbar.tsx (78%) rename frontend/sortify/{app/component => components}/signup/signup.module.css (100%) rename frontend/sortify/{app/component => components}/signup/signup.tsx (100%) diff --git a/frontend/sortify/README.md b/frontend/sortify/README.md index 53eb5221..e215bc4c 100644 --- a/frontend/sortify/README.md +++ b/frontend/sortify/README.md @@ -16,7 +16,7 @@ bun dev Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. -You can start editing the page by modifying `app/mainContent.tsx`. The page auto-updates as you edit the file. +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. diff --git a/frontend/sortify/app/context/searchContext.tsx b/frontend/sortify/app/context/searchContext.tsx new file mode 100644 index 00000000..dab1c564 --- /dev/null +++ b/frontend/sortify/app/context/searchContext.tsx @@ -0,0 +1,25 @@ +'use client'; +import { createContext, useState, useContext, ReactNode } from 'react'; + +type SearchContextType = { + search: string; + setSearch: (value: string) => void; +}; + +const SearchContext = createContext(undefined); + +export const SearchProvider = ({ children }: { children: ReactNode }) => { + const [search, setSearch] = useState(''); + + return ( + + {children} + + ); +}; + +export const useSearch = () => { + const context = useContext(SearchContext); + if (!context) throw new Error('useSearch must be used within a SearchProvider'); + return context; +}; \ No newline at end of file diff --git a/frontend/sortify/app/layout.tsx b/frontend/sortify/app/layout.tsx index 9c0eb430..eee0f792 100644 --- a/frontend/sortify/app/layout.tsx +++ b/frontend/sortify/app/layout.tsx @@ -1,11 +1,12 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; -import Header from "./component/header/header" +import Header from "@/components/header/header" import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter'; -import Footer from "./component/footer/footer"; -import MainContent from "../app/mainContent"; +import Footer from "@/components/footer/footer"; +import Page from "./page"; import styles from "./layout.module.css" +import { SearchProvider } from "@/app/context/searchContext"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -34,10 +35,10 @@ export default function RootLayout({
-
-
- -
+ +
+ {children} +
diff --git a/frontend/sortify/app/mainContent.tsx b/frontend/sortify/app/page.tsx similarity index 51% rename from frontend/sortify/app/mainContent.tsx rename to frontend/sortify/app/page.tsx index 0d7dab3f..4bf0543e 100644 --- a/frontend/sortify/app/mainContent.tsx +++ b/frontend/sortify/app/page.tsx @@ -2,13 +2,15 @@ import dynamic from "next/dynamic"; import styles from './mainContent.module.css'; -const Map = dynamic(() => import("./component/map"), {ssr: false}); +const Map = dynamic(() => import('../components/map'), {ssr: false}); +import { useSearch } from "@/app/context/searchContext"; -export default function MainContent(){ +export default function Page(){ + const { search } = useSearch(); return(

Recycling map

- +
); } \ No newline at end of file diff --git a/frontend/sortify/app/component/dropDownMeny/dropDownMenu.module.css b/frontend/sortify/components/dropDownMeny/dropDownMenu.module.css similarity index 100% rename from frontend/sortify/app/component/dropDownMeny/dropDownMenu.module.css rename to frontend/sortify/components/dropDownMeny/dropDownMenu.module.css diff --git a/frontend/sortify/app/component/dropDownMeny/dropDownMenu.tsx b/frontend/sortify/components/dropDownMeny/dropDownMenu.tsx similarity index 100% rename from frontend/sortify/app/component/dropDownMeny/dropDownMenu.tsx rename to frontend/sortify/components/dropDownMeny/dropDownMenu.tsx diff --git a/frontend/sortify/app/component/footer/footer.module.css b/frontend/sortify/components/footer/footer.module.css similarity index 100% rename from frontend/sortify/app/component/footer/footer.module.css rename to frontend/sortify/components/footer/footer.module.css diff --git a/frontend/sortify/app/component/footer/footer.tsx b/frontend/sortify/components/footer/footer.tsx similarity index 100% rename from frontend/sortify/app/component/footer/footer.tsx rename to frontend/sortify/components/footer/footer.tsx diff --git a/frontend/sortify/app/component/header/header.module.css b/frontend/sortify/components/header/header.module.css similarity index 100% rename from frontend/sortify/app/component/header/header.module.css rename to frontend/sortify/components/header/header.module.css diff --git a/frontend/sortify/app/component/header/header.tsx b/frontend/sortify/components/header/header.tsx similarity index 90% rename from frontend/sortify/app/component/header/header.tsx rename to frontend/sortify/components/header/header.tsx index 2f650895..ef21e73b 100644 --- a/frontend/sortify/app/component/header/header.tsx +++ b/frontend/sortify/components/header/header.tsx @@ -1,7 +1,7 @@ import styles from "./header.module.css"; import Searchbar from "../searchbar/searchbar"; -import SignupModal from "@/app/component/signup/signup"; -import DropdownMenu from "@/app/component/dropDownMeny/dropDownMenu"; +import SignupModal from "@/components/signup/signup"; +import DropdownMenu from "@/components/dropDownMeny/dropDownMenu"; export default function Header() { return ( diff --git a/frontend/sortify/app/component/map.js b/frontend/sortify/components/map.jsx similarity index 80% rename from frontend/sortify/app/component/map.js rename to frontend/sortify/components/map.jsx index 9612e186..f54041e6 100644 --- a/frontend/sortify/app/component/map.js +++ b/frontend/sortify/components/map.jsx @@ -16,7 +16,7 @@ L.Icon.Default.mergeOptions({ shadowUrl: markerShadow.src ?? markerShadow, }); -export default function Map() { +export default function Map({filter}) { // Store references to map and marker instances const mapRef = useRef(null); const markerRef = useRef(null); @@ -28,8 +28,13 @@ export default function Map() { const routeLayerRef = useRef(null); const [routeVisible, setRouteVisible] = useState(false); + console.log("filter: " + filter) + // Initialize map only once on component mount useEffect(() => { + + console.log("Initializing Map") + if (typeof window === 'undefined') return; const map = L.map('map').setView([60.39, 5.32], 11); @@ -45,8 +50,11 @@ export default function Map() { // Fetch user's geolocation when component mounts useEffect(() => { + + console.log("Finding current position"); navigator.geolocation.getCurrentPosition( (position) => { + console.log("coords",position.coords) setUserLocation({ lat: position.coords.latitude, lon: position.coords.longitude, @@ -58,10 +66,22 @@ export default function Map() { // When both map and location are available, update the map view useEffect(() => { - if (!mapRef.current || !userLocation) return; + + console.log("Trying to display locations") + + if (!mapRef.current || !userLocation) { + console.log("Could not find map or userLocation") + return; + } updateUserMarker(mapRef.current, userLocation); - fetchAndDisplayLocations(mapRef.current, userLocation, setLocations, setNearestLocation); - }, [userLocation]); + fetchAndDisplayLocations( + mapRef.current, + userLocation, + setLocations, + setNearestLocation, + filter + ); + }, [userLocation, filter]); // Functionality to toggle the route on or off const toggleRoute = async () => { @@ -133,21 +153,31 @@ function updateUserMarker(map, location) { * Fetches nearby locations from the backend, * highlights the nearest, and displays all with markers. */ -async function fetchAndDisplayLocations(map, userLocation, setLocations, setNearestLocation) { +async function fetchAndDisplayLocations(map, userLocation, setLocations, setNearestLocation, filter) { + console.log("Fetching Locations") try { const res = await fetch(`http://localhost:9876/api/locations/sorted?lat=${userLocation.lat}&lon=${userLocation.lon}`); if (!res.ok) throw new Error("Failed to fetch locations"); - const allLocations = await res.json(); + let allLocations = await res.json(); setLocations(allLocations); + // Set filter + if(filter) { + console.log("Before filter: " + filter, allLocations) + allLocations = allLocations.filter(location => location.wasteTypes.includes(filter)) + console.log("After filter: " + filter, allLocations) + } + console.log(allLocations) + if (!allLocations.length) return; const nearest = allLocations[0]; setNearestLocation(nearest); + addLocationMarkers(map, allLocations); - showNearestMarker(map, nearest); + //showNearestMarker(map, nearest); } catch (err) { console.error("Error fetching locations:", err); } @@ -156,7 +186,14 @@ async function fetchAndDisplayLocations(map, userLocation, setLocations, setNear /** * Adds circular markers for all nearby locations */ +let currentMarkerGroup = null; function addLocationMarkers(map, locations) { + if (currentMarkerGroup) { + map.removeLayer(currentMarkerGroup) + } + const markerGroup = L.layerGroup().addTo(map) + currentMarkerGroup = markerGroup + locations.forEach((loc) => { L.circleMarker([loc.latitude, loc.longitude], { radius: 8, @@ -164,7 +201,7 @@ function addLocationMarkers(map, locations) { fillColor: '#3f51b5', fillOpacity: 0.8, }) - .addTo(map) + .addTo(markerGroup) .bindPopup(` ${loc.name}, ${loc.address}
${[...new Set(loc.wasteTypes)].join(", ")} @@ -180,4 +217,4 @@ function showNearestMarker(map, location) { .addTo(map) .bindPopup(`${location.name}, ${location.address}`) .openPopup(); -} \ No newline at end of file +} diff --git a/frontend/sortify/app/component/searchbar/searchbar.module.css b/frontend/sortify/components/searchbar/searchbar.module.css similarity index 100% rename from frontend/sortify/app/component/searchbar/searchbar.module.css rename to frontend/sortify/components/searchbar/searchbar.module.css diff --git a/frontend/sortify/app/component/searchbar/searchbar.tsx b/frontend/sortify/components/searchbar/searchbar.tsx similarity index 78% rename from frontend/sortify/app/component/searchbar/searchbar.tsx rename to frontend/sortify/components/searchbar/searchbar.tsx index 32777dbc..9895b6f3 100644 --- a/frontend/sortify/app/component/searchbar/searchbar.tsx +++ b/frontend/sortify/components/searchbar/searchbar.tsx @@ -5,6 +5,8 @@ import { InputAdornment, OutlinedInput, Popper, Paper, List, ListItem, ClickAway import SearchIcon from "@mui/icons-material/Search" import styles from "./searchbar.module.css" import { UUID } from "crypto"; +import { useSearch } from "@/app/context/searchContext"; + type wasteItem = { id: UUID, @@ -15,6 +17,8 @@ type wasteItem = { export default function Searcbar(){ + const { search, setSearch } = useSearch() + const [wasteItems, setWasteItems] = useState([]); useEffect(() => { @@ -35,8 +39,8 @@ export default function Searcbar(){ const [query, setQuery] = useState("") - const itemList = wasteItems.map((item) => item.name); - const [queryResult, setQueryResult] = useState([]) + //const itemList = wasteItems.map((item) => item.name); + const [queryResult, setQueryResult] = useState([]) const [open, setOpen] = useState(false); const anchorRef = useRef(null); @@ -48,14 +52,14 @@ export default function Searcbar(){ console.log("Query updated:", newQuery); }; - function searchResults(query: String): string[]{ + function searchResults(query: String): wasteItem[]{ if (query.length === 0) return []; const sortedResults = new Map(); const input = query.toLowerCase(); let score = 1000; - for (let i = 0; i < itemList.length; i++) { - if (itemList[i].length < input.length-2) continue; - const test = itemList[i].toLowerCase(); + for (let i = 0; i < wasteItems.length; i++) { + if (wasteItems[i].name.length < input.length-2) continue; + const test = wasteItems[i].name.toLowerCase(); if (test === input) { score = 0; // Eksakt match (best mulig treff) @@ -66,21 +70,20 @@ export default function Searcbar(){ } else { score = 3 + distance(input, test); // Fuzzy match } - sortedResults.set(itemList[i], score) + sortedResults.set(wasteItems[i], score) } return getSmallestKeys(sortedResults) }; - function getSmallestKeys(map: Map, count = 5): string[] { + function getSmallestKeys(map: Map, count = 5): wasteItem[] { return [...map.entries()] - .sort((a, b) => a[1] - b[1] || a[0].length - b[0].length) // Sort by values in ascending order + .sort((a, b) => a[1] - b[1] || a[0].name.length - b[0].name.length) // Sort by values in ascending order .slice(0, count) // Get the first `count` entries .map(([key]) => key); // Extract and return sorted keys }; - return (
{queryResult.map((item) => ( - - {item} + +

setSearch(item.type)}>{item.name}

))}
diff --git a/frontend/sortify/app/component/signup/signup.module.css b/frontend/sortify/components/signup/signup.module.css similarity index 100% rename from frontend/sortify/app/component/signup/signup.module.css rename to frontend/sortify/components/signup/signup.module.css diff --git a/frontend/sortify/app/component/signup/signup.tsx b/frontend/sortify/components/signup/signup.tsx similarity index 100% rename from frontend/sortify/app/component/signup/signup.tsx rename to frontend/sortify/components/signup/signup.tsx