JourneyPoint / journeypoint / frontend / src / Components / Rating.js
Rating.js
Raw
import React, { useState, useEffect, useRef } from "react";
import Navbar from "./Navbar";
import Footer from "./footer";
import "leaflet/dist/leaflet.css";

const Pin = () => {
    const [suggestions, setSuggestions] = useState([]);
    const [selectedLocation, setSelectedLocation] = useState(null);
    const [ratings, setRatings] = useState({});
    const [ratingInput, setRatingInput] = useState(0);
    const [commentInput, setCommentInput] = useState("");
    const commentsContainerRef = useRef(null);

    const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    const handleInputChange = async (e) => {
        const value = e.target.value;

        if (value.length >= 1) {
            try {
                await delay(2000);
                const response = await fetch(
                    `https://photon.komoot.io/api/?q=${value}&limit=5`
                );
                const data = await response.json();
                setSuggestions(data.features);
            } catch (error) {
                console.error("Error fetching data from Photon:", error);
            }
        } else {
            setSuggestions([]);
        }
    };

    const handleSuggestionClick = (suggestion) => {
        const addressString = [
            suggestion.properties.name,
            suggestion.properties.city,
            suggestion.properties.postcode,
            suggestion.properties.country,
        ]
            .filter((part) => part)
            .join(", ");

        setSelectedLocation({
            id: suggestion.properties.osm_id || suggestion.properties.osm_type,
            name: addressString,
        });
        setSuggestions([]);
    };

    const handleRatingSubmit = async () => {
        if (selectedLocation) {
            const locationName = selectedLocation.name;
            const userName = localStorage.getItem('username');

            try {
                const response = await fetch('https://jp-backend-kc80.onrender.com/api/reviews', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        location: locationName,
                        rating: ratingInput,
                        comment: commentInput,
                        username: userName,
                    }),
                });

                if (response.ok) {
                    fetchRatings();
                    setRatingInput(0);
                    setCommentInput("");
                } else {
                    console.error('Failed to submit rating:', response.statusText);
                }
            } catch (error) {
                console.error('Error submitting rating:', error);
            }
        }
    };

    const fetchRatings = async () => {
        try {
            const response = await fetch('https://jp-backend-kc80.onrender.com/api/reviews');
            if (response.ok) {
                const data = await response.json();
                const groupedRatings = data.reduce((acc, review) => {
                    if (!acc[review.location]) {
                        acc[review.location] = [];
                    }
                    acc[review.location].push(review);
                    return acc;
                }, {});
                setRatings(groupedRatings);
            } else {
                console.error('Failed to fetch ratings:', response.statusText);
            }
        } catch (error) {
            console.error('Error fetching ratings:', error);
        }
    };

    useEffect(() => {
        fetchRatings();
    }, []);

    const calculateAverageRating = (locationName) => {
        const locationRatings = ratings[locationName] || [];
        if (locationRatings.length === 0) return 0;
        const total = locationRatings.reduce((sum, entry) => sum + entry.rating, 0);
        return (total / locationRatings.length).toFixed(1);
    };

    const sortedLocations = Object.keys(ratings)
        .map((locationName) => ({
            name: locationName,
            averageRating: calculateAverageRating(locationName),
            reviews: ratings[locationName],
        }))
        .sort((a, b) => b.averageRating - a.averageRating);

    return (
        <div style={{
            display: 'flex',
            flexDirection: 'column',
            minHeight: '100vh',
            background: 'linear-gradient(-45deg,  #ee7752, #e73c7e, #23a6d5, #23d5ab)',
            backgroundSize: '400% 400%',
            animation: 'gradient 15s ease infinite',
        }}>
            <style>
                {`
                    @keyframes gradient {
                        0% {
                            background-position: 0% 50%;
                        }
                        50% {
                            background-position: 100% 50%;
                        }
                        100% {
                            background-position: 0% 50%;
                        }
                    }
                `}
            </style>
            <Navbar />
            <div className="container mt-4" style={{ flex: 1 }}>
                <div className="row">
                    <div className="col-md-8 offset-md-2">
                        <form className="row g-3">
                            <div className="col-12">
                                <label htmlFor="inputLocation" className="form-label">
                                    Search Location
                                </label>
                                <input
                                    type="text"
                                    className="form-control"
                                    id="inputLocation"
                                    placeholder="Enter location name"
                                    onChange={handleInputChange}
                                />
                                {selectedLocation && (
                                    <p className="mt-2">
                                        <strong>Selected Location:</strong> {selectedLocation.name}
                                    </p>
                                )}

                                {suggestions.length > 0 && (
                                    <ul
                                        className="list-group mt-2"
                                        style={{ maxHeight: "200px", overflowY: "auto" }}
                                    >
                                        {suggestions.map((suggestion, index) => {
                                            const formattedAddress = [
                                                suggestion.properties.name,
                                                suggestion.properties.city,
                                                suggestion.properties.postcode,
                                                suggestion.properties.country,
                                            ]
                                                .filter((part) => part)
                                                .join(", ");

                                            return (
                                                <li
                                                    key={index}
                                                    className="list-group-item list-group-item-action"
                                                    onClick={() => handleSuggestionClick(suggestion)}
                                                >
                                                    {formattedAddress}
                                                </li>
                                            );
                                        })}
                                    </ul>
                                )}
                            </div>

                            {selectedLocation && (
                                <div className="col-12 mt-3">
                                    <label className="form-label mt-3">Rate this location</label>
                                    <div>
                                        {[1, 2, 3, 4, 5].map((value) => (
                                            <label key={value} className="me-2">
                                                <input
                                                    type="radio"
                                                    name="rating"
                                                    value={value}
                                                    checked={ratingInput === value}
                                                    onChange={() => setRatingInput(value)}
                                                />{" "}
                                                {value}
                                            </label>
                                        ))}
                                    </div>

                                    <label htmlFor="comment" className="form-label mt-2">
                                        Comment
                                    </label>
                                    <textarea
                                        className="form-control"
                                        id="comment"
                                        rows="3"
                                        value={commentInput}
                                        onChange={(e) => setCommentInput(e.target.value)}
                                    ></textarea>
                                    <button
                                        type="button"
                                        className="btn btn-success mt-2"
                                        onClick={handleRatingSubmit}
                                    >
                                        Submit Rating
                                    </button>
                                </div>
                            )}
                        </form>

                        <div className="mt-4">
                            <h5>Top Rated Locations</h5>
                            <ul className="list-group" ref={commentsContainerRef} style={{ paddingBottom: '100px' }}>
                                {sortedLocations.map((location) => (
                                    <li key={location.name} className="list-group-item">
                                        <strong>{location.name}</strong> - Average Rating:{" "}
                                        {location.averageRating}
                                        <ul className="mt-2" style={{ maxHeight: '200px', overflowY: 'auto' }}>
                                            {location.reviews.map((review, index) => (
                                                <li key={index}>
                                                    {review.username}, {review.rating}/5 : {" "}
                                                    {review.comment}
                                                </li>
                                            ))}
                                        </ul>
                                    </li>
                                ))}
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
            <Footer />
        </div>
    );
};

export default Pin;