mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-31 12:51:35 +02:00
Convert Chat components to TypeScript (#22672)
GitOrigin-RevId: b47a7fc3f77055335990ee0215bd32ae65b1ebfe
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OLNotification from '@/features/ui/components/ol/ol-notification'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
|
||||
function ChatFallbackError({ reconnect }) {
|
||||
interface ChatFallbackErrorProps {
|
||||
reconnect?: () => void
|
||||
}
|
||||
|
||||
function ChatFallbackError({ reconnect }: ChatFallbackErrorProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
@@ -22,8 +25,4 @@ function ChatFallbackError({ reconnect }) {
|
||||
)
|
||||
}
|
||||
|
||||
ChatFallbackError.propTypes = {
|
||||
reconnect: PropTypes.any,
|
||||
}
|
||||
|
||||
export default ChatFallbackError
|
||||
@@ -1,9 +1,17 @@
|
||||
import { useRef, useEffect, useLayoutEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
|
||||
const SCROLL_END_OFFSET = 30
|
||||
|
||||
interface InfiniteScrollProps {
|
||||
atEnd?: boolean
|
||||
children: React.ReactElement
|
||||
className?: string
|
||||
fetchData(): void
|
||||
itemCount: number
|
||||
isLoading?: boolean
|
||||
}
|
||||
|
||||
function InfiniteScroll({
|
||||
atEnd,
|
||||
children,
|
||||
@@ -11,20 +19,22 @@ function InfiniteScroll({
|
||||
fetchData,
|
||||
itemCount,
|
||||
isLoading,
|
||||
}) {
|
||||
const root = useRef(null)
|
||||
}: InfiniteScrollProps) {
|
||||
const root = useRef<HTMLDivElement>(null)
|
||||
|
||||
// we keep the value in a Ref instead of state so it can be safely used in effects
|
||||
const scrollBottomRef = useRef(0)
|
||||
function setScrollBottom(value) {
|
||||
function setScrollBottom(value: number) {
|
||||
scrollBottomRef.current = value
|
||||
}
|
||||
|
||||
function updateScrollPosition() {
|
||||
root.current.scrollTop =
|
||||
root.current.scrollHeight -
|
||||
root.current.clientHeight -
|
||||
scrollBottomRef.current
|
||||
if (root.current) {
|
||||
root.current.scrollTop =
|
||||
root.current.scrollHeight -
|
||||
root.current.clientHeight -
|
||||
scrollBottomRef.current
|
||||
}
|
||||
}
|
||||
|
||||
// Repositions the scroll after new items are loaded
|
||||
@@ -39,23 +49,29 @@ function InfiniteScroll({
|
||||
}
|
||||
}, [])
|
||||
|
||||
function onScrollHandler(event) {
|
||||
setScrollBottom(
|
||||
root.current.scrollHeight -
|
||||
root.current.scrollTop -
|
||||
root.current.clientHeight
|
||||
)
|
||||
if (event.target !== event.currentTarget) {
|
||||
// Ignore scroll events on nested divs
|
||||
// (this check won't be necessary in React 17: https://github.com/facebook/react/issues/15723
|
||||
return
|
||||
}
|
||||
if (shouldFetchData()) {
|
||||
fetchData()
|
||||
function onScrollHandler(event: React.UIEvent<HTMLDivElement>) {
|
||||
if (root.current) {
|
||||
setScrollBottom(
|
||||
root.current.scrollHeight -
|
||||
root.current.scrollTop -
|
||||
root.current.clientHeight
|
||||
)
|
||||
|
||||
if (event.target !== event.currentTarget) {
|
||||
// Ignore scroll events on nested divs
|
||||
// (this check won't be necessary in React 17: https://github.com/facebook/react/issues/15723
|
||||
return
|
||||
}
|
||||
if (shouldFetchData()) {
|
||||
fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shouldFetchData() {
|
||||
if (!root.current) {
|
||||
return false
|
||||
}
|
||||
const containerIsLargerThanContent =
|
||||
root.current.children[0].clientHeight < root.current.clientHeight
|
||||
if (atEnd || isLoading || containerIsLargerThanContent) {
|
||||
@@ -76,13 +92,4 @@ function InfiniteScroll({
|
||||
)
|
||||
}
|
||||
|
||||
InfiniteScroll.propTypes = {
|
||||
atEnd: PropTypes.bool,
|
||||
children: PropTypes.element.isRequired,
|
||||
className: PropTypes.string,
|
||||
fetchData: PropTypes.func.isRequired,
|
||||
itemCount: PropTypes.number.isRequired,
|
||||
isLoading: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default InfiniteScroll
|
||||
@@ -1,10 +1,11 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import moment from 'moment'
|
||||
import Message from './message'
|
||||
import { UserId } from '../../../../../types/user'
|
||||
import type { Message as MessageType } from '@/features/chat/context/chat-context'
|
||||
|
||||
const FIVE_MINUTES = 5 * 60 * 1000
|
||||
|
||||
function formatTimestamp(date) {
|
||||
function formatTimestamp(date: moment.MomentInput) {
|
||||
if (!date) {
|
||||
return 'N/A'
|
||||
} else {
|
||||
@@ -12,14 +13,28 @@ function formatTimestamp(date) {
|
||||
}
|
||||
}
|
||||
|
||||
function MessageList({ messages, resetUnreadMessages, userId }) {
|
||||
function shouldRenderDate(messageIndex) {
|
||||
interface MessageListProps {
|
||||
messages: MessageType[]
|
||||
resetUnreadMessages(...args: unknown[]): unknown
|
||||
userId: UserId | null
|
||||
}
|
||||
|
||||
function MessageList({
|
||||
messages,
|
||||
resetUnreadMessages,
|
||||
userId,
|
||||
}: MessageListProps) {
|
||||
function shouldRenderDate(messageIndex: number) {
|
||||
if (messageIndex === 0) {
|
||||
return true
|
||||
} else {
|
||||
const message = messages[messageIndex]
|
||||
const previousMessage = messages[messageIndex - 1]
|
||||
return message.timestamp - previousMessage.timestamp > FIVE_MINUTES
|
||||
return (
|
||||
message.timestamp &&
|
||||
previousMessage.timestamp &&
|
||||
message.timestamp - previousMessage.timestamp > FIVE_MINUTES
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +68,4 @@ function MessageList({ messages, resetUnreadMessages, userId }) {
|
||||
)
|
||||
}
|
||||
|
||||
MessageList.propTypes = {
|
||||
messages: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
timestamp: PropTypes.number,
|
||||
})
|
||||
).isRequired,
|
||||
resetUnreadMessages: PropTypes.func.isRequired,
|
||||
userId: PropTypes.string,
|
||||
}
|
||||
|
||||
export default MessageList
|
||||
@@ -1,20 +1,26 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { getHueForUserId } from '../../../shared/utils/colors'
|
||||
import MessageContent from './message-content'
|
||||
import type { Message as MessageType } from '@/features/chat/context/chat-context'
|
||||
import { User } from '../../../../../types/user'
|
||||
|
||||
function Message({ message, userId }) {
|
||||
function hue(user) {
|
||||
interface MessageProps {
|
||||
message: MessageType
|
||||
userId: string | null
|
||||
}
|
||||
|
||||
function Message({ message, userId }: MessageProps) {
|
||||
function hue(user?: User) {
|
||||
return user ? getHueForUserId(user.id, userId) : 0
|
||||
}
|
||||
|
||||
function getMessageStyle(user) {
|
||||
function getMessageStyle(user?: User) {
|
||||
return {
|
||||
borderColor: `hsl(${hue(user)}, 85%, 40%)`,
|
||||
backgroundColor: `hsl(${hue(user)}, 85%, 40%`,
|
||||
}
|
||||
}
|
||||
|
||||
function getArrowStyle(user) {
|
||||
function getArrowStyle(user?: User) {
|
||||
return {
|
||||
borderColor: `hsl(${hue(user)}, 85%, 40%)`,
|
||||
}
|
||||
@@ -24,7 +30,7 @@ function Message({ message, userId }) {
|
||||
|
||||
return (
|
||||
<div className="message-wrapper">
|
||||
{!isMessageFromSelf && (
|
||||
{!isMessageFromSelf && message.user.id && (
|
||||
<div className="name">
|
||||
<span>{message.user.first_name || message.user.email}</span>
|
||||
</div>
|
||||
@@ -43,16 +49,4 @@ function Message({ message, userId }) {
|
||||
)
|
||||
}
|
||||
|
||||
Message.propTypes = {
|
||||
message: PropTypes.shape({
|
||||
contents: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
email: PropTypes.string,
|
||||
first_name: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
userId: PropTypes.string,
|
||||
}
|
||||
|
||||
export default Message
|
||||
@@ -19,13 +19,15 @@ import { useLayoutContext } from '../../../shared/context/layout-context'
|
||||
import { useIdeContext } from '@/shared/context/ide-context'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { User } from '../../../../../types/user'
|
||||
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
export type Message = {
|
||||
id: string
|
||||
timestamp: number
|
||||
contents: string
|
||||
contents: string[]
|
||||
user: User
|
||||
}
|
||||
|
||||
type State = {
|
||||
|
||||
Reference in New Issue
Block a user