commit
2d7af3f717
|
@ -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,23 +368,53 @@ 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
|
this.client
|
||||||
.post(`/accounts/${acct.id}/follow`)
|
.get(`/accounts/relationships`, { id: acct.id })
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
this.props.enqueueSnackbar(
|
// Returns a list, so grab only the first item.
|
||||||
"You are now following this account."
|
let relationship: Relationship = resp.data[0];
|
||||||
);
|
|
||||||
|
// Follow if not following already.
|
||||||
|
if (relationship.following == false) {
|
||||||
|
this.client
|
||||||
|
.post(`/accounts/${acct.id}/follow`)
|
||||||
|
.then((resp: any) => {
|
||||||
|
this.props.enqueueSnackbar(
|
||||||
|
"You are now following this account."
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((err: Error) => {
|
||||||
|
this.props.enqueueSnackbar(
|
||||||
|
"Couldn't follow account: " + err.name,
|
||||||
|
{ variant: "error" }
|
||||||
|
);
|
||||||
|
console.error(err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise notify the user.
|
||||||
|
else {
|
||||||
|
this.props.enqueueSnackbar(
|
||||||
|
"You already follow this account."
|
||||||
|
);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar(
|
this.props.enqueueSnackbar("Couldn't find relationship.", {
|
||||||
"Couldn't follow account: " + err.name,
|
variant: "error"
|
||||||
{ variant: "error" }
|
});
|
||||||
);
|
|
||||||
console.error(err.message);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the notification page.
|
||||||
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { classes } = this.props;
|
const { classes } = this.props;
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue