[IMPROVE] UI/UX enhancements in department pages following the design system (#19421)

* [IMPROVEMENTS] Refactoring departments page to follow design system.

* [FIX] Translation of title page and "new" button.

* [IMPROVE] Removing unnecessary margin bottom from EE inputs and department margins from form.

* Update client/omnichannel/departments/DepartmentEdit.js

Co-authored-by: Renato Becker <renato.augusto.becker@gmail.com>

Co-authored-by: Renato Becker <renato.augusto.becker@gmail.com>
pull/19400/head
Rafael Ferreira 5 years ago committed by GitHub
parent f0a33faac9
commit 21c8c6c440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 42
      client/omnichannel/departments/DepartmentEdit.js
  2. 7
      client/omnichannel/departments/DepartmentsPage.js
  3. 39
      client/omnichannel/departments/DepartmentsRoute.js
  4. 2
      ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js
  5. 2
      ee/client/omnichannel/additionalForms/DepartmentForwarding.js
  6. 2
      ee/client/omnichannel/additionalForms/EeNumberInput.js
  7. 2
      ee/client/omnichannel/additionalForms/EeTextAreaInput.js
  8. 2
      ee/client/omnichannel/additionalForms/EeTextInput.js
  9. 1
      packages/rocketchat-i18n/i18n/en.i18n.json
  10. 1
      packages/rocketchat-i18n/i18n/pt.i18n.json

@ -16,7 +16,7 @@ import Page from '../../components/basic/Page';
import DepartmentsAgentsTable from './DepartmentsAgentsTable';
import { formsSubscription } from '../additionalForms';
import { useComponentDidUpdate } from '../../hooks/useComponentDidUpdate';
import { isEmail } from '../../../app/utils';
export default function EditDepartmentWithData({ id, reload, title }) {
const t = useTranslation();
@ -63,7 +63,7 @@ export function EditDepartment({ data, id, title, reload }) {
const [tags, setTags] = useState((department && department.chatClosingTags) || []);
const [tagsText, setTagsText] = useState();
const { values, handlers } = useForm({
const { values, handlers, hasUnsavedChanges } = useForm({
name: (department && department.name) || '',
email: (department && department.email) || '',
description: (department && department.description) || '',
@ -147,6 +147,9 @@ export function EditDepartment({ data, id, title, reload }) {
useComponentDidUpdate(() => {
setEmailError(!email ? t('The_field_is_required', 'email') : '');
}, [t, email]);
useComponentDidUpdate(() => {
setEmailError(!isEmail(email) ? t('Validate_email_address') : '');
}, [t, email]);
useComponentDidUpdate(() => {
setTagError(requestTagBeforeClosingChat && (!tags || tags.length === 0) ? t('The_field_is_required', 'name') : '');
}, [requestTagBeforeClosingChat, t, tags]);
@ -162,6 +165,10 @@ export function EditDepartment({ data, id, title, reload }) {
setEmailError(t('The_field_is_required', 'email'));
error = true;
}
if (!isEmail(email)) {
setEmailError(t('Validate_email_address'));
error = true;
}
if (requestTagBeforeClosingChat && (!tags || tags.length === 0)) {
setTagError(t('The_field_is_required', 'tags'));
error = true;
@ -203,7 +210,7 @@ export function EditDepartment({ data, id, title, reload }) {
} else {
await saveDepartmentInfo(id, payload, agentList);
}
dispatchToastMessage({ type: 'success', message: t('saved') });
dispatchToastMessage({ type: 'success', message: t('Saved') });
reload();
agentsRoute.push({});
} catch (error) {
@ -214,8 +221,7 @@ export function EditDepartment({ data, id, title, reload }) {
const handleReturn = useMutableCallback(() => {
router.push({});
});
const invalidForm = !name || !email || (requestTagBeforeClosingChat && (!tags || tags.length === 0));
const invalidForm = !name || !email || !isEmail(email) || !hasUnsavedChanges || (requestTagBeforeClosingChat && (!tags || tags.length === 0));
const formId = useUniqueId();
@ -223,7 +229,7 @@ export function EditDepartment({ data, id, title, reload }) {
<Page>
<Page.Header title={title}>
<ButtonGroup>
<Button onClick={handleReturn}>{t('Back')}</Button>
<Button onClick={handleReturn}><Icon name='back'/> {t('Back')}</Button>
<Button type='submit' form={formId} primary disabled={invalidForm}>{t('Save')}</Button>
</ButtonGroup>
</Page.Header>
@ -277,11 +283,21 @@ export function EditDepartment({ data, id, title, reload }) {
<SelectFiltered flexGrow={1} options={channelOpts} value={offlineMessageChannelName} onChange={handleOfflineMessageChannelName} placeholder={t('Channel_name')}/>
</Field.Row>
</Field>
{MaxChats && <MaxChats value={maxNumberSimultaneousChat} handler={handleMaxNumberSimultaneousChat} label={'Max_number_of_chats_per_agent'} placeholder='Max_number_of_chats_per_agent_description' />}
{VisitorInactivity && <VisitorInactivity value={visitorInactivityTimeoutInSeconds} handler={handleVisitorInactivityTimeoutInSeconds} label={'How_long_to_wait_to_consider_visitor_abandonment_in_seconds'} placeholder='Number_in_seconds' />}
{AbandonedMessageInput && <AbandonedMessageInput value={abandonedRoomsCloseCustomMessage} handler={handleAbandonedRoomsCloseCustomMessage} label={'Livechat_abandoned_rooms_closed_custom_message'} placeholder='Enter_a_custom_message' />}
{WaitingQueueMessageInput && <WaitingQueueMessageInput value={waitingQueueMessage} handler={handleWaitingQueueMessage} label={'Waiting_queue_message'} />}
{DepartmentForwarding && <DepartmentForwarding value={departmentsAllowedToForward} handler={handleDepartmentsAllowedToForward} label={'List_of_departments_for_forward_description'} placeholder='Enter_a_department_name' />}
{MaxChats && <Field>
<MaxChats value={maxNumberSimultaneousChat} handler={handleMaxNumberSimultaneousChat} label={'Max_number_of_chats_per_agent'} placeholder='Max_number_of_chats_per_agent_description' />
</Field>}
{VisitorInactivity && <Field>
<VisitorInactivity value={visitorInactivityTimeoutInSeconds} handler={handleVisitorInactivityTimeoutInSeconds} label={'How_long_to_wait_to_consider_visitor_abandonment_in_seconds'} placeholder='Number_in_seconds' />
</Field>}
{AbandonedMessageInput && <Field>
<AbandonedMessageInput value={abandonedRoomsCloseCustomMessage} handler={handleAbandonedRoomsCloseCustomMessage} label={'Livechat_abandoned_rooms_closed_custom_message'} placeholder='Enter_a_custom_message' />
</Field>}
{WaitingQueueMessageInput && <Field>
<WaitingQueueMessageInput value={waitingQueueMessage} handler={handleWaitingQueueMessage} label={'Waiting_queue_message'} />
</Field>}
{DepartmentForwarding && <Field>
<DepartmentForwarding value={departmentsAllowedToForward} handler={handleDepartmentsAllowedToForward} label={'List_of_departments_for_forward'} placeholder='Enter_a_department_name' />
</Field>}
<Field>
<Box display='flex' flexDirection='row'>
<Field.Label>{t('Request_tag_before_closing_chat')}</Field.Label>
@ -303,7 +319,9 @@ export function EditDepartment({ data, id, title, reload }) {
{tags.map((tag, i) => <Chip key={i} onClick={handleTagChipClick(tag)} mie='x8'>{tag}</Chip>)}
</Field.Row>}
</Field>}
{DepartmentBusinessHours && <DepartmentBusinessHours bhId={department && department.businessHourId}/>}
{DepartmentBusinessHours && <Field>
<DepartmentBusinessHours bhId={department && department.businessHourId}/>
</Field>}
<Divider mb='x16' />
<Field>
<Field.Label mb='x4'>{t('Agents')}:</Field.Label>

@ -6,6 +6,7 @@ import Page from '../../components/basic/Page';
import FilterByText from '../../components/FilterByText';
import GenericTable from '../../components/GenericTable';
import { useRoute } from '../../contexts/RouterContext';
import { useTranslation } from '../../contexts/TranslationContext';
function DepartmentsPage({
data,
@ -18,14 +19,16 @@ function DepartmentsPage({
}) {
const departmentsRoute = useRoute('omnichannel-departments');
const t = useTranslation();
const onAddNew = useMutableCallback(() => departmentsRoute.push({
context: 'new',
}));
return <Page flexDirection='row'>
<Page>
<Page.Header title={title}>
<Button small onClick={onAddNew}>
<Icon name='plus' size='x16'/>
<Button onClick={onAddNew}>
<Icon name='plus' /> {t('New')}
</Button>
</Page.Header>
<Page.Content>

@ -1,7 +1,7 @@
import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks';
import React, { useMemo, useCallback, useState } from 'react';
import { Table, Icon } from '@rocket.chat/fuselage';
import { Table, Icon, Button } from '@rocket.chat/fuselage';
import GenericTable from '../../components/GenericTable';
import { useTranslation } from '../../contexts/TranslationContext';
@ -12,20 +12,47 @@ import NotAuthorizedPage from '../../components/NotAuthorizedPage';
import DepartmentsPage from './DepartmentsPage';
import EditDepartmentWithData from './DepartmentEdit';
import { useRouteParameter, useRoute } from '../../contexts/RouterContext';
import DeleteWarningModal from '../../components/DeleteWarningModal';
import { useSetModal } from '../../contexts/ModalContext';
import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext';
export function RemoveDepartmentButton({ _id, reload }) {
const deleteAction = useEndpointAction('DELETE', `livechat/department/${ _id }`);
const setModal = useSetModal();
const dispatchToastMessage = useToastMessageDispatch();
const t = useTranslation();
const handleRemoveClick = useMutableCallback(async (e) => {
e.preventDefault();
e.stopPropagation();
const handleRemoveClick = useMutableCallback(async () => {
const result = await deleteAction();
if (result.success === true) {
reload();
}
});
return <Table.Cell fontScale='p1' color='hint' onClick={handleRemoveClick} withTruncatedText><Icon name='trash' size='x20'/></Table.Cell>;
const handleDelete = useMutableCallback((e) => {
e.stopPropagation();
const onDeleteAgent = async () => {
try {
await handleRemoveClick();
dispatchToastMessage({ type: 'success', message: t('Department_removed') });
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
setModal();
};
setModal(<DeleteWarningModal
onDelete={onDeleteAgent}
onCancel={() => setModal()}
/>);
});
return <Table.Cell fontScale='p1' color='hint' withTruncatedText>
<Button small ghost title={t('Remove')} onClick={handleDelete}>
<Icon name='trash' size='x16'/>
</Button>
</Table.Cell>;
}
const sortDir = (sortDir) => (sortDir === 'asc' ? 1 : -1);
@ -107,7 +134,7 @@ function DepartmentsRoute() {
reload={reload}
header={header}
renderRow={renderRow}
title={'Departments'}>
title={t('Departments')}>
</DepartmentsPage>;
}

@ -11,7 +11,7 @@ export const DepartmentBusinessHours = ({ bhId }) => {
const name = data && data.businessHour && data.businessHour.name;
return <Field mbe='x16'>
return <Field>
<Field.Label>{t('Business_Hour')}</Field.Label>
<Field.Row>
<TextInput disabled value={name || ''}/>

@ -11,7 +11,7 @@ export const DepartmentForwarding = ({ value, handler, label, placeholder }) =>
const options = useMemo(() => (data && [...data.departments.map((department) => [department._id, department.name])]) || [], [data]);
return <Field mbe='x16'>
return <Field>
<Field.Label>{t(label)}</Field.Label>
<Field.Row>
<MultiSelectFiltered value={value} options={options} onChange={handler} disabled={!options} placeholder={t(placeholder)} flexGrow={1} />

@ -7,7 +7,7 @@ import { useTranslation } from '../../../../client/contexts/TranslationContext';
export const EeNumberInput = ({ value, handler, label, placeholder }) => {
const t = useTranslation();
return <Field mbe='x16'>
return <Field>
<Field.Label>{t(label)}</Field.Label>
<Field.Row>
<NumberInput value={value} onChange={handler} flexGrow={1} placeholder={t(placeholder)}/>

@ -7,7 +7,7 @@ import { useTranslation } from '../../../../client/contexts/TranslationContext';
export const EeTextAreaInput = ({ value, handler, label, placeholder }) => {
const t = useTranslation();
return <Field mbe='x16'>
return <Field>
<Field.Label>{t(label)}</Field.Label>
<Field.Row>
<TextAreaInput flexGrow={1} value={value} onChange={handler} placeholder={t(placeholder)} />

@ -7,7 +7,7 @@ import { useTranslation } from '../../../../client/contexts/TranslationContext';
export const EeTextInput = ({ value, handler, label, placeholder }) => {
const t = useTranslation();
return <Field mbe='x16'>
return <Field>
<Field.Label>{t(label)}</Field.Label>
<Field.Row>
<TextInput flexGrow={1} value={value} onChange={handler} placeholder={t(placeholder)} />

@ -2607,6 +2607,7 @@
"Name_Placeholder": "Please enter your name...",
"Navigation_History": "Navigation History",
"Never": "Never",
"New": "New",
"New_users": "New users",
"New_Application": "New Application",
"New_chat_in_queue": "New chat in queue",

@ -2117,6 +2117,7 @@
"Name_optional": "Nome (opcional)",
"Name_Placeholder": "Por favor, insira seu nome...",
"Navigation_History": "Histórico de navegação",
"New": "Novo",
"New_Application": "Nova aplicação",
"New_Custom_Field": "Novo Campo Personalizado",
"New_Department": "Novo Departamento",

Loading…
Cancel
Save