Fix: TypeScript and Lint Errors in Chat List/Page, Message, and Content Modules (#18648)

* rules addition and ts errors fixed on chat list component

* TS fixes and list for chat  list:page, content and message

* Additional fixes

* additional changes

* any type removed

* Update componet.tsx

* Update .eslintrc.js

* fixes

* fixing chat issues
This commit is contained in:
André Castro 2023-09-06 11:24:42 -03:00 committed by GitHub
parent 75dd624d80
commit cd922c2c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 127 deletions

View File

@ -16,6 +16,8 @@ import { Chat } from '/imports/ui/Types/chat';
import { Message } from '/imports/ui/Types/message';
import { useCurrentUser } from '/imports/ui/core/hooks/useCurrentUser';
import { User } from '/imports/ui/Types/user';
import ChatPopupContainer from '../chat-popup/component';
import { defineMessages, useIntl } from "react-intl";
import { Layout } from '/imports/ui/Types/layout';
import ChatPopupContainer from '../chat-popup/component';
import { ChatEvents } from "/imports/ui/core/enums/chat";
@ -42,9 +44,8 @@ interface ChatListProps {
totalPages: number;
chatId: string;
currentUserId: string;
setMessageAsSeenMutation: (variables: any) => void;
totalUnread?: number;
lastSeenAt: number;
setMessageAsSeenMutation: (variables: {chatId: string,
lastSeenAt: number}) => void;
}
const isElement = (el: any): el is HTMLElement => {
return el instanceof HTMLElement;
@ -278,7 +279,7 @@ const ChatMessageList: React.FC<ChatListProps> = ({
<ChatPopupContainer />
{
// @ts-ignore
Array.from({ length: pagesToLoad }, (_v, k) => k + firstPageToLoad).map((page) => {
Array.from({ length: pagesToLoad }, (v, k) => k + firstPageToLoad).map((page) => {
return (
<ChatListPage
key={`page-${page}`}
@ -297,12 +298,11 @@ const ChatMessageList: React.FC<ChatListProps> = ({
</div>
</MessageList>
</MessageListWrapper >
);
}
const ChatMessageListContainer: React.FC<Layout> = ({ }) => {
const idChatOpen = layoutSelect((i: idChatOpen) => i.idChatOpen);
const ChatMessageListContainer: React.FC = ({ }) => {
const idChatOpen = layoutSelect((i: { idChatOpen: any; }) => i.idChatOpen);
const isPublicChat = idChatOpen === PUBLIC_CHAT_KEY;
const chatId = !isPublicChat ? idChatOpen : PUBLIC_GROUP_CHAT_KEY;
const currentChat = useChat((chat) => {

View File

@ -1,26 +1,25 @@
import React, { useCallback, useEffect, useMemo, useRef } from "react";
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { Message } from '/imports/ui/Types/message';
import ChatMessageHeader from './message-header/component';
import ChatMessageTextContent from './message-content/text-content/component';
import ChatPollContent from './message-content/poll-content/component';
import ChatMessagePresentationContent from './message-content/presentation-content/component';
import { defineMessages, useIntl } from 'react-intl';
import {
ChatWrapper,
ChatContent,
ChatAvatar,
} from "./styles";
import ChatMessageHeader from "./message-header/component";
import ChatMessageTextContent from "./message-content/text-content/component";
import ChatPollContent from "./message-content/poll-content/component";
import ChatMessagePresentationContent from "./message-content/presentation-content/component";
import { defineMessages, useIntl } from "react-intl";
import { ChatMessageType } from '/imports/ui/core/enums/chat';
interface ChatMessageProps {
message: Message;
previousMessage?: Message;
lastSenderPreviousPage?: string | null;
previousMessage: Message;
lastSenderPreviousPage: string | null;
scrollRef: React.RefObject<HTMLDivElement>;
markMessageAsSeen: Function;
markMessageAsSeen: (message: Message) => void;
}
const intlMessages = defineMessages({
pollResult: {
id: 'app.chat.pollResult',
@ -44,31 +43,32 @@ function isInViewport(el: HTMLDivElement) {
const rect = el.getBoundingClientRect();
return (
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.bottom >= 0
rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.bottom >= 0
);
}
const messageRef = React.createRef<HTMLDivElement | null>();
const ChatMesssage: React.FC<ChatMessageProps> = ({
message,
previousMessage,
lastSenderPreviousPage,
scrollRef,
message,
markMessageAsSeen,
}) => {
const intl = useIntl();
const messageRef = useRef<HTMLDivElement>(null);
const markMessageAsSeenOnScrollEnd = useCallback((message, messageRef) => {
const markMessageAsSeenOnScrollEnd = useCallback(() => {
if (messageRef.current && isInViewport(messageRef.current)) {
markMessageAsSeen(message);
}
}, []);
}, [message, messageRef]);
useEffect(() => {
// I use a function here to remove the event listener using the same reference
const callbackFunction = () => {
markMessageAsSeenOnScrollEnd(message, messageRef);
if (messageRef.current && isInViewport(messageRef.current)) {
markMessageAsSeen(message); // Pass the 'message' argument here
}
};
if (message && scrollRef.current && messageRef.current) {
if (isInViewport(messageRef.current)) {
markMessageAsSeen(message);
@ -77,14 +77,14 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
}
}
return () => {
scrollRef?.current
?.removeEventListener('scrollend', callbackFunction);
}
}, [message, messageRef]);
scrollRef?.current?.removeEventListener('scrollend', callbackFunction);
};
}, [message, messageRef, markMessageAsSeenOnScrollEnd]);
if (!message) return null;
const sameSender = (previousMessage?.user?.userId || lastSenderPreviousPage) === message?.user?.userId;
const sameSender = (previousMessage?.user?.userId
|| lastSenderPreviousPage) === message?.user?.userId;
const dateTime = new Date(message?.createdTime);
const messageContent: {
name: string,
@ -118,7 +118,7 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
isModerator: true,
component: (
<ChatMessageTextContent
emphasizedMessage={true}
emphasizedMessage
text={intl.formatMessage(intlMessages.chatClear)}
/>
),
@ -135,25 +135,20 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
text={message.message}
/>
),
}
};
}
}, []);
return (
<ChatWrapper
sameSender={sameSender}
ref={messageRef}
>
{(!message?.user || !sameSender)
&& (
<ChatWrapper sameSender={sameSender} ref={messageRef}>
{(!message?.user || !sameSender) && (
<ChatAvatar
avatar={message.user?.avatar}
color={messageContent.color}
moderator={messageContent.isModerator}
>
{messageContent.name.toLowerCase().slice(0, 2) || " "}
{messageContent.name.toLowerCase().slice(0, 2) || ' '}
</ChatAvatar>
)
}
)}
<ChatContent sameSender={message?.user ? sameSender : false}>
<ChatMessageHeader
sameSender={message?.user ? sameSender : false}
@ -161,9 +156,7 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
isOnline={message.user?.isOnline ?? true}
dateTime={dateTime}
/>
{
messageContent.component
}
{messageContent.component}
</ChatContent>
</ChatWrapper>
);

View File

@ -1,6 +1,7 @@
import React from "react";
import React from 'react';
import ReactMarkdown from 'react-markdown';
import Styled from './styles';
interface ChatMessageTextContentProps {
text: string;
emphasizedMessage: boolean;
@ -9,7 +10,13 @@ interface ChatMessageTextContentProps {
const ChatMessageTextContent: React.FC<ChatMessageTextContentProps> = ({
text,
emphasizedMessage,
}) => {
}) => (
<Styled.ChatMessage
emphasizedMessage={emphasizedMessage}
dangerouslySetInnerHTML={{ __html: text }}
/>
);
() => {
// @ts-ignore - temporary, while meteor exists in the project
const { allowedElements } = Meteor.settings.public.chat;
@ -18,9 +25,9 @@ const ChatMessageTextContent: React.FC<ChatMessageTextContentProps> = ({
<ReactMarkdown
linkTarget="_blank"
allowedElements={allowedElements}
unwrapDisallowed={true}
unwrapDisallowed
>
{text}
{Text}
</ReactMarkdown>
</Styled.ChatMessage>
);

View File

@ -1,16 +1,18 @@
import styled from 'styled-components';
import { colorText } from '/imports/ui/stylesheets/styled-components/palette';
export const ChatMessage = styled.div`
interface ChatMessageProps {
emphasizedMessage: boolean;
}
export const ChatMessage = styled.div<ChatMessageProps>`
flex: 1;
display: flex;
flex-flow: row;
flex-direction: column;
color: ${colorText};
word-break: break-word;
${({ emphasizedMessage }) =>
emphasizedMessage &&
`
${({ emphasizedMessage }) => emphasizedMessage && `
font-weight: bold;
`}

View File

@ -15,7 +15,6 @@ import {
colorSuccess,
} from '/imports/ui/stylesheets/styled-components/palette';
interface ChatWrapperProps {
sameSender: boolean;
}
@ -24,6 +23,13 @@ interface ChatContentProps {
sameSender: boolean;
}
interface ChatAvatarProps {
avatar: string;
color: string;
moderator: boolean;
emoji?: string;
}
export const ChatWrapper = styled.div<ChatWrapperProps>`
pointer-events: auto;
[dir='rtl'] & {
@ -32,9 +38,7 @@ export const ChatWrapper = styled.div<ChatWrapperProps>`
display: flex;
flex-flow: row;
position: relative;
${({ sameSender }) =>
sameSender &&
`
${({ sameSender }) => sameSender && `
flex: 1;
margin: ${borderSize} 0 0 ${borderSize};
margin-top: calc(${lineHeightComputed} / 3);
@ -55,15 +59,13 @@ export const ChatContent = styled.div<ChatContentProps>`
flex-flow: column;
width: 100%;
${({ sameSender }) =>
sameSender &&
`
${({ sameSender }) => sameSender && `
margin-left: 2.6rem;
`}
`;
export const ChatAvatar = styled.div`
export const ChatAvatar = styled.div<ChatAvatarProps>`
flex: 0 0 2.25rem;
margin: 0px calc(0.5rem) 0px 0px;
box-flex: 0;
@ -116,17 +118,12 @@ export const ChatAvatar = styled.div`
}
}
${({ moderator }) =>
moderator &&
`
${({ moderator }) => moderator && `
border-radius: 5px;
`}
// ================ image ================
${({ avatar, emoji }) =>
avatar?.length !== 0 &&
!emoji &&
css`
${({ avatar, emoji }) => avatar?.length !== 0 && !emoji && css`
background-image: url(${avatar});
background-repeat: no-repeat;
background-size: contain;

View File

@ -1,11 +1,11 @@
import React from "react";
import { useSubscription } from "@apollo/client";
import React from 'react';
import { useSubscription } from '@apollo/client';
import {
CHAT_MESSAGE_PUBLIC_SUBSCRIPTION,
CHAT_MESSAGE_PRIVATE_SUBSCRIPTION,
ChatMessagePrivateSubscriptionResponse,
ChatMessagePublicSubscriptionResponse,
} from "./queries";
} from './queries';
import { Message } from '/imports/ui/Types/message';
import ChatMessage from './chat-message/componet';
@ -16,11 +16,12 @@ const PUBLIC_GROUP_CHAT_KEY = CHAT_CONFIG.public_group_id;
interface ChatListPageContainerProps {
page: number;
pageSize: number;
setLastSender: Function;
setLastSender: (page: number, message: string) => void;
lastSenderPreviousPage: string | undefined;
// eslint-disable-next-line react/no-unused-prop-types
lastSeenAt: number,
chatId: string;
markMessageAsSeen: Function;
markMessageAsSeen: () => void;
scrollRef: React.RefObject<HTMLDivElement>;
}
@ -28,17 +29,16 @@ interface ChatListPageProps {
messages: Array<Message>;
lastSenderPreviousPage: string | undefined;
page: number;
markMessageAsSeen: Function;
markMessageAsSeen: ()=> void;
scrollRef: React.RefObject<HTMLDivElement>;
}
const verifyIfIsPublicChat = (message: unknown): message is ChatMessagePublicSubscriptionResponse => {
return (message as ChatMessagePublicSubscriptionResponse).chat_message_public !== undefined;
}
const verifyIfIsPublicChat = (message: unknown):
// eslint-disable-next-line max-len
message is ChatMessagePublicSubscriptionResponse => (message as ChatMessagePublicSubscriptionResponse).chat_message_public !== undefined;
const verifyIfIsPrivateChat = (message: unknown): message is ChatMessagePrivateSubscriptionResponse => {
return (message as ChatMessagePrivateSubscriptionResponse).chat_message_private !== undefined;
}
// eslint-disable-next-line max-len
const verifyIfIsPrivateChat = (message: unknown): message is ChatMessagePrivateSubscriptionResponse => (message as ChatMessagePrivateSubscriptionResponse).chat_message_private !== undefined
const ChatListPage: React.FC<ChatListPageProps> = ({
messages,
@ -46,28 +46,26 @@ const ChatListPage: React.FC<ChatListPageProps> = ({
page,
markMessageAsSeen,
scrollRef,
}) => {
return (
}) => (
// eslint-disable-next-line react/jsx-filename-extension
<div key={`messagePage-${page}`} id={`${page}`}>
{
messages.map((message, index, Array) => {
{messages.map((message, index, Array) => {
const previousMessage = Array[index - 1];
return (
<ChatMessage
key={message.createdTime}
message={message}
previousMessage={previousMessage}
lastSenderPreviousPage={!previousMessage ? lastSenderPreviousPage : null}
lastSenderPreviousPage={
!previousMessage ? lastSenderPreviousPage : null
}
scrollRef={scrollRef}
markMessageAsSeen={markMessageAsSeen}
/>
)
})
}
);
})}
</div>
);
}
const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
page,
@ -83,17 +81,25 @@ const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
? CHAT_MESSAGE_PUBLIC_SUBSCRIPTION
: CHAT_MESSAGE_PRIVATE_SUBSCRIPTION;
const defaultVariables = { offset: (page) * pageSize, limit: pageSize };
const variables = isPublicChat ? defaultVariables : { ...defaultVariables, requestedChatId: chatId };
const variables = isPublicChat
? defaultVariables : { ...defaultVariables, requestedChatId: chatId };
const {
data: chatMessageData,
loading: chatMessageLoading,
error: chatMessageError,
} = useSubscription<ChatMessagePublicSubscriptionResponse|ChatMessagePrivateSubscriptionResponse>(
chatQuery,
{ variables }
{ variables },
);
if (chatMessageError) return (<p>chatMessageError: {JSON.stringify(chatMessageError)}</p>);
if (chatMessageError) {
return (
<p>
chatMessageError:
{JSON.stringify(chatMessageError)}
</p>
);
}
if (chatMessageLoading) return null;
let messages: Array<Message> = [];
if (verifyIfIsPublicChat(chatMessageData)) {
@ -104,7 +110,6 @@ const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
if (messages.length > 0) {
setLastSender(page, messages[messages.length - 1].user?.userId);
}
return (
@ -116,6 +121,6 @@ const ChatListPageContainer: React.FC<ChatListPageContainerProps> = ({
scrollRef={scrollRef}
/>
);
}
};
export default ChatListPageContainer;

View File

@ -3,7 +3,11 @@ import { colorWhite, colorPrimary } from '/imports/ui/stylesheets/styled-compone
import { smallOnly } from '/imports/ui/stylesheets/styled-components/breakpoints';
import { mdPaddingX } from '/imports/ui/stylesheets/styled-components/general';
export const Chat = styled.div`
interface ChatProps {
isChrome: boolean;
}
export const Chat = styled.div<ChatProps>`
background-color: ${colorWhite};
padding: ${mdPaddingX};
padding-bottom: 0;
@ -43,9 +47,7 @@ export const Chat = styled.div`
text-decoration-line: none;
}
${({ isChrome }) =>
isChrome &&
`
${({ isChrome }) => isChrome && `
transform: translateZ(0);
`}