This repository has been archived on 2024-10-29. You can view files and clone it, but cannot push or open issues or pull requests.
website/contexts/Messages.tsx

100 lines
2.9 KiB
TypeScript
Raw Permalink Normal View History

2022-08-30 21:30:06 +02:00
import { createContext, useContext, useEffect, useMemo } from 'react'
2022-08-31 21:44:33 +02:00
import type { NextPage } from '../hooks/usePagination'
import { usePagination } from '../hooks/usePagination'
2022-03-16 12:18:09 +01:00
import { useAuthentication } from '../tools/authentication'
2022-08-31 21:44:33 +02:00
import type { MessageWithMember } from '../models/Message'
import type { GuildsChannelsPath } from '../components/Application'
import type { SocketData } from '../tools/handleSocketData'
import { handleSocketData } from '../tools/handleSocketData'
import type { CacheKey } from '../tools/cache'
import { MESSAGES_CACHE_KEY } from '../tools/cache'
export interface Messages {
messages: MessageWithMember[]
hasMore: boolean
nextPage: NextPage
}
const defaultMessagesContext = {} as any
const MessagesContext = createContext<Messages>(defaultMessagesContext)
export interface MessagesProviderProps {
path: GuildsChannelsPath
}
2022-05-12 20:35:46 +02:00
export const MessagesProvider: React.FC<
React.PropsWithChildren<MessagesProviderProps>
> = (props) => {
const { path, children } = props
const { authentication, user } = useAuthentication()
2022-08-30 21:30:06 +02:00
const cacheKey = useMemo<CacheKey>(() => {
return `${path.channelId}-${MESSAGES_CACHE_KEY}`
}, [path.channelId])
const {
items: messages,
hasMore,
nextPage,
2022-01-13 18:21:45 +01:00
resetPagination,
setItems
} = usePagination<MessageWithMember>({
api: authentication.api,
url: `/channels/${path.channelId}/messages`,
inverse: true,
cacheKey
})
2022-01-13 18:21:45 +01:00
useEffect(() => {
authentication?.socket?.on(
2022-01-13 18:21:45 +01:00
'messages',
(data: SocketData<MessageWithMember>) => {
if (data.item.channelId === path.channelId) {
const messagesDiv = window.document.getElementById(
'messages'
) as HTMLDivElement
const isAtBottom =
messagesDiv.scrollHeight - messagesDiv.scrollTop <=
messagesDiv.clientHeight
handleSocketData({ data, setItems, cacheKey })
if (
data.action === 'create' &&
(isAtBottom || data.item.member.userId === user.id)
) {
2022-01-13 18:21:45 +01:00
messagesDiv.scrollTo(0, messagesDiv.scrollHeight)
}
}
}
)
return () => {
authentication?.socket?.off('messages')
2022-01-13 18:21:45 +01:00
}
}, [authentication.socket, setItems, path, user.id, cacheKey])
2022-01-13 18:21:45 +01:00
useEffect(() => {
resetPagination()
nextPage(undefined, () => {
const messagesDiv = window.document.getElementById(
'messages'
) as HTMLDivElement
messagesDiv.scrollTo(0, messagesDiv.scrollHeight)
})
}, [nextPage, resetPagination])
return (
<MessagesContext.Provider value={{ messages, hasMore, nextPage }}>
{children}
</MessagesContext.Provider>
)
}
export const useMessages = (): Messages => {
const messages = useContext(MessagesContext)
if (messages === defaultMessagesContext) {
2022-08-30 21:30:06 +02:00
throw new Error('`useMessages` must be used within a `MessagesProvider`')
}
return messages
}