Skip to content

Commit

Permalink
Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
annadawiec committed Jul 31, 2023
1 parent 6f0706e commit 11112e0
Show file tree
Hide file tree
Showing 21 changed files with 1,222 additions and 62 deletions.
518 changes: 468 additions & 50 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.4.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-loader-spinner": "^5.3.4",
"react-router-dom": "^6.14.2",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.3"
},
Expand Down Expand Up @@ -36,5 +39,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"prop-types": "^15.8.1"
}
}
34 changes: 23 additions & 11 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import { Routes, Route } from 'react-router-dom';
import { lazy } from 'react';

const Layout = lazy(() => import('../pages/Layout/Layout'));
const Home = lazy(() => import('../pages/Home/Home'));
const Movies = lazy(() => import('../pages/Movies/Movies'));
const MovieDetails = lazy(() => import('../pages/MovieDetails/MovieDetails'));
const Cast = lazy(() => import('../components/Cast/Cast'));
const Reviews = lazy(() => import('../components/Reviews/Reviews'));
const NotFound = lazy(() => import('../pages/NotFound'));

export const App = () => {
return (
<div
style={{
height: '100vh',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
fontSize: 40,
color: '#010101'
}}
>
React homework template
<div>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="/movies" element={<Movies />} />
<Route path="/movies/:movieId" element={<MovieDetails />}>
<Route path="cast" element={<Cast />} />
<Route path="reviews" element={<Reviews />} />
</Route>
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</div>
);
};
35 changes: 35 additions & 0 deletions src/components/Cast/Cast.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { searchMovieCredits } from 'components/SearchMovies';
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import css from './Cast.module.css';

const Cast = () => {
const { movieId } = useParams('movieId');
const [credits, setCredits] = useState([]);

useEffect(() => {
searchMovieCredits(movieId).then(setCredits);
}, [movieId]);

return (
<div className={css.cast_container}>
{credits.length > 0 && (
<ul className={css.cast_list}>
{credits.map(({ id, name, character, photo }) => {
return (
<li key={id} className={css.cast_item}>
<img src={photo} alt={name} className={css.cast_img} />
<div className={css.cast_description}>
<p className={css.cast_name}>{name}</p>
<p className={css.cast_character}>Character: {character}</p>
</div>
</li>
);
})}
</ul>
)}
</div>
);
};

export default Cast;
61 changes: 61 additions & 0 deletions src/components/Cast/Cast.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.cast_container {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px;
background-color: #3f51b542;
margin: 20px 30px 30px;
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%),
0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
}

.cast_list {
display: flex;
flex-wrap: wrap;
max-width: 100%;
margin-top: 0;
margin-left: auto;
margin-right: auto;
justify-content: center;
padding: 0;
transition-duration: 300ms;
}

.cast_item {
background: rgb(255, 255, 255);
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%),
0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
width: 100%;
max-width: 200px;
margin: 10px;
border-radius: 5px;
display: inline-block;
text-decoration: none;
color: black;
transition-duration: 300ms;
}

.cast_img {
padding: 0px;
margin: 0px;
height: 260px;
width: 100%;
display: block;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}

.cast_description {
padding: 5px;
margin: 0px;
font-size: 10px;
color: #3f51b5;
}

.cast_name {
margin: 0px;
}

.cast_character {
margin: 0px;
}
Binary file added src/components/Images/noImages.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/components/Loader/Loader.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { RotatingLines } from 'react-loader-spinner';
import css from './Loader.module.css';

const Loader = () => {
return (
<div className={css.loading}>
<RotatingLines
strokeColor="#3f51b590"
strokeWidth="5"
animationDuration="0.75"
width="150"
visible={true}
/>
</div>
);
};

export default Loader;
4 changes: 4 additions & 0 deletions src/components/Loader/Loader.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.loading {
position: relative;
top: 10vh;
}
32 changes: 32 additions & 0 deletions src/components/Reviews/Reviews.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { searchMovieReviews } from 'components/SearchMovies';
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import css from './Reviews.module.css';

