Add grouped notifications messaging
This commit is contained in:
parent
1eec48e7d3
commit
517c21ae52
|
@ -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() => {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>) => {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue