diff --git a/client/src/components/Dashboard/Dashboard.js b/client/src/components/Dashboard/Dashboard.js index c9039f7a5..4488809d3 100644 --- a/client/src/components/Dashboard/Dashboard.js +++ b/client/src/components/Dashboard/Dashboard.js @@ -1,6 +1,5 @@ import React from 'react'; import { Switch, Route } from 'react-router'; -import { useQuery } from 'react-query'; import 'style/pages/Dashboard/Dashboard.scss'; diff --git a/client/src/components/Preferences/PreferencesSubContent.js b/client/src/components/Preferences/PreferencesSubContent.js index df50dee30..6584a16b0 100644 --- a/client/src/components/Preferences/PreferencesSubContent.js +++ b/client/src/components/Preferences/PreferencesSubContent.js @@ -4,7 +4,7 @@ import {Switch, Route, useRouteMatch} from 'react-router-dom'; export default function PreferencesSubContent({ preferenceTab }) { const routes = preferencesTabs[preferenceTab]; - const {path} = useRouteMatch(); + const { path } = useRouteMatch(); if (routes.length <= 0) { return null; } diff --git a/client/src/containers/Alerts/Users/UserActivateAlert.js b/client/src/containers/Alerts/Users/UserActivateAlert.js new file mode 100644 index 000000000..e9d98a6e8 --- /dev/null +++ b/client/src/containers/Alerts/Users/UserActivateAlert.js @@ -0,0 +1,6 @@ + + + +function UserActivateAlert() { + +} \ No newline at end of file diff --git a/client/src/containers/Alerts/Users/UserDeleteAlert.js b/client/src/containers/Alerts/Users/UserDeleteAlert.js new file mode 100644 index 000000000..13ccbb1da --- /dev/null +++ b/client/src/containers/Alerts/Users/UserDeleteAlert.js @@ -0,0 +1,76 @@ +import React from 'react'; +import { Intent, Alert } from '@blueprintjs/core'; +import { FormattedMessage as T, useIntl } from 'react-intl'; + +import { useDeleteUser } from 'hooks/query'; +import { AppToaster } from 'components'; + +import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect'; +import withAlertActions from 'containers/Alert/withAlertActions'; + +import { compose } from 'redux'; + +/** + * User delete alert. + */ +function UserDeleteAlert({ + // #ownProps + name, + + // #withAlertStoreConnect + isOpen, + payload: { userId }, + + // #withAlertActions + closeAlert, +}) { + const { formatMessage } = useIntl(); + const { mutateAsync: deleteUserMutate, isLoading } = useDeleteUser(); + + const handleCancelUserDelete = () => { + closeAlert(name); + }; + + const handleConfirmUserDelete = () => { + deleteUserMutate(userId) + .then((response) => { + AppToaster.show({ + message: formatMessage({ + id: 'the_user_has_been_deleted_successfully', + }), + intent: Intent.SUCCESS, + }); + }) + .catch(({ response: { data: { errors } } }) => { + if (errors.find(e => e.type === 'CANNOT_DELETE_LAST_USER')) { + AppToaster.show({ + message: 'Cannot delete the last user in the system.', + intent: Intent.DANGER, + }); + } + closeAlert(name); + }); + }; + + return ( + } + confirmButtonText={} + intent={Intent.DANGER} + isOpen={isOpen} + onCancel={handleCancelUserDelete} + onConfirm={handleConfirmUserDelete} + loading={isLoading} + > +

+ Once you delete this user, you won't be able to restore it later. Are + you sure you want to delete ? +

+
+ ); +} + +export default compose( + withAlertStoreConnect(), + withAlertActions, +)(UserDeleteAlert); diff --git a/client/src/containers/Alerts/Users/UserInactivateAlert.js b/client/src/containers/Alerts/Users/UserInactivateAlert.js new file mode 100644 index 000000000..335452283 --- /dev/null +++ b/client/src/containers/Alerts/Users/UserInactivateAlert.js @@ -0,0 +1,68 @@ +import React from 'react'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { Alert, Intent } from '@blueprintjs/core'; +import { AppToaster } from 'components'; +import { useInactivateUser } from 'hooks/query'; + +import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect'; +import withAlertActions from 'containers/Alert/withAlertActions'; + +import { compose } from 'utils'; + +/** + * User inactivate alert. + */ +function UserInactivateAlert({ + // #ownProps + name, + + // #withAlertStoreConnect + isOpen, + payload: { userId }, + + // #withAlertActions + closeAlert, +}) { + const { formatMessage } = useIntl(); + + const { mutateAsync: userInactivateMutate } = useInactivateUser(); + + const handleConfirmInactivate = () => { + userInactivateMutate(userId) + .then(() => { + AppToaster.show({ + message: formatMessage({ + id: 'the_user_has_been_inactivated_successfully', + }), + intent: Intent.SUCCESS, + }); + }) + .catch((error) => { + + }); + }; + + const handleCancel = () => { + closeAlert(name); + }; + + return ( + } + confirmButtonText={} + intent={Intent.WARNING} + isOpen={isOpen} + onCancel={handleCancel} + onConfirm={handleConfirmInactivate} + > +

