Дипломная работа: Социальная подкаст-платформа

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

});

};

render() {

this.episodes = [];

let episodeList = this.state.episodes.map(ep =>

<EpisodePanel

episode={ep}

key={ep.id}

history={this.props.history}

closeAllComments={this.closeAllComments}

ref={'episode' + ep.id}

/>

);

return (

<div>

{this.state.episodes.length === 0 && <WelcomePanel/>}

{episodeList}

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\ PodcastPage.js

import Navbar from '../Navbar';

import PodcastProfile from "./PodcastProfile";

import PodcastPageContent from './PodcastPageContent';

import {getCookie} from '../Helper';

const React = require('react');

export default class PodcastPage extends React.Component {

constructor(props) {

super(props);

this.state = {

podcast: null,

coauthors: [],

coauthorsInfo: [],

myPodcast: false

};

}

componentDidMount() {

this.loadPodcastInfo();

}

loadPodcastInfo() {

fetch(`/getPodcastById?id=${this.props.match.params.podcastId}`)

.then((response) => {

return response.json()

})

.then((json) => {

console.log(json);

this.setState({podcast: json});

this.loadCoauthors();

});

}

loadCoauthors() {

fetch(`/getCoauthors?podcastId=${this.props.match.params.podcastId}`)

.then((response) => {

return response.json()

})

.then((json) => {

let coauthorsIds = [this.state.podcast.authorId.toString(),...json.map(x => x.userId.toString())];

console.log(coauthorsIds)

this.setState({coauthors: coauthorsIds});

this.loadCoauthorsInfo(coauthorsIds);

this.myPodcastCheck();

});

}

myPodcastCheck() {

if (this.state.coauthors.indexOf(getCookie("userId")) !== -1) this.setState({myPodcast: true});

}

loadCoauthorsInfo(coauthorsIds) {

let data = {

"ids": coauthorsIds

};

$.ajax({

url: `/getCoauthorsByIdList`,

type: 'post',

contentType: 'application/json',

data: JSON.stringify(data),

success: (response) => {

console.log(response);

this.setState({coauthorsInfo: response});

},

error: (jqXhr, textStatus, errorThrown) => {

console.log(errorThrown + " " + textStatus);

}

});

}

render() {

return (

<div>

<Navbar history={this.props.history}/>

<div className="container-fluid">

{this.state.podcast !== null &&

<div style={{display: "flex",}}>

<div style={{width: "25%"}}>

<PodcastProfile podcast={this.state.podcast} coauthors={this.state.coauthorsInfo}

history={this.props.history}/>

</div>

<div style={{width: "50%"}}>

<PodcastPageContent

feed={false}

podcastId={this.state.podcast.id}

myPodcast={this.state.myPodcast}

history={this.props.history}

/>

</div>

<div style={{width: "25%"}}>

</div>

</div>}

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\ PodcastPageContent.js

import React, {Component} from 'react';

import {Button, ButtonGroup} from 'react-bootstrap';

import PodcastList from './PodcastList';

import TweetPage from './tweets/TweetPage';

export default class PodcastPageContent extends Component {

constructor() {

super();

this.state = {

tweetPage: false

}

}

onTweetPageClick = (e) => {

this.setState({tweetPage: true});

e.target.blur();

};

onPodcastPageClick = (e) => {

this.setState({tweetPage: false});

e.target.blur();

};

render() {

return (

<div style={{textAlign: "center"}}>

<ButtonGroup style={{marginBottom: 20}}>

<Button

onClick={this.onPodcastPageClick}

style={{width: 100}}

bsStyle={!this.state.tweetPage ? "info": "default"}>

Выпуски

</Button>

<Button

onClick={this.onTweetPageClick}

style={{width: 100}}

bsStyle={this.state.tweetPage ? "info": "default"}>

Микроблог

</Button>

</ButtonGroup>

{this.state.tweetPage ? <TweetPage

feed={this.props.feed}

podcastId={this.props.podcastId}

myPodcast={this.props.myPodcast}

history={this.props.history}

/>:

<PodcastList

feed={this.props.feed}

podcastId={this.props.podcastId}

history={this.props.history}

/>

}

</div>

);

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\ PodcastProfile.js

import {getCookie, getFullCSRFParam} from '../Helper';

const React = require('react');

export default class PodcastProfile extends React.Component {

constructor(props) {

super(props);

this.state = {

genres: null,

podcast: null,

myDecision: 0,

mySubscribe: false,

isUserSignedIn: false,

extraSub: 0,

emptyLinks: false

};

}

componentDidMount() {

const podcast = this.state.podcast === null ? this.props.podcast: this.state.podcast;

if (podcast.itunesLink === "" && podcast.vkLink === "" && podcast.twitterLink === "" && podcast.facebookLink === "") this.setState({emptyLinks: true})

this.isUserLogIn();

this.loadAllGenres();

}

loadAllGenres() {

fetch(`/getAllGenres`)

.then((response) => {

return response.json()

})

.then((json) => {

console.log(json)

this.setState({genres: json, loadData: this.state.loadData + 1});

});

}

ratingChange = (rating) => {

if (this.state.isUserSignedIn === false) {

this.props.history.push('/signin');

} else {

let obj = {

"podcastId": this.props.podcast.id,

"userId": getCookie('userId'),

"decision": rating,

};

let rate = JSON.stringify(obj);

const that = this;

$.ajax({

url: `/vote?${getFullCSRFParam()}`,

type: 'post',

contentType: 'application/json',

data: rate,

success: () => {

this.setState({myDecision: rating ? 1: -1});

this.loadNewPodcastInfo();

},

error: (jqXhr, textStatus, errorThrown) => {

console.log(errorThrown + " " + textStatus);

}

});

}

};

isUserLogIn() {

let username = getCookie("username");

if (username === "" || username === undefined) {

this.setState({isUserSignedIn: false});

return false;

}

fetch(`/loginCheck?${getFullCSRFParam()}`, {

method: 'POST'

}).then((response) => {

if (response.status === 200 && !response.redirected) {

this.setState({isUserSignedIn: true});

this.loadUserRatingAndSubscribeInfo();

return true;

} else {

this.setState({isUserSignedIn: false});

return false;

}

});

}

loadNewPodcastInfo() {

fetch(`/getPodcastById?id=${this.props.podcast.id}`)

.then((response) => {

return response.json()

})

.then((json) => {

this.setState({podcast: json});

});

}

loadUserRatingAndSubscribeInfo() {

fetch(`/getMyVote?userId=${getCookie("userId")}&podcastId=${this.props.podcast.id}`)

.then((response) => {

return response.json()

})

.then((json) => {

console.log(json);

this.setState({myDecision: json});

this.loadUserSubscribeInfo();

});

}

loadUserSubscribeInfo() {

fetch(`/getMySubscribe?userId=${getCookie("userId")}&podcastId=${this.props.podcast.id}`)

.then((response) => {

return response.json()

})

.then((json) => {

console.log(json);

this.setState({mySubscribe: json});

});

}

subscribeStateChange = () => {

if (this.state.isUserSignedIn === false) {

this.props.history.push('/signin');

} else {

fetch(`/subscribe?userId=${getCookie("userId")}&podcastId=${this.props.podcast.id}`)

.then((response) => {

if (response.status === 200) {

this.setState({mySubscribe: !this.state.mySubscribe})

this.loadNewPodcastInfo();

}

});

}

};

render() {

const podcast = this.state.podcast === null ? this.props.podcast: this.state.podcast;

return (

<div className="container-fluid">

<div className="panel panel-info">

<div className="panel-body" style={{maxWidth: "100%"}}>

<div className="row">

<div className="col-xs-4" style={{width: "180px", marginBottom: -20}}>

<div className="panel panel-info"

style={{width: "150px", textAlign: "center", paddingBottom: 10}}>

<br></br>

<img src="/images/podcastDefaultLogo.png"

className="img-rounded" style={{width: "120px"}}></img><br></br>

<div className="panel-body">

<button onClick={() => {

this.ratingChange(false)

}} type="button"

className={this.state.myDecision === -1 ? "btn btn-danger btn-xs": "btn btn-info btn-xs"}>

<span

className="glyphicon glyphicon-minus">

</span>

</button>

&#160;<span className="badge">{podcast.rating}</span>&#160;

<button onClick={() => {

this.ratingChange(true)

}} type="button"

className={this.state.myDecision === 1 ? "btn btn-success btn-xs": "btn btn-info btn-xs"}>

<span

className="glyphicon glyphicon-plus">

</span>

</button>

</div>

</div>

<div>

<button

type="button"

style={{width: "150px"}}

className={this.state.mySubscribe ? "btn btn-success btn-md": "btn btn-info btn-md"}

onClick={() => {

this.subscribeStateChange()

}}

>

{this.state.mySubscribe ? "Отписаться": "Подписаться"}

</button>

</div>

<br></br>

</div>

<div className="container-fluid">

<h4>{podcast.name}</h4>

<h4>

{this.state.genres !== null &&

<small>{this.state.genres[podcast.genreId].name}</small>}

</h4>

<hr></hr>

<p className="text-justify" style={{minHeight: 160}}>{podcast.description}</p>

<hr></hr>

<div className="row">

<div className="col-xs-6">

<h5 className="text-center">Подписчиков: {podcast.subscribersCount}</h5>

</div>

<div className="col-xs-6">

<h5 className="text-center">Выпусков: {podcast.episodeCount}</h5>

</div>

</div>

{!this.state.emptyLinks && <div>

<hr></hr>

</div>}

{!this.state.emptyLinks && <div className="container-fluid text-center">

{podcast.itunesLink !== "" && <a href={podcast.itunesLink}><img

src="/images/itunesLogo.png"

className="img-rounded" style={{width: "30px", margin: "0 10px 0 10px"}}></img></a>}

{podcast.vkLink !== "" && <a href={podcast.vkLink}><img

src="/images/vkLogo.png"

className="img-rounded" style={{width: "30px", margin: "0 10px 0 10px"}}></img></a>}

{podcast.twitterLink !== "" && <a href={podcast.twitterLink}><img

src="/images/twitterLogo.png"

className="img-rounded" style={{width: "30px", margin: "0 10px 0 10px"}}></img></a>}

{podcast.facebookLink !== "" && <a href={podcast.facebookLink}><img

src="/images/facebookLogo.png"

className="img-rounded" style={{width: "30px", margin: "0 10px 0 10px"}}></img>

</a>}

</div>}

<hr></hr>

<div>

<h5>Ведущие:</h5>

<div className="container-fluid text-center">

{this.props.coauthors.map(item =>

<a key={item.id} onClick={() => {

this.props.history.push(`/user/${item.username}`)

}}>

<h4>{item.name} (@{item.username})</h4>

</a>

)}

</div>

</div>

</div>

</div>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\tweets\ DeleteTweetButton.js

const React = require('react');

export default class Navbar extends React.Component {

constructor(props) {

super(props);

}

render() {

return (

<button type="button"

className="btn btn-info btn-xs pull-right"

onClick={this.props.onDelete}

style={{marginLeft: -24}}

>

<span className="glyphicon glyphicon-remove"></span>

</button>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\tweets\ LoadingPanel.js

const React = require('react');

export default class LoadingPanel extends React.Component {

constructor(props) {

super(props);

}

render() {

return (

<div hidden={this.props.hidden}>

<img className="center-block" src="/images/loading.svg" width="70" height="70"/>

<br/>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\tweets\ Tweet.js

const React = require('react');

const url = '/deleteTweet?tweetId=';

import DeleteTweetButton from './DeleteTweetButton';

import {getCookie, getFullCSRFParam} from "../../Helper";

export default class Tweet extends React.Component {

constructor(props) {

super(props);

}

delete() {

const that = this;

const tweetId = this.props.tweet.id;

$.ajax({

url: url + tweetId + '&' + getFullCSRFParam(),

type: 'post',

success: () => {

that.props.callbackFromChild(tweetId);

},

error: (jqXhr, textStatus, errorThrown) => {

console.log(errorThrown + " " + textStatus);

}

});

}

render() {

const {text, creationDate, authorUsername} = this.props.tweet;

return (

<div className="container-fluid">

<div className="panel panel-info" style={{marginBottom: 10}}>

<div className="panel-body" style={{backgroundColor: '#ffffff'}}>

<div>

{this.props.myPodcast && getCookie("username") === authorUsername &&

<DeleteTweetButton onDelete={this.delete.bind(this)}/>}

<font size="3"><a onClick={() => {

this.props.history.push(`/user/${authorUsername}`)

}}>@{authorUsername}</a></font>

<h5 style={{color: '#acacac', marginBottom: 0}}>{creationDate}</h5>

</div>

<hr style={{margin: "10px 0 15px 0"}}/>

<font size="3" style={{whiteSpace: "pre-wrap"}}>{text}</font>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\tweets\ TweetInput.js

import {getCookie, getFullCSRFParam} from "../../Helper";

const React = require('react');

const addTweetUrl = '/addTweet';

export default class TweetInput extends React.Component {

constructor(props) {

super(props);

this.state = {value: ''};

}

handleSubmit = () => {

if (this.state.value !== '') {

this.addNewTweet();

}

};

addNewTweet() {

let obj = {

"text": this.state.value,

"authorUsername": getCookie("username"),

"authorId": getCookie("userId"),

"podcastId": this.props.podcastId

};

let tweetJson = JSON.stringify(obj);

const that = this;

$.ajax({

url: addTweetUrl + '?' + getFullCSRFParam(),

type: 'post',

contentType: 'application/json',

data: tweetJson,

success: () => {

that.afterPostNewTwit();

},

error: (jqXhr, textStatus, errorThrown) => {

console.log(errorThrown + " " + textStatus);

}

});

}

afterPostNewTwit() {

console.log("Tweet: " + this.state.value);

this.setState({value: ''});

this.refs.tweetTextarea.value = '';

this.refs.tweetTextarea.focus();

this.props.callbackFromChild();

}

handleChange = (event) => {

this.setState({value: event.target.value});

};

render() {

return (

<div className="container-fluid">

<div className="panel panel-info">

<div className="panel-body">

<div className="form-group shadow-textarea">

<textarea style={{resize: 'none'}} className="form-control z-depth-1"

rows="4" maxLength="200" autoFocus ref="tweetTextarea"

placeholder="What's happening?" onChange={this.handleChange}>

</textarea>

</div>

<div className="btn-group-md">

<button onClick={this.handleSubmit} type="button" className="btn btn-info pull-right"

style={{width: 100}}>Tweet

</button>

</div>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\tweets\ TweetList.js

const React = require('react');

import Tweet from './Tweet';

export default class TweetList extends React.Component {

constructor(props) {

super(props);

}

deleteTwitCallback(id) {

this.props.callbackFromChild(id);

}

render() {

let tweets = this.props.tweets.map(tweet =>

<Tweet id={"tweet" + tweet.id}

key={"tweet" + tweet.id}

tweet={tweet}

callbackFromChild={this.deleteTwitCallback.bind(this)}

myPodcast={this.props.myPodcast}

history={this.props.history}

/>

);

const date = new Date();

console.log("Rerender TweetList at time: " + date.getMinutes() + "." + date.getSeconds() + "." + date.getMilliseconds());

return (

<div>

{tweets}

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\tweets\ TweetPage.js

const React = require('react');

import TweetList from './TweetList';

import TweetInput from './TweetInput';

import WelcomePanel from './WelcomePanel';

import LoadingPanel from './LoadingPanel';

import {getCookie} from '../../Helper';

export default class TweetPage extends React.Component {

constructor(props) {

super(props);

this.state = {

tweets: [],

currPage: 0,

pageSize: 10,

allPages: false,

numberOfTweets: 0,

loading: false,

loadImg: null

};

}

componentDidMount() {

this.getNewPageOfTweetsFromServer(0, this.state.pageSize * (this.state.currPage + 1));

const that = this;

/**

* Проверяет конец страницы, если так и страница не последняя, то грузит новую страницу твитов.

*/

window.onscroll = () => {

if (!that.state.allPages && !that.state.loading) {

if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - 100)) {

let nextPage = that.state.currPage + 1;

console.log("End of page, load next page: " + nextPage);

that.setState({currPage: nextPage, loading: true});

that.getNewPageOfTweetsFromServer(nextPage, that.state.pageSize);

}

}

};

}

/**

* Грузит с сервера последний твит, помещает его в массив твитов, удаляет последний элемент массива

* если не последняя страница и ререндерит компонент.

*/

refreshTweetArrayAfterAdd() {

fetch(`${this.props.feed ? "/getAllTwitsByUserIdFeed": "/getAllTwitsByPodcastId"}?page=0&size=1&id=${this.props.feed ? getCookie('userId'): this.props.podcastId}`)

.then((response) => {

return response.json()

})

.then((json) => {

let array = this.state.tweets;

if (!this.state.allPages) array.splice(array.length - 1, 1);

this.setState({tweets: json.content.concat(array)});

});

}

/**

* Загружает заново с сервера все страницы и ререндерит компонент.

* @param id айдишник удаляемого твита.

*/

refreshTweetArrayAfterDelete(id) {

fetch(`${this.props.feed ? "/getAllTwitsByUserIdFeed": "/getAllTwitsByPodcastId"}?page=0&size=${(this.state.currPage + 1) * this.state.pageSize}&id=${this.props.feed ? getCookie('userId'): this.props.podcastId}`)

.then((response) => {

return response.json()

})

.then((json) => {

this.setState({tweets: json.content});

const date = new Date();