Merge remote-tracking branch 'my/feature/see_connect_merge_with_main' into feature/sse-connect

This commit is contained in:
Untone 2023-11-16 17:53:59 +03:00
commit 46810edaae
8 changed files with 108 additions and 48 deletions

View File

@ -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"
}

View File

@ -476,5 +476,6 @@
"video": "видео",
"view": "просмотр",
"viewsWithCount": "{count} {count, plural, one {просмотр} few {просмотрa} other {просмотров}}",
"yesterday": "вчера"
"yesterday": "вчера",
"To new messages": "К новым сообщениям"
}

View File

@ -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}
>
<Switch
fallback={
<Switch>
<Match when={props.members.length === 2}>
<div class={styles.avatar}>
<Show
when={props.isChatHeader}
fallback={
<div class={styles.avatar}>
<DialogAvatar name={props.members[0].slug} url={props.members[0].userpic} />
</div>
}
fallback={<DialogAvatar name={companions()[0].slug} url={companions()[0].userpic} />}
>
<AuthorBadge nameOnly={true} author={props.members[0]} />
<AuthorBadge nameOnly={true} author={companions()[0]} />
</Show>
}
>
</div>
</Match>
<Match when={props.members.length >= 3}>
<div class={styles.avatar}>
<GroupDialogAvatar users={props.members} />
<GroupDialogAvatar users={companions()} />
</div>
</Match>
</Switch>

View File

@ -25,7 +25,7 @@ export const Message = (props: Props) => {
return (
<div class={clsx(styles.Message, isOwn && styles.own)}>
<Show when={!isOwn}>
<Show when={!isOwn && user}>
<div class={styles.author}>
<DialogAvatar size="small" name={user.name} url={user.userpic} />
<div class={styles.name}>{user.name}</div>

View File

@ -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<Chat>()
const [messageToReply, setMessageToReply] = createSignal<MessageType | null>(null)
const [isClear, setClear] = createSignal(false)
const [isScrollToNewVisible, setIsScrollToNewVisible] = createSignal(false)
const { session } = useSession()
const currentUserId = createMemo(() => session()?.user.id)
const { changeSearchParam, searchParams } = useRouter<InboxSearchParams>()
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 (
<div class={clsx('container', styles.Inbox)}>
<Modal variant="narrow" name="inviteToChat">
@ -221,6 +251,7 @@ export const InboxView = () => {
<div class={clsx('col-md-16', styles.conversation)}>
<Show
keyed={true}
when={currentDialog()}
fallback={
<MessagesFallback
@ -232,7 +263,20 @@ export const InboxView = () => {
>
<DialogHeader ownId={currentUserId()} chat={currentDialog()} />
<div class={styles.conversationMessages}>
<div class={styles.messagesContainer} ref={chatWindow}>
<Show when={isScrollToNewVisible()}>
<Popover content={t('To new messages')}>
{(triggerRef: (el) => void) => (
<div ref={triggerRef} class={styles.scrollToNew} onClick={handleScrollToNew}>
<Icon name="arrow-right" class={styles.icon} />
</div>
)}
</Popover>
</Show>
<div
class={styles.messagesContainer}
ref={(el) => (messagesContainerRef.current = el)}
onScroll={handleScrollMessageContainer}
>
<For each={messages()}>
{(message) => (
<Message

View File

@ -29,15 +29,15 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
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)

View File

@ -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%;

View File

@ -383,7 +383,6 @@ export const apiClient = {
export const inboxClient = {
loadChats: async (options: QueryLoadChatsArgs): Promise<Chat[]> => {
const resp = await privateInboxGraphQLClient.query(myChats, options).toPromise()
console.log('!!! resp:', resp)
return resp.data.loadChats.chats
},