Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
16 changes: 16 additions & 0 deletions .changeset/fuzzy-vans-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/livechat": minor
---

Improved Livechat's theming capabilities
Comment thread
aleksandernsilva marked this conversation as resolved.


| Name (`setTheme`, `initialize`) | Workspace setting | Default value | Description |
|---------------------------------|----------------------------------------|---------------|-------------|
| `position` | Livechat widget position on the screen | `right` | Changes the widget position on the screen. Can be `left` or `right` |
| `background` | Livechat background | `N/A` | Changes the message list background. Accepts the same values as the CSS property [background](https://developer.mozilla.org/en-US/docs/Web/CSS/background) |
| `guestBubbleBackgroundColor` | `N/A` | `N/A` | Changes the guest's message bubble background color |
| `agentBubbleBackgroundColor` | `N/A` | `N/A` | Changes the agent's message bubble background color |
| `hideGuestAvatar` | `N/A` | `false` | Hides/shows the guest avatar |
| `hideAgentAvatar` | `N/A` | `true` | Hides/shows the agent avatar |
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/api/lib/livechat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ export async function settings({ businessUnit = '' }: { businessUnit?: string }
color: initSettings.Livechat_title_color,
offlineTitle: initSettings.Livechat_offline_title,
offlineColor: initSettings.Livechat_offline_title_color,
position: initSettings.Livechat_widget_position || 'right',
background: initSettings.Livechat_background,
Comment thread
tassoevan marked this conversation as resolved.
actionLinks: {
webrtc: [
{
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/lib/LivechatTyped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,8 @@ class LivechatClass {
'Livechat_clear_local_storage_when_chat_ended',
'Livechat_history_monitor_type',
'Livechat_hide_system_messages',
'Livechat_widget_position',
'Livechat_background',
] as const;

type SettingTypes = (typeof validSettings)[number] | 'Livechat_Show_Connecting';
Expand Down
29 changes: 29 additions & 0 deletions apps/meteor/ee/app/livechat-enterprise/server/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,35 @@ export const createSettings = async (): Promise<void> => {
modules: ['livechat-enterprise'],
});

await settingsRegistry.add('Livechat_widget_position', 'right', {
type: 'select',
group: 'Omnichannel',
section: 'Livechat',
i18nLabel: 'Livechat_widget_position_on_the_screen',
public: true,
values: [
{ key: 'left', i18nLabel: 'Left' },
{ key: 'right', i18nLabel: 'Right' },
],
enterprise: true,
invalidValue: 'right',
modules: ['livechat-enterprise'],
enableQuery: omnichannelEnabledQuery,
});

await settingsRegistry.add('Livechat_background', '', {
type: 'string',
Comment thread
aleksandernsilva marked this conversation as resolved.
group: 'Omnichannel',
section: 'Livechat',
i18nDescription: 'Livechat_background_description',
placeholder: '#FFFFFF',
public: true,
enterprise: true,
invalidValue: '',
modules: ['livechat-enterprise'],
enableQuery: omnichannelEnabledQuery,
});

await settingsRegistry.add('Omnichannel_contact_manager_routing', true, {
type: 'boolean',
group: 'Omnichannel',
Expand Down
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 @@ -3117,6 +3117,7 @@
"leave-p_description": "Permission to leave private groups",
"Lets_get_you_new_one_": "Let's get you a new one!",
"Let_them_know": "Let them know",
"Left": "Left",
"License": "License",
"Line": "Line",
"Link": "Link",
Expand Down Expand Up @@ -3176,6 +3177,9 @@
"Livechat_offline_message_sent": "Livechat offline message sent",
"Livechat_OfflineMessageToChannel_enabled": "Send Livechat offline messages to a channel",
"Livechat_hide_system_messages": "Hide system messages",
"Livechat_widget_position_on_the_screen": "Livechat widget position on the screen",
"Livechat_background": "Livechat background",
"Livechat_background_description": "Define a background using hexadecimal (#F5455C), a color name (red) or an image using a URL (`url('https://example.com/image.png')`). This field follows CSS standards. [See documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/background).",
"Omnichannel_chat_closed_due_to_inactivity": "The chat was automatically closed because we haven't received any reply from {{guest}} in {{timeout}} seconds",
"Omnichannel_actions": "Omnichannel actions",
"Omnichannel_on_hold_chat_resumed": "On Hold Chat Resumed: {{comment}}",
Expand Down Expand Up @@ -4449,6 +4453,7 @@
"Review_devices": "Review when and where devices are connecting from",
"Ringing": "Ringing",
"Ringtones_and_visual_indicators_notify_people_of_incoming_calls": "Ringtones and visual indicators notify people of incoming calls.",
"Right": "Right",
"Robot_Instructions_File_Content": "Robots.txt File Contents",
"Root": "Root",
"Required_action": "Required action",
Expand Down
5 changes: 5 additions & 0 deletions packages/i18n/src/locales/pt-BR.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,7 @@
"leave-p": "Deixar grupos privados",
"leave-p_description": "Permissão para deixar grupos privados",
"Lets_get_you_new_one_": "Vamos pegar outro!",
"Left": "Esquerda",
"List_of_Channels": "Lista de Canais",
"List_of_departments_for_forward": "Lista de departamentos permitidos para encaminhamento (opcional).",
"List_of_departments_for_forward_description": "Permite definir uma lista restrita de departamentos que podem receber conversas deste departamento.",
Expand Down Expand Up @@ -2685,6 +2686,9 @@
"Livechat_offline_message_sent": "Mensagem offline do livechat enviada",
"Livechat_OfflineMessageToChannel_enabled": "Envie mensagens offline do livechat para um canal",
"Livechat_hide_system_messages": "Ocultar mensagens do sistema",
"Livechat_widget_position_on_the_screen": "Posição do livechat widget na tela",
"Livechat_background": "Livechat plano de fundo",
"Livechat_background_description": "Defina uma plano de fundo usando hexadecimal (#F5455C), um nome de cor (red) ou uma imagem através de uma URL (`url('https://example.com/image.png')`). Este campo segue os padrões do CSS. [See documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/background).",
"Omnichannel_on_hold_chat_resumed": "Conversa em espera retomada: {{comment}}",
"Omnichannel_on_hold_chat_automatically": "A conversa foi automaticamente retomada de em espera após receber uma nova mensagem de {{guest}}",
"Omnichannel_on_hold_chat_resumed_manually": "A conversa foi manualmente retomada de em espera por {{user}}",
Expand Down Expand Up @@ -3655,6 +3659,7 @@
"Return_to_previous_page": "Retornar para a página anterior",
"Return_to_the_queue": "Retornar para fila",
"Ringing": "Tocando",
"Right": "Direita",
"Robot_Instructions_File_Content": "Conteúdo do arquivo Robots.txt",
"Default_Referrer_Policy": "Política de referência padrão",
"Default_Referrer_Policy_Description": "Controla o cabeçalho 'referência' que é enviado ao solicitar mídia incorporada de outros servidores. Para obter mais informações, consulte [este link do MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy). Lembre-se de que é necessária uma atualização completa da página para ter resultado.",
Expand Down
13 changes: 6 additions & 7 deletions packages/livechat/src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@ import LeaveMessage from '../../routes/LeaveMessage';
import Register from '../../routes/Register';
import SwitchDepartment from '../../routes/SwitchDepartment';
import TriggerMessage from '../../routes/TriggerMessage';
import type { Dispatch } from '../../store';
import type { Dispatch, StoreState } from '../../store';
import { ScreenProvider } from '../Screen/ScreenProvider';

type AppProps = {
config: {
settings: {
registrationForm?: boolean;
nameFieldRegistrationForm?: boolean;
emailFieldRegistrationForm?: boolean;
forceAcceptDataProcessingConsent?: boolean;
};
settings: StoreState['config']['settings'];
theme: StoreState['config']['theme'];
online?: boolean;
departments: Department[];
enabled?: boolean;
Expand Down Expand Up @@ -64,6 +60,7 @@ type AppProps = {
name: string;
email: string;
};
theme: StoreState['iframe']['theme'];
};
i18n: typeof i18next;
};
Expand Down Expand Up @@ -141,11 +138,13 @@ export class App extends Component<AppProps, AppState> {
const {
minimized,
iframe: { visible },
config: { theme },
dispatch,
} = this.props;

parentCall(minimized ? 'minimizeWindow' : 'restoreWindow');
parentCall(visible ? 'showWidget' : 'hideWidget');
parentCall('setWidgetPosition', theme.position || 'right');

visibility.addListener(this.handleVisibilityChange);

Expand Down
15 changes: 13 additions & 2 deletions packages/livechat/src/components/Messages/Message/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,20 @@ const getMessageUsernames = (compact, message) => {
return [username];
};

const Message = ({ avatarResolver, attachmentResolver = getAttachmentUrl, use, me, compact, className, style = {}, t, ...message }) => (
const Message = ({
avatarResolver,
attachmentResolver = getAttachmentUrl,
use,
me,
compact,
className,
style = {},
t,
hideAvatar,
...message
}) => (
<MessageContainer id={message._id} compact={compact} reverse={me} use={use} className={className} style={style} system={!!message.type}>
{!message.type && <MessageAvatars avatarResolver={avatarResolver} usernames={getMessageUsernames(compact, message)} />}
{!message.type && !hideAvatar && <MessageAvatars avatarResolver={avatarResolver} usernames={getMessageUsernames(compact, message)} />}
<MessageContent reverse={me}>
{renderContent({
text: message.type ? getSystemMessageText(message, t) : message.msg,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import { createClassName } from '../../../helpers/createClassName';
import { Avatar } from '../../Avatar';
import styles from './styles.scss';

export const MessageAvatars = memo(({ avatarResolver = () => null, usernames = [], className, style = {} }) => (
<div className={createClassName(styles, 'message-avatars', {}, [className])} style={style}>
{usernames.map((username) => (
<Avatar src={avatarResolver(username)} description={username} className={createClassName(styles, 'message-avatars__avatar')} />
))}
</div>
));
export const MessageAvatars = memo(({ avatarResolver = () => null, usernames = [], className, style = {} }) => {
const avatars = usernames.filter(Boolean);

if (!avatars.length) {
return null;
}

return (
<div className={createClassName(styles, 'message-avatars', {}, [className])} style={style}>
{avatars.map((username) => (
<Avatar src={avatarResolver(username)} description={username} className={createClassName(styles, 'message-avatars__avatar')} />
))}
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ $message-bubble-me-link-color: $color-text-lighter;
$message-bubble-nude-padding: 0;
$message-bubble-quoted-padding: 12px 12px 12px 0;
$message-bubble-quoted-indicator-width: 3px;
$message-bubble-quoted-indicator-margin:
(-2 * $message-bubble-quoted-indicator-width)
(2 * $message-bubble-quoted-indicator-width)
(-2 * $message-bubble-quoted-indicator-width)
$message-bubble-quoted-indicator-width;
$message-bubble-quoted-indicator-margin: (-2 * $message-bubble-quoted-indicator-width) (2 * $message-bubble-quoted-indicator-width)
(-2 * $message-bubble-quoted-indicator-width) $message-bubble-quoted-indicator-width;
$message-bubble-quoted-indicator-border-radius: $default-border-radius;
$message-bubble-quoted-indicator-color: $color-green;

Expand All @@ -28,7 +25,7 @@ $message-bubble-quoted-indicator-color: $color-green;
color: $message-bubble-color;
border-radius: $message-bubble-border-radius;

background-color: $message-bubble-background-color;
background-color: var(--receiver-bubble-background-color, $message-bubble-background-color);
align-items: stretch;
flex-flow: row nowrap;
justify-content: flex-start;
Expand All @@ -39,7 +36,7 @@ $message-bubble-quoted-indicator-color: $color-green;

&--inverse {
color: var(--font-color, $message-bubble-me-color);
background-color: var(--color, $message-bubble-me-background-color);
background-color: var(--sender-bubble-background-color, var(--color, $message-bubble-me-background-color));

a {
color: var(--font-color, $message-bubble-me-link-color);
Expand All @@ -55,13 +52,13 @@ $message-bubble-quoted-indicator-color: $color-green;
&--quoted {
padding: $message-bubble-quoted-padding;

background-color: $message-bubble-background-color;
background-color: var(--receiver-bubble-background-color, $message-bubble-background-color);

&::before {
width: $message-bubble-quoted-indicator-width;
margin: -6px 6px -6px 3px;

content: "";
content: '';

border-radius: $message-bubble-quoted-indicator-border-radius;
background-color: $message-bubble-quoted-indicator-color;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ export class MessageList extends MemoizedComponent {
typingUsernames,
}) => {
const items = [];
const { incomingCallAlert } = store.state;
const { ongoingCall } = store.state;
const { incomingCallAlert, ongoingCall } = store.state;
const { hideSenderAvatar = false, hideReceiverAvatar = false } = this.props || {};

for (let i = 0; i < messages.length; ++i) {
const previousMessage = messages[i - 1];
Expand Down Expand Up @@ -180,14 +180,16 @@ export class MessageList extends MemoizedComponent {
items.push(<MessageSeparator key={`sep-${message.ts}`} use='li' date={message.ts} />);
}

const isMe = uid && message.u && uid === message.u._id;
items.push(
<Suspense fallback={null}>
<Message
key={message._id}
attachmentResolver={attachmentResolver}
avatarResolver={avatarResolver}
use='li'
me={uid && message.u && uid === message.u._id}
me={isMe}
hideAvatar={(isMe && hideSenderAvatar) || (!isMe && hideReceiverAvatar)}
compact={nextMessage && message.u && nextMessage.u && message.u._id === nextMessage.u._id && !nextMessage.t}
conversationFinishedMessage={conversationFinishedMessage}
type={message.t}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
display: flex;
overflow-y: scroll;
flex: 1 1 0;

background: var(--message-list-background, transparent);

align-items: stretch;
flex-flow: column nowrap;

Expand Down
56 changes: 49 additions & 7 deletions packages/livechat/src/components/Screen/ScreenProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { parse } from 'query-string';
import { isActiveSession } from '../../helpers/isActiveSession';
import { parentCall } from '../../lib/parentCall';
import Triggers from '../../lib/triggers';
import store, { StoreContext } from '../../store';
import { StoreContext } from '../../store';

export type ScreenContextValue = {
notificationsEnabled: boolean;
Expand All @@ -27,9 +27,15 @@ export type ScreenContextValue = {
onDismissAlert: () => unknown;
dismissNotification: () => void;
theme?: {
color: string;
fontColor: string;
iconColor: string;
color?: string;
fontColor?: string;
iconColor?: string;
position?: 'left' | 'right';
guestBubbleBackgroundColor?: string;
agentBubbleBackgroundColor?: string;
background?: string;
hideGuestAvatar?: boolean;
hideAgentAvatar?: boolean;
};
};

Expand All @@ -38,6 +44,8 @@ export const ScreenContext = createContext<ScreenContextValue>({
color: '',
fontColor: '',
iconColor: '',
hideAgentAvatar: false,
hideGuestAvatar: true,
},
notificationsEnabled: true,
minimized: true,
Expand All @@ -50,13 +58,41 @@ export const ScreenContext = createContext<ScreenContextValue>({
} as ScreenContextValue);

export const ScreenProvider: FunctionalComponent = ({ children }) => {
const { dispatch, config, sound, minimized = true, undocked, expanded = false, alerts, modal, iframe } = useContext(StoreContext);
const {
dispatch,
config,
sound,
minimized = true,
undocked,
expanded = false,
alerts,
modal,
iframe,
...store
Comment thread
aleksandernsilva marked this conversation as resolved.
} = useContext(StoreContext);
const { department, name, email } = iframe.guest || {};
const { color } = config.theme || {};
const { color: customColor, fontColor: customFontColor, iconColor: customIconColor } = iframe.theme || {};
const { color, position: configPosition, background } = config.theme || {};

const {
color: customColor,
fontColor: customFontColor,
iconColor: customIconColor,
guestBubbleBackgroundColor,
agentBubbleBackgroundColor,
position: customPosition,
background: customBackground,
hideAgentAvatar = false,
hideGuestAvatar = true,
} = iframe.theme || {};

const [poppedOut, setPopedOut] = useState(false);

const position = customPosition || configPosition || 'right';

useEffect(() => {
parentCall('setWidgetPosition', position || 'right');
}, [position]);

const handleEnableNotifications = () => {
dispatch({ sound: { ...sound, enabled: true } });
};
Expand Down Expand Up @@ -118,6 +154,12 @@ export const ScreenProvider: FunctionalComponent = ({ children }) => {
color: customColor || color,
fontColor: customFontColor,
iconColor: customIconColor,
position,
guestBubbleBackgroundColor,
agentBubbleBackgroundColor,
background: customBackground || background,
hideAgentAvatar,
hideGuestAvatar,
},
notificationsEnabled: sound?.enabled,
minimized: !poppedOut && (minimized || undocked),
Expand Down
Loading