-
영화목록 (Netflix) 앱 11 - 모달창 사용하기프로젝트/영화 목록 (Netflix) 앱 2021. 11. 25. 21:52728x90
* 모달창 컴포넌트 추가하기
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> </> }
영화추천 페이지와 동일한 코드가 추가되었다.
728x90'프로젝트 > 영화 목록 (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