8000 feat: Allow hiding 'Expand chat' button via Livechat widget API by aleksandernsilva · Pull Request #36127 · RocketChat/Rocket.Chat · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: Allow hiding 'Expand chat' button via Livechat widget API #36127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .json  (1)

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/popular-games-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/livechat": minor
---

#### Adds support for hiding the "Expand chat" button in the Livechat widget.
This can be configured via the widget API by passing the `hideExpandChat` option to the `setTheme` method, or through the Livechat Appearance settings page by enabling the "Hide 'Expand chat'" option.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ API.v1.addRoute(
'Livechat_widget_position',
'Livechat_hide_system_messages',
'Omnichannel_allow_visitors_to_close_conversation',
'Livechat_hide_expand_chat',
];

const valid = settings.every((setting) => validSettingList.includes(setting._id));
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/livechat/server/api/lib/appearance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export async function findAppearance(): Promise<{ appearance: ISetting[] }> {
'Livechat_widget_position',
'Livechat_hide_system_messages',
'Omnichannel_allow_visitors_to_close_conversation',
'Livechat_hide_expand_chat',
],
},
};
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/livechat/server/api/lib/livechat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export async function settings({ businessUnit = '', userId }: { businessUnit?: s
offlineColor: initSettings.Livechat_offline_title_color,
position: initSettings.Livechat_widget_position || 'right',
background: initSettings.Livechat_background,
hideExpandChat: initSettings.Livechat_hide_expand_chat,
actionLinks: {
webrtc: [
{
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/livechat/server/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export async function getInitSettings() {
'Assets_livechat_widget_logo',
'Livechat_hide_watermark',
'Omnichannel_allow_visitors_to_close_conversation',
'Livechat_hide_expand_chat',
] as const;

type SettingTypes = (typeof validSettings)[number] | 'Livechat_Show_Connecting';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ type AppearanceFieldLabelProps = ComponentProps<typeof FieldLabel> & {
children: string;
};

const AppearanceFieldLabel = ({ children, premium = false }: AppearanceFieldLabelProps) => {
const AppearanceFieldLabel = ({ children, premium = false, ...props }: AppearanceFieldLabelProps) => {
const { t } = useTranslation();
const hasLicense = useHasLicenseModule('livechat-enterprise');
const shouldDisableEnterprise = premium && !hasLicense;

if (!shouldDisableEnterprise) {
return <FieldLabel>{children}</FieldLabel>;
return <FieldLabel {...props}>{children}</FieldLabel>;
}

return (
<FieldLabel>
<FieldLabel {...props}>
<Box is='span' mie={4}>
{children}
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const AppearanceForm = () => {
const livechatBackgroundField = useId();
const livechatHideSystemMessagesField = useId();
const omnichannelVisitorsCanCloseConversationField = useId();
const livechatHideExpandChat = useId();

return (
<Accordion>
Expand Down Expand Up @@ -153,6 +154,17 @@ const AppearanceForm = () => {
/>
</FieldRow>
</Field>
<Field>
<FieldRow>
<AppearanceFieldLabel htmlFor={livechatHideExpandChat}>{t('Livechat_hide_expand_chat')}</AppearanceFieldLabel>
<Controller
name='Livechat_hide_expand_chat'
control={control}
render={({ field: { value, ...field } }) => <ToggleSwitch id={livechatHideExpandChat} {...field} checked={value} />}
/>
</FieldRow>
<FieldHint>{t('Livechat_hide_expand_chat_description')}</FieldHint>
</Field>
</FieldGroup>
</AccordionItem>

Expand Down
12 changes: 12 additions & 0 deletions apps/meteor/ee/app/livechat-enterprise/server/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,16 @@ export const createSettings = async (): Promise<void> => {
key: 'Load_Rotation',
i18nLabel: 'Load_Rotation',
});

await settingsRegistry.add('Livechat_hide_expand_chat', false, {
type: 'boolean',
group: 'Omnichannel',
section: 'Livechat',
i18nDescription: 'Livechat_hide_expand_chat_description',
invalidValue: false,
modules: ['livechat-enterprise'],
enterprise: false,
public: false,
enableQuery: omnichannelEnabledQuery,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ declare const window: Window & {
setGuestName: (name: string) => void;
setGuestToken: (token: string) => void;
setParentUrl: (url: string) => void;
setTheme: (theme: { color?: string; fontColor?: string; iconColor?: string; title?: string; offlineTitle?: string }) => void;
setTheme: (theme: {
color?: string;
fontColor?: string;
iconColor?: string;
title?: string;
offlineTitle?: string;
hideExpandChat?: boolean;
}) => void;
setLanguage: (language: string) => void;
transferChat: (department: string) => void;
onChatMaximized: (callback: () => void) => void;
Expand Down Expand Up @@ -167,6 +174,20 @@ test.describe('OC - Livechat API', () => {
await expect(page.frameLocator('#rocketchat-iframe').locator('header')).toHaveCSS('color', 'rgb(50, 50, 50)');
});

await test.step('expect setTheme set hideExpandChat', async () => {
await poLiveChat.page.evaluate(() => window.RocketChat.livechat.maximizeWidget());

await expect(poLiveChat.btnExpandChat).toBeVisible();

await poLiveChat.page.evaluate(() => window.RocketChat.livechat.setTheme({ hideExpandChat: true }));

await expect(poLiveChat.btnExpandChat).not.toBeVisible();

await poLiveChat.page.evaluate(() => window.RocketChat.livechat.setTheme({ hideExpandChat: false }));

await expect(poLiveChat.btnExpandChat).toBeVisible();
});

// TODO: fix iconColor setTheme property
// await test.step('Expect setTheme set iconColor', async () => {
// await poLiveChat.page.evaluate(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { IS_EE } from '../config/constants';
import { createAuxContext } from '../fixtures/createAuxContext';
import { Users } from '../fixtures/userStates';
import { OmnichannelLiveChat } from '../page-objects';
import { OmnichannelLivechatAppearance } from '../page-objects/omnichannel-livechat-appearance';
import { createAgent, makeAgentAvailable } from '../utils/omnichannel/agents';
import { test, expect } from '../utils/test';

test.skip(!IS_EE, 'Enterprise Only');

test.use({ storageState: Users.admin.state });

test.describe('OC - Livechat - Hide "Expand chat"', async () => {
let agent: Awaited<ReturnType<typeof createAgent>>;
let poLiveChat: OmnichannelLiveChat;
let poLivechatAppearance: OmnichannelLivechatAppearance;

test.beforeAll(async ({ api }) => {
agent = await createAgent(api, 'user1');

const res = await makeAgentAvailable(api, agent.data._id);

await expect(res.status()).toBe(200);
});

test.beforeEach(async ({ browser, api }) => {
const { page: livechatPage } = await createAuxContext(browser, Users.user1, '/livechat', false);

poLiveChat = new OmnichannelLiveChat(livechatPage, api);
});

test.afterEach(async () => {
await poLiveChat.page.close();
});

test.beforeEach(async ({ page }) => {
poLivechatAppearance = new OmnichannelLivechatAppearance(page);

await page.goto('/omnichannel/appearance');
});

test.afterAll(async ({ api }) => {
const res = await api.post('/settings/Livechat_hide_expand_chat', { value: false });
await expect(res.status()).toBe(200);
});

test('OC - Livechat - Hide "Expand chat"', async () => {
await test.step('expect to open Livechat', async () => {
await poLiveChat.openLiveChat();
});

await test.step('expect "Expand chat" button to start visible (default)', async () => {
await expect(poLiveChat.btnExpandChat).toBeVisible();
});

await test.step('expect to change setting', async () => {
await poLivechatAppearance.labelHideExpandChat.click();
await poLivechatAppearance.btnSave.click();
});

await test.step('expect "Expand chat" button to be hidden', async () => {
await poLiveChat.page.reload();
await poLiveChat.openLiveChat();
await expect(poLiveChat.btnExpandChat).toBeHidden();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ export class OmnichannelLivechatAppearance extends OmnichannelAdministration {
return this.page.locator('[name="Livechat_title"]');
}

get inputHideExpandChat(): Locator {
return this.page.getByRole('checkbox', { name: 'Hide "Expand chat"' });
}

get labelHideExpandChat(): Locator {
return this.page.locator('label', { has: this.inputHideExpandChat });
}

findHideSystemMessageOption(option: string): Locator {
return this.page.locator(`[role="option"][value="${option}"]`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ export class OmnichannelLiveChatEmbedded {
return this.page.frameLocator('#rocketchat-iframe').locator('footer div div div:nth-child(3) button');
}

get btnExpandChat(): Locator {
return this.page.frameLocator('#rocketchat-iframe').getByRole('button', { name: 'Expand chat', exact: true });
}

get firstAutoMessage(): Locator {
return this.page.frameLocator('#rocketchat-iframe').locator('div.message-text__WwYco p');
}
Expand Down
4 changes: 4 additions & 0 deletions apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export class OmnichannelLiveChat {
return this.page.locator(`button >> text="Yes"`);
}

get btnExpandChat(): Locator {
return this.page.getByRole('button', { name: 'Expand chat' });
}

get txtHeaderTitle(): Locator {
return this.page.locator('div >> text="Chat Finished"');
}
Expand Down
2 changes: 2 additions & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -3011,6 +3011,8 @@
"Livechat_forward_open_chats_timeout": "Timeout (in seconds) to forward chats",
"Livechat_guest_count": "Guest Counter",
"Livechat_hide_system_messages": "Hide system messages",
"Livechat_hide_expand_chat": "Hide \"Expand chat\"",
"Livechat_hide_expand_chat_description": "Remove the \"Expand chat\" button from the widget",
"Livechat_hide_watermark": "Hide \"powered by Rocket.Chat\"",
"Livechat_hide_watermark_description": "Remove the Rocket.Chat logo from the widget",
"Livechat_last_chatted_agent_routing": "Last-Chatted Agent Preferred",
Expand Down
8 changes: 5 additions & 3 deletions packages/livechat/src/components/Screen/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Header from '../Header';
import Tooltip from '../Tooltip';
import type { ScreenContextValue } from './ScreenProvider';

type screenHeaderProps = {
type ScreenHeaderProps = {
alerts: { id: string; children: ComponentChildren; [key: string]: unknown }[];
agent: Agent;
notificationsEnabled: boolean;
Expand All @@ -31,6 +31,7 @@ type screenHeaderProps = {
spot: number;
};
title: string;
hideExpandChat: boolean;
};

const ScreenHeader = ({
Expand All @@ -48,7 +49,8 @@ const ScreenHeader = ({
onOpenWindow,
queueInfo,
title,
}: screenHeaderProps) => {
hideExpandChat,
}: ScreenHeaderProps) => {
const { t } = useTranslation();
const headerRef = useRef<HTMLElement>(null);

Expand Down Expand Up @@ -114,7 +116,7 @@ const ScreenHeader = ({
</Header.Action>
</Tooltip.Trigger>
)}
{!expanded && !windowed && (
{!hideExpandChat && !expanded && !windowed && (
<Tooltip.Trigger content={t('expand_chat')} placement='bottom-left'>
<Header.Action aria-label={t('expand_chat')} >
<OpenWindowIcon width={20} height={20} />
Expand Down
6 changes: 5 additions & 1 deletion packages/livechat/src/components/Screen/ScreenProvider.tsx < 10000 span data-view-component="true">
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type ScreenContextValue = {
background?: string;
hideGuestAvatar?: boolean;
hideAgentAvatar?: boolean;
hideExpandChat?: boolean;
};
};

Expand All @@ -50,6 +51,7 @@ export const ScreenContext = createContext<ScreenContextValue>({
iconColor: '',
hideAgentAvatar: false,
hideGuestAvatar: true,
hideExpandChat: false,
},
notificationsEnabled: true,
minimized: true,
Expand All @@ -65,7 +67,7 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
const store = useContext(StoreContext);
const { token, dispatch, config, sound, minimized = true, undocked, expanded = false, alerts, modal, iframe, customFieldsQueue } = store;
const { department, name, email } = iframe.guest || {};
const { color, position: configPosition, background } = config.theme || {};
const { color, position: configPosition, background, hideExpandChat } = config.theme || {};
const { livechatLogo, hideWatermark = false } = config.settings || {};

const {
Expand All @@ -78,6 +80,7 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
background: customBackground,
hideAgentAvatar = false,
hideGuestAvatar = true,
hideExpandChat: customHideExpandChat = false,
} = iframe.theme || {};

const [poppedOut, setPopedOut] = useState(false);
Expand Down Expand Up @@ -147,6 +150,7 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
background: customBackground || background,
hideAgentAvatar,
hideGuestAvatar,
hideExpandChat: customHideExpandChat || hideExpandChat,
},
notificationsEnabled: sound?.enabled,
minimized: !poppedOut && (minimized || undocked),
Expand Down
1 change: 1 addition & 0 deletions packages/livechat/src/components/Screen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export const Screen = ({ title, color, agent, children, className, unread, trigg
>
>
queueInfo={queueInfo}
hideExpandChat={theme.hideExpandChat}
/>
)}

Expand Down
2 changes: 2 additions & 0 deletions packages/livechat/src/store/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type StoreState = {
offlineColor?: string;
position: 'left' | 'right';
background?: string;
hideExpandChat?: boolean;
actionLinks?: {
webrtc: {
actionLinksAlignment: string;
Expand Down Expand Up @@ -89,6 +90,7 @@ export type StoreState = {
background?: string;
hideGuestAvatar?: boolean;
hideAgentAvatar?: boolean;
hideExpandChat?: boolean;
};
visible?: boolean;
department?: string;
Expand Down
Loading
0