Commit 595d673b authored by Renato Becker's avatar Renato Becker

Merge branch 'dev'

parents 644c4202 bb189ca8
......@@ -135,6 +135,9 @@ export class App extends Component {
visibility.addListener(this.handleVisibilityChange);
this.handleVisibilityChange();
window.addEventListener('beforeunload', () => {
visibility.removeListener(this.handleVisibilityChange);
});
const configLanguage = () => {
const { config: { settings: { language } = {} } = {} } = this.props;
......
......@@ -128,5 +128,5 @@
}
.popover-menu__overlay {
background-color: rgba(12, 13, 15, 0.2);
background-color: $overlay-bg-color;
}
......@@ -7,9 +7,6 @@ $modal-border-radius: 2 * $default-border-radius;
$modal-shadow: 0 7px 16px 0 rgba(0, 0, 0, 0.1);
$modal-background-color: $bg-color-white;
$modal-overlay-background-color: rgba(255, 255, 255, 0.52);
:global(.is-blurred) {
filter: blur(2px);
}
......@@ -20,7 +17,7 @@ $modal-overlay-background-color: rgba(255, 255, 255, 0.52);
left: 0;
width: 100%;
height: 100%;
background-color: $modal-overlay-background-color;
background-color: $overlay-bg-color;
z-index: 10;
}
......
......@@ -107,15 +107,22 @@ export const createToken = () => (Math.random().toString(36).substring(2, 15) +
export const getAvatarUrl = (username) => (username ? `${ Livechat.client.host }/avatar/${ username }` : null);
export const msgTypesNotDisplayed = ['livechat_video_call', 'livechat_navigation_history', 'au'];
export const msgTypesNotRendered = ['livechat_video_call', 'livechat_navigation_history', 'au', 'command'];
export const renderMessage = (message = {}) => (message.t !== 'command' && !msgTypesNotDisplayed.includes(message.t));
export const canRenderMessage = (message = {}) => (!msgTypesNotRendered.includes(message.t));
export const getAttachmentsUrl = (attachments) => attachments && attachments.map((attachment) => {
const assetUrl = attachment.image_url || attachment.video_url || attachment.audio_url || attachment.title_link;
return { ...attachment, attachment_url: `${ Livechat.client.host }${ assetUrl }` };
});
export const sortArrayByColumn = (array, column, inverted) => array.sort((a, b) => {
if (a[column] < b[column] && !inverted) {
return -1;
}
return 1;
});
export const normalizeDOMRect = (({ left, top, right, bottom }) => ({ left, top, right, bottom }));
......
......@@ -2,7 +2,7 @@ import format from 'date-fns/format';
import { Livechat } from '../api';
import store from '../store';
import constants from '../lib/constants';
import { canRenderMessage } from '../components/helpers';
export const loadConfig = async() => {
const {
......@@ -38,11 +38,12 @@ export const processUnread = async() => {
const { minimized, visible, messages } = store.state;
if (minimized || !visible) {
const { alerts, lastReadMessageId } = store.state;
const lastReadMessageIndex = messages.findIndex((item) => item._id === lastReadMessageId);
const unreadMessages = messages.slice(lastReadMessageIndex + 1);
const renderedMessages = messages.filter((message) => canRenderMessage(message));
const lastReadMessageIndex = renderedMessages.findIndex((item) => item._id === lastReadMessageId);
const unreadMessages = renderedMessages.slice(lastReadMessageIndex + 1);
if (lastReadMessageIndex !== -1) {
const lastReadMessage = messages[lastReadMessageIndex];
const lastReadMessage = renderedMessages[lastReadMessageIndex];
const alertMessage = I18n.t({
one: 'One new message since %{since}',
other: '%{count} new messages since %{since}',
......
......@@ -4,7 +4,7 @@ import { Livechat } from '../../api';
import { Consumer } from '../../store';
import { loadConfig } from '../../lib/main';
import constants from '../../lib/constants';
import { createToken, debounce, getAvatarUrl, renderMessage, throttle } from '../../components/helpers';
import { createToken, debounce, getAvatarUrl, canRenderMessage, throttle } from '../../components/helpers';
import Chat from './component';
import { ModalManager } from '../../components/Modal';
import { initRoom, closeChat } from './room';
......@@ -175,13 +175,11 @@ export class ChatContainer extends Component {
const { alerts, dispatch, room: { _id: rid } = {} } = this.props;
if (!rid) {
return;
}
await dispatch({ loading: true });
try {
await Livechat.closeChat({ rid });
if (rid) {
await Livechat.closeChat({ rid });
}
} catch (error) {
console.error(error);
const alert = { id: createToken(), children: 'Error closing chat.', error: true, timeout: 0 };
......@@ -223,8 +221,8 @@ export class ChatContainer extends Component {
}
canFinishChat = () => {
const { room } = this.props;
return room !== undefined;
const { room, connecting } = this.props;
return (room !== undefined) || connecting;
}
canRemoveUserData = () => {
......@@ -236,8 +234,17 @@ export class ChatContainer extends Component {
this.canSwitchDepartment() || this.canFinishChat() || this.canRemoveUserData()
)
checkConnecting() {
const { dispatch, agent, connecting, showConnecting } = this.props;
const connectingStatus = !!(agent && showConnecting);
if (connecting !== connectingStatus) {
dispatch({ connecting: connectingStatus });
}
}
componentDidMount() {
this.loadMessages();
this.checkConnecting();
}
async componentWillReceiveProps({ messages: nextMessages, visible: nextVisible, minimized: nextMinimized }) {
......@@ -339,7 +346,7 @@ export const ChatConnector = ({ ref, ...props }) => (
phone: (agent.phone && agent.phone[0] && agent.phone[0].phoneNumber) || (agent.customFields && agent.customFields.phone),
} : undefined}
room={room}
messages={messages.filter((message) => renderMessage(message))}
messages={messages.filter((message) => canRenderMessage(message))}
noMoreMessages={noMoreMessages}
emoji={false}
uploads={uploads}
......
import { Livechat } from '../../api';
import { store } from '../../store';
import { route } from 'preact-router';
import { setCookies, upsert } from '../../components/helpers';
import { setCookies, upsert, canRenderMessage } from '../../components/helpers';
import Commands from '../../lib/commands';
import { loadConfig, processUnread } from '../../lib/main';
import { parentCall } from '../../lib/parentCall';
......@@ -35,7 +35,8 @@ const doPlaySound = async(message) => {
};
export const initRoom = async() => {
const { room, config: { settings: showConnecting } } = store.state;
const { state } = store;
const { room, config: { settings: { showConnecting } } = {} } = state;
if (!room) {
return;
......@@ -43,7 +44,7 @@ export const initRoom = async() => {
Livechat.unsubscribeAll();
const { token, agent, room: { _id: rid, servedBy } } = store.state;
const { token, agent, room: { _id: rid, servedBy } } = state;
Livechat.subscribeRoom(rid);
let roomAgent = agent;
......@@ -53,7 +54,6 @@ export const initRoom = async() => {
store.setState({ roomAgent });
await store.setState({ agent: roomAgent });
}
const connecting = !!(!roomAgent && showConnecting);
store.setState({ connecting });
}
......@@ -96,7 +96,13 @@ Livechat.onMessage(async(message) => {
await store.setState({
messages: upsert(store.state.messages, message, ({ _id }) => _id === message._id, ({ ts }) => ts),
});
await processMessage(message);
if (canRenderMessage(message) !== true) {
return;
}
await processUnread();
await doPlaySound(message);
});
......@@ -2,7 +2,7 @@ import { Component } from 'preact';
import Button from '../../components/Button';
import Form, { Validations } from '../../components/Form';
import Screen from '../../components/Screen';
import { createClassName } from '../../components/helpers';
import { createClassName, sortArrayByColumn } from '../../components/helpers';
import styles from './styles';
......@@ -14,12 +14,14 @@ export default class LeaveMessage extends Component {
state = {
name: { value: '' },
email: { value: '' },
department: null,
message: { value: '' },
}
validations = {
name: [Validations.nonEmpty],
email: [Validations.nonEmpty, Validations.email],
department: [],
message: [Validations.nonEmpty],
}
......@@ -47,6 +49,8 @@ export default class LeaveMessage extends Component {
handleEmailChange = this.handleFieldChange('email')
handleDepartmentChange = this.handleFieldChange('department')
handleMessageChange = this.handleFieldChange('message')
handleSubmit = (event) => {
......@@ -63,16 +67,27 @@ export default class LeaveMessage extends Component {
constructor(props) {
super(props);
const { hasDepartmentField, departments } = props;
if (hasDepartmentField && departments) {
if (departments.length > 0) {
this.state.department = { value: '' };
} else {
this.state.department = null;
}
}
this.validateAll();
}
renderForm = ({ loading, valid = this.isValid() }, { name, email, message }) => (
renderForm = ({ loading, departments, valid = this.isValid() }, { name, email, department, message }) => (
<Form onSubmit={this.handleSubmit}>
{name && (
<Form.Item>
<Form.Label error={name.showError} htmlFor="name">{I18n.t('Name')} *</Form.Label>
<Form.TextInput
id="name"
name="name"
placeholder={I18n.t('Insert your name here...')}
disabled={loading}
......@@ -90,7 +105,6 @@ export default class LeaveMessage extends Component {
<Form.Item>
<Form.Label error={email.showError} htmlFor="email">{I18n.t('Email')} *</Form.Label>
<Form.TextInput
id="email"
name="email"
placeholder={I18n.t('Insert your email here...')}
disabled={loading}
......@@ -104,11 +118,28 @@ export default class LeaveMessage extends Component {
</Form.Item>
)}
{department && (
<Form.Item>
<Form.Label error={department.showError} htmlFor="department">{I18n.t('I need help with...')}</Form.Label>
<Form.SelectInput
name="department"
placeholder={I18n.t('Choose an option...')}
options={sortArrayByColumn(departments, 'name').map(({ _id, name }) => ({ value: _id, label: name }))}
disabled={loading}
value={department.value}
error={department.showError}
onInput={this.handleDepartmentChange}
/>
<Form.Description error={department.showError}>
{department.showError && department.error}
</Form.Description>
</Form.Item>
)}
{message && (
<Form.Item>
<Form.Label error={message.showError} htmlFor="message">{I18n.t('Message')} *</Form.Label>
<Form.TextInput
id="message"
name="message"
placeholder={I18n.t('Write your message...')}
multiple={4}
......
......@@ -36,6 +36,7 @@ export const LeaveMessageConnector = ({ ref, ...props }) => (
<Consumer>
{({
config: {
departments = {},
messages: {
offlineMessage: message,
offlineSuccessMessage: successMessage,
......@@ -67,6 +68,8 @@ export const LeaveMessageConnector = ({ ref, ...props }) => (
dispatch={dispatch}
alerts={alerts}
hasForm={displayOfflineForm}
hasDepartmentField={departments && departments.some((dept) => dept.showOnOfflineForm)}
departments={departments.filter((dept) => dept.showOnOfflineForm)}
/>
)}
</Consumer>
......
......@@ -2,7 +2,7 @@ import { Component } from 'preact';
import Button from '../../components/Button';
import Form, { Validations } from '../../components/Form';
import Screen from '../../components/Screen';
import { createClassName } from '../../components/helpers';
import { createClassName, sortArrayByColumn } from '../../components/helpers';
import styles from './styles';
......@@ -168,7 +168,7 @@ export default class Register extends Component {
id="department"
name="department"
placeholder={I18n.t('Choose an option...')}
options={departments.map(({ _id, name }) => ({ value: _id, label: name }))}
options={sortArrayByColumn(departments, 'name').map(({ _id, name }) => ({ value: _id, label: name }))}
disabled={loading}
value={department.value}
error={department.showError}
......@@ -180,7 +180,7 @@ export default class Register extends Component {
</Form.Item>
)}
<Form.Item>
<Form.Item style={{ 'margin-bottom': '0' }}>
<Button loading={loading} disabled={!valid || loading} stack>{I18n.t('Start chat')}</Button>
</Form.Item>
</Form>
......
......@@ -20,3 +20,5 @@ $color-yellow: #FFD21F;
$color-dark-yellow: #F6C502;
$color-green: #2DE0A5;
$color-dark-green: #26D198;
$overlay-bg-color: rgba(12, 13, 15, 0.2);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment