Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -4830,6 +4830,7 @@
"Score": "Score",
"Screen_Lock": "Screen Lock",
"Screen_Share": "Screen Share",
"Screen_sharing_stopped_video_escalation": "Screen sharing was stopped because the call was escalated to a video call",
"Script": "Script",
"Script_Enabled": "Script Enabled",
"Script_Engine": "Script Sandbox",
Expand Down Expand Up @@ -5239,6 +5240,7 @@
"Support": "Support",
"Survey": "Survey",
"Survey_instructions": "Rate each question according to your satisfaction, 1 meaning you are completely unsatisfied and 5 meaning you are completely satisfied.",
"Switched_to_video_call": "Switched to video call",
"Symbols": "Symbols",
"Sync": "Sync",
"Sync / Import": "Sync / Import",
Expand Down Expand Up @@ -5880,6 +5882,8 @@
"VideoConf_Mobile_Ringing_Description": "When enabled, direct calls to mobile users will ring their device as a phone call.",
"VideoConf_Persistent_Chat_Discussion_Name": "Persistent Chat Discussion Name",
"VideoConf_Persistent_Chat_Discussion_Name_Description": "Use [date] tag to set where to include the date. Date will be added to the start if tag is not included.",
"Video_escalation_modal_description": "If you start a video call the current call will be finished, the other participants will be transferred and notified about the new call.",
"Video_escalation_modal_title": "Starting a video call",
"Video_Call_unavailable_for_this_type_of_room": "Video Call is unavailable for this type of room",
"Video_Chat_Window": "Video Chat",
"Video_Conference": "Conference Call",
Expand Down Expand Up @@ -7008,6 +7012,7 @@
"start-discussion-other-user": "Start Discussion (Other-User)",
"start-discussion-other-user_description": "Permission to start a discussion, which gives permission to the user to create a discussion from a message sent by another user as well",
"start-discussion_description": "Permission to start a discussion",
"Start_a_video_call": "Start a video call",
"strike": "strike",
"subscription.callout.activeUsers": "seats",
"subscription.callout.allPremiumCapabilitiesDisabled": "All premium capabilities disabled",
Expand Down
2 changes: 2 additions & 0 deletions packages/rest-typings/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type { LDAPEndpoints } from './v1/ldap';
import type { LicensesEndpoints } from './v1/licenses';
import type { MailerEndpoints } from './v1/mailer';
import type { MeEndpoints } from './v1/me';
import type { MediaCallsEndpoints } from './v1/media-calls';
import type { MiscEndpoints } from './v1/misc';
import type { ModerationEndpoints } from './v1/moderation';
import type { OmnichannelEndpoints } from './v1/omnichannel';
Expand Down Expand Up @@ -90,6 +91,7 @@ export interface Endpoints
AuthEndpoints,
ImportEndpoints,
ServerEventsEndpoints,
MediaCallsEndpoints,
DefaultEndpoints {}

type OperationsByPathPatternAndMethod<
Expand Down
8 changes: 8 additions & 0 deletions packages/rest-typings/src/v1/media-calls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type MediaCallsEndpoints = {
'/v1/media-calls.escalate': {
POST: (params: { callId: string }) => {
providerName: string;
url: string;
};
};
};
4 changes: 2 additions & 2 deletions packages/ui-voip/src/components/Actions/ActionStrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ReactNode } from 'react';
export const ACTION_STRIP_TOTAL_HEIGHT = 52;

type ActionStripProps = {
children: ReactNode;
children?: ReactNode;
leftSlot?: ReactNode;
rightSlot?: ReactNode;
};
Expand All @@ -28,7 +28,7 @@ const ActionStrip = ({ children, leftSlot, rightSlot }: ActionStripProps) => {
{leftSlot}
</Box>
<Box is='span' display='flex' justifyContent='center' alignItems='center' flexGrow={1} flexBasis='60%'>
<ButtonGroup large>{children}</ButtonGroup>
{children && <ButtonGroup large>{children}</ButtonGroup>}
</Box>
<Box is='span' display='flex' justifyContent='end' alignItems='center' flexGrow={0} flexBasis='20%'>
{rightSlot}
Expand Down
44 changes: 44 additions & 0 deletions packages/ui-voip/src/components/VideoCallButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import type { Meta, StoryObj } from '@storybook/react';
import { action } from 'storybook/actions';

import VideoCallButton from './VideoCallButton';

const meta = {
title: 'V2/Components/VideoCallButton',
component: VideoCallButton,
decorators: [
mockAppRoot()
.withTranslations('en', 'core', {
Start_a_video_call: 'Start a video call',
Join_video_call: 'Join video call',
Switched_to_video_call: 'Switched to video call',
VideoConf_start_call_modal_title: 'Starting a video call',
VideoConf_start_call_modal_description: 'If you start a video call the current call will be finished. Do you want to proceed?',
Start_video_call: 'Start video call',
Cancel: 'Cancel',
})
.buildStoryDecorator(),
],
args: {
onClick: action('onClick'),
},
} satisfies Meta<typeof VideoCallButton>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
name: 'Start state (no active video call)',
args: {
escalated: false,
},
};

