Skip to content

Commit

Permalink
refactor: Some Livechat modules to TypeScript (RocketChat#30366)
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Jan 25, 2024
1 parent 3b4176d commit 8cdd0e6
Show file tree
Hide file tree
Showing 81 changed files with 511 additions and 293 deletions.
54 changes: 54 additions & 0 deletions packages/livechat/.storybook/helpers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { action } from '@storybook/addon-actions';
import { type DecoratorFunction } from '@storybook/csf';
import type { Args, PreactFramework } from '@storybook/preact';
import { loremIpsum as originalLoremIpsum } from 'lorem-ipsum';

import gazzoAvatar from './assets/gazzo.jpg';
import martinAvatar from './assets/martin.jpg';
import tassoAvatar from './assets/tasso.jpg';

export const screenDecorator: DecoratorFunction<PreactFramework, Args> = (storyFn) => (
<div style={{ display: 'flex', width: 365, height: 500 }}>{storyFn()}</div>
);

export const screenProps = () => ({
theme: {
color: '',
fontColor: '',
iconColor: '',
},
notificationsEnabled: true,
minimized: false,
windowed: false,
onEnableNotifications: action('enableNotifications'),
onDisableNotifications: action('disableNotifications'),
onMinimize: action('minimize'),
onRestore: action('restore'),
onOpenWindow: action('openWindow'),
});

export const avatarResolver = (username: string) =>
({
'guilherme.gazzo': gazzoAvatar,
'martin.schoeler': martinAvatar,
'tasso.evangelista': tassoAvatar,
}[username]);

export const attachmentResolver = (url: string) => url;

const createRandom = (s: number) => () => {
s = Math.sin(s) * 10000;
return s - Math.floor(s);
};
const loremIpsumRandom = createRandom(42);
export const loremIpsum = (options: Parameters<typeof originalLoremIpsum>[0]) =>
originalLoremIpsum({ random: loremIpsumRandom, ...options });

export { gazzoAvatar, martinAvatar, tassoAvatar };

export { default as sampleAudio } from './assets/sample-audio.mp3';
export { default as sampleImage } from './assets/sample-image.jpg';
export { default as sampleVideo } from './assets/sample-video.mp4';
export { default as accessoryImage } from './assets/accessoryImage.png';
export { default as imageBlock } from './assets/imageBlock.png';
export { default as beepAudio } from './assets/beep.mp3';
3 changes: 3 additions & 0 deletions packages/livechat/.storybook/logo.svg.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare const path: string;

export = path;
60 changes: 0 additions & 60 deletions packages/livechat/.storybook/main.js

This file was deleted.

92 changes: 92 additions & 0 deletions packages/livechat/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { type StorybookConfig } from '@storybook/core-common';
import { type RuleSetRule } from 'webpack';

const config: StorybookConfig = {
stories: ['../src/**/{*.story,story,*.stories,stories}.{js,tsx}'],
addons: [
{
name: '@storybook/addon-essentials',
options: {
backgrounds: false,
},
},
'@storybook/addon-postcss',
'storybook-dark-mode',
],
core: {
builder: 'webpack4',
},
webpackFinal: async (config) => {
if (!config.resolve || !config.module) {
throw new Error('Invalid webpack config');
}

config.resolve.alias = {
...config.resolve.alias,
'react': 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
'react/jsx-runtime': 'preact/jsx-runtime',
[require.resolve('../src/lib/uiKit')]: require.resolve('./mocks/uiKit.ts'),
};

const isRuleSetRule = (rule: any): rule is RuleSetRule => typeof rule === 'object' && rule.test && rule.use;

config.module.rules ??= [];

config.module.rules = config.module.rules.filter(
(rule) => isRuleSetRule(rule) && (typeof rule.loader !== 'string' || !/json-loader/.test(rule.loader)),
);

const fileLoader = config.module.rules.find(
(rule): rule is RuleSetRule => isRuleSetRule(rule) && typeof rule.loader === 'string' && /file-loader/.test(rule.loader),
);
if (!fileLoader) {
throw new Error('Invalid webpack config');
}
fileLoader.test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf|mp3|mp4)(\?.*)?$/;

const urlLoader = config.module.rules
?.filter(isRuleSetRule)
.find(({ loader }) => typeof loader === 'string' && /url-loader/.test(loader));
if (!urlLoader) {
throw new Error('Invalid webpack config');
}
urlLoader.test = /\.(webm|wav|m4a|aac|oga)(\?.*)?$/;

config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
modules: true,
importLoaders: 1,
},
},
'sass-loader',
],
});

// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');

const logoPath = path.resolve(path.join(__dirname, './logo.svg'));

config.module.rules.push({
...fileLoader,
test: (srcPath) => srcPath === logoPath,
});

config.module.rules.push({
test: (srcPath) => srcPath.endsWith('.svg') && srcPath !== logoPath,
use: ['desvg-loader/preact', 'svg-loader'],
});

return config;
},
};

module.exports = config;
16 changes: 0 additions & 16 deletions packages/livechat/.storybook/manager.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const UIKitIncomingInteractionContainerType = {
VIEW: 'view',
};

export const triggerAction = async (payload) => {
export const triggerAction = async (payload: unknown) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
action('dispatchAction')(payload);
};
11 changes: 0 additions & 11 deletions packages/livechat/.storybook/preview.js

This file was deleted.

