Merge pull request #141 from hyperspacedev/HD-3-follow-once

HD-3 #done
This commit is contained in:
Marquis Kurt 2019-12-22 14:54:13 -05:00 committed by GitHub
commit 2d7af3f717
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 114 additions and 9 deletions

View File

@ -33,35 +33,83 @@ import NotificationsIcon from "@material-ui/icons/Notifications";
import Mastodon from "megalodon"; import Mastodon from "megalodon";
import { Notification } from "../types/Notification"; import { Notification } from "../types/Notification";
import { Account } from "../types/Account"; import { Account } from "../types/Account";
import { Relationship } from "../types/Relationship";
import { withSnackbar } from "notistack"; import { withSnackbar } from "notistack";
/**
* The state interface for the notifications page.
*/
interface INotificationsPageState { interface INotificationsPageState {
/**
* The list of notifications, if it exists.
*/
notifications?: [Notification]; notifications?: [Notification];
/**
* Whether the view is still loading.
*/
viewIsLoading: boolean; viewIsLoading: boolean;
/**
* Whether the view has loaded.
*/
viewDidLoad?: boolean; viewDidLoad?: boolean;
/**
* Whether the view has loaded but in error.
*/
viewDidError?: boolean; viewDidError?: boolean;
/**
* The error code for an errored state, if possible.
*/
viewDidErrorCode?: string; viewDidErrorCode?: string;
/**
* Whether the delete confirmation dialog should be open.
*/
deleteDialogOpen: boolean; deleteDialogOpen: boolean;
} }
/**
* The notifications page.
*/
class NotificationsPage extends Component<any, INotificationsPageState> { class NotificationsPage extends Component<any, INotificationsPageState> {
/**
* The Mastodon object to perform notification operations on.
*/
client: Mastodon; client: Mastodon;
/**
* The stream listener for tuning in to notifications.
*/
streamListener: any; streamListener: any;
/**
* Construct the notifications page.
* @param props The properties to pass in
*/
constructor(props: any) { constructor(props: any) {
super(props); super(props);
// Create the Mastodon object.
this.client = new Mastodon( this.client = new Mastodon(
localStorage.getItem("access_token") as string, localStorage.getItem("access_token") as string,
localStorage.getItem("baseurl") + "/api/v1" localStorage.getItem("baseurl") + "/api/v1"
); );
// Initialize the state.
this.state = { this.state = {
viewIsLoading: true, viewIsLoading: true,
deleteDialogOpen: false deleteDialogOpen: false
}; };
} }
/**
* Perform pre-mount tasks.
*/
componentWillMount() { componentWillMount() {
// Get the list of notifications and update the state.
this.client this.client
.get("/notifications") .get("/notifications")
.then((resp: any) => { .then((resp: any) => {
@ -82,10 +130,17 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
}); });
} }
/**
* Perform post-mount tasks.
*/
componentDidMount() { componentDidMount() {
// Start listening for new notifications after fetching.
this.streamNotifications(); this.streamNotifications();
} }
/**
* Set up a stream listener and keep updating notifications.
*/
streamNotifications() { streamNotifications() {
this.streamListener = this.client.stream("/streaming/user"); this.streamListener = this.client.stream("/streaming/user");
@ -98,10 +153,19 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
}); });
} }
/**
* Toggle the state of the delete dialog.
*/
toggleDeleteDialog() { toggleDeleteDialog() {
this.setState({ deleteDialogOpen: !this.state.deleteDialogOpen }); this.setState({ deleteDialogOpen: !this.state.deleteDialogOpen });
} }
/**
* Strip HTML content from a string containing HTML content.
*
* @param text The sanitized HTML to strip
* @returns A string containing the contents of the sanitized HTML
*/
removeHTMLContent(text: string) { removeHTMLContent(text: string) {
const div = document.createElement("div"); const div = document.createElement("div");
div.innerHTML = text; div.innerHTML = text;
@ -111,6 +175,10 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
return innerContent; return innerContent;
} }
/**
* Remove a notification from the server.
* @param id The notification's ID
*/
removeNotification(id: string) { removeNotification(id: string) {
this.client this.client
.post(`/notifications/${id}/dismiss`) .post(`/notifications/${id}/dismiss`)
@ -142,6 +210,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
}); });
} }
/**
* Purge all notifications from the server.
*/
removeAllNotifications() { removeAllNotifications() {
this.client this.client
.post("/notifications/clear") .post("/notifications/clear")
@ -159,6 +230,10 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
}); });
} }
/**
* Render a single notification unit to be used in a list
* @param notif The notification to work with.
*/
createNotification(notif: Notification) { createNotification(notif: Notification) {
const { classes } = this.props; const { classes } = this.props;
let primary = ""; let primary = "";
@ -293,7 +368,20 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
); );
} }
/**
* Follow an account from a notification if already not followed.
* @param acct The account to follow, if possible
*/
followMember(acct: Account) { followMember(acct: Account) {
// Get the relationships for this account.
this.client
.get(`/accounts/relationships`, { id: acct.id })
.then((resp: any) => {
// Returns a list, so grab only the first item.
let relationship: Relationship = resp.data[0];
// Follow if not following already.
if (relationship.following == false) {
this.client this.client
.post(`/accounts/${acct.id}/follow`) .post(`/accounts/${acct.id}/follow`)
.then((resp: any) => { .then((resp: any) => {
@ -310,6 +398,23 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
}); });
} }
// Otherwise notify the user.
else {
this.props.enqueueSnackbar(
"You already follow this account."
);
}
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't find relationship.", {
variant: "error"
});
});
}
/**
* Render the notification page.
*/
render() { render() {
const { classes } = this.props; const { classes } = this.props;
return ( return (