Notify story creator for replies
This commit is contained in:
parent
512d655d32
commit
25bc16300c
16 changed files with 250 additions and 135 deletions
|
@ -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}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue