Notify story creator for replies

This commit is contained in:
Jamie Kyle 2022-10-11 10:59:02 -07:00 committed by GitHub
parent 512d655d32
commit 25bc16300c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 250 additions and 135 deletions

View file

@ -1,7 +1,13 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, {
useCallback,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import classNames from 'classnames';
import { usePopper } from 'react-popper';
import type { AttachmentType } from '../types/Attachment';
@ -12,6 +18,7 @@ import type { InputApi } from './CompositionInput';
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
import type { RenderEmojiPickerProps } from './conversation/ReactionPicker';
import type { ReplyType, StorySendStateType } from '../types/Stories';
import { StoryViewTargetType } from '../types/Stories';
import { Avatar, AvatarSize } from './Avatar';
import { CompositionInput } from './CompositionInput';
import { ContactName } from './conversation/ContactName';
@ -78,7 +85,7 @@ const MESSAGE_DEFAULT_PROPS = {
viewStory: shouldNeverBeCalled,
};
enum Tab {
export enum StoryViewsNRepliesTab {
Replies = 'Replies',
Views = 'Views',
}
@ -109,6 +116,8 @@ export type PropsType = {
sortedGroupMembers?: Array<ConversationType>;
storyPreviewAttachment?: AttachmentType;
views: Array<StorySendStateType>;
viewTarget: StoryViewTargetType;
onChangeViewTarget: (target: StoryViewTargetType) => unknown;
};
export const StoryViewsNRepliesModal = ({
@ -133,14 +142,30 @@ export const StoryViewsNRepliesModal = ({
sortedGroupMembers,
storyPreviewAttachment,
views,
viewTarget,
onChangeViewTarget,
}: PropsType): JSX.Element | null => {
const containerElementRef = useRef<HTMLDivElement | null>(null);
const inputApiRef = useRef<InputApi | undefined>();
const shouldScrollToBottomRef = useRef(false);
const [bottom, setBottom] = useState<HTMLDivElement | null>(null);
const shouldScrollToBottomRef = useRef(true);
const bottomRef = useRef<HTMLDivElement>(null);
const [messageBodyText, setMessageBodyText] = useState('');
const [showReactionPicker, setShowReactionPicker] = useState(false);
const currentTab = useMemo<StoryViewsNRepliesTab>(() => {
return viewTarget === StoryViewTargetType.Replies
? StoryViewsNRepliesTab.Replies
: StoryViewsNRepliesTab.Views;
}, [viewTarget]);
const onTabChange = (tab: string) => {
onChangeViewTarget(
tab === StoryViewsNRepliesTab.Replies
? StoryViewTargetType.Replies
: StoryViewTargetType.Views
);
};
const focusComposer = useCallback(() => {
if (inputApiRef.current) {
inputApiRef.current.focus();
@ -170,12 +195,16 @@ export const StoryViewsNRepliesModal = ({
let composerElement: JSX.Element | undefined;
useEffect(() => {
if (replies.length && shouldScrollToBottomRef.current) {
bottom?.scrollIntoView({ behavior: 'smooth' });
useLayoutEffect(() => {
if (
currentTab === StoryViewsNRepliesTab.Replies &&
replies.length &&
shouldScrollToBottomRef.current
) {
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
shouldScrollToBottomRef.current = false;
}
}, [bottom, replies.length]);
}, [currentTab, replies.length]);
if (canReply) {
composerElement = (
@ -348,7 +377,7 @@ export const StoryViewsNRepliesModal = ({
</div>
)
)}
<div ref={setBottom} />
<div ref={bottomRef} />
</div>
);
} else if (isGroupStory) {
@ -414,23 +443,24 @@ export const StoryViewsNRepliesModal = ({
const tabsElement =
viewsElement && repliesElement ? (
<Tabs
initialSelectedTab={Tab.Views}
selectedTab={currentTab}
onTabChange={onTabChange}
moduleClassName="StoryViewsNRepliesModal__tabs"
tabs={[
{
id: Tab.Views,
id: StoryViewsNRepliesTab.Views,
label: i18n('StoryViewsNRepliesModal__tab--views'),
},
{
id: Tab.Replies,
id: StoryViewsNRepliesTab.Replies,
label: i18n('StoryViewsNRepliesModal__tab--replies'),
},
]}
>
{({ selectedTab }) => (
<>
{selectedTab === Tab.Views && viewsElement}
{selectedTab === Tab.Replies && (
{selectedTab === StoryViewsNRepliesTab.Views && viewsElement}
{selectedTab === StoryViewsNRepliesTab.Replies && (
<>
{repliesElement}
{composerElement}