* 모달창 컴포넌트 추가하기
components 폴더에 아래 파일을 추가한다.
import React from 'react'
import './Modal.css'
function Modal({ open, children }){
return <div className={`Modal-container ${open? "open": "close"}`}>
<div className={`Modal`}>{children}</div>
</div>
}
export default Modal;
Modal.defaultProps = {
open: false
}
Modal.js 파일을 위와 같이 작성하자!
.Modal-container{
width: 100%;
height: 100vh;
background: black;
/* opacity: 0.98; */
position: absolute;
display: none;
top: 0;
left: 0;
}
.Modal {
width: 500px;
box-shadow: rgba(255, 255, 255, 0.35) 0px 3px 15px;
background: url('../assets/images/background.jpg');
color: white;
font-weight: bold;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
text-align: center;
z-index: 1;
}
.open{
display: block;
}
.close{
display: none;
}
Modal.css 파일을 위와 같이 작성하자!
export { default as Input } from './Input'
export { default as Movie } from './Movie'
export { default as Loading } from './Loading'
export { default as Button } from './Button'
export { default as Menu } from './Menu'
export { default as Modal } from './Modal'
index.js 파일에 Modal 컴포넌트를 내보낸다.
* 사용자 등록 화면에 모달창 적용하기
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Input, Button, Modal } from 'components'
import './Register.css'
const Register = () => {
const [id, setId] = useState('')
const [password, setPassword] = useState('')
const [open, setOpen] = useState(false)
const navigate = useNavigate()
const handleChange = (e) => {
const { name, value } = e.target
name === 'id'? setId(value) : setPassword(value)
console.log(name, value)
}
const handleRegister = () => {
// 사용자 정보가 있으면 로그인 페이지로 이동하기
if(JSON.parse(sessionStorage.getItem('user'))){
navigate('/login')
// 사용자 정보가 없으면 사용자를 생성하고 홈페이지로 이동하기
}else {
// 사용자 정보를 입력하지도 않고 그냥 버튼 누르면 곧바로 데이터 저장해버림
if(id !== '' && password !== ''){
sessionStorage.setItem('user', JSON.stringify({ id, password }))
navigate('/home')
}else{
// alert('You need to give right user info.')
openModal()
}
}
}
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
}
return (
<div className='register-container'>
<Input name='id' type='text' placeholder='Type ID ...' value={id} onChange={handleChange}/><br/>
<Input name='password' type='password' placeholder='Type PASSWORD ...' value={password} onChange={handleChange}/>
<Button handleClick={handleRegister}>Register</Button>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
You need to give right user information !
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</div>
)
}
export default Register
Register.js 파일을 위와 같이 작성하자!
import { Input, Button, Modal } from 'components'
Modal 컴포넌트를 추가로 임포트한다.
const [open, setOpen] = useState(false)
모달창을 열고 닫기 위하여 open 상태를 추가한다.
// 사용자 정보를 입력하지도 않고 그냥 버튼 누르면 곧바로 데이터 저장해버림
if(id !== '' && password !== ''){
sessionStorage.setItem('user', JSON.stringify({ id, password }))
navigate('/home')
}else{
// alert('You need to give right user info.')
openModal()
}
경고창 대신 모달창을 오픈한다.
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
}
모달창을 열고 닫는 이벤트핸들러 함수이다. open 상태를 true, false 로 변경한다.
<div className='register-container'>
<Input name='id' type='text' placeholder='Type ID ...' value={id} onChange={handleChange}/><br/>
<Input name='password' type='password' placeholder='Type PASSWORD ...' value={password} onChange={handleChange}/>
<Button handleClick={handleRegister}>Register</Button>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
You need to give right user information !
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</div>
Modal 컴포넌트를 추가한다. 모달창의 header, body, footer 에는 원하는 문구나 입력창을 넣어주면 된다.
.register-container{
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: url('../assets/images/background.jpg');
}
/* 모달창 스타일링 */
.header, .body, .footer{
padding: 5px;
}
.header{
font-size: 1.2rem;
font-weight: bold;
}
.body{
font-size: 1rem;
margin: 20px;
}
.body input{
width: 60%;
height: 30px;
border: 1px solid lightgray;
border-radius: 5px;
margin-bottom: 10px;
}
.footer{
display: flex;
justify-content: flex-end;
align-items: center;
}
Register.css 파일을 위와 같이 수정하자! 모달창의 header, body, footer 관련 스타일이 추가되었다.
* 로그인 화면에 모달창 적용하기
import React, { useReducer, useState } from 'react'
import { useNavigate } from "react-router-dom"
import { Input, Button, Modal } from 'components'
import './Login.css'
const Login = () => {
const [id, setId] = useState('')
const [password, setPassword] = useState('')
const [open, setOpen] = useState(false)
const navigate = useNavigate()
const handleChange = (e) => {
const { name, value } = e.target
name === 'id' ? setId(value) : setPassword(value)
console.log(name, value)
}
const isNotValid = (user) => {
console.log(user)
return user.id === '' || user.password === ''
}
const handleLogin = () => {
// 사용자 정보가 있으니까 불러오기
const user = JSON.parse(sessionStorage.getItem('user'))
if(!isNotValid(user) && (id === user.id && password === user.password)){
navigate('/home')
}else{
// alert('You gaved wrong id or password !')
openModal()
}
}
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
}
return (
<div className='login-container'>
<Input name='id' type='text' placeholder='Type ID ...' value={id} onChange={handleChange}/><br/>
<Input name='password' type='password' placeholder='Type PASSWORD ...' value={password} onChange={handleChange}/><br/>
<Button handleClick={handleLogin}>Login</Button>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
You gaved wrong id or password !
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</div>
)
}
export default Login
Login.js 파일을 위와 같이 수정하자!
import { Input, Button, Modal } from 'components'
Modal 컴포넌트를 추가로 임포트한다.
const [open, setOpen] = useState(false)
모달창을 열고 닫기 위하여 open 상태를 추가한다.
const handleLogin = () => {
// 사용자 정보가 있으니까 불러오기
const user = JSON.parse(sessionStorage.getItem('user'))
if(!isNotValid(user) && (id === user.id && password === user.password)){
navigate('/home')
}else{
// alert('You gaved wrong id or password !')
openModal()
}
}
경고창 대신 모달창을 오픈한다.
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
}
모달창을 열고 닫는 이벤트핸들러 함수이다. open 상태를 true, false 로 변경한다.
<div className='login-container'>
<Input name='id' type='text' placeholder='Type ID ...' value={id} onChange={handleChange}/><br/>
<Input name='password' type='password' placeholder='Type PASSWORD ...' value={password} onChange={handleChange}/><br/>
<Button handleClick={handleLogin}>Login</Button>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
You gaved wrong id or password !
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</div>
Modal 컴포넌트를 추가한다. 모달창의 header, body, footer 에는 원하는 문구나 입력창을 넣어주면 된다.
.login-container{
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: url('../assets/images/background.jpg');
}
/* 모달창 스타일링 */
.header, .body, .footer{
padding: 5px;
}
.header{
font-size: 1.2rem;
font-weight: bold;
}
.body{
font-size: 1rem;
margin: 20px;
}
.body input{
width: 60%;
height: 30px;
border: 1px solid lightgray;
border-radius: 5px;
margin-bottom: 10px;
}
.footer{
display: flex;
justify-content: flex-end;
align-items: center;
}
login.css 파일을 위와 같이 수정하자! 모달창의 header, body, footer 관련 스타일이 추가되었다.
* 영화추천 페이지에 모달창 적용하기
import React, { useState, useEffect } from 'react'
import { useLocation, Link, useNavigate } from 'react-router-dom'
import { Movie, Menu, Button, Modal } from 'components'
import './Recommendation.css'
const Recommendation = () => {
const [open, setOpen] = useState(false)
// 사용자 정보 유무에 따른 페이지 접근 제한하기
const navigateToRegister = useNavigate()
const user = JSON.parse(sessionStorage.getItem('user'))
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
// alert("Sorry ! You need to register first !")
navigateToRegister('/')
}
if(!user){
useEffect ( () => {
openModal()
})
return <>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
"Sorry ! You need to register first !"
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</>
}
const location = useLocation()
const { movies } = location.state
console.log(movies)
const navigate = useNavigate()
const likes = JSON.parse(sessionStorage.getItem('likes')) || {}
console.log(likes)
const toHomePage = () => {
navigate('/home')
}
const bestMovies = movies
.sort( (a, b) => {
return (b.rating - a.rating);
})
.slice(0, 3)
.map(movie =>
<Link key={movie.id}
to='/detail'
state={{ movie }}
style={{ textDecoration: 'none', color: 'white'}}
>
<Movie
title={movie.title}
genres={movie.genres}
cover={movie.medium_cover_image}
summary={movie.summary}
year={movie.year}
rating={movie.rating}
likes={likes[movie.id]}
/>
</Link>
)
// likes 객체를 배열 객체로 변환하기
const likesArray = []
for(let like in likes){
likesArray.push({ id: like, favorite: likes[like]})
}
// favorite (좋아요 숫자) 기준으로 정렬하기
const bestMoviesByLikes = likesArray
.sort( (a, b) => {
return (b.favorite - a.favorite);
})
.slice(0, 3)
.map(likeInfo => {
const movieId = parseInt(likeInfo.id)
const movie = movies.filter(movie => movie.id === movieId)[0]
console.log('movie by likes',parseInt(likeInfo.id))
console.log('movie: ', movie)
return (
<Link key={movie.id}
to='/detail'
state={{ movie }}
style={{ textDecoration: 'none', color: 'white'}}
>
<Movie
title={movie.title}
genres={movie.genres}
cover={movie.medium_cover_image}
summary={movie.summary}
year={movie.year}
rating={movie.rating}
likes={likes[movie.id]}
/>
</Link>
)
} )
return (
<div className='Recommendation-container'>
<Menu>
<Button handleClick={toHomePage}>Home</Button>
</Menu>
<div className='Recommendation-text first-text'>Best Movies by rating</div>
<div className='Recommendation-bestmovies'>{bestMovies}</div>
<div className='Recommendation-text second-text'>Best Movies by likes</div>
<div className='Recommendation-bestmovies'>{bestMoviesByLikes}</div>
</div>
)
}
export default Recommendation
Recommendation.js 파일을 위와 같이 수정하자!
import React, { useState, useEffect } from 'react'
useState 함수를 추가로 임포트한다.
import { Movie, Menu, Button, Modal } from 'components'
Modal 컴포넌트를 추가로 임포트한다.
const [open, setOpen] = useState(false)
모달창을 열고 닫기 위하여 open 상태를 추가한다.
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
// alert("Sorry ! You need to register first !")
navigateToRegister('/')
}
모달창을 열고 닫는 이벤트핸들러 함수이다. 모달창을 닫을때 사용자 등록화면으로 이동한다.
useEffect ( () => {
openModal()
})
컴포넌트 마운트가 완료되었을때 모달창을 오픈한다.
<>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
"Sorry ! You need to register first !"
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</>
모달창을 추가하고 원하는 문구를 header, body, footer 에 넣어준다.
* 홈화면에 모달창 적용하기
import React, { useState, useEffect } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { Movie, Loading, Input, Button, Menu, Modal } from 'components'
import './Home.css'
const Home = () => {
const [open, setOpen] = useState(false)
// 사용자 정보 유무에 따른 페이지 접근 제한하기
const navigateToRegister = useNavigate()
const user = JSON.parse(sessionStorage.getItem('user'))
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
// alert("Sorry ! You need to register first !")
navigateToRegister('/')
}
if(!user){
useEffect ( () => {
openModal()
})
return <>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
"Sorry ! You need to register first !"
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</>
}
const [loading, setLoading] = useState(true)
const [movies, setMovies] = useState([])
const [query, setQuery] = useState('')
const [isSorted, setIsSorted] = useState(-1)
const [limit, setLimit] = useState(6)
const navigate = useNavigate()
const likes = JSON.parse(sessionStorage.getItem('likes')) || {}
console.log(likes)
useEffect( () => {
fetch('https://yts.mx/api/v2/list_movies.json?limit=20')
.then( res => res.json())
.then( result => {
const {data: {movies}} = result
console.log(movies)
setLoading(false)
setMovies(movies)
})
}, [])
const handleChange = (e) => {
const { value } = e.target
setQuery(value)
}
const sortByYear = (e) => {
setIsSorted(isSorted * -1)
}
const updateLikes = (id) => {
const likes = JSON.parse(sessionStorage.getItem('likes')) || {}
if(likes[id] === null || likes[id] === undefined){
likes[id] = 0
}
likes[id] += 1
sessionStorage.setItem('likes', JSON.stringify(likes))
}
const handleRemove = (id) => {
const moviesFiltered = movies.filter(movie => movie.id !== id)
setMovies(moviesFiltered)
// likes 리스트에서도 해당 영화에 대한 좋아요 정보 제거
const likes = JSON.parse(sessionStorage.getItem('likes')) || {}
delete likes[id]
sessionStorage.setItem('likes', JSON.stringify(likes))
}
const displayEntireMovies = () => {
console.log('display all movies !')
setLimit(movies.length)
}
const homeUI = movies
.filter(movie => {
const title = movie.title.toLowerCase()
const genres = movie.genres.join(' ').toLowerCase()
const q = query.toLowerCase()
return title.includes(q) || genres.includes(q)
})
.sort( (a, b) => {
return (b.year - a.year) * isSorted;
})
.slice(0, limit)
.map(movie =>
<div className='movie-item' key={movie.id} >
<div className='movie-delete' onClick={(e) => handleRemove(movie.id)}>X</div>
<Link
to='/detail'
state={{ movie }}
style={{ textDecoration: 'none', color: 'white'}}
onClick={() => updateLikes(movie.id)}
>
<Movie
title={movie.title}
genres={movie.genres}
cover={movie.medium_cover_image}
summary={movie.summary}
year={movie.year}
rating={movie.rating}
likes={likes[movie.id]}
/>
</Link>
</div>
)
const toRankPage = () => {
navigate('/recommend', { state: { movies }})
}
return (
<>
{loading? <Loading/>: <div className='Home-container'>
<Menu>
<Button handleClick={toRankPage}>Rank</Button>
</Menu>
<div className='Home-entire'>
<Button handleClick={displayEntireMovies}>See Entire Movies</Button>
</div>
<div className='Home-contents'>
<Input name='search' type='text' placeholder='Search movies ...' value={query} onChange={handleChange}/>
<Button handleClick={sortByYear}>정렬</Button>
<div className='Home-movies'>{homeUI}</div>
</div>
</div>}
</>
)
}
export default Home
Home.js 파일을 위와 같이 수정하자!
import { Movie, Loading, Input, Button, Menu, Modal } from 'components'
Modal 컴포넌트를 추가로 임포트한다.
const [open, setOpen] = useState(false)
// 사용자 정보 유무에 따른 페이지 접근 제한하기
const navigateToRegister = useNavigate()
const user = JSON.parse(sessionStorage.getItem('user'))
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
// alert("Sorry ! You need to register first !")
navigateToRegister('/')
}
if(!user){
useEffect ( () => {
openModal()
})
return <>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
"Sorry ! You need to register first !"
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</>
}
영화추천 페이지와 동일한 코드가 추가되었다.
* 상세페이지에 모달창 적용하기
import React, { useEffect, useState } from 'react'
import { Movie, Button, Menu, Modal } from 'components'
import { useLocation, useNavigate } from 'react-router-dom'
import './Detail.css'
const Detail = () => {
const [open, setOpen] = useState(false)
// 사용자 정보 유무에 따른 페이지 접근 제한하기
const navigateToRegister = useNavigate()
const user = JSON.parse(sessionStorage.getItem('user'))
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
// alert("Sorry ! You need to register first !")
navigateToRegister('/')
}
if(!user){
useEffect ( () => {
openModal()
})
return <>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
"Sorry ! You need to register first !"
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</>
}
const location = useLocation()
const { movie } = location.state
const { yt_trailer_code } = movie
console.log(movie)
const navigate = useNavigate()
const likes = JSON.parse(sessionStorage.getItem('likes')) || {}
console.log(likes)
const watchMovieTrailer = () => {
window.location.href = yt_trailer_code? `https://www.youtube.com/watch?v=${yt_trailer_code}`: ""
}
const toHomePage = () => {
navigate('/home')
}
return (
<div className='Detail-container'>
<Menu>
<Button handleClick={toHomePage}>Home</Button>
</Menu>
<div className='Detail-contents'>
<Movie title={movie.title}
genres={movie.genres}
cover={movie.medium_cover_image}
summary={movie.summary}
year={movie.year}
rating={movie.rating}
likes={likes[movie.id]}>
</Movie>
<div className='Movie-info'>
<p className='Movie-runtime'>Runtime {movie.runtime} min.</p>
<p className='Movie-summary'>{movie.summary}</p>
<a href={movie.torrents.length !== 0 ? movie.torrents[0].url : ''} download>Download Torrent</a><br/>
<Button handleClick={watchMovieTrailer}>Watch Youtube trailer</Button>
</div>
</div>
</div>
)
}
export default Detail
Detail.js 파일을 위와 같이 작성하자!
import React, { useEffect, useState } from 'react'
useState 함수를 추가로 임포트한다.
import { Movie, Button, Menu, Modal } from 'components'
Modal 컴포넌트를 추가로 임포트한다.
const [open, setOpen] = useState(false)
// 사용자 정보 유무에 따른 페이지 접근 제한하기
const navigateToRegister = useNavigate()
const user = JSON.parse(sessionStorage.getItem('user'))
const openModal = () => {
setOpen(true)
}
const closeModal = () => {
setOpen(false)
// alert("Sorry ! You need to register first !")
navigateToRegister('/')
}
if(!user){
useEffect ( () => {
openModal()
})
return <>
{/* 모달창 */}
<Modal open={open}>
<div className="header">-- Warning message --</div>
<div className="body">
"Sorry ! You need to register first !"
</div>
<div className="footer">
<Button size="small" handleClick={closeModal}>Close</Button>
</div>
</Modal>
</>
}
영화추천 페이지와 동일한 코드가 추가되었다.
'프로젝트 > 영화 목록 (Netflix) 앱' 카테고리의 다른 글
영화목록 (Netflix) 앱 11.2 - 404 페이지 (0) | 2021.11.26 |
---|---|
영화목록 (Netflix) 앱 12 - 파이어베이스에 배포하기 (0) | 2021.11.25 |
영화목록 (Netflix) 앱 10 - 페이지 접근제한 설정하기 (0) | 2021.11.25 |
영화목록 (Netflix) 앱 9 - 홈화면에 영화목록 전체보기 기능 만들기 (0) | 2021.11.25 |
영화목록 (Netflix) 앱 8 - 영화 목록에서 특정 영화 삭제하기 (0) | 2021.11.25 |