mirror of
https://github.com/flarum/framework.git
synced 2024-11-29 21:11:55 +08:00
Extract NotificationList state (#2185)
* Extract NotificationList state
This commit is contained in:
parent
ebf17b72ff
commit
289ebeb5ce
|
@ -14,6 +14,7 @@ import routes from './routes';
|
|||
import alertEmailConfirmation from './utils/alertEmailConfirmation';
|
||||
import Application from '../common/Application';
|
||||
import Navigation from '../common/components/Navigation';
|
||||
import NotificationListState from './states/NotificationListState';
|
||||
|
||||
export default class ForumApplication extends Application {
|
||||
/**
|
||||
|
@ -63,6 +64,13 @@ export default class ForumApplication extends Application {
|
|||
*/
|
||||
history = new History();
|
||||
|
||||
/**
|
||||
* An object which controls the state of the user's notifications.
|
||||
*
|
||||
* @type {NotificationListState}
|
||||
*/
|
||||
notifications = new NotificationListState(this);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ export default class HeaderSecondary extends Component {
|
|||
}
|
||||
|
||||
if (app.session.user) {
|
||||
items.add('notifications', NotificationsDropdown.component(), 10);
|
||||
items.add('notifications', NotificationsDropdown.component({ state: app.notifications }), 10);
|
||||
items.add('session', SessionDropdown.component(), 0);
|
||||
} else {
|
||||
if (app.forum.attribute('allowSignUp')) {
|
||||
|
|
|
@ -10,23 +10,11 @@ import Discussion from '../../common/models/Discussion';
|
|||
*/
|
||||
export default class NotificationList extends Component {
|
||||
init() {
|
||||
/**
|
||||
* Whether or not the notifications are loading.
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.loading = false;
|
||||
|
||||
/**
|
||||
* Whether or not there are more results that can be loaded.
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.moreResults = false;
|
||||
this.state = this.props.state;
|
||||
}
|
||||
|
||||
view() {
|
||||
const pages = app.cache.notifications || [];
|
||||
const pages = this.state.getNotificationPages();
|
||||
|
||||
return (
|
||||
<div className="NotificationList">
|
||||
|
@ -36,7 +24,7 @@ export default class NotificationList extends Component {
|
|||
className: 'Button Button--icon Button--link',
|
||||
icon: 'fas fa-check',
|
||||
title: app.translator.trans('core.forum.notifications.mark_all_as_read_tooltip'),
|
||||
onclick: this.markAllAsRead.bind(this),
|
||||
onclick: this.state.markAllAsRead.bind(this.state),
|
||||
})}
|
||||
</div>
|
||||
|
||||
|
@ -97,7 +85,7 @@ export default class NotificationList extends Component {
|
|||
});
|
||||
})
|
||||
: ''}
|
||||
{this.loading ? (
|
||||
{this.state.isLoading() ? (
|
||||
<LoadingIndicator className="LoadingIndicator--block" />
|
||||
) : pages.length ? (
|
||||
''
|
||||
|
@ -121,8 +109,8 @@ export default class NotificationList extends Component {
|
|||
const contentTop = $scrollParent === $notifications ? 0 : $notifications.offset().top;
|
||||
const contentHeight = $notifications[0].scrollHeight;
|
||||
|
||||
if (this.moreResults && !this.loading && scrollTop + viewportHeight >= contentTop + contentHeight) {
|
||||
this.loadMore();
|
||||
if (this.state.hasMoreResults() && !this.state.isLoading() && scrollTop + viewportHeight >= contentTop + contentHeight) {
|
||||
this.state.loadMore();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -132,77 +120,4 @@ export default class NotificationList extends Component {
|
|||
$scrollParent.off('scroll', scrollHandler);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Load notifications into the application's cache if they haven't already
|
||||
* been loaded.
|
||||
*/
|
||||
load() {
|
||||
if (app.session.user.newNotificationCount()) {
|
||||
delete app.cache.notifications;
|
||||
}
|
||||
|
||||
if (app.cache.notifications) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.session.user.pushAttributes({ newNotificationCount: 0 });
|
||||
|
||||
this.loadMore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the next page of notification results.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
loadMore() {
|
||||
this.loading = true;
|
||||
m.redraw();
|
||||
|
||||
const params = app.cache.notifications ? { page: { offset: app.cache.notifications.length * 10 } } : null;
|
||||
|
||||
return app.store
|
||||
.find('notifications', params)
|
||||
.then(this.parseResults.bind(this))
|
||||
.catch(() => {})
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
m.redraw();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse results and append them to the notification list.
|
||||
*
|
||||
* @param {Notification[]} results
|
||||
* @return {Notification[]}
|
||||
*/
|
||||
parseResults(results) {
|
||||
app.cache.notifications = app.cache.notifications || [];
|
||||
|
||||
if (results.length) app.cache.notifications.push(results);
|
||||
|
||||
this.moreResults = !!results.payload.links.next;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all of the notifications as read.
|
||||
*/
|
||||
markAllAsRead() {
|
||||
if (!app.cache.notifications) return;
|
||||
|
||||
app.session.user.pushAttributes({ unreadNotificationCount: 0 });
|
||||
|
||||
app.cache.notifications.forEach((notifications) => {
|
||||
notifications.forEach((notification) => notification.pushAttributes({ isRead: true }));
|
||||
});
|
||||
|
||||
app.request({
|
||||
url: app.forum.attribute('apiUrl') + '/notifications/read',
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@ export default class NotificationsDropdown extends Dropdown {
|
|||
|
||||
init() {
|
||||
super.init();
|
||||
|
||||
this.list = new NotificationList();
|
||||
}
|
||||
|
||||
getButton() {
|
||||
|
@ -44,7 +42,7 @@ export default class NotificationsDropdown extends Dropdown {
|
|||
getMenu() {
|
||||
return (
|
||||
<div className={'Dropdown-menu ' + this.props.menuClassName} onclick={this.menuClick.bind(this)}>
|
||||
{this.showing ? this.list.render() : ''}
|
||||
{this.showing ? NotificationList.component({ state: this.props.state }) : ''}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -53,7 +51,7 @@ export default class NotificationsDropdown extends Dropdown {
|
|||
if (app.drawer.isOpen()) {
|
||||
this.goToRoute();
|
||||
} else {
|
||||
this.list.load();
|
||||
this.props.state.load();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,16 @@ export default class NotificationsPage extends Page {
|
|||
|
||||
app.history.push('notifications');
|
||||
|
||||
this.list = new NotificationList();
|
||||
this.list.load();
|
||||
app.notifications.load();
|
||||
|
||||
this.bodyClass = 'App--notifications';
|
||||
}
|
||||
|
||||
view() {
|
||||
return <div className="NotificationsPage">{this.list.render()}</div>;
|
||||
return (
|
||||
<div className="NotificationsPage">
|
||||
<NotificationList state={app.notifications}></NotificationList>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
94
framework/core/js/src/forum/states/NotificationListState.js
Normal file
94
framework/core/js/src/forum/states/NotificationListState.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
export default class NotificationListState {
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
|
||||
this.notificationPages = [];
|
||||
|
||||
this.loading = false;
|
||||
|
||||
this.moreResults = false;
|
||||
}
|
||||
|
||||
getNotificationPages() {
|
||||
return this.notificationPages;
|
||||
}
|
||||
|
||||
isLoading() {
|
||||
return this.loading;
|
||||
}
|
||||
|
||||
hasMoreResults() {
|
||||
return this.moreResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load notifications into the application's cache if they haven't already
|
||||
* been loaded.
|
||||
*/
|
||||
load() {
|
||||
if (this.app.session.user.newNotificationCount()) {
|
||||
this.notificationPages = [];
|
||||
}
|
||||
|
||||
if (this.notificationPages.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.app.session.user.pushAttributes({ newNotificationCount: 0 });
|
||||
|
||||
this.loadMore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the next page of notification results.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
loadMore() {
|
||||
this.loading = true;
|
||||
m.redraw();
|
||||
|
||||
const params = this.notificationPages.length > 0 ? { page: { offset: this.notificationPages.length * 10 } } : null;
|
||||
|
||||
return this.app.store
|
||||
.find('notifications', params)
|
||||
.then(this.parseResults.bind(this))
|
||||
.catch(() => {})
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
m.redraw();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse results and append them to the notification list.
|
||||
*
|
||||
* @param {Notification[]} results
|
||||
* @return {Notification[]}
|
||||
*/
|
||||
parseResults(results) {
|
||||
if (results.length) this.notificationPages.push(results);
|
||||
|
||||
this.moreResults = !!results.payload.links.next;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all of the notifications as read.
|
||||
*/
|
||||
markAllAsRead() {
|
||||
if (this.notificationPages.length === 0) return;
|
||||
|
||||
this.app.session.user.pushAttributes({ unreadNotificationCount: 0 });
|
||||
|
||||
this.notificationPages.forEach((notifications) => {
|
||||
notifications.forEach((notification) => notification.pushAttributes({ isRead: true }));
|
||||
});
|
||||
|
||||
this.app.request({
|
||||
url: this.app.forum.attribute('apiUrl') + '/notifications/read',
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user