refactor(html5): recording start/stop modal (#20679)

* refactor(html5): recording start/stop modal

* Add suport for errors
This commit is contained in:
João Victor Nunes 2024-07-16 15:29:29 -03:00 committed by GitHub
parent 1683f4c3fe
commit 1d737fbada
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 211 additions and 146 deletions

View File

@ -18,12 +18,14 @@ const propTypes = {
confirmButtonColor: PropTypes.string,
disableConfirmButton: PropTypes.bool,
description: PropTypes.string,
hideConfirmButton: PropTypes.bool,
};
const defaultProps = {
confirmButtonColor: 'primary',
disableConfirmButton: false,
description: '',
hideConfirmButton: false,
};
class ConfirmationModal extends Component {
@ -46,6 +48,8 @@ class ConfirmationModal extends Component {
checkboxMessageId,
confirmButtonColor,
confirmButtonLabel,
cancelButtonLabel,
hideConfirmButton,
confirmButtonDataTest,
confirmParam,
disableConfirmButton,
@ -92,18 +96,20 @@ class ConfirmationModal extends Component {
</Styled.Description>
<Styled.Footer>
<Styled.ConfirmationButton
color={confirmButtonColor}
label={confirmButtonLabel ? confirmButtonLabel : intl.formatMessage(messages.yesLabel)}
disabled={disableConfirmButton}
data-test={confirmButtonDataTest}
onClick={() => {
onConfirm(confirmParam, checked);
setIsOpen(false);
}}
/>
{!hideConfirmButton && (
<Styled.ConfirmationButton
color={confirmButtonColor}
label={confirmButtonLabel || intl.formatMessage(messages.yesLabel)}
disabled={disableConfirmButton}
data-test={confirmButtonDataTest}
onClick={() => {
onConfirm(confirmParam, checked);
setIsOpen(false);
}}
/>
)}
<Styled.CancelButton
label={intl.formatMessage(messages.noLabel)}
label={cancelButtonLabel || intl.formatMessage(messages.noLabel)}
onClick={() => setIsOpen(false)}
/>
</Styled.Footer>

View File

@ -1,95 +0,0 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import ConfirmationModal from '/imports/ui/components/common/modal/confirmation/component';
const intlMessages = defineMessages({
startTitle: {
id: 'app.recording.startTitle',
description: 'start recording title',
},
stopTitle: {
id: 'app.recording.stopTitle',
description: 'stop recording title',
},
resumeTitle: {
id: 'app.recording.resumeTitle',
description: 'resume recording title',
},
startDescription: {
id: 'app.recording.startDescription',
description: 'start recording description',
},
stopDescription: {
id: 'app.recording.stopDescription',
description: 'stop recording description',
},
});
const propTypes = {
intl: PropTypes.object.isRequired,
toggleRecording: PropTypes.func.isRequired,
recordingTime: PropTypes.number,
recordingStatus: PropTypes.bool,
amIModerator: PropTypes.bool,
isMeteorConnected: PropTypes.bool.isRequired,
};
const defaultProps = {
recordingTime: -1,
recordingStatus: false,
amIModerator: false,
};
class RecordingComponent extends PureComponent {
render() {
const {
intl,
recordingStatus,
recordingTime,
amIModerator,
toggleRecording,
isMeteorConnected,
isOpen,
onRequestClose,
priority,
setIsOpen,
} = this.props;
let title;
if (!recordingStatus) {
title = recordingTime > 0 ? intl.formatMessage(intlMessages.resumeTitle)
: intl.formatMessage(intlMessages.startTitle);
} else {
title = intl.formatMessage(intlMessages.stopTitle);
}
if (!amIModerator) return null;
const description = intl.formatMessage(!recordingStatus
? intlMessages.startDescription
: intlMessages.stopDescription);
return (
<ConfirmationModal
intl={intl}
onConfirm={toggleRecording}
title={title}
description={description}
disableConfirmButton={!isMeteorConnected}
{...{
isOpen,
onRequestClose,
priority,
setIsOpen,
}}
/>
);
}
}
RecordingComponent.propTypes = propTypes;
RecordingComponent.defaultProps = defaultProps;
export default injectIntl(RecordingComponent);

View File

@ -0,0 +1,122 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import ConfirmationModal from '/imports/ui/components/common/modal/confirmation/component';
const intlMessages = defineMessages({
startTitle: {
id: 'app.recording.startTitle',
description: 'start recording title',
},
stopTitle: {
id: 'app.recording.stopTitle',
description: 'stop recording title',
},
resumeTitle: {
id: 'app.recording.resumeTitle',
description: 'resume recording title',
},
startDescription: {
id: 'app.recording.startDescription',
description: 'start recording description',
},
stopDescription: {
id: 'app.recording.stopDescription',
description: 'stop recording description',
},
loadingTitle: {
id: 'app.recording.loadingTitle',
description: 'recording data is loading',
},
loadingDescription: {
id: 'app.recording.loadingDescription',
description: 'recording data is loading',
},
errorTitle: {
id: 'app.recording.errorTitle',
description: 'recording data error',
},
errorDescription: {
id: 'app.recording.errorDescription',
description: 'recording data error',
},
cancelLabel: {
id: 'app.recording.cancelLabel',
description: 'cancel button label',
},
});
interface RecordingComponentProps {
amIModerator: boolean;
connected: boolean;
isOpen: boolean;
recordingError: Error | null,
recordingLoading: boolean;
recordingStatus: boolean,
priority: string;
recordingTime: number,
onRequestClose: () => void;
toggleRecording: () => void,
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
}
const RecordingComponent: React.FC<RecordingComponentProps> = (props) => {
const {
amIModerator,
connected,
isOpen,
recordingError,
recordingLoading,
recordingStatus,
recordingTime,
priority,
onRequestClose,
toggleRecording,
setIsOpen,
} = props;
const intl = useIntl();
let title;
let description;
let cancelButtonLabel;
if (!amIModerator) return null;
if (recordingError) {
title = intl.formatMessage(intlMessages.errorTitle);
description = intl.formatMessage(intlMessages.errorDescription);
cancelButtonLabel = intl.formatMessage(intlMessages.cancelLabel);
} else if (recordingLoading) {
title = intl.formatMessage(intlMessages.loadingTitle);
description = intl.formatMessage(intlMessages.loadingDescription);
cancelButtonLabel = intl.formatMessage(intlMessages.cancelLabel);
} else if (recordingStatus) {
description = intl.formatMessage(intlMessages.stopDescription);
title = intl.formatMessage(intlMessages.stopTitle);
} else {
description = intl.formatMessage(intlMessages.startDescription);
title = recordingTime > 0
? intl.formatMessage(intlMessages.resumeTitle)
: intl.formatMessage(intlMessages.startTitle);
}
return (
<ConfirmationModal
intl={intl}
onConfirm={toggleRecording}
title={title}
description={description}
disableConfirmButton={!connected}
hideConfirmButton={recordingLoading || recordingError}
cancelButtonLabel={cancelButtonLabel}
{...{
isOpen,
onRequestClose,
priority,
setIsOpen,
}}
/>
);
};
export default RecordingComponent;

View File

@ -1,40 +0,0 @@
import React from 'react';
import { useMutation } from '@apollo/client';
import RecordingComponent from './component';
import { SET_RECORDING_STATUS } from './mutations';
import { GET_RECORDINGS } from './queries';
import useDeduplicatedSubscription from '../../core/hooks/useDeduplicatedSubscription';
const RecordingContainer = (props) => {
const { setIsOpen } = props;
const [setRecordingStatus] = useMutation(SET_RECORDING_STATUS);
const {
data: recordingData,
} = useDeduplicatedSubscription(GET_RECORDINGS);
const recording = recordingData?.meeting_recording[0]?.isRecording ?? false;
const time = recordingData?.meeting_recording[0]?.previousRecordedTimeInSeconds ?? 0;
const toggleRecording = () => {
setRecordingStatus({
variables: {
recording: !recording,
},
});
setIsOpen(false);
};
return (
<RecordingComponent
{...{
recordingStatus: recording,
recordingTime: time,
toggleRecording,
...props,
}}
// TODO: Remove this
isMeteorConnected
/>
);
};
export default RecordingContainer;

View File

@ -0,0 +1,60 @@
import React from 'react';
import { useMutation, useReactiveVar } from '@apollo/client';
import RecordingComponent from './component';
import { SET_RECORDING_STATUS } from './mutations';
import { GET_RECORDINGS, GetRecordingResponse } from './queries';
import useDeduplicatedSubscription from '/imports/ui/core/hooks/useDeduplicatedSubscription';
import ConnectionStatus from '/imports/ui/core/graphql/singletons/connectionStatus';
interface RecordingContainerProps {
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
amIModerator: boolean;
onRequestClose: () => void;
priority: string;
isOpen: boolean;
}
const RecordingContainer: React.FC<RecordingContainerProps> = (props) => {
const {
amIModerator, isOpen, onRequestClose, priority, setIsOpen,
} = props;
const [setRecordingStatus] = useMutation(SET_RECORDING_STATUS);
const connected = useReactiveVar(ConnectionStatus.getConnectedStatusVar());
const {
data: recordingData,
loading: recordingLoading,
error: recordingError,
} = useDeduplicatedSubscription<GetRecordingResponse>(GET_RECORDINGS);
const recording = recordingData?.meeting_recording[0]?.isRecording ?? false;
const time = recordingData?.meeting_recording[0]?.previousRecordedTimeInSeconds ?? 0;
const toggleRecording = () => {
setRecordingStatus({
variables: {
recording: !recording,
},
});
setIsOpen(false);
};
return (
<RecordingComponent
{...{
amIModerator,
connected,
isOpen,
recordingError,
recordingLoading,
onRequestClose,
priority,
recordingTime: time,
recordingStatus: recording,
setIsOpen,
toggleRecording,
}}
/>
);
};
export default RecordingContainer;

View File

@ -1,5 +1,12 @@
import { gql } from '@apollo/client';
export interface GetRecordingResponse {
meeting_recording: {
isRecording: boolean;
previousRecordedTimeInSeconds: number;
}[]
}
export const GET_RECORDINGS = gql`
subscription getRecordingData {
meeting_recording {

View File

@ -1045,6 +1045,11 @@
"app.recording.resumeTitle": "Resume recording",
"app.recording.startDescription": "You can select the record button again later to pause the recording.",
"app.recording.stopDescription": "Are you sure you want to pause the recording? You can resume by selecting the record button again.",
"app.recording.cancelLabel": "Cancel",
"app.recording.loadingTitle": "Loading...",
"app.recording.loadingDescription": "Please wait. We are checking the latest recording status.",
"app.recording.errorTitle": "Something went wrong...",
"app.recording.errorDescription": "Something went wrong while checking recording status.",
"app.recording.notify.title": "Recording has started",
"app.recording.notify.description": "A recording will be available based on the remainder of this session",
"app.recording.notify.continue": "Continue",