diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index d6eb744b..4ee390c4 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -452,5 +452,6 @@ "video": "video", "view": "view", "viewsWithCount": "{count} {count, plural, one {view} other {views}}", - "yesterday": "yesterday" + "yesterday": "yesterday", + "To new messages": "To new messages" } diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 3640e6a3..1d1877dd 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -476,5 +476,6 @@ "video": "видео", "view": "просмотр", "viewsWithCount": "{count} {count, plural, one {просмотр} few {просмотрa} other {просмотров}}", - "yesterday": "вчера" + "yesterday": "вчера", + "To new messages": "К новым сообщениям" } diff --git a/src/components/Inbox/DialogCard.tsx b/src/components/Inbox/DialogCard.tsx index 52465089..fbc6a179 100644 --- a/src/components/Inbox/DialogCard.tsx +++ b/src/components/Inbox/DialogCard.tsx @@ -1,4 +1,4 @@ -import { Show, Switch, Match, createMemo } from 'solid-js' +import { Show, Switch, Match, createMemo, createEffect } from 'solid-js' import DialogAvatar from './DialogAvatar' import type { ChatMember } from '../../graphql/types.gen' import GroupDialogAvatar from './GroupDialogAvatar' @@ -41,23 +41,20 @@ const DialogCard = (props: DialogProps) => { })} onClick={props.onClick} > - - - - } - > - - - } - > + + +
+ } + > + + +
+
= 3}>
- +
diff --git a/src/components/Inbox/Message.tsx b/src/components/Inbox/Message.tsx index c9a9df00..2e35c071 100644 --- a/src/components/Inbox/Message.tsx +++ b/src/components/Inbox/Message.tsx @@ -25,7 +25,7 @@ export const Message = (props: Props) => { return (
- +
{user.name}
diff --git a/src/components/Views/Inbox.tsx b/src/components/Views/Inbox.tsx index 438c1d26..f77a4249 100644 --- a/src/components/Views/Inbox.tsx +++ b/src/components/Views/Inbox.tsx @@ -1,4 +1,4 @@ -import { For, createSignal, Show, onMount, createEffect, createMemo } from 'solid-js' +import { For, createSignal, Show, onMount, createEffect, createMemo, on } from 'solid-js' import type { Author, Chat, Message as MessageType } from '../../graphql/types.gen' import DialogCard from '../Inbox/DialogCard' import Search from '../Inbox/Search' @@ -19,6 +19,7 @@ import { clsx } from 'clsx' import styles from '../../styles/Inbox.module.scss' import { useLocalize } from '../../context/localize' import SimplifiedEditor from '../Editor/SimplifiedEditor' +import { Popover } from '../_shared/Popover' type InboxSearchParams = { initChat: string @@ -47,9 +48,15 @@ export const InboxView = () => { const [currentDialog, setCurrentDialog] = createSignal() const [messageToReply, setMessageToReply] = createSignal(null) const [isClear, setClear] = createSignal(false) + const [isScrollToNewVisible, setIsScrollToNewVisible] = createSignal(false) const { session } = useSession() const currentUserId = createMemo(() => session()?.user.id) const { changeSearchParam, searchParams } = useRouter() + + const messagesContainerRef: { current: HTMLDivElement } = { + current: null + } + // Поиск по диалогам const getQuery = (query) => { if (query().length >= 2) { @@ -60,8 +67,6 @@ export const InboxView = () => { } } - let chatWindow - const handleOpenChat = async (chat: Chat) => { setCurrentDialog(chat) changeSearchParam({ @@ -72,24 +77,13 @@ export const InboxView = () => { } catch (error) { console.error('[getMessages]', error) } finally { - chatWindow.scrollTop = chatWindow.scrollHeight + messagesContainerRef.current.scroll({ + top: messagesContainerRef.current.scrollHeight, + behavior: 'instant' + }) } } - /* - createEffect(() => { - setInterval(async () => { - if (!currentDialog()) return - try { - await getMessages(currentDialog().id) - } catch (error) { - console.error('[getMessages]', error) - } finally { - chatWindow.scrollTop = chatWindow.scrollHeight - } - }, 2000) - }) - */ onMount(async () => { try { const response = await loadRecipients({ days: 365 }) @@ -108,7 +102,7 @@ export const InboxView = () => { }) setClear(true) setMessageToReply(null) - chatWindow.scrollTop = chatWindow.scrollHeight + messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight setClear(false) } @@ -152,6 +146,42 @@ export const InboxView = () => { return messages().find((message) => message.id === messageId) } + createEffect( + on( + () => messages(), + () => { + if (!messagesContainerRef.current) { + return + } + if (messagesContainerRef.current.scrollTop >= messagesContainerRef.current.scrollHeight) { + return + } + messagesContainerRef.current.scroll({ + top: messagesContainerRef.current.scrollHeight, + behavior: 'smooth' + }) + } + ), + { defer: true } + ) + const handleScrollMessageContainer = () => { + if ( + messagesContainerRef.current.scrollHeight - messagesContainerRef.current.scrollTop > + messagesContainerRef.current.clientHeight * 1.5 + ) { + setIsScrollToNewVisible(true) + } else { + setIsScrollToNewVisible(false) + } + } + const handleScrollToNew = () => { + messagesContainerRef.current.scroll({ + top: messagesContainerRef.current.scrollHeight, + behavior: 'smooth' + }) + setIsScrollToNewVisible(false) + } + return (
@@ -221,6 +251,7 @@ export const InboxView = () => {
{ >
-
+ + + {(triggerRef: (el) => void) => ( +
+ +
+ )} +
+
+
(messagesContainerRef.current = el)} + onScroll={handleScrollMessageContainer} + > {(message) => ( { actions: { setMessageHandler } } = useNotifications() - const handleMessage = (m) => { - console.log('[context.inbox]:', m) + const handleMessage = (sseMessage) => { + console.log('[context.inbox]:', sseMessage) // TODO: handle all action types: create update delete join left - if (['create', 'update', 'delete'].includes(m.action)) { - const msg = m.payload - setMessages((mmm) => [msg, ...mmm]) - } else if (['left', 'join'].includes(m.action)) { + if (['create', 'update', 'delete'].includes(sseMessage.action)) { + const relivedMessage = sseMessage.payload + setMessages((prev) => [...prev, relivedMessage]) + } else if (['left', 'join'].includes(sseMessage.action)) { // TODO: set chat members - console.debug(m) + console.debug(sseMessage) } } @@ -50,7 +50,6 @@ export const InboxProvider = (props: { children: JSX.Element }) => { const loadChats = async () => { try { const newChats = await inboxClient.loadChats({ limit: 50, offset: 0 }) - console.log('!!! newChats:', newChats) setChats(newChats) } catch (error) { console.log('[loadChats]', error) diff --git a/src/styles/Inbox.module.scss b/src/styles/Inbox.module.scss index eb229baf..822602b0 100644 --- a/src/styles/Inbox.module.scss +++ b/src/styles/Inbox.module.scss @@ -114,6 +114,25 @@ main { overflow: auto; position: relative; + .scrollToNew { + osition: absolute; + z-index: 2; + bottom: 8px; + overflow: hidden; + right: 0; + width: 40px; + padding: 1rem; + border: 2px solid var(--black-100); + border-radius: 50%; + height: 40px; + cursor: pointer; + background: var(--background-color); + + .icon { + rotate: 90deg; + } + } + .messagesContainer { left: 0; height: 100%; diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index 4cb2f618..dfbe4249 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -383,7 +383,6 @@ export const apiClient = { export const inboxClient = { loadChats: async (options: QueryLoadChatsArgs): Promise => { const resp = await privateInboxGraphQLClient.query(myChats, options).toPromise() - console.log('!!! resp:', resp) return resp.data.loadChats.chats },