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

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

console.log("Deleting tweet at time: " + date.getMinutes() + "." + date.getSeconds() + "." + date.getMilliseconds());

this.lastPageCheck(json);

});

}

/**

* Получает новую страницу твитов, добавляет её к уже существующему массиву твитов и ререндерит компонент.

*/

getNewPageOfTweetsFromServer(page, pagesize) {

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

.then((response) => {

return response.json()

})

.then((json) => {

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

this.setState({numberOfTweets: json.totalElements});

this.lastPageCheck(json);

this.setState({loading: false});

});

}

lastPageCheck(json) {

this.setState({allPages: json.last});

}

addTweetCallback() {

this.refreshTweetArrayAfterAdd();

this.setState({numberOfTweets: (this.state.numberOfTweets + 1)});

}

deleteTwitCallback(id) {

this.refreshTweetArrayAfterDelete(id);

this.setState({numberOfTweets: (this.state.numberOfTweets - 1)});

}

render() {

return (

<div>

{this.props.myPodcast &&

<TweetInput podcastId={this.props.podcastId} callbackFromChild={this.addTweetCallback.bind(this)}/>}

<TweetList

tweets={this.state.tweets}

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

myPodcast={this.props.myPodcast}

history={this.props.history}

/>

{!this.state.loading && this.state.numberOfTweets === 0 && <WelcomePanel/>}

<LoadingPanel hidden={!this.state.loading}/>

</div>

)

}

}

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

const React = require('react');

