2024-01-16 03:49:09 +08:00
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
import { defineMessages, useIntl } from 'react-intl';
|
2024-06-04 21:40:54 +08:00
|
|
|
import { useMutation } from '@apollo/client';
|
2024-01-16 03:49:09 +08:00
|
|
|
import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component';
|
2024-05-01 20:39:03 +08:00
|
|
|
import PadContainer from '/imports/ui/components/pads/pads-graphql/component';
|
2024-01-16 03:49:09 +08:00
|
|
|
import browserInfo from '/imports/utils/browserInfo';
|
|
|
|
import Header from '/imports/ui/components/common/control-header/component';
|
|
|
|
import NotesDropdown from './notes-dropdown/component';
|
2024-04-19 22:08:13 +08:00
|
|
|
import {
|
|
|
|
PANELS, ACTIONS,
|
|
|
|
} from '/imports/ui/components/layout/enums';
|
2024-01-16 03:49:09 +08:00
|
|
|
import { layoutSelectInput, layoutDispatch, layoutSelectOutput } from '/imports/ui/components/layout/context';
|
|
|
|
import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser';
|
|
|
|
import useHasPermission from './hooks/useHasPermission';
|
|
|
|
import Styled from './styles';
|
|
|
|
import { PINNED_PAD_SUBSCRIPTION, PinnedPadSubscriptionResponse } from './queries';
|
|
|
|
import { PIN_NOTES } from './mutations';
|
2024-02-14 04:47:04 +08:00
|
|
|
import { EXTERNAL_VIDEO_STOP } from '/imports/ui/components/external-video-player/mutations';
|
2024-02-14 03:39:45 +08:00
|
|
|
import {
|
|
|
|
screenshareHasEnded,
|
2024-06-14 22:35:23 +08:00
|
|
|
useIsScreenBroadcasting,
|
2024-02-14 03:39:45 +08:00
|
|
|
} from '/imports/ui/components/screenshare/service';
|
2024-06-04 21:40:54 +08:00
|
|
|
import useDeduplicatedSubscription from '../../core/hooks/useDeduplicatedSubscription';
|
2024-06-15 04:57:40 +08:00
|
|
|
import { useIsPresentationEnabled } from '../../services/features';
|
2024-06-19 22:54:25 +08:00
|
|
|
import { useStorageKey } from '/imports/ui/services/storage/hooks';
|
2024-01-16 03:49:09 +08:00
|
|
|
|
|
|
|
const intlMessages = defineMessages({
|
|
|
|
hide: {
|
|
|
|
id: 'app.notes.hide',
|
|
|
|
description: 'Label for hiding shared notes button',
|
|
|
|
},
|
|
|
|
title: {
|
|
|
|
id: 'app.notes.title',
|
|
|
|
description: 'Title for the shared notes',
|
|
|
|
},
|
|
|
|
unpinNotes: {
|
|
|
|
id: 'app.notes.notesDropdown.unpinNotes',
|
|
|
|
description: 'Label for unpin shared notes button',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
interface NotesContainerGraphqlProps {
|
|
|
|
area: 'media' | undefined;
|
|
|
|
isToSharedNotesBeShow: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface NotesGraphqlProps extends NotesContainerGraphqlProps {
|
|
|
|
hasPermission: boolean;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
layoutContextDispatch: (action: any) => void;
|
|
|
|
isResizing: boolean;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
sidebarContent: any;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
sharedNotesOutput: any;
|
|
|
|
amIPresenter: boolean;
|
|
|
|
isRTL: boolean;
|
|
|
|
shouldShowSharedNotesOnPresentationArea: boolean;
|
|
|
|
handlePinSharedNotes: (pinned: boolean) => void;
|
2024-06-15 04:57:40 +08:00
|
|
|
isPresentationEnabled: boolean;
|
2024-01-16 03:49:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const sidebarContentToIgnoreDelay = ['captions'];
|
|
|
|
|
|
|
|
const NotesGraphql: React.FC<NotesGraphqlProps> = (props) => {
|
|
|
|
const {
|
|
|
|
hasPermission,
|
|
|
|
isRTL,
|
|
|
|
layoutContextDispatch,
|
|
|
|
isResizing,
|
|
|
|
area,
|
|
|
|
sidebarContent,
|
|
|
|
sharedNotesOutput,
|
|
|
|
amIPresenter,
|
|
|
|
isToSharedNotesBeShow,
|
|
|
|
shouldShowSharedNotesOnPresentationArea,
|
|
|
|
handlePinSharedNotes,
|
2024-06-15 04:57:40 +08:00
|
|
|
isPresentationEnabled,
|
2024-01-16 03:49:09 +08:00
|
|
|
} = props;
|
|
|
|
const [shouldRenderNotes, setShouldRenderNotes] = useState(false);
|
|
|
|
const intl = useIntl();
|
|
|
|
|
|
|
|
const { isChrome } = browserInfo;
|
|
|
|
const isOnMediaArea = area === 'media';
|
|
|
|
const style = isOnMediaArea ? {
|
|
|
|
position: 'absolute',
|
|
|
|
...sharedNotesOutput,
|
|
|
|
} : {};
|
|
|
|
|
|
|
|
const isHidden = (isOnMediaArea && (style.width === 0 || style.height === 0))
|
|
|
|
|| (!isToSharedNotesBeShow
|
|
|
|
&& !sidebarContentToIgnoreDelay.includes(sidebarContent.sidebarContentPanel))
|
|
|
|
|| shouldShowSharedNotesOnPresentationArea;
|
|
|
|
|
|
|
|
if (isHidden && !isOnMediaArea) {
|
|
|
|
style.padding = 0;
|
|
|
|
style.display = 'none';
|
|
|
|
}
|
2024-05-29 21:26:11 +08:00
|
|
|
|
|
|
|
const DELAY_UNMOUNT_SHARED_NOTES = window.meetingClientSettings.public.app.delayForUnmountOfSharedNote;
|
|
|
|
|
2024-09-11 04:10:28 +08:00
|
|
|
let timoutRef: NodeJS.Timeout | undefined;
|
2024-01-16 03:49:09 +08:00
|
|
|
useEffect(() => {
|
|
|
|
if (isToSharedNotesBeShow) {
|
|
|
|
setShouldRenderNotes(true);
|
2024-09-11 04:10:28 +08:00
|
|
|
clearTimeout(timoutRef!);
|
2024-01-16 03:49:09 +08:00
|
|
|
} else {
|
|
|
|
timoutRef = setTimeout(() => {
|
|
|
|
setShouldRenderNotes(false);
|
|
|
|
}, (sidebarContentToIgnoreDelay.includes(sidebarContent.sidebarContentPanel)
|
|
|
|
|| shouldShowSharedNotesOnPresentationArea)
|
|
|
|
? 0 : DELAY_UNMOUNT_SHARED_NOTES);
|
|
|
|
}
|
2024-09-11 04:10:28 +08:00
|
|
|
return () => clearTimeout(timoutRef!);
|
2024-01-16 03:49:09 +08:00
|
|
|
}, [isToSharedNotesBeShow, sidebarContent.sidebarContentPanel]);
|
|
|
|
|
|
|
|
const renderHeaderOnMedia = () => {
|
|
|
|
return amIPresenter ? (
|
|
|
|
<Styled.Header
|
|
|
|
rightButtonProps={{
|
|
|
|
'aria-label': intl.formatMessage(intlMessages.unpinNotes),
|
|
|
|
'data-test': 'unpinNotes',
|
|
|
|
icon: 'close',
|
|
|
|
label: intl.formatMessage(intlMessages.unpinNotes),
|
|
|
|
onClick: () => {
|
|
|
|
handlePinSharedNotes(false);
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
) : null;
|
|
|
|
};
|
|
|
|
|
2024-05-29 21:26:11 +08:00
|
|
|
const NOTES_CONFIG = window.meetingClientSettings.public.notes;
|
|
|
|
|
2024-01-16 03:49:09 +08:00
|
|
|
return (shouldRenderNotes || shouldShowSharedNotesOnPresentationArea) && (
|
|
|
|
<Styled.Notes
|
|
|
|
data-test="notes"
|
|
|
|
isChrome={isChrome}
|
|
|
|
style={style}
|
|
|
|
>
|
|
|
|
{!isOnMediaArea ? (
|
|
|
|
// @ts-ignore Until everything in Typescript
|
|
|
|
<Header
|
|
|
|
leftButtonProps={{
|
|
|
|
onClick: () => {
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
|
|
|
|
value: false,
|
|
|
|
});
|
|
|
|
layoutContextDispatch({
|
|
|
|
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
|
|
|
|
value: PANELS.NONE,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
'data-test': 'hideNotesLabel',
|
|
|
|
'aria-label': intl.formatMessage(intlMessages.hide),
|
|
|
|
label: intl.formatMessage(intlMessages.title),
|
|
|
|
}}
|
|
|
|
customRightButton={
|
2024-06-15 04:57:40 +08:00
|
|
|
<NotesDropdown handlePinSharedNotes={handlePinSharedNotes} presentationEnabled={isPresentationEnabled} />
|
2024-01-16 03:49:09 +08:00
|
|
|
}
|
|
|
|
/>
|
|
|
|
) : renderHeaderOnMedia()}
|
|
|
|
<PadContainer
|
2024-05-29 21:26:11 +08:00
|
|
|
externalId={NOTES_CONFIG.id}
|
2024-01-16 03:49:09 +08:00
|
|
|
hasPermission={hasPermission}
|
|
|
|
isResizing={isResizing}
|
|
|
|
isRTL={isRTL}
|
|
|
|
/>
|
|
|
|
</Styled.Notes>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const NotesContainerGraphql: React.FC<NotesContainerGraphqlProps> = (props) => {
|
2024-04-19 22:08:13 +08:00
|
|
|
const { area, isToSharedNotesBeShow } = props;
|
2024-01-16 03:49:09 +08:00
|
|
|
|
|
|
|
const hasPermission = useHasPermission();
|
2024-10-09 19:40:48 +08:00
|
|
|
const { data: pinnedPadData } = useDeduplicatedSubscription<PinnedPadSubscriptionResponse>(PINNED_PAD_SUBSCRIPTION);
|
2024-09-11 04:10:28 +08:00
|
|
|
|
2024-01-16 03:49:09 +08:00
|
|
|
const { data: currentUserData } = useCurrentUser((user) => ({
|
|
|
|
presenter: user.presenter,
|
|
|
|
}));
|
|
|
|
const [pinSharedNotes] = useMutation(PIN_NOTES);
|
|
|
|
|
|
|
|
// @ts-ignore Until everything in Typescript
|
|
|
|
const cameraDock = layoutSelectInput((i) => i.cameraDock);
|
|
|
|
// @ts-ignore Until everything in Typescript
|
|
|
|
const sharedNotesOutput = layoutSelectOutput((i) => i.sharedNotes);
|
|
|
|
// @ts-ignore Until everything in Typescript
|
|
|
|
const sidebarContent = layoutSelectInput((i) => i.sidebarContent);
|
|
|
|
const { isResizing } = cameraDock;
|
|
|
|
const layoutContextDispatch = layoutDispatch();
|
|
|
|
const amIPresenter = !!currentUserData?.presenter;
|
|
|
|
|
2024-05-29 21:26:11 +08:00
|
|
|
const NOTES_CONFIG = window.meetingClientSettings.public.notes;
|
|
|
|
|
2024-01-16 03:49:09 +08:00
|
|
|
const isRTL = document.documentElement.getAttribute('dir') === 'rtl';
|
2024-06-19 22:54:25 +08:00
|
|
|
const { isOpen: isSidebarContentOpen } = sidebarContent;
|
|
|
|
const isGridLayout = useStorageKey('isGridEnabled');
|
|
|
|
|
2024-10-09 19:40:48 +08:00
|
|
|
const shouldShowSharedNotesOnPresentationArea = isGridLayout ? !!pinnedPadData
|
|
|
|
&& pinnedPadData.sharedNotes[0]?.sharedNotesExtId === NOTES_CONFIG.id
|
|
|
|
&& isSidebarContentOpen : !!pinnedPadData
|
|
|
|
&& pinnedPadData.sharedNotes[0]?.sharedNotesExtId === NOTES_CONFIG.id;
|
2024-01-16 03:49:09 +08:00
|
|
|
|
2024-02-14 03:39:45 +08:00
|
|
|
const [stopExternalVideoShare] = useMutation(EXTERNAL_VIDEO_STOP);
|
2024-06-14 22:35:23 +08:00
|
|
|
const isScreenBroadcasting = useIsScreenBroadcasting();
|
2024-06-15 04:57:40 +08:00
|
|
|
const isPresentationEnabled = useIsPresentationEnabled();
|
2024-02-14 03:39:45 +08:00
|
|
|
|
2024-01-16 03:49:09 +08:00
|
|
|
const handlePinSharedNotes = (pinned: boolean) => {
|
2024-02-14 03:39:45 +08:00
|
|
|
if (pinned) {
|
|
|
|
stopExternalVideoShare();
|
2024-06-14 22:35:23 +08:00
|
|
|
if (isScreenBroadcasting) screenshareHasEnded();
|
2024-02-14 03:39:45 +08:00
|
|
|
}
|
2024-01-16 03:49:09 +08:00
|
|
|
pinSharedNotes({ variables: { pinned } });
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<NotesGraphql
|
|
|
|
area={area}
|
|
|
|
hasPermission={hasPermission}
|
|
|
|
layoutContextDispatch={layoutContextDispatch}
|
|
|
|
isResizing={isResizing}
|
|
|
|
sidebarContent={sidebarContent}
|
|
|
|
sharedNotesOutput={sharedNotesOutput}
|
|
|
|
amIPresenter={amIPresenter}
|
|
|
|
shouldShowSharedNotesOnPresentationArea={shouldShowSharedNotesOnPresentationArea}
|
|
|
|
isRTL={isRTL}
|
|
|
|
isToSharedNotesBeShow={isToSharedNotesBeShow}
|
|
|
|
handlePinSharedNotes={handlePinSharedNotes}
|
2024-06-15 04:57:40 +08:00
|
|
|
isPresentationEnabled={isPresentationEnabled}
|
2024-01-16 03:49:09 +08:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default injectWbResizeEvent(NotesContainerGraphql);
|