36 changes: 36 additions & 0 deletions packages/livechat/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { type Parameters } from '@storybook/addons';
import { themes } from '@storybook/theming';

import manifest from '../package.json';
import logo from './logo.svg';
import 'emoji-mart/css/emoji-mart.css';
import '../src/styles/index.scss';

export const parameters: Parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
backgrounds: {
grid: {
cellSize: 4,
cellAmount: 4,
opacity: 0.5,
},
},
options: {
storySort: ([, a], [, b]) => a.kind.localeCompare(b.kind),
},
layout: 'fullscreen',
darkMode: {
dark: {
...themes.dark,
brandTitle: manifest.name,
brandImage: logo,
brandUrl: manifest.homepage,
},
light: {
...themes.normal,
brandTitle: manifest.name,
brandImage: logo,
brandUrl: manifest.homepage,
},
},
};
2 changes: 2 additions & 0 deletions packages/livechat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"url": "https://github.com/RocketChat/Rocket.Chat",
"directory": "packages/livechat"
},
"homepage": "https://rocket.chat",
"scripts": {
"clean": "rimraf dist",
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack-cli --mode production",
Expand Down Expand Up @@ -111,6 +112,7 @@
"query-string": "^7.1.3",
"react-hook-form": "~7.45.4",
"react-i18next": "~13.2.2",
"storybook-dark-mode": "~3.0.1",
"whatwg-fetch": "^3.6.19"
},
"browserslist": [
Expand Down
6 changes: 6 additions & 0 deletions packages/livechat/src/Theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type CSSProperties } from 'preact/compat';

export type Theme = {
color: CSSProperties['backgroundColor'];
fontColor: CSSProperties['color'];
};
2 changes: 1 addition & 1 deletion packages/livechat/src/components/Alert/stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Meta, Story } from '@storybook/preact';
import type { ComponentProps } from 'preact';

import Alert from '.';
import { loremIpsum, screenDecorator } from '../../helpers.stories';
import { loremIpsum, screenDecorator } from '../../../.storybook/helpers';

export default {
title: 'Components/Alert',
Expand Down
2 changes: 1 addition & 1 deletion packages/livechat/src/components/Avatar/stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Meta, Story } from '@storybook/preact';
import type { ComponentProps } from 'preact';

import { Avatar } from '.';
import { gazzoAvatar } from '../../helpers.stories';
import { gazzoAvatar } from '../../../.storybook/helpers';

export default {
title: 'Components/Avatar',
Expand Down
1 change: 1 addition & 0 deletions packages/livechat/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type ButtonProps = {
style?: CSSProperties;
img?: string;
onClick?: JSXInternal.MouseEventHandler<HTMLButtonElement>;
onMouseUp?: JSXInternal.MouseEventHandler<HTMLButtonElement>;
full?: boolean;
};

Expand Down
2 changes: 1 addition & 1 deletion packages/livechat/src/components/Button/stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Meta, Story } from '@storybook/preact';
import type { ComponentProps } from 'preact';

import { Button } from '.';
import { gazzoAvatar } from '../../helpers.stories';
import { gazzoAvatar } from '../../../.storybook/helpers';
import ChatIcon from '../../icons/chat.svg';

const iconElement = <ChatIcon />;
Expand Down
16 changes: 7 additions & 9 deletions packages/livechat/src/components/FilesDropTarget/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { ComponentChildren, Ref } from 'preact';
import type { TargetedEvent } from 'preact/compat';
import { useState } from 'preact/hooks';
import type { JSXInternal } from 'preact/src/jsx';
import { useState, type CSSProperties, type ChangeEvent, type TargetedEvent } from 'preact/compat';

import { createClassName } from '../../helpers/createClassName';
import styles from './styles.scss';
Expand All @@ -14,7 +12,7 @@ type FilesDropTargetProps = {
accept?: string;
multiple?: boolean;
className?: string;
style?: JSXInternal.CSSProperties;
style?: CSSProperties;
children?: ComponentChildren;
inputRef?: Ref<HTMLInputElement>;
onUpload?: (files: File[]) => void;
Expand All @@ -33,21 +31,21 @@ export const FilesDropTarget = ({
}: FilesDropTargetProps) => {
const [dragLevel, setDragLevel] = useState(0);

const handleDragOver = (event: DragEvent) => {
const handleDragOver = (event: TargetedEvent<HTMLElement, DragEvent>) => {
event.preventDefault();
};

const handleDragEnter = (event: DragEvent) => {
const handleDragEnter = (event: TargetedEvent<HTMLElement, DragEvent>) => {
event.preventDefault();
setDragLevel(dragLevel + 1);
};

const handleDragLeave = (event: DragEvent) => {
const handleDragLeave = (event: TargetedEvent<HTMLElement, DragEvent>) => {
event.preventDefault();
setDragLevel(dragLevel - 1);
};

const handleDrop = (event: DragEvent) => {
const handleDrop = (event: TargetedEvent<HTMLElement, DragEvent>) => {
event.preventDefault();

if (dragLevel === 0 || !event?.dataTransfer?.files?.length) {
Expand All @@ -59,7 +57,7 @@ export const FilesDropTarget = ({
handleUpload(event?.dataTransfer?.files);
};

const handleInputChange = (event: TargetedEvent<HTMLInputElement>) => {
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
if (!event?.currentTarget?.files?.length) {
return;
}
Expand Down
Loading

0 comments on commit 8cdd0e6

Please sign in to comment.