Skip to content
Snippets Groups Projects
Unverified Commit 4b8c2156 authored by Martin Schoeler's avatar Martin Schoeler Committed by GitHub
Browse files

refactor: Start `Livechat/Message` conversion to TS (#32290)

parent f9e39a8d
No related branches found
No related tags found
No related merge requests found
Showing
with 149 additions and 41 deletions
......@@ -5,7 +5,13 @@ import { createClassName } from '../../../helpers/createClassName';
import { MessageBubble } from '../MessageBubble';
import styles from './styles.scss';
const AudioAttachment = ({ url, className, t, ...messageBubbleProps }) => (
type AudioAttachmentProps = {
url: string;
className?: string;
t: (key: string) => string;
};
const AudioAttachment = ({ url, className, t, ...messageBubbleProps }: AudioAttachmentProps) => (
<MessageBubble nude className={createClassName(styles, 'audio-attachment', {}, [className])} {...messageBubbleProps}>
<audio src={url} controls className={createClassName(styles, 'audio-attachment__inner')}>
{t('you_browser_doesn_t_support_audio_element')}
......
......@@ -6,7 +6,13 @@ import { FileAttachmentIcon } from '../FileAttachmentIcon';
import { MessageBubble } from '../MessageBubble';
import styles from './styles.scss';
export const FileAttachment = memo(({ url, title, className, ...messageBubbleProps }) => (
type FileAttachmentProps = {
url: string;
title: string;
className?: string;
};
export const FileAttachment = memo(({ url, title, className, ...messageBubbleProps }: FileAttachmentProps) => (
<MessageBubble className={createClassName(styles, 'file-attachment', {}, [className])} {...messageBubbleProps}>
<a href={url} download target='_blank' rel='noopener noreferrer' className={createClassName(styles, 'file-attachment__inner')}>
<FileAttachmentIcon url={url} />
......
......@@ -7,15 +7,16 @@ import PPTIcon from '../../../icons/ppt.svg';
import SheetIcon from '../../../icons/sheet.svg';
import ZipIcon from '../../../icons/zip.svg';
export const FileAttachmentIcon = memo(({ url }) => {
export const FileAttachmentIcon = memo(({ url }: { url?: string }) => {
const extension = url ? url.split('.').pop() : null;
const Icon =
(/pdf/i.test(extension) && PDFIcon) ||
(/doc|docx|rtf|txt|odt|pages|log/i.test(extension) && DocIcon) ||
(/ppt|pptx|pps/i.test(extension) && PPTIcon) ||
(/xls|xlsx|csv/i.test(extension) && SheetIcon) ||
(/zip|rar|7z|gz/i.test(extension) && ZipIcon) ||
FileIcon;
extension &&
((/pdf/i.test(extension) && PDFIcon) ||
(/doc|docx|rtf|txt|odt|pages|log/i.test(extension) && DocIcon) ||
(/ppt|pptx|pps/i.test(extension) && PPTIcon) ||
(/xls|xlsx|csv/i.test(extension) && SheetIcon) ||
(/zip|rar|7z|gz/i.test(extension) && ZipIcon) ||
FileIcon);
return <Icon width={32} />;
});
......@@ -4,7 +4,12 @@ import { createClassName } from '../../../helpers/createClassName';
import { MessageBubble } from '../MessageBubble';
import styles from './styles.scss';
export const ImageAttachment = memo(({ url, className, ...messageBubbleProps }) => (
type ImageAttachmentProps = {
url: string;
className?: string;
};
export const ImageAttachment = memo(({ url, className, ...messageBubbleProps }: ImageAttachmentProps) => (
<MessageBubble nude className={createClassName(styles, 'image-attachment', {}, [className])} {...messageBubbleProps}>
<img src={url} className={createClassName(styles, 'image-attachment__inner')} />
</MessageBubble>
......
......@@ -4,7 +4,14 @@ import { createClassName } from '../../../helpers/createClassName';
import { Avatar } from '../../Avatar';
import styles from './styles.scss';
export const MessageAvatars = memo(({ avatarResolver = () => null, usernames = [], className, style = {} }) => {
type MessageAvatarsProps = {
avatarResolver: (username: string) => string | undefined;
usernames: string[];
className?: string;
style?: React.CSSProperties;
};
export const MessageAvatars = memo(({ avatarResolver = () => undefined, usernames = [], className, style = {} }: MessageAvatarsProps) => {
const avatars = usernames.filter(Boolean);
if (!avatars.length) {
......
......@@ -6,9 +6,15 @@ import { renderMessageBlocks } from '../../uiKit';
import Surface from '../../uiKit/message/Surface';
import styles from './styles.scss';
const MessageBlocks = ({ blocks = [], mid = undefined, rid = undefined }) => {
type MessageBlocksProps = {
blocks?: unknown[];
mid?: string;
rid?: string;
};
const MessageBlocks = ({ blocks = [], mid = undefined, rid = undefined }: MessageBlocksProps) => {
const dispatchAction = useCallback(
({ appId, actionId, payload }) =>
({ appId, actionId, payload }: { appId: string; actionId: string; payload: unknown }) =>
triggerAction({
appId,
type: UIKitIncomingInteractionType.BLOCK,
......
import type { ComponentChildren } from 'preact';
import { memo } from 'preact/compat';
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
export const MessageBubble = memo(({ inverse, nude, quoted, className, style = {}, children, system = false }) => (
type MessageBubbleProps = {
inverse?: boolean;
nude?: boolean;
quoted?: boolean;
className?: string;
style?: React.CSSProperties;
system?: boolean;
children?: ComponentChildren;
};
export const MessageBubble = memo(({ inverse, nude, quoted, className, style = {}, children, system = false }: MessageBubbleProps) => (
<div
data-qa='message-bubble'
className={createClassName(styles, 'message-bubble', { inverse, nude, quoted, system }, [className])}
......
import { memo } from 'preact/compat';
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
export const MessageContainer = memo(({ id, compact, reverse, use: Element = 'div', className, style = {}, children, system = false }) => (
<Element id={id} className={createClassName(styles, 'message-container', { compact, reverse, system }, [className])} style={style}>
{children}
</Element>
));
import type { ComponentChildren } from 'preact';
import { memo } from 'preact/compat';
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
type MessageContainerProps = {
id?: string;
compact?: boolean;
reverse?: boolean;
use?: any;
className?: string;
style?: React.CSSProperties;
system?: boolean;
children?: ComponentChildren;
};
export const MessageContainer = memo(
// TODO: find a better way to pass `use` and do not default to a string
// eslint-disable-next-line @typescript-eslint/naming-convention
({ id, compact, reverse, use: Element = 'div', className, style = {}, children, system = false }: MessageContainerProps) => (
<Element id={id} className={createClassName(styles, 'message-container', { compact, reverse, system }, [className])} style={style}>
{children}
</Element>
),
);
import type { ComponentChildren } from 'preact';
import { memo } from 'preact/compat';
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
export const MessageContent = memo(({ reverse, className, style = {}, children }) => (
type MessageContentProps = {
reverse?: boolean;
className?: string;
style?: React.CSSProperties;
children?: ComponentChildren;
};
export const MessageContent = memo(({ reverse, className, style = {}, children }: MessageContentProps) => (
<div className={createClassName(styles, 'message-content', { reverse }, [className])} style={style}>
{children}
</div>
......
import type { TFunction } from 'i18next';
import type { CSSProperties } from 'preact/compat';
import { memo } from 'preact/compat';
import { withTranslation } from 'react-i18next';
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
const MessageSeparator = ({ date, unread, use: Element = 'div', className, style = {}, t }) => (
type MessageSeparatorProps = {
date?: string;
unread?: boolean;
className?: string;
style?: CSSProperties;
t: TFunction;
use?: any;
};
// TODO: find a better way to pass `use` and do not default to a string
// eslint-disable-next-line @typescript-eslint/naming-convention
const MessageSeparator = ({ date, unread, use: Element = 'div', className, style = {}, t }: MessageSeparatorProps) => (
<Element
className={createClassName(
styles,
......
import { parseISO } from 'date-fns/fp';
import isToday from 'date-fns/isToday';
import type { TFunction } from 'i18next';
import { memo } from 'preact/compat';
import { withTranslation } from 'react-i18next';
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
const parseDate = (ts, t) => {
const parseDate = (ts: number, t: TFunction) => {
const timestamp = new Date(ts).toISOString();
return t('message_time', {
val: new Date(timestamp),
......@@ -16,16 +17,26 @@ const parseDate = (ts, t) => {
});
};
const MessageTime = ({ ts, normal, inverted, className, style = {}, t }) => (
<div className={createClassName(styles, 'message-time-wrapper')}>
<time
dateTime={new Date(ts).toISOString()}
className={createClassName(styles, 'message-time', { normal, inverted }, [className])}
style={style}
>
{parseDate(ts, t)}
</time>
</div>
);
type MessageTimeProps = {
ts: number;
normal?: boolean;
inverted?: boolean;
className?: string;
style?: React.CSSProperties;
t: TFunction;
};
const MessageTime = ({ ts, normal, inverted, className, style = {}, t }: MessageTimeProps) => {
return (
<div className={createClassName(styles, 'message-time-wrapper')}>
<time
dateTime={new Date(ts).toISOString()}
className={createClassName(styles, 'message-time', { normal, inverted }, [className])}
style={style}
>
{parseDate(ts, t)}
</time>
</div>
);
};
export default withTranslation()(memo(MessageTime));
import { createClassName } from '../../../helpers/createClassName';
import styles from './styles.scss';
export const TypingDots = ({ text, className, style = {} }) => (
type TypingDotsProps = {
text: string;
className?: string;
style?: React.CSSProperties;
};
export const TypingDots = ({ text, className, style = {} }: TypingDotsProps) => (
<div aria-label={text} className={createClassName(styles, 'typing-dots', {}, [className])} style={style}>
<span class={createClassName(styles, 'typing-dots__dot')} />
<span class={createClassName(styles, 'typing-dots__dot')} />
......
......@@ -6,7 +6,13 @@ import { MessageContainer } from '../MessageContainer';
import { MessageContent } from '../MessageContent';
import { TypingDots } from '../TypingDots';
export const TypingIndicator = memo(({ avatarResolver = () => null, usernames = [], text, ...containerProps }) => (
type TypingIndicatorProps = {
avatarResolver: (username: string) => string | undefined;
usernames?: string[];
text: string;
};
export const TypingIndicator = memo(({ avatarResolver, usernames = [], text, ...containerProps }: TypingIndicatorProps) => (
<MessageContainer {...containerProps}>
<MessageAvatars avatarResolver={avatarResolver} usernames={usernames} />
<MessageContent>
......
import type { TFunction } from 'i18next';
import { memo } from 'preact/compat';
import { withTranslation } from 'react-i18next';
......@@ -5,7 +6,12 @@ import { createClassName } from '../../../helpers/createClassName';
import { MessageBubble } from '../MessageBubble';
import styles from './styles.scss';
const VideoAttachment = ({ url, className, t, ...messageBubbleProps }) => (
type VideoAttachmentProps = {
url: string;
className?: string;
t: TFunction;
};
const VideoAttachment = ({ url, className, t, ...messageBubbleProps }: VideoAttachmentProps) => (
<MessageBubble nude className={createClassName(styles, 'video-attachment', {}, [className])} {...messageBubbleProps}>
<video src={url} controls className={createClassName(styles, 'video-attachment__inner')}>
{t('you_browser_doesn_t_support_video_element')}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment