diff --git a/public/pictures/hammer.png b/public/pictures/hammer.png new file mode 100644 index 0000000..227d5c9 Binary files /dev/null and b/public/pictures/hammer.png differ diff --git a/src/components/loader.jsx b/src/components/loader.jsx new file mode 100644 index 0000000..112cbaf --- /dev/null +++ b/src/components/loader.jsx @@ -0,0 +1,9 @@ +import '../style/loader.scss'; + +export default function Loader() { + return ( +
+

Loading.....

+
+ ); +} diff --git a/src/components/marvel-characters.jsx b/src/components/marvel-characters.jsx index 7dbb5d6..9708628 100644 --- a/src/components/marvel-characters.jsx +++ b/src/components/marvel-characters.jsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'; import Card from '../components/card'; import Modal from '../components/modal'; import Profile from '../components/profile'; +import Loader from './loader'; const publicKey = import.meta.env.VITE_PUBLIC_KEY; @@ -12,10 +13,12 @@ export default function MarvelCharacters({ addToFavorites }) { const [isModalOpen, setIsModalOpen] = useState(false); const [comics, setComics] = useState([]); const [currentPage, setCurrentPage] = useState(0); - const charactersPerPage = 20; + const [loading, setLoading] = useState(true); + const [err, setError] = useState(null); + const charactersPerPage = 15; useEffect(() => { - const apiComics = `https://gateway.marvel.com/v1/public/characters?apikey=${publicKey}&limit=100`; + const apiComics = `https://gateway.marvel.com/v1/public/characters?apikey=${publicKey}&limit=40`; fetch(apiComics) .then((res) => { @@ -23,14 +26,29 @@ export default function MarvelCharacters({ addToFavorites }) { return res.json(); }) .then((data) => { - const randomCharacters = data.data.results.sort(() => Math.random() - 1); - setMarvelCharacter(randomCharacters); + const filteredCharacters = data.data.results.filter( + (marvel) => + marvel.thumbnail && + marvel.thumbnail.path && + marvel.thumbnail.extension && + !marvel.thumbnail.path.includes('image_not_available'), + ); + setLoading(false); + setMarvelCharacter(filteredCharacters); }) - // eslint-disable-next-line no-console - .catch((err) => console.error(err)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [MarvelCharacters]); + .catch((err) => { + setError(err); + setLoading(false); + }); + }, []); + + if (loading) + return ( +
+ +
+ ); const handleAddToFavorites = (character) => { addToFavorites(character); }; @@ -84,6 +102,8 @@ export default function MarvelCharacters({ addToFavorites }) { ) .slice(currentPage * charactersPerPage, (currentPage + 1) * charactersPerPage); + if (err) return
Error: {err.message}
; + return (
diff --git a/src/style/loader.scss b/src/style/loader.scss new file mode 100644 index 0000000..50cae57 --- /dev/null +++ b/src/style/loader.scss @@ -0,0 +1,29 @@ +@use 'settings' as *; + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.load { + display: flex; + flex-direction: column; + align-items: center; + + p { + padding-bottom: 20px; + color: white; + font-size: 50px; + + font-family: $font-family; + } + img { + width: 150px; + animation: spin 1s linear infinite; + padding-top: 20px; + } +}