diff --git a/app/javascript/flavours/glitch/actions/notification_groups.ts b/app/javascript/flavours/glitch/actions/notification_groups.ts
index e39c9d6846..f85dfac933 100644
--- a/app/javascript/flavours/glitch/actions/notification_groups.ts
+++ b/app/javascript/flavours/glitch/actions/notification_groups.ts
@@ -8,6 +8,7 @@ import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
import type {
ApiNotificationGroupJSON,
ApiNotificationJSON,
+ NotificationType,
} from 'flavours/glitch/api_types/notifications';
import { allNotificationTypes } from 'flavours/glitch/api_types/notifications';
import type { ApiStatusJSON } from 'flavours/glitch/api_types/statuses';
@@ -15,6 +16,7 @@ import { usePendingItems } from 'flavours/glitch/initial_state';
import type { NotificationGap } from 'flavours/glitch/reducers/notification_groups';
import {
selectSettingsNotificationsExcludedTypes,
+ selectSettingsNotificationsGroupFollows,
selectSettingsNotificationsQuickFilterActive,
selectSettingsNotificationsShows,
} from 'flavours/glitch/selectors/settings';
@@ -68,17 +70,19 @@ function dispatchAssociatedRecords(
dispatch(importFetchedStatuses(fetchedStatuses));
}
-const supportedGroupedNotificationTypes = ['favourite', 'reblog'];
+function selectNotificationGroupedTypes(state: RootState) {
+ const types: NotificationType[] = ['favourite', 'reblog'];
-export function shouldGroupNotificationType(type: string) {
- return supportedGroupedNotificationTypes.includes(type);
+ if (selectSettingsNotificationsGroupFollows(state)) types.push('follow');
+
+ return types;
}
export const fetchNotifications = createDataLoadingThunk(
'notificationGroups/fetch',
async (_params, { getState }) =>
apiFetchNotificationGroups({
- grouped_types: supportedGroupedNotificationTypes,
+ grouped_types: selectNotificationGroupedTypes(getState()),
exclude_types: getExcludedTypes(getState()),
}),
({ notifications, accounts, statuses }, { dispatch }) => {
@@ -102,7 +106,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
'notificationGroups/fetchGap',
async (params: { gap: NotificationGap }, { getState }) =>
apiFetchNotificationGroups({
- grouped_types: supportedGroupedNotificationTypes,
+ grouped_types: selectNotificationGroupedTypes(getState()),
max_id: params.gap.maxId,
exclude_types: getExcludedTypes(getState()),
}),
@@ -119,7 +123,7 @@ export const pollRecentNotifications = createDataLoadingThunk(
'notificationGroups/pollRecentNotifications',
async (_params, { getState }) => {
return apiFetchNotificationGroups({
- grouped_types: supportedGroupedNotificationTypes,
+ grouped_types: selectNotificationGroupedTypes(getState()),
max_id: undefined,
exclude_types: getExcludedTypes(getState()),
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
@@ -168,7 +172,10 @@ export const processNewNotificationForGroups = createAppAsyncThunk(
dispatchAssociatedRecords(dispatch, [notification]);
- return notification;
+ return {
+ notification,
+ groupedTypes: selectNotificationGroupedTypes(state),
+ };
},
);
diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx
index ea57f2999b..81a9d9e1d1 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx
+++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx
@@ -40,6 +40,7 @@ class ColumnSettings extends PureComponent {
const alertStr = ;
const showStr = ;
const soundStr = ;
+ const groupStr = ;
const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');
const pushStr = showPushSettings && ;
@@ -96,6 +97,10 @@ class ColumnSettings extends PureComponent {
+
+
+
+
diff --git a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js
index 3c4c4b30ca..3e0da03e33 100644
--- a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js
@@ -56,11 +56,12 @@ const mapDispatchToProps = (dispatch) => ({
} else {
dispatch(changeSetting(['notifications', ...path], checked));
}
- } else if(path[0] === 'groupingBeta') {
- dispatch(changeSetting(['notifications', ...path], checked));
- dispatch(initializeNotifications());
} else {
dispatch(changeSetting(['notifications', ...path], checked));
+
+ if(path[0] === 'group' && path[1] === 'follow') {
+ dispatch(initializeNotifications());
+ }
}
},
diff --git a/app/javascript/flavours/glitch/features/notifications_v2/components/notification_follow.tsx b/app/javascript/flavours/glitch/features/notifications_v2/components/notification_follow.tsx
index f154e801fb..cabb671815 100644
--- a/app/javascript/flavours/glitch/features/notifications_v2/components/notification_follow.tsx
+++ b/app/javascript/flavours/glitch/features/notifications_v2/components/notification_follow.tsx
@@ -1,16 +1,19 @@
import { FormattedMessage } from 'react-intl';
+import { Link } from 'react-router-dom';
+
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
import { FollowersCounter } from 'flavours/glitch/components/counters';
import { FollowButton } from 'flavours/glitch/components/follow_button';
import { ShortNumber } from 'flavours/glitch/components/short_number';
+import { me } from 'flavours/glitch/initial_state';
import type { NotificationGroupFollow } from 'flavours/glitch/models/notification_group';
import { useAppSelector } from 'flavours/glitch/store';
import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status';
-const labelRenderer: LabelRenderer = (displayedName, total) => {
+const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
if (total === 1)
return (
{
return (
+ seeMoreHref ? {chunks} : chunks,
}}
/>
);
@@ -46,6 +51,10 @@ export const NotificationFollow: React.FC<{
notification: NotificationGroupFollow;
unread: boolean;
}> = ({ notification, unread }) => {
+ const username = useAppSelector(
+ (state) => state.accounts.getIn([me, 'username']) as string,
+ );
+
let actions: JSX.Element | undefined;
let additionalContent: JSX.Element | undefined;
@@ -68,6 +77,7 @@ export const NotificationFollow: React.FC<{
timestamp={notification.latest_page_notification_at}
count={notification.notifications_count}
labelRenderer={labelRenderer}
+ labelSeeMoreHref={`/@${username}/followers`}
unread={unread}
actions={actions}
additionalContent={additionalContent}
diff --git a/app/javascript/flavours/glitch/reducers/notification_groups.ts b/app/javascript/flavours/glitch/reducers/notification_groups.ts
index d1dacc7964..09c0c5c3ee 100644
--- a/app/javascript/flavours/glitch/reducers/notification_groups.ts
+++ b/app/javascript/flavours/glitch/reducers/notification_groups.ts
@@ -21,7 +21,6 @@ import {
unmountNotifications,
refreshStaleNotificationGroups,
pollRecentNotifications,
- shouldGroupNotificationType,
} from 'flavours/glitch/actions/notification_groups';
import {
disconnectTimeline,
@@ -30,6 +29,7 @@ import {
import type {
ApiNotificationJSON,
ApiNotificationGroupJSON,
+ NotificationType,
} from 'flavours/glitch/api_types/notifications';
import { compareId } from 'flavours/glitch/compare_id';
import { usePendingItems } from 'flavours/glitch/initial_state';
@@ -205,8 +205,9 @@ function mergeGapsAround(
function processNewNotification(
groups: NotificationGroupsState['groups'],
notification: ApiNotificationJSON,
+ groupedTypes: NotificationType[],
) {
- if (!shouldGroupNotificationType(notification.type)) {
+ if (!groupedTypes.includes(notification.type)) {
notification = {
...notification,
group_key: `ungrouped-${notification.id}`,
@@ -476,11 +477,13 @@ export const notificationGroupsReducer = createReducer(
trimNotifications(state);
})
.addCase(processNewNotificationForGroups.fulfilled, (state, action) => {
- const notification = action.payload;
- if (notification) {
+ if (action.payload) {
+ const { notification, groupedTypes } = action.payload;
+
processNewNotification(
usePendingItems ? state.pendingGroups : state.groups,
notification,
+ groupedTypes,
);
updateLastReadId(state);
trimNotifications(state);
diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js
index 660b5f11ca..bfea4abe44 100644
--- a/app/javascript/flavours/glitch/reducers/settings.js
+++ b/app/javascript/flavours/glitch/reducers/settings.js
@@ -79,6 +79,10 @@ const initialState = ImmutableMap({
'admin.sign_up': true,
'admin.report': true,
}),
+
+ group: ImmutableMap({
+ follow: true
+ }),
}),
firehose: ImmutableMap({
diff --git a/app/javascript/flavours/glitch/selectors/settings.ts b/app/javascript/flavours/glitch/selectors/settings.ts
index d66f00f0e1..5229b15cf0 100644
--- a/app/javascript/flavours/glitch/selectors/settings.ts
+++ b/app/javascript/flavours/glitch/selectors/settings.ts
@@ -52,4 +52,7 @@ export const selectSettingsNotificationsMinimizeFilteredBanner = (
) =>
state.settings.getIn(['notifications', 'minimizeFilteredBanner']) as boolean;
+export const selectSettingsNotificationsGroupFollows = (state: RootState) =>
+ state.settings.getIn(['notifications', 'group', 'follow']) as boolean;
+
/* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */