Do not allow replies to self story

This commit is contained in:
Josh Perez 2022-09-21 15:19:16 -04:00 committed by GitHub
parent d221895b3a
commit b04fbb6d8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 17 deletions

View File

@ -5591,6 +5591,10 @@
"message": "No replies yet",
"description": "Placeholder text for when there are no replies"
},
"StoryViewsNRepliesModal__no-views": {
"message": "No views yet",
"description": "Placeholder text for when there are no views"
},
"StoryViewsNRepliesModal__tab--views": {
"message": "Views",
"description": "Title for views tab"

View File

@ -23,6 +23,7 @@
display: flex;
flex: 1;
justify-content: center;
padding: 80px 0;
user-select: none;
}
}

View File

@ -424,8 +424,10 @@ export const StoryViewer = ({
muteClassName = 'StoryViewer__soundless';
}
const isSent = Boolean(sendState);
const contextMenuOptions: ReadonlyArray<ContextMenuOptionType<unknown>> =
sendState
isSent
? [
{
icon: 'StoryListItem__icon--info',
@ -654,7 +656,7 @@ export const StoryViewer = ({
))}
</div>
<div className="StoryViewer__actions">
{(canReply || sendState) && (
{(canReply || isSent) && (
<button
className="StoryViewer__reply"
onClick={() => setHasStoryViewsNRepliesModal(true)}
@ -662,12 +664,12 @@ export const StoryViewer = ({
type="button"
>
<>
{sendState || replyCount > 0 ? (
{isSent || replyCount > 0 ? (
<span className="StoryViewer__reply__chevron">
{sendState && !hasReadReceiptSetting && !replyCount && (
{isSent && !hasReadReceiptSetting && !replyCount && (
<>{i18n('StoryViewer__views-off')}</>
)}
{sendState &&
{isSent &&
hasReadReceiptSetting &&
(viewCount === 1 ? (
<Intl
@ -682,7 +684,7 @@ export const StoryViewer = ({
components={[<strong>{viewCount}</strong>]}
/>
))}
{(sendState || viewCount > 0) && replyCount > 0 && ' '}
{(isSent || viewCount > 0) && replyCount > 0 && ' '}
{replyCount > 0 &&
(replyCount === 1 ? (
<Intl
@ -699,7 +701,7 @@ export const StoryViewer = ({
))}
</span>
) : null}
{!sendState && !replyCount && (
{!isSent && !replyCount && (
<span className="StoryViewer__reply__arrow">
{isGroupStory
? i18n('StoryViewer__reply-group')
@ -758,6 +760,7 @@ export const StoryViewer = ({
canReply={Boolean(canReply)}
getPreferredBadge={getPreferredBadge}
hasReadReceiptSetting={hasReadReceiptSetting}
hasViewsCapability={isSent}
i18n={i18n}
isGroupStory={isGroupStory}
onClose={() => setHasStoryViewsNRepliesModal(false)}

View File

@ -31,6 +31,9 @@ export default {
hasReadReceiptSetting: {
defaultValue: true,
},
hasViewsCapability: {
defaultValue: false,
},
i18n: {
defaultValue: i18n,
},
@ -168,10 +171,20 @@ CanReply.storyName = 'Can reply';
export const ViewsOnly = Template.bind({});
ViewsOnly.args = {
canReply: false,
hasViewsCapability: true,
views: getViewsAndReplies().views,
};
ViewsOnly.storyName = 'Views only';
export const NoViews = Template.bind({});
NoViews.args = {
canReply: false,
hasViewsCapability: true,
views: [],
};
NoViews.storyName = 'No views';
export const InAGroupNoReplies = Template.bind({});
InAGroupNoReplies.args = {
isGroupStory: true,
@ -182,6 +195,7 @@ export const InAGroup = Template.bind({});
{
const { views, replies } = getViewsAndReplies();
InAGroup.args = {
hasViewsCapability: true,
isGroupStory: true,
replies,
views,
@ -210,6 +224,7 @@ export const ReadReceiptsTurnedOff = Template.bind({});
ReadReceiptsTurnedOff.args = {
canReply: false,
hasReadReceiptSetting: false,
hasViewsCapability: true,
views: getViewsAndReplies().views,
};
ReadReceiptsTurnedOff.storyName = 'Read receipts turned off';
@ -219,6 +234,7 @@ export const GroupReadReceiptsOff = Template.bind({});
const { views, replies } = getViewsAndReplies();
GroupReadReceiptsOff.args = {
hasReadReceiptSetting: false,
hasViewsCapability: true,
isGroupStory: true,
replies,
views,

View File

@ -88,6 +88,7 @@ export type PropsType = {
canReply: boolean;
getPreferredBadge: PreferredBadgeSelectorType;
hasReadReceiptSetting: boolean;
hasViewsCapability: boolean;
i18n: LocalizerType;
isGroupStory?: boolean;
onClose: () => unknown;
@ -115,6 +116,7 @@ export const StoryViewsNRepliesModal = ({
canReply,
getPreferredBadge,
hasReadReceiptSetting,
hasViewsCapability,
i18n,
isGroupStory,
onClose,
@ -353,7 +355,7 @@ export const StoryViewsNRepliesModal = ({
}
let viewsElement: JSX.Element | undefined;
if (!hasReadReceiptSetting) {
if (hasViewsCapability && !hasReadReceiptSetting) {
viewsElement = (
<div className="StoryViewsNRepliesModal__read-receipts-off">
{i18n('StoryViewsNRepliesModal__read-receipts-off')}
@ -397,10 +399,16 @@ export const StoryViewsNRepliesModal = ({
))}
</div>
);
} else if (hasViewsCapability) {
viewsElement = (
<div className="StoryViewsNRepliesModal__replies--none">
{i18n('StoryViewsNRepliesModal__no-views')}
</div>
);
}
const tabsElement =
views.length && replies.length ? (
viewsElement && repliesElement ? (
<Tabs
initialSelectedTab={Tab.Views}
moduleClassName="StoryViewsNRepliesModal__tabs"

View File

@ -1667,7 +1667,9 @@ function canReplyOrReact(
}
if (isStory(message)) {
return Boolean(message.canReplyToStory);
return (
Boolean(message.canReplyToStory) && conversation.id !== ourConversationId
);
}
// Fail safe.

View File

@ -29,6 +29,7 @@ import {
getConversationSelector,
getMe,
} from './conversations';
import { getUserConversationId } from './user';
import { getDistributionListSelector } from './storyDistributionLists';
import { getStoriesEnabled } from './items';
import { calculateExpirationTimestamp } from '../../util/expirationTimer';
@ -126,6 +127,7 @@ function getAvatarData(
export function getStoryView(
conversationSelector: GetConversationByIdType,
ourConversationId: string | undefined,
story: StoryDataType
): StoryViewType {
const sender = pick(conversationSelector(story.sourceUuid || story.source), [
@ -176,7 +178,7 @@ export function getStoryView(
return {
attachment,
canReply: canReply(story, undefined, conversationSelector),
canReply: canReply(story, ourConversationId, conversationSelector),
isHidden: Boolean(sender.hideStory),
isUnread: story.readStatus === ReadStatus.Unread,
messageId: story.messageId,
@ -193,6 +195,7 @@ export function getStoryView(
export function getConversationStory(
conversationSelector: GetConversationByIdType,
ourConversationId: string | undefined,
story: StoryDataType
): ConversationStoryType {
const sender = pick(conversationSelector(story.sourceUuid || story.source), [
@ -212,7 +215,11 @@ export function getConversationStory(
'title',
]);
const storyView = getStoryView(conversationSelector, story);
const storyView = getStoryView(
conversationSelector,
ourConversationId,
story
);
return {
conversationId: conversation.id,
@ -292,10 +299,12 @@ export const getStories = createSelector(
getConversationSelector,
getDistributionListSelector,
getStoriesState,
getUserConversationId,
(
conversationSelector,
distributionListSelector,
{ stories }: Readonly<StoriesStateType>
{ stories }: Readonly<StoriesStateType>,
ourConversationId
): {
hiddenStories: Array<ConversationStoryType>;
myStories: Array<MyStoryType>;
@ -312,6 +321,7 @@ export const getStories = createSelector(
const conversationStory = getConversationStory(
conversationSelector,
ourConversationId,
story
);
@ -339,7 +349,11 @@ export const getStories = createSelector(
return;
}
const storyView = getStoryView(conversationSelector, story);
const storyView = getStoryView(
conversationSelector,
ourConversationId,
story
);
const existingMyStory = myStoriesById.get(sentId) || { stories: [] };
@ -427,7 +441,8 @@ export const getHasStoriesSelector = createSelector(
export const getStoryByIdSelector = createSelector(
getStoriesState,
({ stories }) =>
getUserConversationId,
({ stories }, ourConversationId) =>
(
conversationSelector: GetConversationByIdType,
messageId: string
@ -441,8 +456,12 @@ export const getStoryByIdSelector = createSelector(
}
return {
conversationStory: getConversationStory(conversationSelector, story),
storyView: getStoryView(conversationSelector, story),
conversationStory: getConversationStory(
conversationSelector,
ourConversationId,
story
),
storyView: getStoryView(conversationSelector, ourConversationId, story),
};
}
);