Add grouped notifications messaging

This commit is contained in:
Justin 2022-05-24 16:49:59 -04:00
parent 1eec48e7d3
commit 517c21ae52
4 changed files with 50 additions and 3 deletions

View File

@ -28,6 +28,31 @@ describe('<Notification />', () => {
expect(screen.getByTestId('notification')).toBeInTheDocument(); expect(screen.getByTestId('notification')).toBeInTheDocument();
expect(screen.getByTestId('account')).toContainHTML('neko@rdrama.cc'); expect(screen.getByTestId('account')).toContainHTML('neko@rdrama.cc');
expect(screen.getByTestId('message')).toHaveTextContent('Nekobit followed you');
});
describe('grouped notifications', () => {
it('renders a grouped follow notification for more than 2', async() => {
const { notification, state } = normalize(require('soapbox/__fixtures__/notification-follow.json'));
const groupedNotification = { ...notification.toJS(), total_count: 5 };
render(<Notification notification={groupedNotification} />, undefined, state);
expect(screen.getByTestId('notification')).toBeInTheDocument();
expect(screen.getByTestId('account')).toContainHTML('neko@rdrama.cc');
expect(screen.getByTestId('message')).toHaveTextContent('Nekobit + 4 others followed you');
});
it('renders a grouped follow notification for 1', async() => {
const { notification, state } = normalize(require('soapbox/__fixtures__/notification-follow.json'));
const groupedNotification = { ...notification.toJS(), total_count: 2 };
render(<Notification notification={groupedNotification} />, undefined, state);
expect(screen.getByTestId('notification')).toBeInTheDocument();
expect(screen.getByTestId('account')).toContainHTML('neko@rdrama.cc');
expect(screen.getByTestId('message')).toHaveTextContent('Nekobit + 1 other followed you');
});
}); });
it('renders a favourite notification', async() => { it('renders a favourite notification', async() => {

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { HotKeys } from 'react-hotkeys'; import { HotKeys } from 'react-hotkeys';
import { defineMessages, IntlShape, MessageDescriptor } from 'react-intl'; import { defineMessages, FormattedMessage, IntlShape, MessageDescriptor } from 'react-intl';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
@ -102,13 +102,27 @@ const buildMessage = (
intl: IntlShape, intl: IntlShape,
type: NotificationType, type: NotificationType,
account: Account, account: Account,
totalCount: number | null,
targetName: string, targetName: string,
instanceTitle: string, instanceTitle: string,
): React.ReactNode => { ): React.ReactNode => {
const link = buildLink(account); const link = buildLink(account);
const name = intl.formatMessage({
id: 'notification.name',
defaultMessage: '{link}{others}',
}, {
link,
others: totalCount && totalCount > 0 ? (
<FormattedMessage
id='notification.others'
defaultMessage=' + {count} {count, plural, one {other} other {others}}'
values={{ count: totalCount - 1 }}
/>
) : '',
});
return intl.formatMessage(messages[type], { return intl.formatMessage(messages[type], {
name: link, name,
targetName, targetName,
instance: instanceTitle, instance: instanceTitle,
}); });
@ -268,7 +282,7 @@ const Notification: React.FC<INotificaton> = (props) => {
const targetName = notification.target && typeof notification.target === 'object' ? notification.target.acct : ''; const targetName = notification.target && typeof notification.target === 'object' ? notification.target.acct : '';
const message: React.ReactNode = type && account && typeof account === 'object' ? buildMessage(intl, type, account, targetName, instance.title) : null; const message: React.ReactNode = type && account && typeof account === 'object' ? buildMessage(intl, type, account, notification.total_count, targetName, instance.title) : null;
return ( return (
<HotKeys handlers={getHandlers()} data-testid='notification'> <HotKeys handlers={getHandlers()} data-testid='notification'>
@ -300,6 +314,7 @@ const Notification: React.FC<INotificaton> = (props) => {
theme='muted' theme='muted'
size='sm' size='sm'
truncate truncate
data-testid='message'
> >
{message} {message}
</Text> </Text>

View File

@ -34,6 +34,7 @@ export const NotificationRecord = ImmutableRecord({
status: null as EmbeddedEntity<Status>, status: null as EmbeddedEntity<Status>,
target: null as EmbeddedEntity<Account>, // move target: null as EmbeddedEntity<Account>, // move
type: '' as NotificationType | '', type: '' as NotificationType | '',
total_count: null as number | null, // grouped notifications
}); });
export const normalizeNotification = (notification: Record<string, any>) => { export const normalizeNotification = (notification: Record<string, any>) => {

View File

@ -274,6 +274,7 @@ describe('notifications reducer', () => {
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: null, chat_message: null,
total_count: null,
})], })],
['10743', ImmutableMap({ ['10743', ImmutableMap({
id: '10743', id: '10743',
@ -284,6 +285,7 @@ describe('notifications reducer', () => {
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: null, emoji: null,
chat_message: null, chat_message: null,
total_count: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -294,6 +296,7 @@ describe('notifications reducer', () => {
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: null, emoji: null,
chat_message: null, chat_message: null,
total_count: null,
})], })],
['10734', ImmutableMap({ ['10734', ImmutableMap({
id: '10734', id: '10734',
@ -339,6 +342,7 @@ describe('notifications reducer', () => {
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: null, chat_message: null,
total_count: null,
})], })],
['10743', ImmutableMap({ ['10743', ImmutableMap({
id: '10743', id: '10743',
@ -349,6 +353,7 @@ describe('notifications reducer', () => {
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: null, emoji: null,
chat_message: null, chat_message: null,
total_count: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -359,6 +364,7 @@ describe('notifications reducer', () => {
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: null, emoji: null,
chat_message: null, chat_message: null,
total_count: null,
})], })],
]), ]),
unread: 1, unread: 1,