2023-11-16 12:23:55 +00:00
|
|
|
import { For, createSignal, Show, onMount, createEffect, createMemo, on } from 'solid-js'
|
2022-12-17 03:27:00 +00:00
|
|
|
import type { Author, Chat, Message as MessageType } from '../../graphql/types.gen'
|
2022-11-10 15:06:02 +00:00
|
|
|
import DialogCard from '../Inbox/DialogCard'
|
|
|
|
import Search from '../Inbox/Search'
|
2023-02-17 09:21:02 +00:00
|
|
|
import { Message } from '../Inbox/Message'
|
2022-12-17 03:27:00 +00:00
|
|
|
import CreateModalContent from '../Inbox/CreateModalContent'
|
|
|
|
import DialogHeader from '../Inbox/DialogHeader'
|
|
|
|
import MessagesFallback from '../Inbox/MessagesFallback'
|
|
|
|
import QuotedMessage from '../Inbox/QuotedMessage'
|
|
|
|
import { Icon } from '../_shared/Icon'
|
|
|
|
import { useSession } from '../../context/session'
|
2023-01-26 06:59:43 +00:00
|
|
|
import { loadRecipients } from '../../stores/inbox'
|
2023-02-17 09:21:02 +00:00
|
|
|
|
2022-11-27 05:49:48 +00:00
|
|
|
import { Modal } from '../Nav/Modal'
|
|
|
|
import { showModal } from '../../stores/ui'
|
2022-12-17 03:27:00 +00:00
|
|
|
import { useInbox } from '../../context/inbox'
|
|
|
|
import { useRouter } from '../../stores/router'
|
|
|
|
import { clsx } from 'clsx'
|
|
|
|
import styles from '../../styles/Inbox.module.scss'
|
2023-02-17 09:21:02 +00:00
|
|
|
import { useLocalize } from '../../context/localize'
|
2023-07-24 08:58:07 +00:00
|
|
|
import SimplifiedEditor from '../Editor/SimplifiedEditor'
|
2023-11-16 14:20:05 +00:00
|
|
|
import { Popover } from '../_shared/Popover'
|
2022-11-09 12:20:13 +00:00
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
type InboxSearchParams = {
|
|
|
|
initChat: string
|
|
|
|
chat: string
|
2022-11-09 12:20:13 +00:00
|
|
|
}
|
2023-05-01 18:32:32 +00:00
|
|
|
|
|
|
|
const userSearch = (array: Author[], keyword: string) => {
|
|
|
|
return array.filter((value) => new RegExp(keyword.trim(), 'gi').test(value.name))
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleOpenInviteModal = () => {
|
|
|
|
showModal('inviteToChat')
|
|
|
|
}
|
2022-11-09 12:20:13 +00:00
|
|
|
|
2022-09-22 09:37:49 +00:00
|
|
|
export const InboxView = () => {
|
2023-02-17 09:21:02 +00:00
|
|
|
const { t } = useLocalize()
|
2022-12-17 03:27:00 +00:00
|
|
|
const {
|
|
|
|
chats,
|
|
|
|
messages,
|
|
|
|
actions: { loadChats, getMessages, sendMessage, createChat }
|
|
|
|
} = useInbox()
|
|
|
|
|
2022-11-24 12:58:07 +00:00
|
|
|
const [recipients, setRecipients] = createSignal<Author[]>([])
|
2023-07-24 08:58:07 +00:00
|
|
|
const [sortByGroup, setSortByGroup] = createSignal(false)
|
|
|
|
const [sortByPerToPer, setSortByPerToPer] = createSignal(false)
|
2022-12-17 03:27:00 +00:00
|
|
|
const [currentDialog, setCurrentDialog] = createSignal<Chat>()
|
|
|
|
const [messageToReply, setMessageToReply] = createSignal<MessageType | null>(null)
|
2023-07-24 08:58:07 +00:00
|
|
|
const [isClear, setClear] = createSignal(false)
|
2023-11-16 14:20:05 +00:00
|
|
|
const [isScrollToNewVisible, setIsScrollToNewVisible] = createSignal(false)
|
2022-11-15 12:48:42 +00:00
|
|
|
const { session } = useSession()
|
2022-12-17 03:27:00 +00:00
|
|
|
const currentUserId = createMemo(() => session()?.user.id)
|
2023-07-24 08:58:07 +00:00
|
|
|
const { changeSearchParam, searchParams } = useRouter<InboxSearchParams>()
|
2023-11-16 12:23:55 +00:00
|
|
|
|
|
|
|
const messagesContainerRef: { current: HTMLDivElement } = {
|
|
|
|
current: null
|
|
|
|
}
|
|
|
|
|
2022-11-11 04:34:18 +00:00
|
|
|
// Поиск по диалогам
|
2022-11-10 15:06:02 +00:00
|
|
|
const getQuery = (query) => {
|
2023-05-01 18:32:32 +00:00
|
|
|
if (query().length >= 2) {
|
|
|
|
const match = userSearch(recipients(), query())
|
|
|
|
setRecipients(match)
|
|
|
|
} else {
|
|
|
|
// setRecipients(cashedRecipients())
|
|
|
|
}
|
2022-11-10 15:06:02 +00:00
|
|
|
}
|
2022-11-11 04:34:18 +00:00
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
const handleOpenChat = async (chat: Chat) => {
|
|
|
|
setCurrentDialog(chat)
|
2023-09-29 12:48:58 +00:00
|
|
|
changeSearchParam({
|
|
|
|
chat: chat.id
|
|
|
|
})
|
2022-11-15 13:55:00 +00:00
|
|
|
try {
|
2022-12-17 03:27:00 +00:00
|
|
|
await getMessages(chat.id)
|
2022-11-15 13:55:00 +00:00
|
|
|
} catch (error) {
|
2022-12-17 03:27:00 +00:00
|
|
|
console.error('[getMessages]', error)
|
2022-11-15 13:55:00 +00:00
|
|
|
} finally {
|
2023-11-16 12:23:55 +00:00
|
|
|
messagesContainerRef.current.scroll({
|
|
|
|
top: messagesContainerRef.current.scrollHeight,
|
|
|
|
behavior: 'instant'
|
|
|
|
})
|
2022-11-15 13:55:00 +00:00
|
|
|
}
|
2022-12-17 03:27:00 +00:00
|
|
|
}
|
2022-11-23 04:12:11 +00:00
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
onMount(async () => {
|
2022-11-23 04:12:11 +00:00
|
|
|
try {
|
2022-11-24 09:06:48 +00:00
|
|
|
const response = await loadRecipients({ days: 365 })
|
2022-11-24 12:58:07 +00:00
|
|
|
setRecipients(response as unknown as Author[])
|
2022-11-27 07:10:04 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.log(error)
|
|
|
|
}
|
2022-12-17 03:27:00 +00:00
|
|
|
await loadChats()
|
2022-11-10 15:06:02 +00:00
|
|
|
})
|
2022-11-11 04:34:18 +00:00
|
|
|
|
2023-07-24 08:58:07 +00:00
|
|
|
const handleSubmit = async (message: string) => {
|
2022-12-17 03:27:00 +00:00
|
|
|
await sendMessage({
|
2023-07-24 08:58:07 +00:00
|
|
|
body: message,
|
2022-12-17 03:27:00 +00:00
|
|
|
chat: currentDialog().id.toString(),
|
|
|
|
replyTo: messageToReply()?.id
|
|
|
|
})
|
2023-07-24 08:58:07 +00:00
|
|
|
setClear(true)
|
2022-12-17 03:27:00 +00:00
|
|
|
setMessageToReply(null)
|
2023-11-16 12:23:55 +00:00
|
|
|
messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight
|
2023-07-24 08:58:07 +00:00
|
|
|
setClear(false)
|
2022-11-09 12:20:13 +00:00
|
|
|
}
|
2022-11-16 04:56:15 +00:00
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
createEffect(async () => {
|
|
|
|
if (searchParams().chat) {
|
|
|
|
const chatToOpen = chats()?.find((chat) => chat.id === searchParams().chat)
|
|
|
|
if (!chatToOpen) return
|
|
|
|
await handleOpenChat(chatToOpen)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (searchParams().initChat) {
|
|
|
|
try {
|
|
|
|
const newChat = await createChat([Number(searchParams().initChat)], '')
|
|
|
|
await loadChats()
|
2023-09-29 12:48:58 +00:00
|
|
|
changeSearchParam({
|
|
|
|
initChat: null,
|
|
|
|
chat: newChat.chat.id
|
|
|
|
})
|
2022-12-17 03:27:00 +00:00
|
|
|
const chatToOpen = chats().find((chat) => chat.id === newChat.chat.id)
|
|
|
|
await handleOpenChat(chatToOpen)
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error)
|
|
|
|
}
|
|
|
|
}
|
2022-11-16 04:56:15 +00:00
|
|
|
})
|
2022-11-09 12:20:13 +00:00
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
const chatsToShow = () => {
|
|
|
|
const sorted = chats().sort((a, b) => {
|
|
|
|
return b.updatedAt - a.updatedAt
|
|
|
|
})
|
|
|
|
if (sortByPerToPer()) {
|
2023-02-17 09:21:02 +00:00
|
|
|
return sorted.filter((chat) => (chat.title || '').trim().length === 0)
|
2022-12-17 03:27:00 +00:00
|
|
|
} else if (sortByGroup()) {
|
2023-02-17 09:21:02 +00:00
|
|
|
return sorted.filter((chat) => (chat.title || '').trim().length > 0)
|
2022-12-17 03:27:00 +00:00
|
|
|
} else {
|
|
|
|
return sorted
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const findToReply = (messageId) => {
|
|
|
|
return messages().find((message) => message.id === messageId)
|
|
|
|
}
|
|
|
|
|
2023-11-16 12:23:55 +00:00
|
|
|
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 }
|
|
|
|
)
|
2023-11-16 14:20:05 +00:00
|
|
|
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)
|
|
|
|
}
|
2023-11-16 12:23:55 +00:00
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
return (
|
2022-12-17 03:27:00 +00:00
|
|
|
<div class={clsx('container', styles.Inbox)}>
|
2022-11-27 05:49:48 +00:00
|
|
|
<Modal variant="narrow" name="inviteToChat">
|
|
|
|
<CreateModalContent users={recipients()} />
|
|
|
|
</Modal>
|
2022-12-17 03:27:00 +00:00
|
|
|
<div class={clsx('row', styles.row)}>
|
2023-03-10 17:42:48 +00:00
|
|
|
<div class={clsx(styles.chatList, 'col-md-8')}>
|
2022-12-17 03:27:00 +00:00
|
|
|
<div class={styles.sidebarHeader}>
|
2022-11-27 05:49:48 +00:00
|
|
|
<Search placeholder="Поиск" onChange={getQuery} />
|
2022-12-17 03:27:00 +00:00
|
|
|
<button type="button" onClick={handleOpenInviteModal}>
|
2022-11-27 05:49:48 +00:00
|
|
|
<Icon name="plus-button" style={{ width: '40px', height: '40px' }} />
|
2022-12-17 03:27:00 +00:00
|
|
|
</button>
|
2022-11-27 05:49:48 +00:00
|
|
|
</div>
|
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
<Show when={chatsToShow}>
|
2023-06-08 21:53:58 +00:00
|
|
|
<ul class="view-switcher">
|
|
|
|
<li class={clsx({ 'view-switcher__item--selected': !sortByPerToPer() && !sortByGroup() })}>
|
|
|
|
<button
|
2022-12-17 03:27:00 +00:00
|
|
|
onClick={() => {
|
|
|
|
setSortByPerToPer(false)
|
|
|
|
setSortByGroup(false)
|
|
|
|
}}
|
|
|
|
>
|
2023-06-08 21:53:58 +00:00
|
|
|
{t('All')}
|
|
|
|
</button>
|
|
|
|
</li>
|
|
|
|
<li class={clsx({ 'view-switcher__item--selected': sortByPerToPer() })}>
|
|
|
|
<button
|
2022-12-17 03:27:00 +00:00
|
|
|
onClick={() => {
|
|
|
|
setSortByPerToPer(true)
|
|
|
|
setSortByGroup(false)
|
|
|
|
}}
|
|
|
|
>
|
2023-06-08 21:53:58 +00:00
|
|
|
{t('Personal')}
|
|
|
|
</button>
|
|
|
|
</li>
|
|
|
|
<li class={clsx({ 'view-switcher__item--selected': sortByGroup() })}>
|
|
|
|
<button
|
2022-12-17 03:27:00 +00:00
|
|
|
onClick={() => {
|
|
|
|
setSortByGroup(true)
|
|
|
|
setSortByPerToPer(false)
|
|
|
|
}}
|
|
|
|
>
|
2023-06-08 21:53:58 +00:00
|
|
|
{t('Groups')}
|
|
|
|
</button>
|
|
|
|
</li>
|
|
|
|
</ul>
|
2022-12-17 03:27:00 +00:00
|
|
|
</Show>
|
|
|
|
<div class={styles.holder}>
|
|
|
|
<div class={styles.dialogs}>
|
|
|
|
<For each={chatsToShow()}>
|
|
|
|
{(chat) => (
|
|
|
|
<DialogCard
|
|
|
|
onClick={() => handleOpenChat(chat)}
|
|
|
|
isOpened={chat.id === currentDialog()?.id}
|
|
|
|
members={chat.members}
|
|
|
|
ownId={currentUserId()}
|
|
|
|
lastUpdate={chat.updatedAt}
|
|
|
|
counter={chat.unread}
|
|
|
|
message={chat.messages.pop()?.body}
|
|
|
|
/>
|
2022-11-09 12:20:13 +00:00
|
|
|
)}
|
|
|
|
</For>
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2022-12-17 03:27:00 +00:00
|
|
|
</div>
|
|
|
|
|
2023-03-10 17:42:48 +00:00
|
|
|
<div class={clsx('col-md-16', styles.conversation)}>
|
2022-12-17 03:27:00 +00:00
|
|
|
<Show
|
2023-11-16 14:20:05 +00:00
|
|
|
keyed={true}
|
2022-12-17 03:27:00 +00:00
|
|
|
when={currentDialog()}
|
|
|
|
fallback={
|
|
|
|
<MessagesFallback
|
|
|
|
message={t('Choose who you want to write to')}
|
|
|
|
onClick={handleOpenInviteModal}
|
|
|
|
actionText={t('Start conversation')}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<DialogHeader ownId={currentUserId()} chat={currentDialog()} />
|
|
|
|
<div class={styles.conversationMessages}>
|
2023-11-16 14:20:05 +00:00
|
|
|
<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}
|
|
|
|
>
|
2022-12-17 03:27:00 +00:00
|
|
|
<For each={messages()}>
|
|
|
|
{(message) => (
|
|
|
|
<Message
|
|
|
|
content={message}
|
|
|
|
ownId={currentUserId()}
|
|
|
|
members={currentDialog().members}
|
|
|
|
replyBody={message.replyTo && findToReply(message.replyTo).body}
|
|
|
|
replyClick={() => setMessageToReply(message)}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
{/*<div class={styles.conversationDate}>*/}
|
|
|
|
{/* <time>12 сентября</time>*/}
|
|
|
|
{/*</div>*/}
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-12-17 03:27:00 +00:00
|
|
|
<div class={styles.messageForm}>
|
|
|
|
<Show when={messageToReply()}>
|
2023-11-13 14:43:08 +00:00
|
|
|
<p>FIXME: messageToReply</p>
|
|
|
|
{/*<QuotedMessage*/}
|
|
|
|
{/* variant="reply"*/}
|
|
|
|
{/* author={*/}
|
|
|
|
{/* currentDialog().members.find((member) => member.id === Number(messageToReply().author))*/}
|
|
|
|
{/* .name*/}
|
|
|
|
{/* }*/}
|
|
|
|
{/* body={messageToReply().body}*/}
|
|
|
|
{/* cancel={() => setMessageToReply(null)}*/}
|
|
|
|
{/*/>*/}
|
2022-12-17 03:27:00 +00:00
|
|
|
</Show>
|
|
|
|
<div class={styles.wrapper}>
|
2023-07-24 08:58:07 +00:00
|
|
|
<SimplifiedEditor
|
|
|
|
smallHeight={true}
|
|
|
|
imageEnabled={true}
|
2023-11-13 14:43:08 +00:00
|
|
|
isCancelButtonVisible={false}
|
2023-07-24 08:58:07 +00:00
|
|
|
placeholder={t('Write message')}
|
|
|
|
setClear={isClear()}
|
|
|
|
onSubmit={(message) => handleSubmit(message)}
|
2023-10-16 07:40:34 +00:00
|
|
|
submitByCtrlEnter={true}
|
2023-07-24 08:58:07 +00:00
|
|
|
/>
|
2022-11-16 04:56:15 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2022-12-17 03:27:00 +00:00
|
|
|
</Show>
|
2022-09-09 11:53:35 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|