diff --git a/src/components/ProfilePreview.tsx b/src/components/ProfilePreview.tsx index 46f0a1089..3da40c028 100644 --- a/src/components/ProfilePreview.tsx +++ b/src/components/ProfilePreview.tsx @@ -13,6 +13,8 @@ export type ProfilePreviewProps = ComponentProps<'div'> & { address: string className?: string avatarClassName?: string + addressesContainerClassName?: string + showMaxOneAddress?: boolean withGrillAddress?: boolean withEvmAddress?: boolean nameClassName?: string @@ -23,6 +25,8 @@ const ProfilePreview = ({ className, avatarClassName, nameClassName, + addressesContainerClassName, + showMaxOneAddress = false, withGrillAddress = true, withEvmAddress = true, ...props @@ -42,25 +46,26 @@ const ProfilePreview = ({ address={address} className={cx('h-20 w-20', avatarClassName)} /> -
+
{showingAnyAddress && ( -
- {withGrillAddress && ( -
- - -
- )} +
+ {withGrillAddress && + (!isShowingEvmAddress || !showMaxOneAddress) && ( +
+ + +
+ )} {isShowingEvmAddress && (
diff --git a/src/components/auth/LoginModal/LoginModal.tsx b/src/components/auth/LoginModal/LoginModal.tsx index 74a57fd70..40e9ad381 100644 --- a/src/components/auth/LoginModal/LoginModal.tsx +++ b/src/components/auth/LoginModal/LoginModal.tsx @@ -13,9 +13,10 @@ const CaptchaInvisible = dynamic( ) export type LoginModalProps = ModalFunctionalityProps & { + initialOpenState?: LoginModalStep + onBackClick?: () => void afterLogin?: () => void beforeLogin?: () => void - openModal: () => void } type ModalTitle = { @@ -69,15 +70,18 @@ const modalHeader: ModalTitle = { export default function LoginModal({ afterLogin, beforeLogin, + initialOpenState = 'login', + onBackClick, ...props }: LoginModalProps) { const inputRef = useRef(null) - const [currentStep, setCurrentStep] = useState('login') + const [currentStep, setCurrentStep] = + useState(initialOpenState) - const onBackClick = () => setCurrentStep('login') + const usedOnBackClick = onBackClick || (() => setCurrentStep('login')) useEffect(() => { - if (props.isOpen) setCurrentStep('login') + if (props.isOpen) setCurrentStep(initialOpenState) }, [props.isOpen]) const ModalContent = loginModalContents[currentStep] @@ -91,7 +95,7 @@ export default function LoginModal({ title={title} withCloseButton description={desc} - onBackClick={withBackButton ? onBackClick : undefined} + onBackClick={withBackButton ? usedOnBackClick : undefined} closeModal={() => { props.closeModal() }} diff --git a/src/components/auth/LoginModal/LoginModalContent.tsx b/src/components/auth/LoginModal/LoginModalContent.tsx index 7f1f6a627..d643fdbdf 100644 --- a/src/components/auth/LoginModal/LoginModalContent.tsx +++ b/src/components/auth/LoginModal/LoginModalContent.tsx @@ -37,7 +37,6 @@ export type LoginModalStep = type ContentProps = ModalFunctionalityProps & { setCurrentStep: Dispatch> currentStep: LoginModalStep - openModal: () => void runCaptcha: () => Promise termsAndService: (className?: string) => JSX.Element afterLogin?: () => void diff --git a/src/components/auth/ProfileModal/contents/notifications/TelegramNotificationContent.tsx b/src/components/auth/ProfileModal/contents/notifications/TelegramNotificationContent.tsx index 240ab36ce..5c069e45f 100644 --- a/src/components/auth/ProfileModal/contents/notifications/TelegramNotificationContent.tsx +++ b/src/components/auth/ProfileModal/contents/notifications/TelegramNotificationContent.tsx @@ -31,7 +31,7 @@ export default function TelegramNotificationContent(props: ContentProps) { if (!isLoadingAccount && !firstLinkedAccount) { return ( <> - {!isAfterDisconnect && ( + {isAfterDisconnect && ( You have disconnected your account from Grill's telegram bot. diff --git a/src/components/chats/ChatItem/ChatItemMenus.tsx b/src/components/chats/ChatItem/ChatItemMenus.tsx index 610f688b5..2e474c1f1 100644 --- a/src/components/chats/ChatItem/ChatItemMenus.tsx +++ b/src/components/chats/ChatItem/ChatItemMenus.tsx @@ -204,7 +204,6 @@ export default function ChatItemMenus({ )} setModalState('login')} closeModal={() => setModalState(null)} beforeLogin={() => (isLoggingInWithKey.current = true)} afterLogin={() => (isLoggingInWithKey.current = false)} diff --git a/src/components/chats/ChatList/ChatList.tsx b/src/components/chats/ChatList/ChatList.tsx index 9d54b643c..87355d9a3 100644 --- a/src/components/chats/ChatList/ChatList.tsx +++ b/src/components/chats/ChatList/ChatList.tsx @@ -73,6 +73,7 @@ function ChatListContent({ const [initialNewMessageCount, setInitialNewMessageCount] = useState(0) const lastReadId = useFocusedLastMessageId(chatId) + const [recipient, setRecipient] = useState('') const [messageModalMsgId, setMessageModalMsgId] = useState('') const prevMessageModalMsgId = usePrevious(messageModalMsgId) @@ -136,6 +137,7 @@ function ChatListContent({ hasScrolledToMessageRef.current = true const messageId = getUrlQuery('messageId') + const recipient = getUrlQuery('targetAcc') const isMessageIdsFetched = rawMessageIds !== undefined if (!isMessageIdsFetched) return @@ -160,6 +162,7 @@ function ChatListContent({ } setMessageModalMsgId(messageId) + setRecipient(recipient) // eslint-disable-next-line react-hooks/exhaustive-deps }, [rawMessageIds, filteredMessageIdsRef, hasScrolledToMessageRef]) @@ -298,6 +301,7 @@ function ChatListContent({ closeModal={() => setMessageModalMsgId('')} messageId={messageModalMsgId} scrollToMessage={scrollToMessage} + recipient={recipient} />
diff --git a/src/components/modals/MessageModal.stories.tsx b/src/components/modals/MessageModal.stories.tsx new file mode 100644 index 000000000..a9bc9da6f --- /dev/null +++ b/src/components/modals/MessageModal.stories.tsx @@ -0,0 +1,50 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { useState } from 'react' +import Button from '../Button' +import MessageModal, { MessageModalProps } from './MessageModal' + +function MessageModalWrapper( + props: Omit +) { + const [isOpen, setIsOpen] = useState(false) + + return ( + <> + + setIsOpen(false)} + /> + + ) +} + +const meta = { + title: 'Components/MessageModal', + component: MessageModalWrapper, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + args: { + hubId: '1001', + messageId: '7687', + scrollToMessage: async (messageId) => { + alert('Scroll to message: ' + messageId) + }, + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: {}, +} + +export const WithTargetAccount: Story = { + args: { + recipient: '3szaLms2V18XCr2ztvjzcPF16BxvbGeAW4fEG2yeb19XGdGV', + }, +} diff --git a/src/components/modals/MessageModal.tsx b/src/components/modals/MessageModal.tsx index 48c1c204a..7c0f44dd9 100644 --- a/src/components/modals/MessageModal.tsx +++ b/src/components/modals/MessageModal.tsx @@ -1,23 +1,38 @@ import { getPostQuery } from '@/services/api/query' +import { useSendEvent } from '@/stores/analytics' +import { useMyAccount } from '@/stores/my-account' import { cx } from '@/utils/class-names' import { CommentData } from '@subsocial/api/types' -import { useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' +import { HiOutlineInformationCircle } from 'react-icons/hi2' +import LoginModal from '../auth/LoginModal' import Button from '../Button' +import Card from '../Card' import ChatItem from '../chats/ChatItem' +import PopOver from '../floating/PopOver' +import ProfilePreview from '../ProfilePreview' import Modal, { ModalFunctionalityProps } from './Modal' export type MessageModalProps = ModalFunctionalityProps & { messageId: string scrollToMessage?: (messageId: string) => Promise hubId: string + recipient?: string } export default function MessageModal({ messageId, scrollToMessage, hubId, + recipient, ...props }: MessageModalProps) { + const myAddress = useMyAccount((state) => state.address) + const isInitialized = useMyAccount((state) => state.isInitialized) + const isDifferentRecipient = recipient !== myAddress + + const [isOpenLoginModal, setIsOpenLoginModal] = useState(false) + const { data: message } = getPostQuery.useQuery(messageId) const chatId = (message as unknown as CommentData)?.struct.rootPostId const { data: chat } = getPostQuery.useQuery(chatId) @@ -30,6 +45,17 @@ export default function MessageModal({ ) + const sendEvent = useSendEvent() + useEffect(() => { + if (!isInitialized) return + + if (props.isOpen && recipient) + sendEvent('open_tg_notification', { + isMyNotif: (myAddress === recipient) + '', + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.isOpen, isInitialized]) + const handleScrollToMessage = async () => { if (!scrollToMessage) return @@ -41,41 +67,79 @@ export default function MessageModal({ } return ( - Message from {chatTitle} - } - > -
+ Message from {chatTitle} + } > - {message && ( - - )} -
- {scrollToMessage && ( - - )} - + {message && ( + + )} + {scrollToMessage && ( + + )} +
+ {isDifferentRecipient && recipient && ( + +
+ Notification recipient + } + triggerOnHover + panelSize='sm' + yOffset={6} + placement='top' + > +

You are not currently logged in to this account.

+
+
+ + +
+ )} + + setIsOpenLoginModal(false)} + initialOpenState='enter-secret-key' + onBackClick={() => setIsOpenLoginModal(false)} + /> + ) } diff --git a/src/components/navbar/Navbar/Navbar.tsx b/src/components/navbar/Navbar/Navbar.tsx index 02e0d81b0..e9b08c895 100644 --- a/src/components/navbar/Navbar/Navbar.tsx +++ b/src/components/navbar/Navbar/Navbar.tsx @@ -154,7 +154,6 @@ export default function Navbar({ setOpenLoginModal(true)} closeModal={() => setOpenLoginModal(false)} beforeLogin={() => (isLoggingInWithKey.current = true)} afterLogin={() => (isLoggingInWithKey.current = false)} diff --git a/src/modules/chat/ChatPage/ChatPage.tsx b/src/modules/chat/ChatPage/ChatPage.tsx index 54e440d77..0a119a2d6 100644 --- a/src/modules/chat/ChatPage/ChatPage.tsx +++ b/src/modules/chat/ChatPage/ChatPage.tsx @@ -68,7 +68,7 @@ export default function ChatPage({ if (isNewChat) setIsOpenCreateSuccessModal(true) }, []) useEffect(() => { - if (!isOpenCreateSuccessModal) replaceUrl(getCurrentUrlWithoutQuery()) + if (!isOpenCreateSuccessModal) replaceUrl(getCurrentUrlWithoutQuery('new')) }, [isOpenCreateSuccessModal]) const { data: messageIds } = useCommentIdsByPostId(chatId, { diff --git a/src/utils/links.ts b/src/utils/links.ts index 71e6fa7c4..506a5e1f8 100644 --- a/src/utils/links.ts +++ b/src/utils/links.ts @@ -22,6 +22,7 @@ export function getCurrentUrlWithoutQuery(queryNameToRemove?: string) { return ( window.location.origin + window.location.pathname + + '?' + searchParams.toString() ) }