fix(fuselage-ui-kit): Handle invalid context on `VideoConferenceBlock` component (#29965)

pull/29873/head^2
Tasso Evangelista 2 years ago committed by GitHub
parent 0f2c841938
commit dce4a829fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .changeset/violet-frogs-cheer.md
  2. 3
      packages/fuselage-ui-kit/package.json
  3. 175
      packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx
  4. 2
      packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfData.ts
  5. 7
      packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfDataStream.ts
  6. 4
      packages/fuselage-ui-kit/src/elements/MarkdownTextElement.tsx
  7. 9
      packages/fuselage-ui-kit/src/elements/PlainTextElement.tsx
  8. 2
      packages/fuselage-ui-kit/src/stories/Message.stories.tsx
  9. 12
      packages/fuselage-ui-kit/src/surfaces/FuselageSurfaceRenderer.tsx
  10. 8
      packages/fuselage-ui-kit/src/surfaces/index.ts

@ -0,0 +1,5 @@
---
'@rocket.chat/fuselage-ui-kit': patch
---
Handle invalid context on `VideoConferenceBlock` component

@ -31,8 +31,7 @@
".:build:clean": "rimraf dist",
".:build:esm": "tsc -p tsconfig-esm.json",
".:build:cjs": "tsc -p tsconfig-cjs.json",
"eslint": "eslint --ext .js,.jsx,.ts,.tsx .",
"eslint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix",
"lint": "eslint --ext .js,.jsx,.ts,.tsx .",
"docs": "cross-env NODE_ENV=production build-storybook -o ../../static/fuselage-ui-kit",
"storybook": "start-storybook -p 6006",
"build-storybook": "cross-env NODE_ENV=production build-storybook",

@ -1,5 +1,5 @@
import type * as UiKit from '@rocket.chat/ui-kit';
import { useTranslation, useUserId } from '@rocket.chat/ui-contexts';
import type * as UiKit from '@rocket.chat/ui-kit';
import {
VideoConfMessageSkeleton,
VideoConfMessage,
@ -17,10 +17,10 @@ import {
import type { MouseEventHandler, ReactElement } from 'react';
import { useContext, memo } from 'react';
import { kitContext } from '../..';
import { useSurfaceType } from '../../contexts/SurfaceContext';
import type { BlockProps } from '../../utils/BlockProps';
import { useVideoConfDataStream } from './hooks/useVideoConfDataStream';
import { kitContext } from '../..';
type VideoConferenceBlockProps = BlockProps<UiKit.VideoConferenceBlock>;
@ -37,11 +37,11 @@ const VideoConferenceBlock = ({
const { action, viewId, rid } = useContext(kitContext);
if (surfaceType !== 'message') {
return <></>;
throw new Error('VideoConferenceBlock cannot be rendered outside message');
}
if (!callId || !rid) {
return <></>;
if (!rid) {
throw new Error('VideoConferenceBlock cannot be rendered without rid');
}
const result = useVideoConfDataStream({ rid, callId });
@ -85,109 +85,110 @@ const VideoConferenceBlock = ({
);
};
if (result.isSuccess) {
const { data } = result;
const isUserCaller = data.createdBy._id === userId;
if ('endedAt' in data) {
return (
<VideoConfMessage>
<VideoConfMessageRow>
<VideoConfMessageContent>
<VideoConfMessageIcon />
<VideoConfMessageText>{t('Call_ended')}</VideoConfMessageText>
</VideoConfMessageContent>
<VideoConfMessageActions>
<VideoConfMessageAction icon='info' onClick={openCallInfo} />
</VideoConfMessageActions>
</VideoConfMessageRow>
<VideoConfMessageFooter>
{data.type === 'direct' && (
<>
<VideoConfMessageButton onClick={callAgainHandler}>
{isUserCaller ? t('Call_again') : t('Call_back')}
</VideoConfMessageButton>
<VideoConfMessageFooterText>
{t('Call_was_not_answered')}
</VideoConfMessageFooterText>
</>
)}
{data.type !== 'direct' &&
(data.users.length ? (
<>
<VideoConfMessageUserStack users={data.users} />
<VideoConfMessageFooterText>
{data.users.length > MAX_USERS
? t('__usersCount__member_joined', {
usersCount: data.users.length - MAX_USERS,
})
: t('joined')}
</VideoConfMessageFooterText>
</>
) : (
<VideoConfMessageFooterText>
{t('Call_was_not_answered')}
</VideoConfMessageFooterText>
))}
</VideoConfMessageFooter>
</VideoConfMessage>
);
}
if (data.type === 'direct' && data.status === 0) {
return (
<VideoConfMessage>
<VideoConfMessageRow>
<VideoConfMessageContent>
<VideoConfMessageIcon variant='incoming' />
<VideoConfMessageText>{t('Calling')}</VideoConfMessageText>
</VideoConfMessageContent>
<VideoConfMessageActions>
<VideoConfMessageAction icon='info' onClick={openCallInfo} />
</VideoConfMessageActions>
</VideoConfMessageRow>
<VideoConfMessageFooter>
<VideoConfMessageFooterText>
{t('Waiting_for_answer')}
</VideoConfMessageFooterText>
</VideoConfMessageFooter>
</VideoConfMessage>
);
}
if (result.isLoading || result.isError) {
// TODO: error handling
return <VideoConfMessageSkeleton />;
}
const { data } = result;
const isUserCaller = data.createdBy._id === userId;
if ('endedAt' in data) {
return (
<VideoConfMessage>
<VideoConfMessageRow>
<VideoConfMessageContent>
<VideoConfMessageIcon variant='outgoing' />
<VideoConfMessageText>{t('Call_ongoing')}</VideoConfMessageText>
<VideoConfMessageIcon />
<VideoConfMessageText>{t('Call_ended')}</VideoConfMessageText>
</VideoConfMessageContent>
<VideoConfMessageActions>
<VideoConfMessageAction icon='info' onClick={openCallInfo} />
</VideoConfMessageActions>
</VideoConfMessageRow>
<VideoConfMessageFooter>
<VideoConfMessageButton primary onClick={joinHandler}>
{t('Join')}
</VideoConfMessageButton>
{Boolean(data.users.length) && (
{data.type === 'direct' && (
<>
<VideoConfMessageUserStack users={data.users} />
<VideoConfMessageButton onClick={callAgainHandler}>
{isUserCaller ? t('Call_again') : t('Call_back')}
</VideoConfMessageButton>
<VideoConfMessageFooterText>
{data.users.length > MAX_USERS
? t('__usersCount__member_joined', {
usersCount: data.users.length - MAX_USERS,
})
: t('joined')}
{t('Call_was_not_answered')}
</VideoConfMessageFooterText>
</>
)}
{data.type !== 'direct' &&
(data.users.length ? (
<>
<VideoConfMessageUserStack users={data.users} />
<VideoConfMessageFooterText>
{data.users.length > MAX_USERS
? t('__usersCount__member_joined', {
usersCount: data.users.length - MAX_USERS,
})
: t('joined')}
</VideoConfMessageFooterText>
</>
) : (
<VideoConfMessageFooterText>
{t('Call_was_not_answered')}
</VideoConfMessageFooterText>
))}
</VideoConfMessageFooter>
</VideoConfMessage>
);
}
if (data.type === 'direct' && data.status === 0) {
return (
<VideoConfMessage>
<VideoConfMessageRow>
<VideoConfMessageContent>
<VideoConfMessageIcon variant='incoming' />
<VideoConfMessageText>{t('Calling')}</VideoConfMessageText>
</VideoConfMessageContent>
<VideoConfMessageActions>
<VideoConfMessageAction icon='info' onClick={openCallInfo} />
</VideoConfMessageActions>
</VideoConfMessageRow>
<VideoConfMessageFooter>
<VideoConfMessageFooterText>
{t('Waiting_for_answer')}
</VideoConfMessageFooterText>
</VideoConfMessageFooter>
</VideoConfMessage>
);
}
return <VideoConfMessageSkeleton />;
return (
<VideoConfMessage>
<VideoConfMessageRow>
<VideoConfMessageContent>
<VideoConfMessageIcon variant='outgoing' />
<VideoConfMessageText>{t('Call_ongoing')}</VideoConfMessageText>
</VideoConfMessageContent>
<VideoConfMessageActions>
<VideoConfMessageAction icon='info' onClick={openCallInfo} />
</VideoConfMessageActions>
</VideoConfMessageRow>
<VideoConfMessageFooter>
<VideoConfMessageButton primary onClick={joinHandler}>
{t('Join')}
</VideoConfMessageButton>
{Boolean(data.users.length) && (
<>
<VideoConfMessageUserStack users={data.users} />
<VideoConfMessageFooterText>
{data.users.length > MAX_USERS
? t('__usersCount__member_joined', {
usersCount: data.users.length - MAX_USERS,
})
: t('joined')}
</VideoConfMessageFooterText>
</>
)}
</VideoConfMessageFooter>
</VideoConfMessage>
);
};
export default memo(VideoConferenceBlock);

@ -1,5 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import { useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
export const useVideoConfData = ({ callId }: { callId: string }) => {
const getVideoConfInfo = useEndpoint('GET', '/v1/video-conference.info');

@ -1,6 +1,7 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { useSingleStream } from '@rocket.chat/ui-contexts';
import { useEffect } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';
import { useVideoConfData } from './useVideoConfData';
@ -8,7 +9,7 @@ export const useVideoConfDataStream = ({
rid,
callId,
}: {
rid: string;
rid: IRoom['_id'];
callId: string;
}) => {
const queryClient = useQueryClient();
@ -22,7 +23,7 @@ export const useVideoConfDataStream = ({
id === callId &&
queryClient.invalidateQueries(['video-conference', callId])
);
}, [rid, callId]);
}, [rid, callId, subscribeNotifyRoom, queryClient]);
return useVideoConfData({ callId });
};

@ -1,6 +1,6 @@
import { useTranslation } from '@rocket.chat/ui-contexts';
import { parse } from '@rocket.chat/message-parser';
import { Markup } from '@rocket.chat/gazzodown';
import { parse } from '@rocket.chat/message-parser';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { TextObject } from '@rocket.chat/ui-kit';
import { useUiKitContext } from '../contexts/kitContext';

@ -1,6 +1,5 @@
import type { TextObject } from '@rocket.chat/ui-kit';
import { Fragment } from 'react';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { TextObject } from '@rocket.chat/ui-kit';
import { useUiKitContext } from '../contexts/kitContext';
@ -14,12 +13,10 @@ const PlainTextElement = ({ textObject }: { textObject: TextObject }) => {
const { i18n } = textObject;
if (i18n) {
return (
<Fragment>{t(`apps-${appId}-${i18n.key}`, { ...i18n.args })}</Fragment>
);
return <>{t(`apps-${appId}-${i18n.key}`, { ...i18n.args })}</>;
}
return <Fragment>{textObject.text}</Fragment>;
return <>{textObject.text}</>;
};
export default PlainTextElement;

@ -35,7 +35,7 @@ const createStory = (blocks: readonly UiKit.LayoutBlock[]) => {
6hY+0yM88TzeNZY4luYwpVYyduOfrvhPTnr0pXSX9y5mCsyJMdyxxvwq599em+taItqCSNc90ChvZRUruUcT0JiO18Elpk7t8v41LWzacxkB
SuvjQ/FFJayjDWrCTepAQ2vUH0oo/Jk3ovpwJJeVCP5CN+lFFaaMqy+nAyuChvrTI2kN9JAsi2ZOy4IBHMnkSCP+iqBexSWdxLazoUljJVlP
UH2oorkV10pRc7b1zXb/hZOzuJvM86QWEXeELxOzHSIPcmiiiunVlF2RNTpRkrs//Z'
size={'x36'}
size='x36'
/>
</Message.LeftContainer>
<Message.Container>

@ -2,6 +2,7 @@ import * as UiKit from '@rocket.chat/ui-kit';
import type { ReactElement } from 'react';
import ActionsBlock from '../blocks/ActionsBlock';
import CalloutBlock from '../blocks/CalloutBlock';
import ContextBlock from '../blocks/ContextBlock';
import DividerBlock from '../blocks/DividerBlock';
import ImageBlock from '../blocks/ImageBlock';
@ -9,20 +10,19 @@ import InputBlock from '../blocks/InputBlock';
import PreviewBlock from '../blocks/PreviewBlock';
import SectionBlock from '../blocks/SectionBlock';
import ButtonElement from '../elements/ButtonElement';
import CheckboxElement from '../elements/CheckboxElement';
import DatePickerElement from '../elements/DatePickerElement';
import ImageElement from '../elements/ImageElement';
import LinearScaleElement from '../elements/LinearScaleElement';
import MarkdownTextElement from '../elements/MarkdownTextElement';
import MultiStaticSelectElement from '../elements/MultiStaticSelectElement';
import OverflowElement from '../elements/OverflowElement';
import PlainTextElement from '../elements/PlainTextElement';
import PlainTextInputElement from '../elements/PlainTextInputElement';
import StaticSelectElement from '../elements/StaticSelectElement';
import ToggleSwitchElement from '../elements/ToggleSwitchElement';
import RadioButtonElement from '../elements/RadioButtonElement';
import CheckboxElement from '../elements/CheckboxElement';
import CalloutBlock from '../blocks/CalloutBlock';
import StaticSelectElement from '../elements/StaticSelectElement';
import TimePickerElement from '../elements/TimePickerElement';
import MarkdownTextElement from '../elements/MarkdownTextElement';
import PlainTextElement from '../elements/PlainTextElement';
import ToggleSwitchElement from '../elements/ToggleSwitchElement';
export type FuselageSurfaceRendererProps = ConstructorParameters<
typeof UiKit.SurfaceRenderer

@ -1,12 +1,12 @@
import BannerSurface from './BannerSurface';
import ContextualBarSurface from './ContextualBarSurface';
import { FuselageContextualBarSurfaceRenderer } from './FuselageContextualBarRenderer';
import { FuselageModalSurfaceRenderer } from './FuselageModalSurfaceRenderer';
import { FuselageSurfaceRenderer } from './FuselageSurfaceRenderer';
import MessageSurface from './MessageSurface';
import { FuselageMessageSurfaceRenderer } from './MessageSurfaceRenderer';
import ModalSurface from './ModalSurface';
import { createSurfaceRenderer } from './createSurfaceRenderer';
import { FuselageMessageSurfaceRenderer } from './MessageSurfaceRenderer';
import { FuselageModalSurfaceRenderer } from './FuselageModalSurfaceRenderer';
import { FuselageContextualBarSurfaceRenderer } from './FuselageContextualBarRenderer';
import ContextualBarSurface from './ContextualBarSurface';
// export const attachmentParser = new FuselageSurfaceRenderer();
export const bannerParser = new FuselageSurfaceRenderer();

Loading…
Cancel
Save