const Reviews = () => {
const { movieId } = useParams('movieId');
const [reviews, setReviews] = useState([]);

useEffect(() => {
searchMovieReviews(movieId).then(setReviews);
}, [movieId]);

return (
<div className={css.reviews_container}>
{reviews.length > 0 ? (
<ul>
{reviews.map(({ id, author, content }) => (
<li key={id}>
<h3>{author}</h3>
<p>{content}</p>
</li>
))}
</ul>
) : (
<p>We don`t have any reviews for this movie</p>
)}
</div>
);
};

export default Reviews;
10 changes: 10 additions & 0 deletions src/components/Reviews/Reviews.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.reviews_container {
display: flex;
padding: 30px;
background-color: #3f51b542;
margin: 20px 30px 30px;
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%),
0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
flex-direction: column;
align-items: center;
}
100 changes: 100 additions & 0 deletions src/components/SearchMovies.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import axios from 'axios';
import noPhoto from '../components/Images/noImages.png';

axios.defaults.baseURL = 'https://api.themoviedb.org/3';
axios.defaults.params = {
api_key: 'd3144e85ee72b64927195b1f7c37d3bd',
include_adult: false,
};

const IMG_URL = 'https://image.tmdb.org/t/p/w500';

export const searchTranding = async () => {
return axios
.get(`/trending/all/day?`)
.then(({ data: { results } }) =>
results.map(({ id, title, poster_path: poster }) => ({
id,
title,
poster: IMG_URL + poster,
}))
)
.catch(error => {
console.log(error.message);
});
};

export const searchByName = async name => {
return axios
.get(`/search/movie?query=${name}`)
.then(({ data: { results } }) =>
results.map(({ id, title, poster_path: poster }) => ({
id,
title,
poster: IMG_URL + poster,
}))
)
.catch(error => {
console.log(error.message);
});
};

export const searchMovieDetails = movieId => {
return axios
.get(`/movie/${movieId}?`)
.then(
({
data: {
id,
poster_path: poster,
title,
release_date: releaseYear,
vote_average: userScore,
overview,
genres,
},
}) => ({
id,
poster: IMG_URL + poster,
title,
releaseYear: new Date(releaseYear).getFullYear(),
userScore: Math.round(userScore * 10),
overview,
genres,
})
)
.catch(error => {
console.log(error.message);
});
};

export const searchMovieCredits = movieId => {
return axios
.get(`/movie/${movieId}/credits?`)
.then(({ data: { cast } }) =>
cast.map(({ id, name, character, profile_path: photo }) => ({
id,
name,
character,
photo: photo ? IMG_URL + photo : noPhoto,
}))
)
.catch(error => {
console.log(error.message);
});
};

export const searchMovieReviews = movieId => {
return axios
.get(`/movie/${movieId}/reviews?`)
.then(({ data: { results } }) =>
results.map(({ id, author, content }) => ({
id,
author,
content,
}))
)
.catch(error => {
console.log(error.message);
});
};
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from 'components/App';
import { BrowserRouter } from 'react-router-dom';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
37 changes: 37 additions & 0 deletions src/pages/Home/Home.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useState, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { searchTranding } from 'components/SearchMovies';
import { Link } from 'react-router-dom';
import css from './Home.module.css';

const Home = () => {
const [movies, setMovies] = useState([]);
const location = useLocation();
useEffect(() => {
searchTranding().then(setMovies);
}, []);

return (
<div className={css.home_container}>
<h1 className={css.home_title}>Tranding today</h1>
{movies.length > 0 && (
<ul className={css.movie_list}>
{movies.map(({ id, title, poster }) => (
<li key={id} className={css.movie_item}>
<Link
to={`/movies/${id}`}
state={{ from: location }}
className={css.movie_link}
>
<img src={poster} alt={title} className={css.movie_img} />
<h3 className={css.movie_title}>{title}</h3>
</Link>
</li>
))}
</ul>
)}
</div>
);
};

export default Home;
Loading

0 comments on commit 11112e0

Please sign in to comment.