From 29ede5aa27e368020e8f786df3c17aebaa36c928 Mon Sep 17 00:00:00 2001
From: Sami Mazouz <sychocouldy@gmail.com>
Date: Tue, 14 May 2024 21:10:07 +0100
Subject: [PATCH] feat: JS `Notification` extender (#3974)

* feat: JS `Notification` extender

* fix
---
 extensions/likes/js/src/forum/extend.ts       |  4 +++
 extensions/likes/js/src/forum/index.js        |  3 ---
 extensions/lock/js/src/forum/extend.ts        |  4 +++
 extensions/lock/js/src/forum/index.js         |  3 ---
 extensions/mentions/js/src/forum/extend.ts    |  8 ++++++
 extensions/mentions/js/src/forum/index.js     |  7 ------
 .../subscriptions/js/src/forum/extend.ts      |  4 +++
 .../subscriptions/js/src/forum/index.js       |  4 ---
 extensions/suspend/js/src/forum/extend.ts     |  6 +++++
 extensions/suspend/js/src/forum/index.js      |  5 ----
 .../js/src/common/extenders/Notification.ts   | 25 +++++++++++++++++++
 .../core/js/src/common/extenders/index.ts     |  2 ++
 12 files changed, 53 insertions(+), 22 deletions(-)
 create mode 100644 framework/core/js/src/common/extenders/Notification.ts

diff --git a/extensions/likes/js/src/forum/extend.ts b/extensions/likes/js/src/forum/extend.ts
index 1a8b41bac..ddb6b7bae 100644
--- a/extensions/likes/js/src/forum/extend.ts
+++ b/extensions/likes/js/src/forum/extend.ts
@@ -2,11 +2,15 @@ import Extend from 'flarum/common/extenders';
 import Post from 'flarum/common/models/Post';
 import User from 'flarum/common/models/User';
 import LikesUserPage from './components/LikesUserPage';
+import PostLikedNotification from './components/PostLikedNotification';
 
 export default [
   new Extend.Routes() //
     .add('user.likes', '/u/:username/likes', LikesUserPage),
 
+  new Extend.Notification() //
+    .add('postLiked', PostLikedNotification),
+
   new Extend.Model(Post) //
     .hasMany<User>('likes')
     .attribute<number>('likesCount')
diff --git a/extensions/likes/js/src/forum/index.js b/extensions/likes/js/src/forum/index.js
index 45adb6891..78175ef31 100644
--- a/extensions/likes/js/src/forum/index.js
+++ b/extensions/likes/js/src/forum/index.js
@@ -3,14 +3,11 @@ import app from 'flarum/forum/app';
 
 import addLikeAction from './addLikeAction';
 import addLikesList from './addLikesList';
-import PostLikedNotification from './components/PostLikedNotification';
 import addLikesTabToUserProfile from './addLikesTabToUserProfile';
 
 export { default as extend } from './extend';
 
 app.initializers.add('flarum-likes', () => {
-  app.notificationComponents.postLiked = PostLikedNotification;
-
   addLikeAction();
   addLikesList();
   addLikesTabToUserProfile();
diff --git a/extensions/lock/js/src/forum/extend.ts b/extensions/lock/js/src/forum/extend.ts
index 2a65da563..3c45553a5 100644
--- a/extensions/lock/js/src/forum/extend.ts
+++ b/extensions/lock/js/src/forum/extend.ts
@@ -3,6 +3,7 @@ import Discussion from 'flarum/common/models/Discussion';
 import DiscussionLockedPost from './components/DiscussionLockedPost';
 
 import commonExtend from '../common/extend';
+import DiscussionLockedNotification from './components/DiscussionLockedNotification';
 
 export default [
   ...commonExtend,
@@ -10,6 +11,9 @@ export default [
   new Extend.PostTypes() //
     .add('discussionLocked', DiscussionLockedPost),
 
+  new Extend.Notification() //
+    .add('discussionLocked', DiscussionLockedNotification),
+
   new Extend.Model(Discussion) //
     .attribute<boolean>('isLocked')
     .attribute<boolean>('canLock'),
diff --git a/extensions/lock/js/src/forum/index.js b/extensions/lock/js/src/forum/index.js
index fd3f9cda0..86d8bafd4 100644
--- a/extensions/lock/js/src/forum/index.js
+++ b/extensions/lock/js/src/forum/index.js
@@ -1,15 +1,12 @@
 import { extend } from 'flarum/common/extend';
 import app from 'flarum/forum/app';
 
-import DiscussionLockedNotification from './components/DiscussionLockedNotification';
 import addLockBadge from './addLockBadge';
 import addLockControl from './addLockControl';
 
 export { default as extend } from './extend';
 
 app.initializers.add('flarum-lock', () => {
-  app.notificationComponents.discussionLocked = DiscussionLockedNotification;
-
   addLockBadge();
   addLockControl();
 
diff --git a/extensions/mentions/js/src/forum/extend.ts b/extensions/mentions/js/src/forum/extend.ts
index e14c8fca3..240edf3b3 100644
--- a/extensions/mentions/js/src/forum/extend.ts
+++ b/extensions/mentions/js/src/forum/extend.ts
@@ -2,6 +2,9 @@ import Extend from 'flarum/common/extenders';
 import Post from 'flarum/common/models/Post';
 import User from 'flarum/common/models/User';
 import MentionsUserPage from './components/MentionsUserPage';
+import PostMentionedNotification from './components/PostMentionedNotification';
+import UserMentionedNotification from './components/UserMentionedNotification';
+import GroupMentionedNotification from './components/GroupMentionedNotification';
 
 export default [
   new Extend.Routes() //
@@ -11,6 +14,11 @@ export default [
     .hasMany<Post>('mentionedBy')
     .attribute<number>('mentionedByCount'),
 
+  new Extend.Notification() //
+    .add('postMentioned', PostMentionedNotification)
+    .add('userMentioned', UserMentionedNotification)
+    .add('groupMentioned', GroupMentionedNotification),
+
   new Extend.Model(User) //
     .attribute<boolean>('canMentionGroups'),
 ];
diff --git a/extensions/mentions/js/src/forum/index.js b/extensions/mentions/js/src/forum/index.js
index a8797b006..385f6960e 100644
--- a/extensions/mentions/js/src/forum/index.js
+++ b/extensions/mentions/js/src/forum/index.js
@@ -9,9 +9,6 @@ import addMentionedByList from './addMentionedByList';
 import addPostReplyAction from './addPostReplyAction';
 import addPostQuoteButton from './addPostQuoteButton';
 import addComposerAutocomplete from './addComposerAutocomplete';
-import PostMentionedNotification from './components/PostMentionedNotification';
-import UserMentionedNotification from './components/UserMentionedNotification';
-import GroupMentionedNotification from './components/GroupMentionedNotification';
 import MentionFormats from './mentionables/formats/MentionFormats';
 import UserPage from 'flarum/forum/components/UserPage';
 import LinkButton from 'flarum/common/components/LinkButton';
@@ -40,10 +37,6 @@ app.initializers.add('flarum-mentions', function () {
   // posts or users that the user could mention.
   addComposerAutocomplete();
 
-  app.notificationComponents.postMentioned = PostMentionedNotification;
-  app.notificationComponents.userMentioned = UserMentionedNotification;
-  app.notificationComponents.groupMentioned = GroupMentionedNotification;
-
   // Add notification preferences.
   extend('flarum/forum/components/NotificationGrid', 'notificationTypes', function (items) {
     items.add('postMentioned', {
diff --git a/extensions/subscriptions/js/src/forum/extend.ts b/extensions/subscriptions/js/src/forum/extend.ts
index 065976b40..1ee1c1afd 100644
--- a/extensions/subscriptions/js/src/forum/extend.ts
+++ b/extensions/subscriptions/js/src/forum/extend.ts
@@ -3,6 +3,7 @@ import IndexPage from 'flarum/forum/components/IndexPage';
 import Discussion from 'flarum/common/models/Discussion';
 
 import commonExtend from '../common/extend';
+import NewPostNotification from './components/NewPostNotification';
 
 export default [
   ...commonExtend,
@@ -10,6 +11,9 @@ export default [
   new Extend.Routes() //
     .add('following', '/following', IndexPage),
 
+  new Extend.Notification() //
+    .add('newPost', NewPostNotification),
+
   new Extend.Model(Discussion) //
     .attribute('subscription'),
 ];
diff --git a/extensions/subscriptions/js/src/forum/index.js b/extensions/subscriptions/js/src/forum/index.js
index 3857652bf..49a9a0fc2 100644
--- a/extensions/subscriptions/js/src/forum/index.js
+++ b/extensions/subscriptions/js/src/forum/index.js
@@ -6,13 +6,9 @@ import addSubscriptionControls from './addSubscriptionControls';
 import addSubscriptionFilter from './addSubscriptionFilter';
 import addSubscriptionSettings from './addSubscriptionSettings';
 
-import NewPostNotification from './components/NewPostNotification';
-
 export { default as extend } from './extend';
 
 app.initializers.add('subscriptions', function () {
-  app.notificationComponents.newPost = NewPostNotification;
-
   addSubscriptionBadge();
   addSubscriptionControls();
   addSubscriptionFilter();
diff --git a/extensions/suspend/js/src/forum/extend.ts b/extensions/suspend/js/src/forum/extend.ts
index 8432a3462..30e8990e3 100644
--- a/extensions/suspend/js/src/forum/extend.ts
+++ b/extensions/suspend/js/src/forum/extend.ts
@@ -3,10 +3,16 @@ import User from 'flarum/common/models/User';
 import Model from 'flarum/common/Model';
 
 import commonExtend from '../common/extend';
+import UserSuspendedNotification from './components/UserSuspendedNotification';
+import UserUnsuspendedNotification from './components/UserUnsuspendedNotification';
 
 export default [
   ...commonExtend,
 
+  new Extend.Notification() //
+    .add('userSuspended', UserSuspendedNotification)
+    .add('userUnsuspended', UserUnsuspendedNotification),
+
   new Extend.Model(User)
     .attribute<Date | null | undefined, string | null | undefined>('suspendedUntil', Model.transformDate)
     .attribute<string | null | undefined>('suspendReason')
diff --git a/extensions/suspend/js/src/forum/index.js b/extensions/suspend/js/src/forum/index.js
index cec962116..5a4a01ecf 100644
--- a/extensions/suspend/js/src/forum/index.js
+++ b/extensions/suspend/js/src/forum/index.js
@@ -6,16 +6,11 @@ import Badge from 'flarum/common/components/Badge';
 import User from 'flarum/common/models/User';
 
 import SuspendUserModal from './components/SuspendUserModal';
-import UserSuspendedNotification from './components/UserSuspendedNotification';
-import UserUnsuspendedNotification from './components/UserUnsuspendedNotification';
 import checkForSuspension from './checkForSuspension';
 
 export { default as extend } from './extend';
 
 app.initializers.add('flarum-suspend', () => {
-  app.notificationComponents.userSuspended = UserSuspendedNotification;
-  app.notificationComponents.userUnsuspended = UserUnsuspendedNotification;
-
   extend(UserControls, 'moderationControls', (items, user) => {
     if (user.canSuspend()) {
       items.add(
diff --git a/framework/core/js/src/common/extenders/Notification.ts b/framework/core/js/src/common/extenders/Notification.ts
new file mode 100644
index 000000000..15985f9b9
--- /dev/null
+++ b/framework/core/js/src/common/extenders/Notification.ts
@@ -0,0 +1,25 @@
+import IExtender, { IExtensionModule } from './IExtender';
+import type Component from '../Component';
+import ForumApplication from '../../forum/ForumApplication';
+import type Application from '../Application';
+import type { NewComponent } from '../Application';
+
+export default class Notification implements IExtender {
+  private notificationComponents: Record<string, new () => Component> = {};
+
+  /**
+   * Register a new notification component type.
+   *
+   * @param name The name of the notification type.
+   * @param component The component class to render the notification.
+   */
+  add(name: string, component: NewComponent<any>): Notification {
+    this.notificationComponents[name] = component;
+
+    return this;
+  }
+
+  extend(app: Application, extension: IExtensionModule): void {
+    Object.assign((app as unknown as ForumApplication).notificationComponents, this.notificationComponents);
+  }
+}
diff --git a/framework/core/js/src/common/extenders/index.ts b/framework/core/js/src/common/extenders/index.ts
index 86efd55d2..8702e00d3 100644
--- a/framework/core/js/src/common/extenders/index.ts
+++ b/framework/core/js/src/common/extenders/index.ts
@@ -3,6 +3,7 @@ import PostTypes from './PostTypes';
 import Routes from './Routes';
 import Store from './Store';
 import Search from './Search';
+import Notification from './Notification';
 
 const extenders = {
   Model,
@@ -10,6 +11,7 @@ const extenders = {
   Routes,
   Store,
   Search,
+  Notification,
 };
 
 export default extenders;