Skip to content

Commit

Permalink
fix(Livechat): Popout mode not working in cross domains (RocketChat#3…
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinSchoeler authored Nov 18, 2024
1 parent 8839f86 commit 5b3f6b0
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-suns-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/livechat": patch
---

Fixes livechat popout mode not working correctly in cross domain situations
3 changes: 2 additions & 1 deletion packages/livechat/src/components/Screen/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Alert from '../Alert';
import { Avatar } from '../Avatar';
import Header from '../Header';
import Tooltip from '../Tooltip';
import type { ScreenContextValue } from './ScreenProvider';

type screenHeaderProps = {
alerts: { id: string; children: ComponentChildren; [key: string]: unknown }[];
Expand All @@ -24,7 +25,7 @@ type screenHeaderProps = {
onEnableNotifications: () => unknown;
onDisableNotifications: () => unknown;
onMinimize: () => unknown;
onRestore: () => unknown;
onRestore: ScreenContextValue['onRestore'];
onOpenWindow: () => unknown;
queueInfo: {
spot: number;
Expand Down
29 changes: 14 additions & 15 deletions packages/livechat/src/components/Screen/ScreenProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { useCallback, useContext, useEffect, useState } from 'preact/hooks';
import { parse } from 'query-string';

import { isActiveSession } from '../../helpers/isActiveSession';
import { loadConfig } from '../../lib/main';
import { parentCall } from '../../lib/parentCall';
import { loadMessages } from '../../lib/room';
import Triggers from '../../lib/triggers';
import { StoreContext } from '../../store';

Expand All @@ -24,7 +26,7 @@ export type ScreenContextValue = {
onEnableNotifications: () => unknown;
onDisableNotifications: () => unknown;
onMinimize: () => unknown;
onRestore: () => unknown;
onRestore: () => Promise<void>;
onOpenWindow: () => unknown;
onDismissAlert: () => unknown;
dismissNotification: () => void;
Expand Down Expand Up @@ -55,7 +57,7 @@ export const ScreenContext = createContext<ScreenContextValue>({
onEnableNotifications: () => undefined,
onDisableNotifications: () => undefined,
onMinimize: () => undefined,
onRestore: () => undefined,
onRestore: async () => undefined,
onOpenWindow: () => undefined,
} as ScreenContextValue);

Expand Down Expand Up @@ -109,26 +111,23 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
dispatch({ minimized: true });
};

const handleRestore = () => {
const handleRestore = async () => {
parentCall('restoreWindow');
const dispatchRestore = () => dispatch({ minimized: false, undocked: false });

const dispatchEvent = () => {
dispatchRestore();
store.off('storageSynced', dispatchEvent);
};

if (undocked) {
store.on('storageSynced', dispatchEvent);
} else {
dispatchRestore();
// Cross-tab communication will not work here due cross origin (usually the widget parent and the RC server will have different urls)
// So we manually update the widget to get the messages and actions done while undocked
await loadConfig();
await loadMessages();
}

dispatch({ minimized: false, undocked: false });

Triggers.callbacks?.emit('chat-opened-by-visitor');
};

const handleOpenWindow = () => {
parentCall('openPopout');
parentCall('openPopout', store.token);
dispatch({ undocked: true, minimized: false });
};

Expand All @@ -144,7 +143,7 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
setPopedOut(poppedOut);

if (poppedOut) {
dispatch({ minimized: false });
dispatch({ minimized: false, undocked: true });
}
}, [dispatch]);

Expand All @@ -167,7 +166,7 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
notificationsEnabled: sound?.enabled,
minimized: !poppedOut && (minimized || undocked),
expanded: !minimized && expanded,
windowed: !minimized && poppedOut,
windowed: poppedOut,
livechatLogo,
hideWatermark,
sound,
Expand Down
4 changes: 2 additions & 2 deletions packages/livechat/src/routes/TriggerMessage/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export const TriggerMessageContainer: FunctionalComponent<{ path: string }> = ({
const { messages, agent, unread } = useContext(StoreContext);
const { theme, onRestore } = useContext(ScreenContext);

const handleStart = () => {
const handleStart = async () => {
parentCall('setFullScreenDocumentMobile');
parentCall('openWidget');
onRestore();
await onRestore();
route('/');
};

Expand Down
12 changes: 10 additions & 2 deletions packages/livechat/src/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type InternalWidgetAPI = {
ready: () => void;
minimizeWindow: () => void;
restoreWindow: () => void;
openPopout: () => void;
openPopout: (token?: string) => void;
openWidget: () => void;
resizeWidget: (height: number) => void;
removeWidget: () => void;
Expand Down Expand Up @@ -484,7 +484,7 @@ const api: InternalWidgetAPI = {
openWidget();
},

openPopout() {
openPopout(token = '') {
closeWidget();
if (!config.url) {
throw new Error('Config.url is not set!');
Expand All @@ -494,6 +494,14 @@ const api: InternalWidgetAPI = {
'livechat-popout',
`width=${WIDGET_OPEN_WIDTH}, height=${widgetHeight}, toolbars=no`,
);

const data = {
src: 'rocketchat',
fn: 'setGuestToken',
args: [token],
};

api.popup?.postMessage(data, '*');
api.popup?.focus();
},

Expand Down

0 comments on commit 5b3f6b0

Please sign in to comment.