-
Youtube 만들기 - 8) 구독기능 만들기NODE.JS 2021. 5. 14. 19:15
이번에는 동영상의 구독기능을 만들 것이다.
model은 구독 받는 사람과 구독하는 사람으로 나누어 나타낸다.
구독하고 있으면 subscribed (회색)
구독 하지 않고 있으면 subscribe(빨간색)
버튼으로 나오도록 지정할 것이다.
먼저 server>models>Subscribers.js파일을 만들어 준다.
const mongoose = require('mongoose'); const Schema = mongoose.Schema; const subscriberSchema = mongoose.Schema({ userTo: { type:Schema.Types.ObjectId, ref:'User' }, userFrom:{ type:Schema.Types.ObjectId, ref:'User' } }, {timestamps:true})//업데이트 시간 표시 const Subscriber = mongoose.model('Subscriber', subscriberSchema) module.exports = {Subscriber }
이번엔 subscribe 버튼을 만들자.
videodetail페이지의 actions에 들어가야 하는데,
여기에 넣으면 디테일페이지의 양이 너무 길어지니까 subscribe기능을 구현하는 새로운 페이지를 이용해보자.
views>videoDetailPage>Sections>Subscribe.js파일을 새로 하나 만들어 준다.
우선 videoDetailPage안에 다음과 같이 Subscribe.js파일을 넣어준다.
import Subscribe from './Sections/Subscribe'; <List.Item actions ={[<Subscribe/>]} <List.Item.Meta avatar = {<Avatar src={VideoDetail.writer.image}/>} title = {VideoDetail.writer.name} description = {VideoDetail.description} /> </List.Item>
Subscribe.js
import Axios from 'axios' import { response } from 'express' import React, {useEffect, useState} from 'react' function Subscribe(props) { return ( <div> <button style={{backgroundColor:#CC0000, borderRadius:'4px', color:'white', padding:'10px 16px', fontWeight:'500', fontSize:'1rem', textTransform:'uppercase'}} onClick={onSubscritbe} > 0 Subscribe </button> </div> ) } export default Subscribe
db에서 구독자 수 정보를 가져와서 화면에 나타내도록 해보자.
function Subscribe(props) { const [SubscribeNumber, setSubscribeNumber] = useState(0) const [Subscribed, setSubscribed] = useState(false) useEffect(() => { let variable = {userTo: props.userTo} Axios.post('/api/subscribe/subscribeNumber', variable) .then(response=>{ if(response.data.success){ setSubscribeNumber(response.data.SubscribeNumber) }else{ alert('구독자 수 정보를 가져오는데 실패했습니다.') } }) }, [])
여기서 props.userTo는 비디오 디테일 페이지에서 subscribe에서 보내줌으로서 설정할 수 있다.
actions ={[<Subscribe userTo = {VideoDetail.writer._id} userFrom= {localStorage.getItem('userId')}/>]}//여기서 userTO 보내주면 Subscribe에서 prop으로 받아서 사용가능하다.
axios를 작성했으니 router를 구현해줘야 한다.
server의 index.js에 다음과 같은 구문을 추가해주고,
app.use('/api/subscribe', require('./routes/subscribe'));
routes>subscribe.js파일을 새로 생성해서 작성해준다.
const express = require('express'); const router = express.Router(); const {Subscriber } = require("../models/Subscriber"); const { route } = require('./users'); //================================= // Subscribe //================================= route.post("/subscribeNumber", (req, res)=>{ Subscriber.find({'userTo': req.body.userTo}) .exec((err, subscribe)=>{ if(err){ return res.status(400).send(err); } return res.status(200).json({success: true, subscribeNumger :subscribe.length})//몇명이 구독하고 있는지 길이를 센다. }) }); module.exports = router;
이번엔 사용자가 구독했는지 구독여부 정보를 가져오자.
userFrom은 로그인할때 유저의 아이디만 localStorage에 저장해두므로 그것을 가져와서 조회한다.
import Axios from 'axios' import { response } from 'express' import React, {useEffect, useState} from 'react' function Subscribe(props) { const [SubscribeNumber, setSubscribeNumber] = useState(0) const [Subscribed, setSubscribed] = useState(false) useEffect(() => { let subscribedVariable = {userTo: props.userTo, userFrom:localStorage.getItem('userId')} Axios.post('/api/subscribe/subscribed',subscribedVariable) .then(response=>{ if(response.data.success){ setSubscribed(response.data.subscribed) }else{ alert('정보를 가져오지 못했습니다.') } }) }, [])
route에 가서 다시 구독여부 정보를 가져오는 라우터를 작성해준다.
subscriber.find의 결과가 1만 되어도 이미 구독하고 있다는 뜻이 된다.
route.post("/subscribed", (req, res)=>{ Subscriber.find({'userTo': req.body.userTo, 'userFrom': req.body.userFrom}) .exec((err, subscribe)=>{ if(err){ return res.status(400).send(err); } let result = false if(subscribe.length!==0){ result = true } return res.status(200).json({success: true, subscribed : result}) }) });
구독 여부에 따라서 나타나는 버튼의 모양도 바뀌도록 설정해준다. (Subscribe.js)
return ( <div> <button style={{backgroundColor:`${Subscribed? '#AAAAAA' : '#CC0000'}`, borderRadius:'4px', color:'white', padding:'10px 16px', fontWeight:'500', fontSize:'1rem', textTransform:'uppercase'}} onClick={onSubscritbe} > {SubscribeNumber} {Subscribed ? 'Subscribed' : 'Subscribe'} </button> </div> ) }
이번에는 버튼을 클릭하므로서 생기는 구독기능과 구독취소기능을 만들 것이다.
우선 Subscribe.js에 onSubscribe 함수를 만들어 준다.
userTo와 userFrom은 비디오 디테일 페이지에서 props로 보내준 것을 가지고 온 것이다.
actions ={[<Subscribe userTo = {VideoDetail.writer._id} userFrom= {localStorage.getItem('userId')}/>]}//여기서 userTO 보내주면 Subscribe에서 prop으로 받아서 사용가능하다.
const onSubscribe = ()=>{ let subscribedVariable = { userTo: props.userTo, userFrom:props.userFrom } // 이미 구독중이라면 if(Subscribed){ Axios.post('/api/subscribe/unssubcribe', subscribedVariable) .then(response =>{ if(response.data.success){ setSubscribeNumber(SubscribeNumber-1) setSubscribed(!Subscribed) }else{ alert('구독을 취소하는데에 실패했습니다.') } }) } // 아직 구독중이 아니라면 else{ Axios.post('/api/subscribe/subscribe', subscribedVariable) .then(response =>{ if(response.data.success){ setSubscribeNumber(SubscribeNumber+1) setSubscribed(!Subscribed) }else{ alert('구독하는데에 실패했습니다.') } }) } }
axios를 작성해 주었으니 router도 작성해준다.
//구독취소 기능 route.post("/unsubscribe", (req, res)=>{ Subscriber.findOneAndDelete({'userTo': req.body.userTo, 'userFrom': req.body.userFrom}) .exec((err, doc)=>{ if(err){ return res.status(400).json({success:false, err}); } return res.status(200).json({success: true, doc}) }) }); //구독기능 route.post("/subscribe", (req, res)=>{ //새로운 구독자를 생성(userTo, userFrom 저장) const subscribe = new Subscriber(req.body) //db에 저장 subscribe.save((err, doc)=>{ if(err){ return res.status(400).json({success:false, err}); } return res.status(200).json({success: true}) }) });
추가로 만약 동영상 올린사람이 지금 로그인 된 사람과 같은 사람이라면 구독버튼이 나타나면 안되므로,
비디오 디테일 페이지를 다음과 같이 수정해준다.
import React, {useEffect, useState}from 'react' import {Row, Col, List, Avatar} from 'antd'; import Axios from 'axios'; import {response} from 'express'; import SideVideo from './Sections/SideVideo'; import Subscribe from './Sections/Subscribe'; function VideoDetailPage(props) { const videoId =props.match.params.videoId//app.js에서 :videoId 보냈기 때문에 가져올 수 있다. const variable = {videoId: videoId} const [VideoDetail, setVideoDetail] = useState([]) useEffect(() => { Axios.post('/api/video/getVideoDetail', variable) .then(response =>{ if(response.data.success){ setVideoDetail(response.data.videoDetail) }else{ alert('비디오 정보를 가져오길 실패했습니다.') } }) }, []) if(VideoDetail.writer){ //영상주인과 구독하려는 사람이 다를때만 subscribeButton 설정 const subscribeButton = VideoDetail.writer._id !==localStorage.getItem('userId') &&<Subscribe userTo = {VideoDetail.writer._id} userFrom= {localStorage.getItem('userId')}/> return ( <Row gutter={[16, 16]}> <Col lg = {18} xs = {24}> <div tyle = {{ width:'100%', padding = '3rem 4rem' }}> <video style = {{width:'100%' }}src={`http:/localhost:5000/${VideoDetail.filePath}`} controls /> <List.Item actions ={[subscribeButton]}//여기서 userTO 보내주면 Subscribe에서 prop으로 받아서 사용가능하다. > <List.Item.Meta avatar = {<Avatar src={VideoDetail.writer.image}/>} title = {VideoDetail.writer.name} description = {VideoDetail.description} /> </List.Item> {/* Comments */} </div> </Col> <Col lg = {6} xs={24}> <SideVideo /> </Col> </Row> ) } else { return ( <div>...loading</div> ) } } export default VideoDetailPage
완성된 화면을 보면,
'NODE.JS' 카테고리의 다른 글
Youtube 만들기 - 10) 댓글 기능 만들기 (0) 2021.05.14 Youtube 만들기 - 9) 구독 비디오 페이지 만들기 (0) 2021.05.14 Youtube 만들기 - 7) 비디오 디테일 페이지 만들기 (0) 2021.05.14 Youtube 만들기 - 6) 랜딩페이지에 비디오들 나타내기 (0) 2021.05.14 Youtube 만들기 - 5) 비디오 업로드 Form 만들기 4(비디오 업로드 하기) (0) 2021.05.14