From 21c8c6c440b3aadce4e4c3666d4a2a02b290ced9 Mon Sep 17 00:00:00 2001 From: Rafael Ferreira Date: Tue, 17 Nov 2020 23:38:17 -0300 Subject: [PATCH] [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 Co-authored-by: Renato Becker --- .../omnichannel/departments/DepartmentEdit.js | 42 +++++++++++++------ .../departments/DepartmentsPage.js | 7 +++- .../departments/DepartmentsRoute.js | 39 ++++++++++++++--- .../DepartmentBusinessHours.js | 2 +- .../additionalForms/DepartmentForwarding.js | 2 +- .../additionalForms/EeNumberInput.js | 2 +- .../additionalForms/EeTextAreaInput.js | 2 +- .../additionalForms/EeTextInput.js | 2 +- packages/rocketchat-i18n/i18n/en.i18n.json | 1 + packages/rocketchat-i18n/i18n/pt.i18n.json | 1 + 10 files changed, 75 insertions(+), 25 deletions(-) diff --git a/client/omnichannel/departments/DepartmentEdit.js b/client/omnichannel/departments/DepartmentEdit.js index feaa3ce0fdf..c190d7c72a0 100644 --- a/client/omnichannel/departments/DepartmentEdit.js +++ b/client/omnichannel/departments/DepartmentEdit.js @@ -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 }) { - + @@ -277,11 +283,21 @@ export function EditDepartment({ data, id, title, reload }) { - {MaxChats && } - {VisitorInactivity && } - {AbandonedMessageInput && } - {WaitingQueueMessageInput && } - {DepartmentForwarding && } + {MaxChats && + + } + {VisitorInactivity && + + } + {AbandonedMessageInput && + + } + {WaitingQueueMessageInput && + + } + {DepartmentForwarding && + + } {t('Request_tag_before_closing_chat')} @@ -303,7 +319,9 @@ export function EditDepartment({ data, id, title, reload }) { {tags.map((tag, i) => {tag})} } } - {DepartmentBusinessHours && } + {DepartmentBusinessHours && + + } {t('Agents')}: diff --git a/client/omnichannel/departments/DepartmentsPage.js b/client/omnichannel/departments/DepartmentsPage.js index 0c0efca7288..2e67d951701 100644 --- a/client/omnichannel/departments/DepartmentsPage.js +++ b/client/omnichannel/departments/DepartmentsPage.js @@ -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 - diff --git a/client/omnichannel/departments/DepartmentsRoute.js b/client/omnichannel/departments/DepartmentsRoute.js index 46c08269193..ffcdf3ca786 100644 --- a/client/omnichannel/departments/DepartmentsRoute.js +++ b/client/omnichannel/departments/DepartmentsRoute.js @@ -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 ; + 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( setModal()} + />); + }); + + + return + + ; } const sortDir = (sortDir) => (sortDir === 'asc' ? 1 : -1); @@ -107,7 +134,7 @@ function DepartmentsRoute() { reload={reload} header={header} renderRow={renderRow} - title={'Departments'}> + title={t('Departments')}> ; } diff --git a/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js b/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js index 49ea87039a1..eec0e0b1074 100644 --- a/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js +++ b/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js @@ -11,7 +11,7 @@ export const DepartmentBusinessHours = ({ bhId }) => { const name = data && data.businessHour && data.businessHour.name; - return + return {t('Business_Hour')} diff --git a/ee/client/omnichannel/additionalForms/DepartmentForwarding.js b/ee/client/omnichannel/additionalForms/DepartmentForwarding.js index c8b40cdd250..f696be5a965 100644 --- a/ee/client/omnichannel/additionalForms/DepartmentForwarding.js +++ b/ee/client/omnichannel/additionalForms/DepartmentForwarding.js @@ -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 + return {t(label)} diff --git a/ee/client/omnichannel/additionalForms/EeNumberInput.js b/ee/client/omnichannel/additionalForms/EeNumberInput.js index f3dca042d33..f136e263d45 100644 --- a/ee/client/omnichannel/additionalForms/EeNumberInput.js +++ b/ee/client/omnichannel/additionalForms/EeNumberInput.js @@ -7,7 +7,7 @@ import { useTranslation } from '../../../../client/contexts/TranslationContext'; export const EeNumberInput = ({ value, handler, label, placeholder }) => { const t = useTranslation(); - return + return {t(label)} diff --git a/ee/client/omnichannel/additionalForms/EeTextAreaInput.js b/ee/client/omnichannel/additionalForms/EeTextAreaInput.js index aa302699d25..0e2659aef46 100644 --- a/ee/client/omnichannel/additionalForms/EeTextAreaInput.js +++ b/ee/client/omnichannel/additionalForms/EeTextAreaInput.js @@ -7,7 +7,7 @@ import { useTranslation } from '../../../../client/contexts/TranslationContext'; export const EeTextAreaInput = ({ value, handler, label, placeholder }) => { const t = useTranslation(); - return + return {t(label)} diff --git a/ee/client/omnichannel/additionalForms/EeTextInput.js b/ee/client/omnichannel/additionalForms/EeTextInput.js index 078d25d651c..2707a8a3430 100644 --- a/ee/client/omnichannel/additionalForms/EeTextInput.js +++ b/ee/client/omnichannel/additionalForms/EeTextInput.js @@ -7,7 +7,7 @@ import { useTranslation } from '../../../../client/contexts/TranslationContext'; export const EeTextInput = ({ value, handler, label, placeholder }) => { const t = useTranslation(); - return + return {t(label)} diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 7f6bcb87433..e6e8e106a48 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -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", diff --git a/packages/rocketchat-i18n/i18n/pt.i18n.json b/packages/rocketchat-i18n/i18n/pt.i18n.json index 7b1bfa7cba3..e1573516600 100644 --- a/packages/rocketchat-i18n/i18n/pt.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt.i18n.json @@ -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",