export default class WelcomePanel extends React.Component {

render() {

return (

<div className="container-fluid">

<div className="panel panel-info" style={{height: '240px'}}>

<div className="panel-body text-center">

<h3 style={{color: '#a0a0a0'}}>Здесь еще ничего нет,</h3>

<h3 style={{color: '#a0a0a0'}}>но скоро обязательно что-то появится!</h3>

<br/>

<img src="/images/smile.png" width="60"/>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\searchPage\PodcastLine.js

const React = require('react');

export default class PodcastLine extends React.Component {

constructor(props) {

super(props);

this.state = {

podcast: null

};

}

render() {

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

return (

<div className="container-fluid">

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

<div className="panel-body">

<div className="row">

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

<div className="panel panel-info"

style={{width: "150px", textAlign: "center", marginBottom: 0}}>

<br></br>

<img src="images/podcastDefaultLogo.png"

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

<div className="panel-body">

<span className="badge">{podcast.rating}</span>

</div>

</div>

</div>

<div className="container-fluid">

<h4>{podcast.name}

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

</h4>

<hr/>

<p className="text-justify">{podcast.description}

</p>

<a>

<button type="button"

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

onClick={() => {

this.props.history.push(`/podcast/${podcast.id}`);

}}

>Подробнее

</button>

</a>

</div>

</div>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\searchPage\PodcastList.js

const React = require('react');

import PodcastLine from "./PodcastLine";

export default class PodcastList extends React.Component {

constructor(props) {

super(props);

}

render() {

let podcastList = this.props.podcasts.map(podcast =>

<PodcastLine

history={this.props.history}

key={podcast.id}

podcast={podcast}

genres={this.props.genres}/>

);

return (

<div>

{podcastList}

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\searchPage\SearchPage.js

import PodcastList from "./PodcastList";

import Navbar from '../Navbar';

import SearchPanel from './SearchPanel';

import {getGenres} from "../Helper";

const React = require('react');

export default class SearchPage extends React.Component {

constructor(props) {

super(props);

this.state = {

podcasts: [],

genres: [],

loadData: 0,

pageSize: 5,

loading: false,

currPage: 0,

allPages: false,

filter: "",

notInGenres: [],

byRating: false

};

}

componentDidMount() {

const {state} = this.props.location;

if (state) {

this.loadPodcasts(state.filterValue, [], false, 0);

} else {

this.loadPodcasts("", [], false, 0);

}

this.loadAllGenres();

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.loadPodcasts(this.state.filter, this.state.notInGenres, this.state.byRating, nextPage);

}

}

};

}

loadAllGenres() {

getGenres().then(genres => {

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

})

}

loadPodcasts(filter, notInGenres, byRating, page) {

let data = {

"filter": filter,

"genres": notInGenres.length === 0 ? [-1]: notInGenres.map(i => i - 1),

"byRating": byRating

};

$.ajax({

url: `/getPodcastsInPage?page=${page}&size=${this.state.pageSize}`,

type: 'post',

contentType: 'application/json',

data: JSON.stringify(data),

success: (response) => {

console.log(response);

this.setState(

page !== 0 ? {

podcasts: this.state.podcasts.concat(response.content),

loading: false,

allPages: response.last,

filter: filter,

notInGenres: notInGenres,

byRating: byRating

}:

{

podcasts: response.content,

loading: false,

allPages: response.last,

filter: filter,

notInGenres: notInGenres,

byRating: byRating,

currPage: 0

}

);

},

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

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

}

});

}

submitFilter = (filter, notInGenres, byRating) => {

this.loadPodcasts(filter, notInGenres, byRating, 0);

};

render() {

return (

<div>

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

<div className="container-fluid">

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

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

<SearchPanel genres={this.state.genres}

onSubmit={(filter, notInGenres, byRating) => this.submitFilter(filter, notInGenres, byRating)}

filterValue={this.props.location.state ? this.props.location.state.filterValue: ""}

/>

</div>

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

{this.state.loadData === 1 &&

<PodcastList history={this.props.history} podcasts={this.state.podcasts}

genres={this.state.genres}/>}

</div>

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

</div>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\searchPage\SearchPanel.js

import React, {Component} from 'react';

import {

Button,

ButtonGroup,

FormControl,

FormGroup,

Glyphicon,

InputGroup,

ListGroup,

ListGroupItem

} from 'react-bootstrap';

export default class SearchPanel extends Component {

constructor() {

super();

this.state = {

filterValue: "",

unselectedGenres: [],

byRating: false

}

}

componentDidMount() {

this.setState({filterValue: this.props.filterValue});

}

clearFilter = (e) => {

this.setState({filterValue: ""});

e.target.blur();

this.props.onSubmit("", this.state.unselectedGenres, this.state.byRating);

};

applyFilter = (e) => {

e.preventDefault();

this.props.onSubmit(this.state.filterValue, this.state.unselectedGenres, this.state.byRating);

};

handleChange = (e) => {

this.setState({filterValue: e.target.value});

};

unselectGenre = (id) => {

let tmp = this.state.unselectedGenres;

let index = tmp.indexOf(id);

index === -1 ? tmp = [...tmp, id]: tmp.splice(index, 1);

this.setState({unselectedGenres: tmp});

};

searchHeight = 40;

changeByRatingVal = (val) => {

this.setState({byRating: val});

this.props.onSubmit(this.state.filterValue, this.state.unselectedGenres, val);

};

render() {

return (

<div className="container-fluid">

<div className="panel panel-info">

<div className="panel-body">

<form

onSubmit={(event) => {

this.applyFilter(event)

}}

>

<FormGroup>

<InputGroup>

<FormControl

type="text"

placeholder="Search"

value={this.state.filterValue}

id="searchPanelFilter"

onChange={this.handleChange}

style={{height: this.searchHeight}}

/>

<InputGroup.Button>

<Button onClick={this.clearFilter}

style={{height: this.searchHeight, minWidth: this.searchHeight}}>

<Glyphicon glyph="remove" style={{fontSize: "1.2em"}}/>

</Button>

</InputGroup.Button>

</InputGroup>

</FormGroup>

</form>

<ButtonGroup style={{width: '100%', marginBottom: 15}}>

<Button

style={{width: '50%'}}

className="btn btn-sm"

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

onClick={() => this.changeByRatingVal(false)}>

По новизне

</Button>

<Button

style={{width: '50%'}}

className="btn btn-sm"

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

onClick={() => this.changeByRatingVal(true)}>

По рейтингу

</Button>

</ButtonGroup>

<ListGroup className='search-list' style={{marginBottom: 0}}>

{this.props.genres && this.props.genres.map((item, pos) =>

<ListGroupItem

style={{height: 50, backgroundColor: pos % 2 === 0 ? "#fcfcfc": "#ffffff"}}

key={item.id} onClick={(e) => {

this.unselectGenre(item.id);

e.target.blur();

}}

>

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

<div style={{minWidth: "50px"}}>

<Glyphicon style={{

color: this.state.unselectedGenres.includes(item.id) ? "#d5d5d5": "#5bc0de",

fontSize: "1.8em"

}} glyph="ok"/>

</div>

<h5>{item.name}</h5>

</div>

</ListGroupItem>

)}

</ListGroup>

</div>

</div>

</div>

);

}

}

Файл: Discasst\src\main\resources\static\app\components\statistics\StatisticsPage.js

import React, {Component} from 'react';

import StatisticsPanel from './StatisticsPanel';

import Navbar from "../Navbar";

export default class StatisticsPage extends Component {

constructor() {

super();

this.state = {

usersPerDay: '...',

usersPerMonth: '...',

podcastPerDay: '...',

podcastPerMonth: '...',

episodePerDay: '...',

episodePerMonth: '...',

}

}

componentDidMount() {

this.loadData();

}

loadData() {

fetch(`/getEpisodesCountToday`)

.then((response) => {

return response.json();

})

.then((json) => {

this.setState({episodePerDay: json});

});

fetch(`/getEpisodesCountThisMounth`)

.then((response) => {

return response.json();

})

.then((json) => {

this.setState({episodePerMonth: json});

});

fetch(`/getPodcastsCountToday`)

.then((response) => {

return response.json();

})

.then((json) => {

this.setState({podcastPerDay: json});

});

fetch(`/getPodcastsCountThisMounth`)

.then((response) => {

return response.json();

})

.then((json) => {

this.setState({podcastPerMonth: json});

});

fetch(`/getUsersCountToday`)

.then((response) => {

return response.json();

})

.then((json) => {

this.setState({usersPerDay: json});

});

fetch(`/getUsersCountThisMounth`)

.then((response) => {

return response.json();

})

.then((json) => {

this.setState({usersPerMonth: json});

});

}

render() {

const ts = this.state;

return (

<div>

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

<div>

<div style={{display: "flex", justifyContent: "center", flexWrap: "wrap"}}>

<StatisticsPanel time={statTime.MONTH} stat={stats.USER} number={ts.usersPerMonth}/>

<StatisticsPanel time={statTime.MONTH} stat={stats.EPISODE} number={ts.episodePerMonth}/>

<StatisticsPanel time={statTime.MONTH} stat={stats.PODCAST} number={ts.podcastPerMonth}/>

</div>

<div style={{display: "flex", justifyContent: "center", flexWrap: "wrap"}}>

<StatisticsPanel time={statTime.DAY} stat={stats.USER} number={ts.usersPerDay}/>

<StatisticsPanel time={statTime.DAY} stat={stats.EPISODE} number={ts.episodePerDay}/>

<StatisticsPanel time={statTime.DAY} stat={stats.PODCAST} number={ts.podcastPerDay}/>

</div>

</div>

</div>

);

}

}

const statTime = {

MONTH: 0,

DAY: 1

};

const stats = {

USER: 0,

PODCAST: 1,

EPISODE: 2,

};

export {stats, statTime};

Файл: Discasst\src\main\resources\static\app\components\statistics\StatisticsPanel.js

import React, {Component} from 'react';

import {Panel} from 'react-bootstrap';

import {stats, statTime} from './StatisticsPage';

export default class StatisticsPanel extends Component {

constructor() {

super();

this.state = {}

}

getStat() {

if (this.props.stat === stats.USER) return "Новых пользователей:";

if (this.props.stat === stats.PODCAST) return "Подкастов создано:";

if (this.props.stat === stats.EPISODE) return "Выпусков загружено:";

}

getTime() {

if (this.props.time === statTime.MONTH) return "ЗА МЕСЯЦ";

if (this.props.time === statTime.DAY) return "СЕГОДНЯ";

}

getLabelClass() {

if (this.props.time === statTime.MONTH) return "label label-info";

if (this.props.time === statTime.DAY) return "label label-success";

}

render() {

return (

<Panel style={{width: 320, margin: 10}}>

<Panel.Body>

<div className="text-center" style={{display: "flex", justifyContent: "center", flexWrap: "wrap"}}>

<h3>

<div className={this.getLabelClass()}>{this.getTime()}</div>

</h3>

<h3>{this.getStat()}</h3>

<Panel style={{width: "50%", backgroundColor: "#f1f1f1"}}>

<Panel.Body>

<h1 style={{margin: 0}}><strong><u>{this.props.number}</u></strong></h1>

</Panel.Body>

</Panel>

</div>

</Panel.Body>

</Panel>

);

}

}

Файл: Discasst\src\main\resources\static\app\components\userPage\AddCoauthorsPage.js

import React, {Component} from 'react';

import Navbar from "../Navbar";

import CoauthorsList from "./CoauthorsList";

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

export default class AddCoauthorsPage extends Component {

constructor() {

super();

this.state = {

coauthors: []

}

}

componentDidMount() {

this.loadCoauthors();

}

loadCoauthors() {

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

.then((response) => {

return response.json()

})

.then((json) => {

console.log(json)

let coauthorsIds = json.map(x => x.userId.toString());

this.setState({coauthors: coauthorsIds});

});

}

isId(x) {

return (x >= 0 && x % 1 === 0 && x.indexOf('.') === -1 && x.length <= 10 && x !== "")

}

addCoauthor = () => {

let tmp = this.state.coauthors;

let cid = this.refs.coauthorInput.value;

if (cid !== getCookie('userId'))

if (tmp.length <= 3 && this.isId(cid)) {

let newCoauthor = cid;

console.log(tmp.indexOf(newCoauthor));

if (tmp.indexOf(newCoauthor) < 0) {

this.refs.coauthorInput.value = "";

tmp = [...tmp, newCoauthor];

this.setState({coauthors: tmp});

}

}

};

deleteCoauthor = (item) => {

let tmp = this.state.coauthors;

let index = tmp.indexOf(item);

tmp.splice(index, 1);

this.setState({coauthors: tmp});

};

saveChanges = () => {

let authorsIds = JSON.stringify(this.state.coauthors);

const that = this;

$.ajax({

url: `/addCoauthors?podcastId=${this.props.match.params.podcastId}&${getFullCSRFParam()}`,

type: 'post',

contentType: 'application/json',

data: authorsIds,

success: () => {

that.changesIsApplyed();

},

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

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

}

});

};

changesIsApplyed = () => {

this.props.history.push(`/user/${getCookie("username")}`);

};

render() {

return (

<div>

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

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

<div className="container-fluid" style={{width: "50%"}}>

<br/><br/><br/>

<div className="panel panel-default">

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

{this.state.coauthors.length <= 3 ?

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

<input ref="coauthorInput" maxLength="10" className="form-control"

placeholder="Id соведущего" type="number" min="0" step="1"

max="999999999"/>&#160;&#160;

<button type="button" className="btn btn-info"

onClick={this.addCoauthor}>Добавить ведущего

</button>

</div>: <h4>Соведущие:</h4>}

{this.state.coauthors.length > 0 && <br/>}

<CoauthorsList coauthors={this.state.coauthors} onClick={this.deleteCoauthor}/>

<br/>

<button

type="button"

className="btn btn-info"

onClick={this.saveChanges}>Сохранить

</button>

<br/>

</div>

</div>

</div>

</div>

</div>

);

}

}

Файл: Discasst\src\main\resources\static\app\components\userPage\CoauthorsList.js

import React, {Component} from 'react';

export default class CoauthorsList extends Component {

constructor() {

super();

this.state = {}

}

render() {

return (<div className="container-fluid">

<div style={{display: "flex", justifyContent: "flex-start", flexWrap: "wrap"}}>

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

<button key={item} onClick={() => this.props.onClick(item)} style={{margin: "2px"}}

className="btn btn-info">id: {item} <span className="glyphicon glyphicon-remove"></span>

</button>

)}

</div>

</div>

);

}

}

Файл: Discasst\src\main\resources\static\app\components\userPage\ CreateNewEpisodePage.js

import React, {Component} from 'react';

import Navbar from "../Navbar";

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