diff --git a/components/Book.tsx b/components/Book.tsx index 3d81233..0b66ca5 100644 --- a/components/Book.tsx +++ b/components/Book.tsx @@ -25,5 +25,5 @@ const Book = React.memo(({ book, isFavorite, handleFavorite }) => { ); }); -export default Book; +export {Book}; diff --git a/components/BookSearch.tsx b/components/BookSearch.tsx index 6a8429b..cd094e1 100644 --- a/components/BookSearch.tsx +++ b/components/BookSearch.tsx @@ -1,125 +1,147 @@ -import React, { useState, useEffect } from 'react'; -import Book from './Book'; -import styles from '../styles/book-search.module.css'; +import React, { useEffect, useState } from "react"; -const baseUrl = 'https://gutendex.com/books'; -export const languages = ['pl', 'en', 'fr']; +import styles from "../styles/book-search.module.css"; +import { Book } from "./Book"; +import type { AppContextType, Book_t, JsonResponse } from "./appContext"; +const baseUrl = "https://gutendex.com/books"; +export const languages = ["pl", "en", "fr"]; -export function toggleStringInList(string, list) { +const DELAY = 300; + +export function toggleStringInList(string: string, list: string[]): string[] { const index = list.indexOf(string); if (index === -1) { - // String not found in the list, so add it - list.push(string); + // String not found in the list, so add it + list.push(string); } else { - // String found in the list, so remove it - list.splice(index, 1); + // String found in the list, so remove it + list.splice(index, 1); } return list; } - -function BooksSearch({ favorites, handleFavorite}) { - const [books, setBooks] = useState(null); - const [searchQuery, setSearchQuery] = useState(''); +function BooksSearch({ favorites, handleFavorite }: AppContextType) { + const [books, setBooks] = useState(null); + const [searchQuery, setSearchQuery] = useState(""); const [currUrl, setCurrUrl] = useState(baseUrl); const [prevUrl, setPrevUrl] = useState(""); const [nextUrl, setNextUrl] = useState(""); const [filterTags, setFilterdTags] = useState([]); - console.log(filterTags); - - useEffect(() => { - const delay = searchQuery ? 300 : 0; // no delay for initial fetch - const getBooksByDebouncing = setTimeout(async () => { + const delay = searchQuery ? DELAY : 0; // no delay for initial fetch + const handler = async () => { const url = new URL(currUrl); if (searchQuery) { - url.searchParams.append('search', searchQuery); - } - console.log(filterTags); - - if(filterTags.length >= 1){ - url.searchParams.append('languages', filterTags.join(',')); + url.searchParams.append("search", searchQuery); } - console.log(url); + if (filterTags.length >= 1) { + url.searchParams.append("languages", filterTags.join(",")); + } try { const response = await fetch(url); - const data = await response.json(); - const booksWithHtml = data.results.map(book => { + const data = (await response.json()) as JsonResponse; + const booksWithHtml = data.results.map((book) => { return { ...book, - htmlLink: book.formats['text/html'] + htmlLink: book.formats["text/html"], }; }); setBooks(booksWithHtml); setPrevUrl(data.previous); setNextUrl(data.next); } catch (error) { - console.error('An error occured:', error); + // eslint-disable-next-line no-console + console.error("Error fetching books", error); } - }, delay); - - return () => clearTimeout(getBooksByDebouncing) - - }, [searchQuery, currUrl, filterTags]); + }; + const getBooksByDebouncing = setTimeout(handler, delay); + return () => clearTimeout(getBooksByDebouncing); + }, [searchQuery, currUrl, filterTags]); - if(!books ){ + if (!books) { return
Loading books...
; } return (
-
+
+
+ { + setCurrUrl(baseUrl); + setSearchQuery(e.target.value); + }} + placeholder="Search for books..." + /> +
+ +
+ {languages.map((clickedLanguage) => ( + + ))} +
+ +
+ {prevUrl ? ( +
+ +
+ ) : null} + {nextUrl ? ( +
+ +
+ ) : null} +
+
- { setCurrUrl(baseUrl); setSearchQuery(e.target.value); }} - placeholder="Search for books..." - /> + {books.map((book) => ( + f.id === book.id)} + handleFavorite={handleFavorite} + /> + ))}
- -
- { - languages.map(clickedLanguage => ( - - )) - } -
- -
- {prevUrl &&
} - {nextUrl &&
} -
- - - -
- - -
- {books.map(book => ( - f.id === book.id)} - handleFavorite={handleFavorite} - /> - ))} -
); } -export default BooksSearch; +export { BooksSearch }; diff --git a/components/Favorites.tsx b/components/Favorites.tsx index 46ddb1f..8e91f6f 100644 --- a/components/Favorites.tsx +++ b/components/Favorites.tsx @@ -1,9 +1,10 @@ import React, { useState, useEffect } from 'react'; -import Book from './Book'; +import {Book} from './Book'; import styles from '../styles/book-search.module.css'; import { languages, toggleStringInList } from './BookSearch'; +import type { AppContextType } from './appContext'; -function Favorites({ favorites, handleFavorite }) { +function Favorites({ favorites, handleFavorite }: AppContextType) { const [favoriteBooks, setFavoriteBooks] = useState([]); const [searchQuery, setSearchQuery] = useState(''); const [filterTags, setFilterdTags] = useState([]); @@ -58,7 +59,7 @@ function Favorites({ favorites, handleFavorite }) {
- {favoriteBooks.map(book => ( + {favoriteBooks.map(book => ( { ); }; -export default Footer; +export {Footer} + \ No newline at end of file diff --git a/components/Hero.tsx b/components/Hero.tsx index 60c967e..bc0b8c4 100644 --- a/components/Hero.tsx +++ b/components/Hero.tsx @@ -11,5 +11,5 @@ const Hero = () => { ); }; -export default Hero; +export {Hero} diff --git a/components/NavBar.tsx b/components/NavBar.tsx index 7625716..65aed71 100644 --- a/components/NavBar.tsx +++ b/components/NavBar.tsx @@ -1,32 +1,22 @@ -import Link from 'next/link'; -import React from 'react'; -import styles from '../styles/navbar.module.css'; +import Link from "next/link"; +import React from "react"; -const NavBar = () => { +import styles from "../styles/navbar.module.css"; + +export const NavBar = () => { return ( ); }; - -export default NavBar; - - - diff --git a/components/appContext.tsx b/components/appContext.tsx index 6a4fda6..8654ea9 100644 --- a/components/appContext.tsx +++ b/components/appContext.tsx @@ -1,8 +1,40 @@ -import { createContext, useContext } from 'react'; +import { createContext, useContext } from "react"; +import type { ReactNode } from "react"; +import { Book } from "./Book"; -const AppContext = createContext(); +export interface AppContextType { + favorites: never[]; + handleFavorite?: (book: Book) => void; +} + +const AppContext = createContext({ + favorites: [], // Przykładowa domyślna wartość, dostosuj do swoich potrzeb + handleFavorite: () => {}, +}); + +export interface Book_t { + id: string; + title: string; + authors: Array<{ name: string }>; + formats: { "text/html": string} + htmlLink: string; +} + +interface AppContextProviderProps { + children: ReactNode; + value: AppContextType; +} + +export interface JsonResponse { + results: Book_t[]; + previous: string; + next: string; +} -export function AppContextProvider({ children, value }) { +export function AppContextProvider({ + children, + value, +}: AppContextProviderProps) { return {children}; } diff --git a/package-lock.json b/package-lock.json index 95c6b36..cdd2d19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "devDependencies": { "@alergeek-ventures/eslint-config": "^9.0.17", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/react": "18.3.1", + "@types/react": "^18.3.1", "@typescript-eslint/parser": "^7.6.0", "eslint": "8.57.0", "eslint-config-next": "14.2.1", diff --git a/package.json b/package.json index 3ea5250..badf9fa 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@alergeek-ventures/eslint-config": "^9.0.17", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@types/react": "18.3.1", + "@types/react": "^18.3.1", "@typescript-eslint/parser": "^7.6.0", "eslint": "8.57.0", "eslint-config-next": "14.2.1", diff --git a/pages/books.tsx b/pages/books.tsx index 20237fb..b1a0e99 100644 --- a/pages/books.tsx +++ b/pages/books.tsx @@ -1,8 +1,6 @@ - - -import NavBar from '../components/NavBar'; -import { useAppContext } from '../components/appContext'; -import BooksSearch from '../components/BookSearch'; +import { BooksSearch } from "../components/BookSearch"; +import { NavBar } from "../components/NavBar"; +import { useAppContext } from "../components/appContext"; function Books() { const { favorites, handleFavorite } = useAppContext(); @@ -16,5 +14,3 @@ function Books() { } export default Books; - - diff --git a/pages/favorites.tsx b/pages/favorites.tsx index aac1984..d9e8eb8 100644 --- a/pages/favorites.tsx +++ b/pages/favorites.tsx @@ -1,18 +1,18 @@ -import React from 'react'; -import Favorites from '../components/Favorites'; -import NavBar from '../components/NavBar'; +import React from "react"; -import { useAppContext } from '../components/appContext'; +import { Favorites } from "../components/Favorites"; +import { NavBar } from "../components/NavBar"; +import { useAppContext } from "../components/appContext"; const Fav = () => { - const { favorites, handleFavorite } = useAppContext(); + const { favorites, handleFavorite } = useAppContext(); - return ( -
- - -
- ) -} + return ( +
+ + +
+ ); +}; -export default Fav; \ No newline at end of file +export default Fav; diff --git a/pages/index.tsx b/pages/index.tsx index 037c50e..ee55ca6 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,15 +1,15 @@ 'use client'; import React from 'react'; -import NavBar from '../components/NavBar'; -import Footer from '../components/Footer'; +import {NavBar} from '../components/NavBar'; +import {Footer} from '../components/Footer'; import styles from '../styles/Home.module.css'; -import Hero from '../components/Hero'; +import {Hero} from '../components/Hero'; const Page = () => { return (
-
+
diff --git a/tsconfig.json b/tsconfig.json index 287a5e7..e99e73f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "@assets/*": ["public/legacy/assets/*"], "@public/*": ["public/*"], "@/*": ["src/*"] + }, "target": "es2016", "esModuleInterop": true,