Skip to content

Commit

Permalink
Chore: TS conversion folder client (#25031)
Browse files Browse the repository at this point in the history
  • Loading branch information
ggazzo committed Apr 4, 2022
1 parent 78cdaa7 commit 3bedb58
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 115 deletions.
6 changes: 3 additions & 3 deletions client/components/Header/Header.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const room: IRoom = {

export const ChatHeader = () => {
const icon = useRoomIcon(room);
const avatar = <RoomAvatar room={room} />;
const avatar = <RoomAvatar size='x40' room={room} />;

return (
<Header>
Expand Down Expand Up @@ -169,7 +169,7 @@ addAction('render-action-example-badge-danger', {

export const WithToolboxContext: ComponentStory<typeof Header> = () => {
const icon = useRoomIcon(room);
const avatar = <RoomAvatar room={room} />;
const avatar = <RoomAvatar size='x40' room={room} />;
return (
<Header>
<Header.Avatar>{avatar}</Header.Avatar>
Expand All @@ -196,7 +196,7 @@ export const WithToolboxContext: ComponentStory<typeof Header> = () => {

export const Omnichannel = () => {
const icon = useRoomIcon(room);
const avatar = <RoomAvatar room={room} />;
const avatar = <RoomAvatar size='x40' room={room} />;
return (
<Header>
<Header.Avatar>{avatar}</Header.Avatar>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box, Skeleton } from '@rocket.chat/fuselage';
import React from 'react';
import React, { FC } from 'react';

export const FormSkeleton = (props) => (
export const FormSkeleton: FC = (props) => (
<Box w='full' pb='x24' {...props}>
<Skeleton mbe='x8' />
<Skeleton mbe='x4' />
Expand Down
12 changes: 0 additions & 12 deletions client/components/avatar/AppAvatar.js

This file was deleted.

26 changes: 26 additions & 0 deletions client/components/avatar/AppAvatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Box } from '@rocket.chat/fuselage';
import React, { ReactElement } from 'react';

import BaseAvatar from './BaseAvatar';

// TODO: frontend chapter day - Remove inline Styling

type AppAvatarProps = {
/* @deprecated */
size: 'x36' | 'x28' | 'x16' | 'x40' | 'x124';
/* @deprecated */
mie?: 'x80' | 'x20' | 'x8';
/* @deprecated */
alignSelf?: 'center';

iconFileContent: string;
iconFileData: string;
};

export default function AppAvatar({ iconFileContent, size, iconFileData, ...props }: AppAvatarProps): ReactElement {
return (
<Box {...props}>
<BaseAvatar size={size} objectFit url={iconFileContent || `data:image/png;base64,${iconFileData}`} />
</Box>
);
}
12 changes: 0 additions & 12 deletions client/components/avatar/RoomAvatar.js

This file was deleted.

28 changes: 28 additions & 0 deletions client/components/avatar/RoomAvatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, { memo, ReactElement } from 'react';

import { useRoomAvatarPath } from '../../contexts/AvatarUrlContext';
import BaseAvatar from './BaseAvatar';

// TODO: frontend chapter day - Remove inline Styling

type RoomAvatarProps = {
/* @deprecated */
size?: 'x16' | 'x20' | 'x28' | 'x36' | 'x40' | 'x124';
/* @deprecated */
url?: string;

room: {
_id: string;
type?: string;
t: string;
avatarETag?: string;
};
};

const RoomAvatar = function RoomAvatar({ room, ...rest }: RoomAvatarProps): ReactElement {
const getRoomPathAvatar = useRoomAvatarPath();
const { url = getRoomPathAvatar(room), ...props } = rest;
return <BaseAvatar url={url} {...props} />;
};

export default memo(RoomAvatar);
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { Icon } from '@rocket.chat/fuselage';
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState, MouseEventHandler, FC } from 'react';

import { useConnectionStatus } from '../../contexts/ConnectionStatusContext';
import { useTranslation } from '../../contexts/TranslationContext';
import './ConnectionStatusBar.css';
import './ConnectionStatusBar.styles.css';

const getReconnectCountdown = (retryTime) => {
// TODO: frontend chapter day - fix unknown translation keys

const getReconnectCountdown = (retryTime: number): number => {
const timeDiff = retryTime - Date.now();
return (timeDiff > 0 && Math.round(timeDiff / 1000)) || 0;
};

const useReconnectCountdown = (retryTime, status) => {
const reconnectionTimerRef = useRef();
const [reconnectCountdown, setReconnectCountdown] = useState(() => getReconnectCountdown(retryTime));
const useReconnectCountdown = (
retryTime: number | undefined,
status: 'connected' | 'connecting' | 'failed' | 'waiting' | 'offline',
): number => {
const reconnectionTimerRef = useRef<ReturnType<typeof setInterval>>();
const [reconnectCountdown, setReconnectCountdown] = useState(() => (retryTime ? getReconnectCountdown(retryTime) : 0));

useEffect(() => {
if (status === 'waiting') {
Expand All @@ -21,26 +26,26 @@ const useReconnectCountdown = (retryTime, status) => {
}

reconnectionTimerRef.current = setInterval(() => {
setReconnectCountdown(getReconnectCountdown(retryTime));
retryTime && setReconnectCountdown(getReconnectCountdown(retryTime));
}, 500);
return;
}

clearInterval(reconnectionTimerRef.current);
reconnectionTimerRef.current = null;
reconnectionTimerRef.current && clearInterval(reconnectionTimerRef.current);
reconnectionTimerRef.current = undefined;
}, [retryTime, status]);

useEffect(
() => () => {
clearInterval(reconnectionTimerRef.current);
() => (): void => {
reconnectionTimerRef.current && clearInterval(reconnectionTimerRef.current);
},
[],
);

return reconnectCountdown;
};

function ConnectionStatusBar() {
const ConnectionStatusBar: FC = function ConnectionStatusBar() {
const { connected, retryTime, status, reconnect } = useConnectionStatus();
const reconnectCountdown = useReconnectCountdown(retryTime, status);
const t = useTranslation();
Expand All @@ -49,15 +54,15 @@ function ConnectionStatusBar() {
return null;
}

const handleRetryClick = (event) => {
const handleRetryClick: MouseEventHandler<HTMLAnchorElement> = (event) => {
event.preventDefault();
reconnect && reconnect();
reconnect?.();
};

return (
<div className='ConnectionStatusBar' role='alert'>
<strong>
<Icon name='warning' /> {t('meteor_status', { context: status })}
<Icon name='warning' /> {t('meteor_status' as Parameters<typeof t>[0], { context: status })}
</strong>

{status === 'waiting' && <> {t('meteor_status_reconnect_in', { count: reconnectCountdown })}</>}
Expand All @@ -66,12 +71,12 @@ function ConnectionStatusBar() {
<>
{' '}
<a className='ConnectionStatusBar__retry-link' href='#' onClick={handleRetryClick}>
{t('meteor_status_try_now', { context: status })}
{t('meteor_status_try_now' as Parameters<typeof t>[0], { context: status })}
</a>
</>
)}
</div>
);
}
};

export default ConnectionStatusBar;
4 changes: 2 additions & 2 deletions client/contexts/AvatarUrlContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ const AvatarUrlContextValueDefault: AvatarContextValue = {

export const AvatarUrlContext = createContext<AvatarContextValue>(AvatarUrlContextValueDefault);

export const useRoomAvatarPath = (): ((uid: string, etag?: string) => string) => useContext(AvatarUrlContext).getRoomPathAvatar;
export const useRoomAvatarPath = (): ((...args: any) => string) => useContext(AvatarUrlContext).getRoomPathAvatar;

export const useUserAvatarPath = (): ((...args: any) => string) => useContext(AvatarUrlContext).getUserPathAvatar;
export const useUserAvatarPath = (): ((uid: string, etag?: string) => string) => useContext(AvatarUrlContext).getUserPathAvatar;
27 changes: 25 additions & 2 deletions client/contexts/ServerContext/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { SaveSettingsMethod } from './methods/saveSettings';
import { SaveUserPreferencesMethod } from './methods/saveUserPreferences';
import { UnfollowMessageMethod } from './methods/unfollowMessage';

// TODO: frontend chapter day - define methods

export type ServerMethods = {
'2fa:checkCodesRemaining': (...args: any[]) => any;
'2fa:disable': (...args: any[]) => any;
Expand All @@ -37,7 +39,14 @@ export type ServerMethods = {
'checkUsernameAvailability': (...args: any[]) => any;
'cleanRoomHistory': (...args: any[]) => any;
'clearIntegrationHistory': (...args: any[]) => any;
'cloud:checkRegisterStatus': (...args: any[]) => any;
'cloud:checkRegisterStatus': () => {
connectToCloud: string;
workspaceRegistered: string;
workspaceId: string;
uniqueId: string;
token: string;
email: string;
};
'cloud:checkUserLoggedIn': (...args: any[]) => any;
'cloud:connectWorkspace': (...args: any[]) => any;
'cloud:disconnectWorkspace': (...args: any[]) => any;
Expand Down Expand Up @@ -76,7 +85,21 @@ export type ServerMethods = {
'livechat:changeLivechatStatus': (...args: any[]) => any;
'livechat:closeRoom': (...args: any[]) => any;
'livechat:discardTranscript': (...args: any[]) => any;
'livechat:facebook': (...args: any[]) => any;

// TODO: chapter day backend - enhance/deprecate
'livechat:facebook':
| ((...args: [{ action: 'initialState' }]) => {
enabled: boolean;
hasToken: boolean;
})
| ((...args: [{ action: 'list-pages' }]) => {
name: string;
subscribed: boolean;
id: string;
}[])
| ((...args: [{ action: 'subscribe' | 'unsubscribe'; page: string }]) => {})
| ((...args: [{ action: 'enable' }]) => { url: string } | undefined)
| ((...args: [{ action: 'disable' }]) => {});
'livechat:getAgentOverviewData': (...args: any[]) => any;
'livechat:getAnalyticsChartData': (...args: any[]) => any;
'livechat:getAnalyticsOverviewData': (...args: any[]) => any;
Expand Down
2 changes: 1 addition & 1 deletion client/contexts/ServerContext/methods/getReadReceipts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IMessage } from '../../../../definition/IMessage';
import type { ReadReceipt } from '../../../../definition/ReadReceipt';

export type GetReadReceiptsMethod = (options: { mid: IMessage['_id'] }) => Array<ReadReceipt>;
export type GetReadReceiptsMethod = (options: { messageId: IMessage['_id'] }) => Array<ReadReceipt>;
20 changes: 10 additions & 10 deletions client/hooks/useMethodData.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { useCallback, useEffect } from 'react';

import { ServerMethods, useMethod } from '../contexts/ServerContext';
import type { Awaited } from '../../definition/utils';
import { ServerMethodFunction, ServerMethodParameters, ServerMethods, useMethod } from '../contexts/ServerContext';
import { useToastMessageDispatch } from '../contexts/ToastMessagesContext';
import { AsyncState, useAsyncState } from './useAsyncState';

const defaultArgs: unknown[] = [];

export const useMethodData = <T>(
methodName: keyof ServerMethods,
args: any[] = defaultArgs,
initialValue?: T | (() => T),
): AsyncState<T> & { reload: () => void } => {
const { resolve, reject, reset, ...state } = useAsyncState<T>(initialValue);
export const useMethodData = <MethodName extends keyof ServerMethods, Result = Awaited<ReturnType<ServerMethodFunction<MethodName>>>>(
methodName: MethodName,
args: ServerMethodParameters<MethodName>,
initialValue?: Result | (() => Result),
): AsyncState<Result> & { reload: () => void } => {
const { resolve, reject, reset, ...state } = useAsyncState<Result>(initialValue);
const dispatchToastMessage = useToastMessageDispatch();
const getData: (...args: unknown[]) => Promise<T> = useMethod(methodName);
const getData: ServerMethodFunction<MethodName> = useMethod(methodName);

const fetchData = useCallback(() => {
reset();
Expand All @@ -30,6 +29,7 @@ export const useMethodData = <T>(
}, [reset, getData, args, resolve, dispatchToastMessage, reject]);

useEffect(() => {
console.log('as');
fetchData();
}, [fetchData]);

Expand Down
11 changes: 6 additions & 5 deletions client/hooks/usePolledMethodData.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { useEffect } from 'react';

import { ServerMethods } from '../contexts/ServerContext';
import { Awaited } from '../../definition/utils';
import { ServerMethodFunction, ServerMethodParameters, ServerMethods } from '../contexts/ServerContext';
import { AsyncState } from './useAsyncState';
import { useMethodData } from './useMethodData';

export const usePolledMethodData = <T>(
export const usePolledMethodData = <MethodName extends keyof ServerMethods, Result = Awaited<ReturnType<ServerMethodFunction<MethodName>>>>(
methodName: keyof ServerMethods,
args: any[] = [],
args: ServerMethodParameters<MethodName>,
intervalMs: number,
): AsyncState<T> & { reload: () => void } => {
const { reload, ...state } = useMethodData<T>(methodName, args);
): AsyncState<Result> & { reload: () => void } => {
const { reload, ...state } = useMethodData(methodName, args);

useEffect(() => {
const timer = setInterval(() => {
Expand Down
2 changes: 1 addition & 1 deletion client/views/admin/apps/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type App = {
price: number;
purchaseType: string;
pricingPlans: unknown[];
iconFileContent: unknown;
iconFileContent: string;
installed?: boolean;
isEnterpriseOnly?: boolean;
bundledIn: {
Expand Down
Loading

0 comments on commit 3bedb58

Please sign in to comment.