Merge branch 'pr2462'
This commit is contained in:
commit
4778c61349
@ -504,3 +504,75 @@ export function toggleFavourite(statusId, skipModal = false) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const addReaction = (statusId, name, url) => (dispatch, getState) => {
|
||||||
|
const status = getState().get('statuses').get(statusId);
|
||||||
|
let alreadyAdded = false;
|
||||||
|
if (status) {
|
||||||
|
const reaction = status.get('reactions').find(x => x.get('name') === name);
|
||||||
|
if (reaction && reaction.get('me')) {
|
||||||
|
alreadyAdded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
dispatch(addReactionRequest(statusId, name, url));
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeURIComponent is required for the Keycap Number Sign emoji, see:
|
||||||
|
// <https://github.com/glitch-soc/mastodon/pull/1980#issuecomment-1345538932>
|
||||||
|
api(getState).post(`/api/v1/statuses/${statusId}/react/${encodeURIComponent(name)}`).then(() => {
|
||||||
|
dispatch(addReactionSuccess(statusId, name));
|
||||||
|
}).catch(err => {
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
dispatch(addReactionFail(statusId, name, err));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addReactionRequest = (statusId, name, url) => ({
|
||||||
|
type: REACTION_ADD_REQUEST,
|
||||||
|
id: statusId,
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addReactionSuccess = (statusId, name) => ({
|
||||||
|
type: REACTION_ADD_SUCCESS,
|
||||||
|
id: statusId,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addReactionFail = (statusId, name, error) => ({
|
||||||
|
type: REACTION_ADD_FAIL,
|
||||||
|
id: statusId,
|
||||||
|
name,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeReaction = (statusId, name) => (dispatch, getState) => {
|
||||||
|
dispatch(removeReactionRequest(statusId, name));
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${statusId}/unreact/${encodeURIComponent(name)}`).then(() => {
|
||||||
|
dispatch(removeReactionSuccess(statusId, name));
|
||||||
|
}).catch(err => {
|
||||||
|
dispatch(removeReactionFail(statusId, name, err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeReactionRequest = (statusId, name) => ({
|
||||||
|
type: REACTION_REMOVE_REQUEST,
|
||||||
|
id: statusId,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeReactionSuccess = (statusId, name) => ({
|
||||||
|
type: REACTION_REMOVE_SUCCESS,
|
||||||
|
id: statusId,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const removeReactionFail = (statusId, name) => ({
|
||||||
|
type: REACTION_REMOVE_FAIL,
|
||||||
|
id: statusId,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
@ -11,6 +11,7 @@ export const allNotificationTypes = [
|
|||||||
'follow',
|
'follow',
|
||||||
'follow_request',
|
'follow_request',
|
||||||
'favourite',
|
'favourite',
|
||||||
|
'reaction',
|
||||||
'reblog',
|
'reblog',
|
||||||
'mention',
|
'mention',
|
||||||
'poll',
|
'poll',
|
||||||
@ -24,6 +25,7 @@ export const allNotificationTypes = [
|
|||||||
|
|
||||||
export type NotificationWithStatusType =
|
export type NotificationWithStatusType =
|
||||||
| 'favourite'
|
| 'favourite'
|
||||||
|
| 'reaction'
|
||||||
| 'reblog'
|
| 'reblog'
|
||||||
| 'status'
|
| 'status'
|
||||||
| 'mention'
|
| 'mention'
|
||||||
|
@ -15,6 +15,7 @@ import { NotificationFollowRequest } from './notification_follow_request';
|
|||||||
import { NotificationMention } from './notification_mention';
|
import { NotificationMention } from './notification_mention';
|
||||||
import { NotificationModerationWarning } from './notification_moderation_warning';
|
import { NotificationModerationWarning } from './notification_moderation_warning';
|
||||||
import { NotificationPoll } from './notification_poll';
|
import { NotificationPoll } from './notification_poll';
|
||||||
|
import { NotificationReaction } from './notification_reaction';
|
||||||
import { NotificationReblog } from './notification_reblog';
|
import { NotificationReblog } from './notification_reblog';
|
||||||
import { NotificationSeveredRelationships } from './notification_severed_relationships';
|
import { NotificationSeveredRelationships } from './notification_severed_relationships';
|
||||||
import { NotificationStatus } from './notification_status';
|
import { NotificationStatus } from './notification_status';
|
||||||
@ -78,6 +79,14 @@ export const NotificationGroup: React.FC<{
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'reaction':
|
||||||
|
content = (
|
||||||
|
<NotificationReaction
|
||||||
|
unread={unread}
|
||||||
|
notification={notificationGroup}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
case 'severed_relationships':
|
case 'severed_relationships':
|
||||||
content = (
|
content = (
|
||||||
<NotificationSeveredRelationships
|
<NotificationSeveredRelationships
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import MoodIcon from '@/material-icons/400-24px/mood.svg?react';
|
||||||
|
import type { NotificationGroupReaction } from 'flavours/glitch/models/notification_group';
|
||||||
|
|
||||||
|
import type { LabelRenderer } from './notification_group_with_status';
|
||||||
|
import { NotificationGroupWithStatus } from './notification_group_with_status';
|
||||||
|
|
||||||
|
const labelRenderer: LabelRenderer = (values) => (
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.reaction'
|
||||||
|
defaultMessage='{name} reacted to your status'
|
||||||
|
values={values}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const NotificationReaction: React.FC<{
|
||||||
|
notification: NotificationGroupReaction;
|
||||||
|
unread: boolean;
|
||||||
|
}> = ({ notification, unread }) => {
|
||||||
|
return (
|
||||||
|
<NotificationGroupWithStatus
|
||||||
|
type='reaction'
|
||||||
|
icon={MoodIcon}
|
||||||
|
iconId='react'
|
||||||
|
accountIds={notification.sampleAccountIds}
|
||||||
|
statusId={notification.statusId}
|
||||||
|
timestamp={notification.latest_page_notification_at}
|
||||||
|
count={notification.notifications_count}
|
||||||
|
labelRenderer={labelRenderer}
|
||||||
|
unread={unread}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -5,6 +5,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|||||||
|
|
||||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||||
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
||||||
|
import MoodIcon from '@/material-icons/400-24px/mood.svg?react';
|
||||||
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
||||||
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||||
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
||||||
@ -23,6 +24,10 @@ const tooltips = defineMessages({
|
|||||||
id: 'notifications.filter.favourites',
|
id: 'notifications.filter.favourites',
|
||||||
defaultMessage: 'Favorites',
|
defaultMessage: 'Favorites',
|
||||||
},
|
},
|
||||||
|
reactions: {
|
||||||
|
id: 'notifications.filter.reactions',
|
||||||
|
defaultMessage: 'Reactions',
|
||||||
|
},
|
||||||
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },
|
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' },
|
||||||
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
|
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
|
||||||
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
|
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
|
||||||
@ -91,6 +96,14 @@ export const FilterBar: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<Icon id='star' icon={StarIcon} />
|
<Icon id='star' icon={StarIcon} />
|
||||||
</BarButton>
|
</BarButton>
|
||||||
|
<BarButton
|
||||||
|
selectedFilter={selectedFilter}
|
||||||
|
type='reaction'
|
||||||
|
key='reaction'
|
||||||
|
title={intl.formatMessage(tooltips.reactions)}
|
||||||
|
>
|
||||||
|
<Icon id='react' icon={MoodIcon} />
|
||||||
|
</BarButton>
|
||||||
<BarButton
|
<BarButton
|
||||||
selectedFilter={selectedFilter}
|
selectedFilter={selectedFilter}
|
||||||
type='reblog'
|
type='reblog'
|
||||||
|
@ -31,6 +31,7 @@ interface BaseNotification<Type extends NotificationType>
|
|||||||
|
|
||||||
export type NotificationGroupFavourite =
|
export type NotificationGroupFavourite =
|
||||||
BaseNotificationWithStatus<'favourite'>;
|
BaseNotificationWithStatus<'favourite'>;
|
||||||
|
export type NotificationGroupReaction = BaseNotificationWithStatus<'reaction'>;
|
||||||
export type NotificationGroupReblog = BaseNotificationWithStatus<'reblog'>;
|
export type NotificationGroupReblog = BaseNotificationWithStatus<'reblog'>;
|
||||||
export type NotificationGroupStatus = BaseNotificationWithStatus<'status'>;
|
export type NotificationGroupStatus = BaseNotificationWithStatus<'status'>;
|
||||||
export type NotificationGroupMention = BaseNotificationWithStatus<'mention'>;
|
export type NotificationGroupMention = BaseNotificationWithStatus<'mention'>;
|
||||||
@ -76,6 +77,7 @@ export interface NotificationGroupAdminReport
|
|||||||
|
|
||||||
export type NotificationGroup =
|
export type NotificationGroup =
|
||||||
| NotificationGroupFavourite
|
| NotificationGroupFavourite
|
||||||
|
| NotificationGroupReaction
|
||||||
| NotificationGroupReblog
|
| NotificationGroupReblog
|
||||||
| NotificationGroupStatus
|
| NotificationGroupStatus
|
||||||
| NotificationGroupMention
|
| NotificationGroupMention
|
||||||
@ -120,6 +122,7 @@ export function createNotificationGroupFromJSON(
|
|||||||
|
|
||||||
switch (group.type) {
|
switch (group.type) {
|
||||||
case 'favourite':
|
case 'favourite':
|
||||||
|
case 'reaction':
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
case 'status':
|
case 'status':
|
||||||
case 'mention':
|
case 'mention':
|
||||||
@ -179,6 +182,7 @@ export function createNotificationGroupFromNotificationJSON(
|
|||||||
|
|
||||||
switch (notification.type) {
|
switch (notification.type) {
|
||||||
case 'favourite':
|
case 'favourite':
|
||||||
|
case 'reaction':
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
case 'status':
|
case 'status':
|
||||||
case 'mention':
|
case 'mention':
|
||||||
|
@ -10946,6 +10946,10 @@ noscript {
|
|||||||
color: $gold-star;
|
color: $gold-star;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--reaction &__icon {
|
||||||
|
color: $blurple-300;
|
||||||
|
}
|
||||||
|
|
||||||
&--reblog &__icon {
|
&--reblog &__icon {
|
||||||
color: $valid-value-color;
|
color: $valid-value-color;
|
||||||
}
|
}
|
||||||
@ -11119,7 +11123,8 @@ noscript {
|
|||||||
$icon-margin: 48px; // 40px avatar + 8px gap
|
$icon-margin: 48px; // 40px avatar + 8px gap
|
||||||
|
|
||||||
.status__content,
|
.status__content,
|
||||||
.status__action-bar {
|
.status__action-bar,
|
||||||
|
.reactions-bar {
|
||||||
margin-inline-start: $icon-margin;
|
margin-inline-start: $icon-margin;
|
||||||
width: calc(100% - $icon-margin);
|
width: calc(100% - $icon-margin);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class REST::NotificationGroupSerializer < ActiveModel::Serializer
|
|||||||
belongs_to :account_warning, key: :moderation_warning, if: :moderation_warning_event?, serializer: REST::AccountWarningSerializer
|
belongs_to :account_warning, key: :moderation_warning, if: :moderation_warning_event?, serializer: REST::AccountWarningSerializer
|
||||||
|
|
||||||
def status_type?
|
def status_type?
|
||||||
[:favourite, :reblog, :status, :mention, :poll, :update].include?(object.type)
|
[:favourite, :reaction, :reblog, :status, :mention, :poll, :update].include?(object.type)
|
||||||
end
|
end
|
||||||
|
|
||||||
def report_type?
|
def report_type?
|
||||||
|
@ -206,7 +206,7 @@ class NotifyService < BaseService
|
|||||||
private
|
private
|
||||||
|
|
||||||
def notification_group_key
|
def notification_group_key
|
||||||
return nil if @notification.filtered || %i(favourite reblog).exclude?(@notification.type)
|
return nil if @notification.filtered || %i(favourite reaction reblog).exclude?(@notification.type)
|
||||||
|
|
||||||
type_prefix = "#{@notification.type}-#{@notification.target_status.id}"
|
type_prefix = "#{@notification.type}-#{@notification.target_status.id}"
|
||||||
redis_key = "notif-group/#{@recipient.id}/#{type_prefix}"
|
redis_key = "notif-group/#{@recipient.id}/#{type_prefix}"
|
||||||
|
Loading…
Reference in New Issue
Block a user