hyperspace-desktop-client-w.../src/pages/Home.tsx

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));