158 lines
5.3 KiB
TypeScript
158 lines
5.3 KiB
TypeScript
|
import React, { Component } from 'react';
|
||
|
import { withStyles, CircularProgress, Typography, Paper, Button} from '@material-ui/core';
|
||
|
import {styles} from './PageLayout.styles';
|
||
|
import Post from '../components/Post';
|
||
|
import { Status } from '../types/Status';
|
||
|
import Mastodon from 'megalodon';
|
||
|
import {withSnackbar} from 'notistack';
|
||
|
|
||
|
interface IHomePageState {
|
||
|
posts?: [Status];
|
||
|
viewIsLoading: boolean;
|
||
|
viewDidLoad?: boolean;
|
||
|
viewDidError?: boolean;
|
||
|
viewDidErrorCode?: any;
|
||
|
}
|
||
|
|
||
|
|
||
|
class HomePage extends Component<any, IHomePageState> {
|
||
|
|
||
|
client: Mastodon;
|
||
|
streamListener: any;
|
||
|
|
||
|
constructor(props: any) {
|
||
|
super(props);
|
||
|
|
||
|
this.state = {
|
||
|
viewIsLoading: true
|
||
|
}
|
||
|
|
||
|
this.client = new Mastodon(localStorage.getItem('access_token') as string, localStorage.getItem('baseurl') as string + "/api/v1");
|
||
|
|
||
|
}
|
||
|
|
||
|
componentWillMount() {
|
||
|
this.streamListener = this.client.stream('/streaming/home');
|
||
|
|
||
|
this.streamListener.on('connect', () => {
|
||
|
this.client.get('/timelines/home', {limit: 40}).then((resp: any) => {
|
||
|
let statuses: [Status] = resp.data;
|
||
|
this.setState({
|
||
|
posts: statuses,
|
||
|
viewIsLoading: false,
|
||
|
viewDidLoad: true,
|
||
|
viewDidError: false
|
||
|
})
|
||
|
}).catch((resp: any) => {
|
||
|
this.setState({
|
||
|
viewIsLoading: false,
|
||
|
viewDidLoad: true,
|
||
|
viewDidError: true,
|
||
|
viewDidErrorCode: String(resp)
|
||
|
})
|
||
|
this.props.enqueueSnackbar("Failed to get posts.", {
|
||
|
variant: 'error',
|
||
|
});
|
||
|
})
|
||
|
});
|
||
|
|
||
|
this.streamListener.on('update', (status: Status) => {
|
||
|
let posts = this.state.posts;
|
||
|
if (posts) {
|
||
|
posts.unshift(status)
|
||
|
}
|
||
|
this.setState({ posts });
|
||
|
})
|
||
|
|
||
|
this.streamListener.on('delete', (id: number) => {
|
||
|
let posts = this.state.posts;
|
||
|
if (posts) {
|
||
|
posts.forEach((post: Status) => {
|
||
|
if (posts && parseInt(post.id) === id) {
|
||
|
posts.splice(posts.indexOf(post), 1);
|
||
|
}
|
||
|
})
|
||
|
this.setState({ posts });
|
||
|
}
|
||
|
})
|
||
|
|
||
|
this.streamListener.on('error', (err: Error) => {
|
||
|
this.setState({
|
||
|
viewDidError: true,
|
||
|
viewDidErrorCode: err.message
|
||
|
})
|
||
|
this.props.enqueueSnackbar("An error occured.", {
|
||
|
variant: 'error',
|
||
|
});
|
||
|
})
|
||
|
|
||
|
this.streamListener.on('heartbeat', () => {
|
||
|
|
||
|
})
|
||
|
}
|
||
|
|
||
|
loadMoreTimelinePieces() {
|
||
|
this.setState({ viewDidLoad: false, viewIsLoading: true})
|
||
|
if (this.state.posts) {
|
||
|
this.client.get('/timelines/home', { max_id: this.state.posts[this.state.posts.length - 1].id, limit: 20 }).then((resp: any) => {
|
||
|
let newPosts: [Status] = resp.data;
|
||
|
let posts = this.state.posts as [Status];
|
||
|
newPosts.forEach((post: Status) => {
|
||
|
posts.push(post);
|
||
|
});
|
||
|
this.setState({
|
||
|
viewIsLoading: false,
|
||
|
viewDidLoad: true,
|
||
|
posts
|
||
|
})
|
||
|
}).catch((err: Error) => {
|
||
|
this.setState({
|
||
|
viewIsLoading: false,
|
||
|
viewDidError: true,
|
||
|
viewDidErrorCode: err.message
|
||
|
})
|
||
|
this.props.enqueueSnackbar("Failed to get posts", {
|
||
|
variant: 'error',
|
||
|
});
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
render() {
|
||
|
const {classes} = this.props;
|
||
|
|
||
|
return (
|
||
|
<div className={classes.pageLayoutMaxConstraints}>
|
||
|
{ this.state.posts?
|
||
|
<div>
|
||
|
{this.state.posts.map((post: Status) => {
|
||
|
return <Post key={post.id} post={post} client={this.client}/>
|
||
|
})}
|
||
|
<br/>
|
||
|
{
|
||
|
this.state.viewDidLoad && !this.state.viewDidError? <div style={{textAlign: "center"}} onClick={() => this.loadMoreTimelinePieces()}><Button variant="contained">Load more</Button></div>: null
|
||
|
}
|
||
|
</div>:
|
||
|
<span/>
|
||
|
}
|
||
|
{
|
||
|
this.state.viewDidError?
|
||
|
<Paper className={classes.errorCard}>
|
||
|
<Typography variant="h4">Bummer.</Typography>
|
||
|
<Typography variant="h6">Something went wrong when loading this timeline.</Typography>
|
||
|
<Typography>{this.state.viewDidErrorCode? this.state.viewDidErrorCode: ""}</Typography>
|
||
|
</Paper>:
|
||
|
<span/>
|
||
|
}
|
||
|
{
|
||
|
this.state.viewIsLoading?
|
||
|
<div style={{ textAlign: 'center' }}><CircularProgress className={classes.progress} color="primary" /></div>:
|
||
|
<span/>
|
||
|
}
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export default withStyles(styles)(withSnackbar(HomePage));
|