// Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useState } from 'react'; import classNames from 'classnames'; import type { AttachmentType } from '../types/Attachment'; import type { LocalizerType } from '../types/Util'; import type { ConversationType } from '../state/ducks/conversations'; import { Avatar, AvatarSize, AvatarStoryRing } from './Avatar'; import { ConfirmationDialog } from './ConfirmationDialog'; import { ContextMenuPopper } from './ContextMenu'; import { MessageTimestamp } from './conversation/MessageTimestamp'; import { StoryImage } from './StoryImage'; import { getAvatarColor } from '../types/Colors'; export type ConversationStoryType = { conversationId: string; group?: Pick< ConversationType, | 'acceptedMessageRequest' | 'avatarPath' | 'color' | 'id' | 'name' | 'profileName' | 'sharedGroupNames' | 'title' >; hasMultiple?: boolean; isHidden?: boolean; searchNames?: string; // This is just here to satisfy Fuse's types stories: Array; }; export type StoryViewType = { attachment?: AttachmentType; canReply?: boolean; hasReplies?: boolean; hasRepliesFromSelf?: boolean; isHidden?: boolean; isUnread?: boolean; messageId: string; sender: Pick< ConversationType, | 'acceptedMessageRequest' | 'avatarPath' | 'color' | 'firstName' | 'id' | 'isMe' | 'name' | 'profileName' | 'sharedGroupNames' | 'title' >; timestamp: number; }; export type PropsType = Pick< ConversationStoryType, 'group' | 'hasMultiple' | 'isHidden' > & { i18n: LocalizerType; onClick: () => unknown; onGoToConversation: (conversationId: string) => unknown; onHideStory: (conversationId: string) => unknown; queueStoryDownload: (storyId: string) => unknown; story: StoryViewType; }; export const StoryListItem = ({ group, hasMultiple, i18n, isHidden, onClick, onGoToConversation, onHideStory, queueStoryDownload, story, }: PropsType): JSX.Element => { const [hasConfirmHideStory, setHasConfirmHideStory] = useState(false); const [isShowingContextMenu, setIsShowingContextMenu] = useState(false); const [referenceElement, setReferenceElement] = useState(null); const { attachment, hasReplies, hasRepliesFromSelf, isUnread, sender, timestamp, } = story; const { acceptedMessageRequest, avatarPath, color, firstName, isMe, name, profileName, sharedGroupNames, title, } = sender; let avatarStoryRing: AvatarStoryRing | undefined; if (attachment) { avatarStoryRing = isUnread ? AvatarStoryRing.Unread : AvatarStoryRing.Read; } let repliesElement: JSX.Element | undefined; if (hasRepliesFromSelf) { repliesElement =
; } else if (hasReplies) { repliesElement =
; } return ( <> { if (isHidden) { onHideStory(sender.id); } else { setHasConfirmHideStory(true); } }, }, { icon: 'StoryListItem__icon--chat', label: i18n('StoryListItem__go-to-chat'), onClick: () => { onGoToConversation(sender.id); }, }, ]} onClose={() => setIsShowingContextMenu(false)} popperOptions={{ placement: 'bottom', strategy: 'absolute', }} referenceElement={referenceElement} /> {hasConfirmHideStory && ( onHideStory(sender.id), style: 'affirmative', text: i18n('StoryListItem__hide-modal--confirm'), }, ]} i18n={i18n} onClose={() => { setHasConfirmHideStory(false); }} > {i18n('StoryListItem__hide-modal--body', [String(firstName)])} )} ); };