Skip to content

Commit f20bf6f

Browse files
refactor(core): improve extensibility on steroids
1 parent 893f150 commit f20bf6f

File tree

1 file changed

+105
-56
lines changed

1 file changed

+105
-56
lines changed

framework/core/js/src/forum/components/NotificationList.js

Lines changed: 105 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -85,63 +85,112 @@ export default class NotificationList extends Component {
8585
return <div className="NotificationList-empty">{app.translator.trans('core.forum.notifications.empty_text')}</div>;
8686
}
8787

88-
return state.getPages().map((page) => {
89-
const groups = [];
90-
const discussions = {};
91-
92-
page.items.forEach((notification) => {
93-
const subject = notification.subject();
94-
95-
if (typeof subject === 'undefined') return;
96-
97-
// Get the discussion that this notification is related to. If it's not
98-
// directly related to a discussion, it may be related to a post or
99-
// other entity which is related to a discussion.
100-
let discussion = null;
101-
if (subject instanceof Discussion) discussion = subject;
102-
else if (subject && subject.discussion) discussion = subject.discussion();
103-
104-
// If the notification is not related to a discussion directly or
105-
// indirectly, then we will assign it to a neutral group.
106-
const key = discussion ? discussion.id() : 0;
107-
discussions[key] = discussions[key] || { discussion: discussion, notifications: [] };
108-
discussions[key].notifications.push(notification);
109-
110-
if (groups.indexOf(discussions[key]) === -1) {
111-
groups.push(discussions[key]);
112-
}
113-
});
114-
115-
return groups.map((group) => {
116-
const badges = group.discussion && group.discussion.badges().toArray();
117-
118-
return (
119-
<div className="NotificationGroup">
120-
{group.discussion ? (
121-
<Link className="NotificationGroup-header" href={app.route.discussion(group.discussion)}>
122-
{badges && !!badges.length && <ul className="NotificationGroup-badges badges">{listItems(badges)}</ul>}
123-
<span>{group.discussion.title()}</span>
124-
</Link>
125-
) : (
126-
<div className="NotificationGroup-header">{this.groupTitle(group)}</div>
127-
)}
128-
129-
<ul className="NotificationGroup-content">
130-
{group.notifications.map((notification) => {
131-
const NotificationComponent = app.notificationComponents[notification.contentType()];
132-
return (
133-
!!NotificationComponent && (
134-
<li>
135-
<NotificationComponent notification={notification} />
136-
</li>
137-
)
138-
);
139-
})}
140-
</ul>
141-
</div>
142-
);
143-
});
88+
return state.getPages().flatMap((page) => this.pageItems(page).toArray());
89+
}
90+
91+
pageItems(page) {
92+
const items = new ItemList();
93+
94+
const groups = this.buildGroups(page);
95+
96+
groups.forEach((group, index) => {
97+
items.add(`group-${index}`, this.groupView(group), -index);
14498
});
99+
100+
return items;
101+
}
102+
103+
buildGroups(page) {
104+
const groups = [];
105+
const discussions = {};
106+
107+
page.items.forEach((notification) => {
108+
const subject = notification.subject();
109+
if (typeof subject === 'undefined') return;
110+
111+
// Get the discussion that this notification is related to. If it's not
112+
// directly related to a discussion, it may be related to a post or
113+
// other entity which is related to a discussion.
114+
let discussion = null;
115+
if (subject instanceof Discussion) discussion = subject;
116+
else if (subject && subject.discussion) discussion = subject.discussion();
117+
118+
// If the notification is not related to a discussion directly or
119+
// indirectly, then we will assign it to a neutral group.
120+
const key = discussion ? discussion.id() : 0;
121+
discussions[key] = discussions[key] || { discussion, notifications: [] };
122+
discussions[key].notifications.push(notification);
123+
124+
if (groups.indexOf(discussions[key]) === -1) {
125+
groups.push(discussions[key]);
126+
}
127+
});
128+
129+
return groups;
130+
}
131+
132+
groupKey(group, fallbackIndex) {
133+
return group.discussion ? group.discussion.id() : `neutral-${fallbackIndex}`;
134+
}
135+
136+
groupView(group) {
137+
const badges = group.discussion && group.discussion.badges().toArray();
138+
139+
const items = this.groupItems(group, badges).toArray();
140+
141+
return <div className="NotificationGroup">{items}</div>;
142+
}
143+
144+
groupItems(group, badges) {
145+
const items = new ItemList();
146+
147+
items.add('header', this.groupHeaderItems(group, badges).toArray()[0], 100);
148+
149+
items.add('body', this.groupBodyItems(group).toArray()[0], 90);
150+
151+
return items;
152+
}
153+
154+
groupHeaderItems(group, badges) {
155+
const items = new ItemList();
156+
157+
if (group.discussion) {
158+
items.add(
159+
'discussion',
160+
<Link className="NotificationGroup-header" href={app.route.discussion(group.discussion)}>
161+
{badges && !!badges.length && <ul className="NotificationGroup-badges badges">{listItems(badges)}</ul>}
162+
<span>{group.discussion.title()}</span>
163+
</Link>,
164+
100
165+
);
166+
} else {
167+
items.add('neutral', <div className="NotificationGroup-header">{this.groupTitle(group)}</div>, 0);
168+
}
169+
170+
return items;
171+
}
172+
173+
groupBodyItems(group) {
174+
const items = new ItemList();
175+
176+
items.add(
177+
'list',
178+
<ul className="NotificationGroup-content">{group.notifications.map((n, i) => this.notificationItem(n, i)).filter(Boolean)}</ul>,
179+
100
180+
);
181+
182+
return items;
183+
}
184+
185+
notificationItem(notification) {
186+
const NotificationComponent = app.notificationComponents[notification.contentType()];
187+
if (!NotificationComponent) return null;
188+
189+
return (
190+
<li>
191+
<NotificationComponent notification={notification} />
192+
</li>
193+
);
145194
}
146195

147196
groupTitle(group) {

0 commit comments

Comments
 (0)