Notification: restore most notification types

next-virtuoso
Alex Gleason 2022-04-16 14:15:37 -05:00
rodzic 5d2e10b2fa
commit 69e22a4144
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
3 zmienionych plików z 62 dodań i 25 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ import { useHistory } from 'react-router-dom';
import Icon from '../../../components/icon'; import Icon from '../../../components/icon';
import Permalink from '../../../components/permalink'; import Permalink from '../../../components/permalink';
import { HStack, Text } from '../../../components/ui'; import { HStack, Text, Emoji } from '../../../components/ui';
import AccountContainer from '../../../containers/account_container'; import AccountContainer from '../../../containers/account_container';
import StatusContainer from '../../../containers/status_container'; import StatusContainer from '../../../containers/status_container';
@ -39,22 +39,28 @@ const buildLink = (account: Account): JSX.Element => (
</bdi> </bdi>
); );
export const NOTIFICATION_TYPES = ['follow', 'mention', 'favourite', 'reblog', 'status']; const icons: Record<NotificationType, string> = {
const icons = {
follow: require('@tabler/icons/icons/user-plus.svg'), follow: require('@tabler/icons/icons/user-plus.svg'),
follow_request: require('@tabler/icons/icons/user-plus.svg'),
mention: require('@tabler/icons/icons/at.svg'), mention: require('@tabler/icons/icons/at.svg'),
favourite: require('@tabler/icons/icons/heart.svg'), favourite: require('@tabler/icons/icons/heart.svg'),
reblog: require('@tabler/icons/icons/repeat.svg'), reblog: require('@tabler/icons/icons/repeat.svg'),
status: require('@tabler/icons/icons/home.svg'), status: require('@tabler/icons/icons/home.svg'),
poll: require('@tabler/icons/icons/chart-bar.svg'),
move: require('@tabler/icons/icons/briefcase.svg'),
'pleroma:chat_mention': require('@tabler/icons/icons/messages.svg'),
'pleroma:emoji_reaction': require('@tabler/icons/icons/mood-happy.svg'), // FIXME: show the actual emoji
}; };
// @ts-ignore
const messages: Record<NotificationType, { id: string, defaultMessage: string }> = { const messages: Record<NotificationType, { id: string, defaultMessage: string }> = {
follow: { follow: {
id: 'notification.follow', id: 'notification.follow',
defaultMessage: '{name} followed you', defaultMessage: '{name} followed you',
}, },
follow_request: {
id: 'notification.follow_request',
defaultMessage: '{name} has requested to follow you',
},
mention: { mention: {
id: 'notification.mentioned', id: 'notification.mentioned',
defaultMessage: '{name} mentioned you', defaultMessage: '{name} mentioned you',
@ -71,6 +77,22 @@ const messages: Record<NotificationType, { id: string, defaultMessage: string }>
id: 'notification.status', id: 'notification.status',
defaultMessage: '{name} just posted', defaultMessage: '{name} just posted',
}, },
poll: {
id: 'notification.poll',
defaultMessage: 'A poll you have voted in has ended',
},
move: {
id: 'notification.move',
defaultMessage: '{name} moved to {targetName}',
},
'pleroma:chat_mention': {
id: 'notification.chat_mention',
defaultMessage: '{name} sent you a message',
},
'pleroma:emoji_reaction': {
id: 'notification.pleroma:emoji_reaction',
defaultMessage: '{name} reacted to your post',
},
}; };
const buildMessage = (type: NotificationType, account: Account): JSX.Element => { const buildMessage = (type: NotificationType, account: Account): JSX.Element => {
@ -170,9 +192,30 @@ const Notification: React.FC<INotificaton> = (props) => {
onMoveDown(notification.id); onMoveDown(notification.id);
}; };
const renderIcon = (): React.ReactNode => {
if (type === 'pleroma:emoji_reaction' && notification.emoji) {
return (
<Emoji
emoji={notification.emoji}
className='w-4 h-4'
/>
);
} else if (type) {
return (
<Icon
src={icons[type]}
className='text-primary-600'
/>
);
} else {
return null;
}
};
const renderContent = () => { const renderContent = () => {
switch (type) { switch (type) {
case 'follow': case 'follow':
case 'follow_request':
return account && typeof account === 'object' ? ( return account && typeof account === 'object' ? (
<AccountContainer <AccountContainer
id={account.id} id={account.id}
@ -180,10 +223,14 @@ const Notification: React.FC<INotificaton> = (props) => {
avatarSize={48} avatarSize={48}
/> />
) : null; ) : null;
case 'move':
// TODO
return null;
case 'favourite': case 'favourite':
case 'mention': case 'mention':
case 'reblog': case 'reblog':
case 'status': case 'status':
case 'pleroma:emoji_reaction':
return status && typeof status === 'object' ? ( return status && typeof status === 'object' ? (
<StatusContainer <StatusContainer
// @ts-ignore // @ts-ignore
@ -204,11 +251,7 @@ const Notification: React.FC<INotificaton> = (props) => {
} }
}; };
if (!NOTIFICATION_TYPES.includes(type)) { const message: React.ReactNode = type && account && typeof account === 'object' ? buildMessage(type, account) : null;
return null;
}
const message: React.ReactNode = account && typeof account === 'object' ? buildMessage(type, account) : null;
return ( return (
<HotKeys handlers={getHandlers()}> <HotKeys handlers={getHandlers()}>
@ -219,8 +262,8 @@ const Notification: React.FC<INotificaton> = (props) => {
notificationForScreenReader( notificationForScreenReader(
intl, intl,
intl.formatMessage({ intl.formatMessage({
id: messages[type].id, id: type && messages[type].id,
defaultMessage: messages[type].defaultMessage, defaultMessage: type && messages[type].defaultMessage,
}, },
{ {
name: account && typeof account === 'object' ? account.acct : '', name: account && typeof account === 'object' ? account.acct : '',
@ -232,11 +275,7 @@ const Notification: React.FC<INotificaton> = (props) => {
<div className='p-4 focusable'> <div className='p-4 focusable'>
<div className='mb-2'> <div className='mb-2'>
<HStack alignItems='center' space={1.5}> <HStack alignItems='center' space={1.5}>
<Icon {renderIcon()}
// @ts-ignore
src={icons[type]}
className='text-primary-600'
/>
<div> <div>
<Text <Text

Wyświetl plik

@ -23,7 +23,6 @@ import ScrollableList from '../../components/scrollable_list';
import TimelineQueueButtonHeader from '../../components/timeline_queue_button_header'; import TimelineQueueButtonHeader from '../../components/timeline_queue_button_header';
import { Column } from '../../components/ui'; import { Column } from '../../components/ui';
import { NOTIFICATION_TYPES } from './components/notification';
import FilterBarContainer from './containers/filter_bar_container'; import FilterBarContainer from './containers/filter_bar_container';
import NotificationContainer from './containers/notification_container'; import NotificationContainer from './containers/notification_container';
@ -200,13 +199,12 @@ class Notifications extends React.PureComponent {
} }
this.scrollableContent = scrollableContent; this.scrollableContent = scrollableContent;
const notificationsToRender = notifications.filter((notification) => NOTIFICATION_TYPES.includes(notification.get('type')));
const scrollContainer = ( const scrollContainer = (
<ScrollableList <ScrollableList
scrollKey='notifications' scrollKey='notifications'
isLoading={isLoading} isLoading={isLoading}
showLoading={isLoading && notificationsToRender.size === 0} showLoading={isLoading && notifications.size === 0}
hasMore={hasMore} hasMore={hasMore}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
placeholderComponent={PlaceholderNotification} placeholderComponent={PlaceholderNotification}
@ -216,8 +214,8 @@ class Notifications extends React.PureComponent {
onScrollToTop={this.handleScrollToTop} onScrollToTop={this.handleScrollToTop}
onScroll={this.handleScroll} onScroll={this.handleScroll}
className={classNames({ className={classNames({
'divide-y divide-gray-200 dark:divide-gray-600 divide-solid': notificationsToRender.size > 0, 'divide-y divide-gray-200 dark:divide-gray-600 divide-solid': notifications.size > 0,
'space-y-2': notificationsToRender.size === 0, 'space-y-2': notifications.size === 0,
})} })}
> >
{scrollableContent} {scrollableContent}

Wyświetl plik

@ -11,8 +11,8 @@ import {
import type { Account, Status, EmbeddedEntity } from 'soapbox/types/entities'; import type { Account, Status, EmbeddedEntity } from 'soapbox/types/entities';
export type NotificationType = '' export type NotificationType =
| 'follow' 'follow'
| 'follow_request' | 'follow_request'
| 'mention' | 'mention'
| 'reblog' | 'reblog'
@ -32,7 +32,7 @@ export const NotificationRecord = ImmutableRecord({
id: '', id: '',
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 | '',
}); });
export const normalizeNotification = (notification: Record<string, any>) => { export const normalizeNotification = (notification: Record<string, any>) => {