2

mail@pastecode.io avatar
unknown
plain_text
a month ago
13 kB
2
Indexable
Never
import React, { useEffect, useState } from "react";
import "./Home.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowRight } from "@fortawesome/free-solid-svg-icons";
import { faBook } from "@fortawesome/free-solid-svg-icons"; // Import the specific icon
import Footer from "../components/Footer";
import { Link } from "react-router-dom";
import Navbar from "../components/Navbar";
import Sidebar from "../components/Sidebar";
import Loader from "../components/Loader";
import { BASE_URL } from "../server/Endpoint";

const Home = () => {
  const [loading, setLoading] = useState(true);
  const [popularBooks, setPopularBooks] = useState([]);
  const [newBooks, setNewBooks] = useState([]);
  const [vipBooks, setVipBooks] = useState([]);
  const [authors, setAuthors] = useState([]);
  const [topBooks, setTopBooks] = useState([]);

  useEffect(() => {
    fetchBooks();
    fetchAuthors();
    fetchTopBooks(); 
  }, []);

  const fetchBooks = async () => {
    try {
      const popularResponse = await fetch(
        `${BASE_URL}api/public/books/pagedAndSorted?page=0&size=4&sortBy=views&sortDir=DESC`,
        {
          method: "GET",
          headers: {
            "ngrok-skip-browser-warning": "69420",
          },
        }
      );
      if (!popularResponse.ok) {
        throw new Error("Error fetching popular books");
      }
      const popularData = await popularResponse.json();
      const popularBooksWithRatings = await Promise.all(
        popularData.content.map(async (book) => ({
          ...book,
          averageRating: await fetchRating(book.id),
        }))
      );
      setPopularBooks(popularBooksWithRatings);

      // Fetch new books
      const newResponse = await fetch(
        `${BASE_URL}api/public/books/pagedAndSorted?page=0&size=4&sortBy=createdAt&sortDir=DESC`,
        {
          method: "GET",
          headers: {
            "ngrok-skip-browser-warning": "69420",
          },
        }
      );
      if (!newResponse.ok) {
        throw new Error("Error fetching new books");
      }
      const newData = await newResponse.json();
      const newBooksWithRatings = await Promise.all(
        newData.content.map(async (book) => ({
          ...book,
          averageRating: await fetchRating(book.id),
        }))
      );
      setNewBooks(newBooksWithRatings);

      // Fetch VIP books
      const vipResponse = await fetch(
        `${BASE_URL}api/public/books/pagedAndSorted?page=2&size=4&sortBy=title&sortDir=ASC`,
        {
          method: "GET",
          headers: {
            "ngrok-skip-browser-warning": "69420",
          },
        }
      );
      if (!vipResponse.ok) {
        throw new Error("Error fetching VIP books");
      }
      const vipData = await vipResponse.json();
      const vipBooksWithRatings = await Promise.all(
        vipData.content.map(async (book) => ({
          ...book,
          averageRating: await fetchRating(book.id),
        }))
      );
      setVipBooks(vipBooksWithRatings);

      setLoading(false);
    } catch (error) {
      console.error("Error fetching books:", error);
      setLoading(false);
    }
  };

  const fetchAuthors = async () => {
    try {
      const response = await fetch(`${BASE_URL}api/public/author/getAll`, {
        method: "GET",
        headers: {
          "ngrok-skip-browser-warning": "69420",
        },
      });
      if (!response.ok) {
        throw new Error("Error fetching authors");
      }
      const data = await response.json();
      setAuthors(data);
    } catch (error) {
      console.error("Error fetching authors:", error);
    }
  };

  const fetchTopBooks = async () => {
    try {
      const response = await fetch(
        `${BASE_URL}api/public/books/pagedAndSorted?sortBy=views&sortDir=DESC&page=0&size=5`,
        {
          method: "GET",
          headers: {
            "ngrok-skip-browser-warning": "69420",
          },
        }
      );
      if (!response.ok) {
        throw new Error("Error fetching top books");
      }
      const data = await response.json();
      const topBooksWithRatings = await Promise.all(
        data.content.map(async (book) => ({
          ...book,
          averageRating: await fetchRating(book.id),
        }))
      );
      setTopBooks(topBooksWithRatings);
    } catch (error) {
      console.error("Error fetching top books:", error);
    }
  };

  const fetchRating = async (bookId) => {
    try {
      const response = await fetch(
        `${BASE_URL}api/public/review/ave-rat/${bookId}/average-rating`,
        {
          method: "GET",
          headers: {
            "ngrok-skip-browser-warning": "69420",
          },
        }
      );
      if (!response.ok) {
        throw new Error("Error fetching rating");
      }
      const data = await response.json();
      return data.averageRating;
    } catch (error) {
      console.error(`Error fetching rating for book ${bookId}:`, error);
      return null;
    }
  };

  const renderRating = (rating) => {
    if (rating === null || rating === undefined) {
      return "No rating available";
    } else {
      const fullStars = Math.floor(rating);
      const emptyStars = 5 - fullStars;
      return (
        <>
          {"★".repeat(fullStars)}
          {"☆".repeat(emptyStars)}
        </>
      );
    }
  };

  if (loading) {
    return <Loader />;
  }

  const chunkArray = (arr, size) => {
    const chunkedArray = [];
    for (let i = 0; i < arr.length; i += size) {
      chunkedArray.push(arr.slice(i, i + size));
    }
    return chunkedArray;
  };

  return (
    <div className="container-home">
      <Navbar />
      <div className="content-home">
        <div className="main">
          <Sidebar></Sidebar>
          <section className="section-popular">
            <div className="section-title">
              <h2>Popular Books</h2>
              <Link to="/books?sortBy=views&sortDir=DESC" className="see-more">
                <span>View All</span>
                <FontAwesomeIcon icon={faArrowRight} />
              </Link>
            </div>
            <div className="bookshome-list">
              {popularBooks.map((book) => (
                <div className="bookshome-item" key={book.id}>
                  <Link to={`/book/${book.id}`}>
                    <div className="package-tag-popular">
                      <p>Popular</p>
                    </div>
                    <img src={book.cover} alt={book.title} />
                    <div className="bookshome-inf">
                      <h3>{book.title}</h3>
                      <p className="rating">
                        {renderRating(book.averageRating)}
                      </p>
                    </div>
                  </Link>
                </div>
              ))}
            </div>
          </section>

          <section className="section-subject">
            <div className="section-title">
              <h2>Subject Section</h2>
            </div>
            <div className="grid-container">
              <Link to="/books?genre=Novel" className="subject">
                Novel
              </Link>
              <Link to="/books?genre=Self-Development" className="subject">
                Self-Development
              </Link>
              <Link to="/books?genre=Love language" className="subject">
                Love language
              </Link>
              <Link to="/books?genre=Detective" className="subject">
                Detective
              </Link>
              <Link to="/books?genre=Children's Stories" className="subject">
                Children's Stories
              </Link>
              <Link to="/books" className="subject">
                Others
              </Link>
            </div>
          </section>

          <section className="section-new">
            <div className="section-title">
              <h2>New Books</h2>
              <Link
                to="/books?sortBy=createdAt&sortDir=DESC"
                className="see-more"
              >
                <span>View All</span>
                <FontAwesomeIcon icon={faArrowRight} />
              </Link>
            </div>
            <div className="bookshome-list">
              {newBooks.map((book) => (
                <div className="bookshome-item" key={book.id}>
                  <Link to={`/book/${book.id}`}>
                    <div className="package-tag-new">
                      <p>NEW</p>
                    </div>
                    <img src={book.cover} alt={book.title} />
                    <div className="bookshome-inf">
                      <h3>{book.title}</h3>
                      <p className="rating">
                        {renderRating(book.averageRating)}
                      </p>
                    </div>
                  </Link>
                </div>
              ))}
            </div>
          </section>

          <section className="section-vip">
            <div className="section-title">
              <h2>VIP Books</h2>
              <Link to="/authors" className="see-more">
                <span>View All</span>
                <FontAwesomeIcon icon={faArrowRight} />
              </Link>
            </div>
            <div className="bookshome-list">
              {vipBooks.map((book) => (
                <div className="bookshome-item" key={book.id}>
                  <Link to={`/book/${book.id}`}>
                    <div className="package-tag-vip">
                      <p>VIP</p>
                    </div>
                    <img src={book.cover} alt={book.title} />
                    <div className="bookshome-inf">
                      <h3>{book.title}</h3>
                      <p className="rating">
                        {renderRating(book.averageRating)}
                      </p>
                    </div>
                  </Link>
                </div>
              ))}
            </div>
          </section>
        </div>

        <div className="main-second">
          <section className="section-top-books">
            <div className="section-title">
              <h2>Top 5 Books</h2>
              <Link to="/books" className="see-more">
                <span>View All</span>
                <FontAwesomeIcon icon={faArrowRight} />
              </Link>
            </div>
            <div className="bookshome-list-top">
              {topBooks.map((book, index) => (
                <div className="bookshome-item-top" key={book.id}>
                  <div className="book-rank">{index + 1}</div>
                  <div className="book-cover">
                    <img src={book.cover} alt={book.title} />
                  </div>
                  <div className="book-info">
                    <h3>{book.title}</h3>
                    <p className="rating-top">Views: {book.views}</p>
                  </div>
                </div>
              ))}
            </div>
          </section>

          <section className="section-authors">
            <div className="section-title">
              <h2>Authors</h2>
              <Link to="/authors" className="see-more">
                <span>View All</span>
                <FontAwesomeIcon icon={faArrowRight} />
              </Link>
            </div>
            <div className="authors-list">
              {chunkArray(authors.slice(0, 6), 2).map(
                (authorGroup, rowIndex) => (
                  <div className="author-row" key={rowIndex}>
                    {authorGroup.map((author) => (
                      <div key={author.id} className="authorhome-card">
                        <div className="author-header">
                          <img
                            src={author.avatar}
                            alt={author.fullName}
                            className="authorhome-image"
                          />
                          <span className="book-count">
                            <FontAwesomeIcon icon={faBook} /> :{" "}
                            {author.books.length}
                          </span>
                        </div>
                        <div className="authorhome-info">
                          <Link className="author-link">{author.fullName}</Link>
                        </div>
                      </div>
                    ))}
                  </div>
                )
              )}
            </div>
          </section>
        </div>
      </div>
      <Footer />
    </div>
  );
};

export default Home;
Leave a Comment