+ +

+
+ ); +} + +export default compose( + withAlertStoreConnect(), + withAlertActions, +)(UserInactivateAlert); diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js index 31f10bed2..61df70c3f 100644 --- a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormFields.js @@ -1,19 +1,14 @@ -import React, { useMemo, useCallback } from 'react'; +import React from 'react'; import { - Button, Classes, FormGroup, InputGroup, - Intent, } from '@blueprintjs/core'; -import { Form, useFormikContext, FastField } from 'formik'; -import { FormattedMessage as T, useIntl } from 'react-intl'; -import { pick } from 'lodash'; +import { FastField } from 'formik'; +import { FormattedMessage as T } from 'react-intl'; import { ErrorMessage, - AppToaster, FieldRequiredHint, - DialogContent, } from 'components'; import { useAutofocus } from 'hooks'; @@ -33,7 +28,7 @@ export default function CurrencyFormFields() { className={'form-group--currency-name'} intent={inputIntent({ error, touched })} helperText={} - inline={true} + // inline={true} > (currencyNameFieldRef.current = ref)} @@ -51,7 +46,7 @@ export default function CurrencyFormFields() { className={'form-group--currency-code'} intent={inputIntent({ error, touched })} helperText={} - inline={true} + // inline={true} > diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js index 6098b5649..545b86b47 100644 --- a/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js +++ b/client/src/containers/Dialogs/CurrencyFormDialog/CurrencyFormProvider.js @@ -14,7 +14,7 @@ function CurrencyFormProvider({ isEditMode, currency, dialogName, ...props }) { const { mutateAsync: editCurrencyMutate } = useEditCurrency(); // fetch Currencies list. - const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies(); + const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); // Provider state. const provider = { diff --git a/client/src/containers/Dialogs/CurrencyFormDialog/index.js b/client/src/containers/Dialogs/CurrencyFormDialog/index.js index fe98130f2..5125602b9 100644 --- a/client/src/containers/Dialogs/CurrencyFormDialog/index.js +++ b/client/src/containers/Dialogs/CurrencyFormDialog/index.js @@ -1,5 +1,5 @@ import React, { lazy } from 'react'; -import { FormattedMessage as T, useIntl } from 'react-intl'; +import { FormattedMessage as T } from 'react-intl'; import { Dialog, DialogSuspense } from 'components'; import withDialogRedux from 'components/DialogReduxConnect'; import { compose } from 'utils'; @@ -30,6 +30,7 @@ function CurrencyFormDialog({ isOpen={isOpen} autoFocus={true} canEscapeKeyClose={true} + style={{ width: '450px' }} > { - const fields = {}; - - if (errors.find(error => error.type === 'EMAIL.ALREADY.INVITED')) { - fields.email = formatMessage({ id: 'email_is_already_used' }); - } - return fields; - } \ No newline at end of file + const fields = {}; + + if (errors.find((error) => error.type === 'EMAIL.ALREADY.INVITED')) { + fields.email = formatMessage({ id: 'email_is_already_used' }); + } + return fields; +}; diff --git a/client/src/containers/Preferences/Currencies/CurrenciesProvider.js b/client/src/containers/Preferences/Currencies/CurrenciesProvider.js index 19bc96928..cdf777fb1 100644 --- a/client/src/containers/Preferences/Currencies/CurrenciesProvider.js +++ b/client/src/containers/Preferences/Currencies/CurrenciesProvider.js @@ -8,7 +8,7 @@ const CurrenciesContext = createContext(); */ function CurrenciesProvider({ ...props }) { // fetches the currencies list. - const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies(); + const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); const state = { currencies, @@ -16,9 +16,7 @@ function CurrenciesProvider({ ...props }) { }; return ( - <> - - + ); } diff --git a/client/src/containers/Preferences/Users/Users.js b/client/src/containers/Preferences/Users/Users.js index ebb0405cf..31ec33693 100644 --- a/client/src/containers/Preferences/Users/Users.js +++ b/client/src/containers/Preferences/Users/Users.js @@ -2,10 +2,16 @@ import React from 'react'; import { Tabs, Tab } from '@blueprintjs/core'; import classNames from 'classnames'; +import 'style/pages/Preferences/Users.scss' + import { CLASSES } from 'common/classes'; import PreferencesSubContent from 'components/Preferences/PreferencesSubContent'; + import withUserPreferences from 'containers/Preferences/Users/withUserPreferences'; +/** + * Preferences page - Users page. + */ function UsersPreferences({ openDialog }) { const onChangeTabs = (currentTabId) => {}; diff --git a/client/src/containers/Preferences/Users/UsersAlerts.js b/client/src/containers/Preferences/Users/UsersAlerts.js new file mode 100644 index 000000000..73717281f --- /dev/null +++ b/client/src/containers/Preferences/Users/UsersAlerts.js @@ -0,0 +1,14 @@ +import React from 'react'; +import UserDeleteAlert from 'containers/Alerts/Users/UserDeleteAlert'; +import UserInactivateAlert from 'containers/Alerts/Users/UserInactivateAlert'; +// import UserActivateAlert from 'containers/Alerts/UserActivateAlert'; + +export default function UsersAlerts() { + return ( + <> + + + {/* */} + + ); +} diff --git a/client/src/containers/Preferences/Users/UsersDataTable.js b/client/src/containers/Preferences/Users/UsersDataTable.js index a2c9f05d6..3243b860a 100644 --- a/client/src/containers/Preferences/Users/UsersDataTable.js +++ b/client/src/containers/Preferences/Users/UsersDataTable.js @@ -1,178 +1,78 @@ -import React, { useCallback, useState, useMemo } from 'react'; -import { - Intent, - Button, - Popover, - Menu, - MenuDivider, - Tag, - MenuItem, - Position, -} from '@blueprintjs/core'; -import { withRouter } from 'react-router'; -import { snakeCase } from 'lodash'; +import React, { useCallback } from 'react'; -import { FormattedMessage as T, useIntl } from 'react-intl'; -import { compose, firstLettersArgs } from 'utils'; - -import { DataTable, Icon, If } from 'components'; +import { compose } from 'utils'; +import { DataTable } from 'components'; import withDialogActions from 'containers/Dialog/withDialogActions'; -import withUsers from 'containers/Users/withUsers'; +import withAlertActions from 'containers/Alert/withAlertActions'; -const AvatarCell = (row) => { - return { firstLettersArgs(row.email) }; -} +import { ActionsMenu, useUsersListColumns } from './components'; +import { useUsersListContext } from './UsersProvider'; +/** + * Users datatable. + */ function UsersDataTable({ // #withDialogActions openDialog, - // #withUsers - usersList, - usersLoading, - - // #ownProps - loading, - onFetchData, - onInactiveUser, - onDeleteUser, - onSelectedRowsChange, + // #withAlertActions + openAlert, }) { - const { formatMessage } = useIntl(); - - const onEditUser = useCallback( - (user) => () => { - const form = Object.keys(user).reduce((obj, key) => { - const camelKey = snakeCase(key); - obj[camelKey] = user[key]; - return obj; - }, {}); - - openDialog('userList-form', { action: 'edit', user: form }); + // Handle edit user action. + const handleEditUserAction = useCallback( + (user) => { + openDialog('userList-form', { action: 'edit', userId: user.id }); }, [openDialog], ); - - const actionMenuList = useCallback( - (user) => ( - - - } - text={formatMessage({ id: 'edit_user' })} - onClick={onEditUser(user)} - /> - - - onInactiveUser(user)} - /> - - - } - text={formatMessage({ id: 'delete_user' })} - onClick={() => onDeleteUser(user)} - intent={Intent.DANGER} - /> - - ), - [onInactiveUser, onDeleteUser, onEditUser, formatMessage], - ); - const onRowContextMenu = useCallback( - (cell) => { - return actionMenuList(cell.row.original); + // Handle inactivate user action. + const handleInactivateUser = useCallback( + (user) => { + openAlert('user-inactivate', { userId: user.id }); }, - [actionMenuList], + [openAlert] ); - - const columns = useMemo( - () => [ - { - id: 'avatar', - Header: '', - accessor: AvatarCell, - width: 100, - }, - { - id: 'full_name', - Header: formatMessage({ id: 'full_name' }), - accessor: 'full_name', - width: 150, - }, - { - id: 'email', - Header: formatMessage({ id: 'email' }), - accessor: 'email', - width: 150, - }, - { - id: 'phone_number', - Header: formatMessage({ id: 'phone_number' }), - accessor: 'phone_number', - width: 120, - }, - { - id: 'status', - Header: 'Status', - accessor: (user) => - !user.invite_accepted_at ? ( - - - - ) : user.active ? ( - - - - ) : ( - - - - ), - width: 80, - className: 'status', - }, - { - id: 'actions', - Header: '', - Cell: ({ cell }) => ( - -