export const VideoCallActive: Story = {
name: 'Active state (video call escalated)',
args: {
escalated: true,
},
};
29 changes: 29 additions & 0 deletions packages/ui-voip/src/components/VideoCallButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Button } from '@rocket.chat/fuselage';
import type { ComponentProps } from 'react';
import { useTranslation } from 'react-i18next';

type VideoCallButtonProps = Omit<ComponentProps<typeof Button>, 'onClick'> & {
escalated?: boolean;
loading?: boolean;
onClick: () => void;
};

const VideoCallButton = ({ escalated, loading, onClick, ...props }: VideoCallButtonProps) => {
const { t } = useTranslation();

return (
<>
{escalated ? (
<Button primary icon='video' loading={loading} aria-busy={loading} onClick={() => onClick()} {...props}>
{t('Join_video_call')}
</Button>
) : (
<Button icon='video' loading={loading} aria-busy={loading} onClick={() => onClick()} {...props}>
{t('Start_a_video_call')}
</Button>
)}
</>
);
};

export default VideoCallButton;
50 changes: 50 additions & 0 deletions packages/ui-voip/src/components/VideoCallWidgetAction.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import type { Meta, StoryObj } from '@storybook/react';
import { action } from 'storybook/actions';

import VideoCallWidgetAction from './VideoCallWidgetAction';

const meta = {
title: 'V2/Components/VideoCallWidgetAction',
component: VideoCallWidgetAction,
decorators: [
mockAppRoot()
.withTranslations('en', 'core', {
Start_a_video_call: 'Start a video call',
Join_video_call: 'Join video call',
Switched_to_video_call: 'Switched to video call',
})
.buildStoryDecorator(),
],
args: {
onClick: action('onClick'),
},
} satisfies Meta<typeof VideoCallWidgetAction>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
name: 'Default (not escalated)',
args: {
escalated: false,
loading: false,
},
};

export const Escalated: Story = {
name: 'Escalated (video call active)',
args: {
escalated: true,
loading: false,
},
};

export const Loading: Story = {
name: 'Loading state',
args: {
escalated: false,
loading: true,
},
};
26 changes: 26 additions & 0 deletions packages/ui-voip/src/components/VideoCallWidgetAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Box } from '@rocket.chat/fuselage';
import { useTranslation } from 'react-i18next';

import VideoCallButton from './VideoCallButton';

type VideoCallWidgetActionProps = {
escalated?: boolean;
loading?: boolean;
onClick: () => void | Promise<void>;
};

const VideoCallWidgetAction = ({ escalated, loading, onClick }: VideoCallWidgetActionProps) => {
const { t } = useTranslation();
return (
<Box mbs={8}>
{escalated && (
<Box role='status' aria-atomic='true' fontScale='p2' mbe={8}>
{t('Switched_to_video_call')}
</Box>
)}
<VideoCallButton w='full' escalated={escalated} loading={loading} onClick={onClick} />
</Box>
);
};

export default VideoCallWidgetAction;
2 changes: 2 additions & 0 deletions packages/ui-voip/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export { default as Timer } from './Timer';
export { default as DevicePicker } from './DevicePicker';
export { default as CallHistoryInternalUser } from './CallHistoryInternalUser';
export { default as CallHistoryExternalUser } from './CallHistoryExternalUser';
export { default as VideoCallWidgetAction } from './VideoCallWidgetAction';
export { default as VideoCallButton } from './VideoCallButton';
5 changes: 5 additions & 0 deletions packages/ui-voip/src/context/MediaCallViewContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export type MediaCallStreams = {

type MediaCallViewContextValue = {
sessionState: SessionState;
isRequestingVideoCall: boolean;
onRequestVideoCall: () => void;
onClickDirectMessage?: () => void;
onMute: () => void;
onHold: () => void;
Expand Down Expand Up @@ -41,11 +43,14 @@ const defaultSessionState: SessionState = {
remoteMuted: false,
remoteHeld: false,
callId: undefined,
escalated: false,
supportedFeatures: ['audio', 'transfer', 'hold'],
};

export const defaultMediaCallContextValue: MediaCallViewContextValue = {
sessionState: defaultSessionState,
isRequestingVideoCall: false,
onRequestVideoCall: () => undefined,
onMute: () => undefined,
onHold: () => undefined,
onDeviceChange: () => undefined,
Expand Down
1 change: 1 addition & 0 deletions packages/ui-voip/src/context/definitions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface IBaseSession {
remoteHeld: boolean;
startedAt?: Date;
hidden: boolean;
escalated: boolean;
supportedFeatures: readonly CallFeature[];
}

Expand Down
Loading
Loading