diff --git a/client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogContent.js b/client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogContent.js
index baf2dfd4b..846cfc2d0 100644
--- a/client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogContent.js
+++ b/client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogContent.js
@@ -1,101 +1,21 @@
import React from 'react';
-import { Intent } from '@blueprintjs/core';
-import { pick, snakeCase } from 'lodash';
-import { queryCache, useQuery } from 'react-query';
-import { useIntl } from 'react-intl';
-import { Formik } from 'formik';
-import { AppToaster, DialogContent } from 'components';
-import withUsersActions from 'containers/Users/withUsersActions';
-import withDialogActions from 'containers/Dialog/withDialogActions';
+import InviteUserForm from './InviteUserForm';
+import { InviteUserFormProvider } from './InviteUserFormProvider';
-import { compose, objectKeysTransform } from 'utils';
-import { InviteUserFormSchema } from './InviteUserDialog.schema';
-import UserFormDialogForm from './InviteUserDialogForm';
-
-import { transformApiErrors } from './utils';
-
-import 'style/pages/Users/InviteFormDialog.scss'
+import 'style/pages/Users/InviteFormDialog.scss';
/**
* Invite user dialog content.
*/
-function InviteUserDialogContent({
- // #wihtCurrenciesActions
- requestFetchUser,
- requestSubmitInvite,
-
- // #withDialogActions
- closeDialog,
-
- // #ownProp
+export default function InviteUserDialogContent({
action,
userId,
dialogName,
}) {
- const { formatMessage } = useIntl();
-
- // Fetch user details.
- const fetchHook = useQuery(
- ['user', userId],
- (key, id) => requestFetchUser(id),
- { enabled: userId },
- );
-
- const initialValues = {
- status: 1,
- ...(action === 'edit' &&
- pick(
- objectKeysTransform(userId, snakeCase),
- Object.keys(InviteUserFormSchema.fields),
- )),
- };
-
- const handleSubmit = (values, { setSubmitting, setErrors }) => {
- const form = { ...values };
-
- requestSubmitInvite(form)
- .then((response) => {
- closeDialog(dialogName);
- AppToaster.show({
- message: formatMessage({
- id: 'teammate_invited_to_organization_account',
- }),
- intent: Intent.SUCCESS,
- });
- setSubmitting(false);
- queryCache.invalidateQueries('users-table');
- })
- .catch((errors) => {
- const errorsTransformed = transformApiErrors(errors);
-
- setErrors({ ...errorsTransformed });
- setSubmitting(false);
- });
- };
-
- const handleCancelBtnClick = () => {
- closeDialog('invite-user');
- };
-
return (
-
-
-
-
-
+
+
+
);
}
-
-export default compose(
- // UserFormDialogConnect,
- withDialogActions,
- withUsersActions,
-)(InviteUserDialogContent);
diff --git a/client/src/containers/Dialogs/InviteUserDialog/InviteUserForm.js b/client/src/containers/Dialogs/InviteUserDialog/InviteUserForm.js
new file mode 100644
index 000000000..7c322db10
--- /dev/null
+++ b/client/src/containers/Dialogs/InviteUserDialog/InviteUserForm.js
@@ -0,0 +1,77 @@
+import React from 'react';
+import { Formik } from 'formik';
+import { Intent } from '@blueprintjs/core';
+import { pick, snakeCase } from 'lodash';
+import { useIntl } from 'react-intl';
+import { AppToaster } from 'components';
+
+import withDialogActions from 'containers/Dialog/withDialogActions';
+
+import { InviteUserFormSchema } from './InviteUserDialog.schema';
+import InviteUserFormContent from './InviteUserFormContent';
+import { useInviteUserFormContext } from './InviteUserFormProvider';
+
+import { transformApiErrors } from './utils';
+
+import { compose, objectKeysTransform } from 'utils';
+
+function InviteUserForm({
+ // #withDialogActions
+ closeDialog,
+}) {
+ const { formatMessage } = useIntl();
+
+ const {
+ dialogName,
+ isEditMode,
+ inviteUserMutate,
+ userId,
+ } = useInviteUserFormContext();
+
+ const initialValues = {
+ status: 1,
+ ...(isEditMode &&
+ pick(
+ objectKeysTransform(userId, snakeCase),
+ Object.keys(InviteUserFormSchema.fields),
+ )),
+ };
+
+ const handleSubmit = (values, { setSubmitting, setErrors }) => {
+ const form = { ...values };
+
+ // Handle close the dialog after success response.
+ const afterSubmit = () => {
+ closeDialog(dialogName);
+ };
+ const onSuccess = ({ response }) => {
+ AppToaster.show({
+ message: formatMessage({
+ id: 'teammate_invited_to_organization_account',
+ }),
+ intent: Intent.SUCCESS,
+ });
+ afterSubmit(response);
+ };
+
+ // Handle the response error.
+ const onError = (errors) => {
+ const errorsTransformed = transformApiErrors(errors);
+
+ setErrors({ ...errorsTransformed });
+ setSubmitting(false);
+ };
+ inviteUserMutate(form).then(onSuccess).catch(onError);
+ };
+
+ return (
+
+
+
+ );
+}
+export default compose(withDialogActions)(InviteUserForm);
diff --git a/client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogForm.js b/client/src/containers/Dialogs/InviteUserDialog/InviteUserFormContent.js
similarity index 64%
rename from client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogForm.js
rename to client/src/containers/Dialogs/InviteUserDialog/InviteUserFormContent.js
index a8efbbe1f..79981128c 100644
--- a/client/src/containers/Dialogs/InviteUserDialog/InviteUserDialogForm.js
+++ b/client/src/containers/Dialogs/InviteUserDialog/InviteUserFormContent.js
@@ -1,21 +1,24 @@
import React from 'react';
-import {
- FormGroup,
- InputGroup,
- Intent,
- Button,
-} from '@blueprintjs/core';
+import { FormGroup, InputGroup, Intent, Button } from '@blueprintjs/core';
import { FastField, Form, useFormikContext, ErrorMessage } from 'formik';
import { FormattedMessage as T } from 'react-intl';
import { CLASSES } from 'common/classes';
import classNames from 'classnames';
-import { inputIntent, saveInvoke } from 'utils';
+import { inputIntent } from 'utils';
+import { useInviteUserFormContext } from './InviteUserFormProvider';
-export default function InviteUserDialogForm({ onCancelClick, action }) {
+import withDialogActions from 'containers/Dialog/withDialogActions';
+import { compose } from 'utils';
+
+function InviteUserFormContent({
+ // #withDialogActions
+ closeDialog,
+}) {
const { isSubmitting } = useFormikContext();
+ const { isEditMode, dialogName } = useInviteUserFormContext();
- const handleCancelBtnClick = (event) => {
- saveInvoke(onCancelClick, event);
+ const handleClose = () => {
+ closeDialog(dialogName);
};
return (
@@ -38,19 +41,21 @@ export default function InviteUserDialogForm({ onCancelClick, action }) {
)}
-
+
-
);
}
+
+export default compose(withDialogActions)(InviteUserFormContent);
diff --git a/client/src/containers/Dialogs/InviteUserDialog/InviteUserFormProvider.js b/client/src/containers/Dialogs/InviteUserDialog/InviteUserFormProvider.js
new file mode 100644
index 000000000..cd8c92ac7
--- /dev/null
+++ b/client/src/containers/Dialogs/InviteUserDialog/InviteUserFormProvider.js
@@ -0,0 +1,35 @@
+import React, { createContext } from 'react';
+import { useCreateInviteUser, useUsers } from 'hooks/query';
+import { DialogContent } from 'components';
+
+const InviteUserFormContext = createContext();
+
+/**
+ * Invite user Form page provider.
+ */
+function InviteUserFormProvider({ userId, isEditMode, dialogName, ...props }) {
+ // Create and edit item currency mutations.
+ const { mutateAsync: inviteUserMutate } = useCreateInviteUser();
+
+ // fetch users list.
+ const { isFetching: isUsersLoading } = useUsers();
+
+ // Provider state.
+ const provider = {
+ inviteUserMutate,
+ dialogName,
+ userId,
+ isUsersLoading,
+ isEditMode,
+ };
+
+ return (
+
+
+
+ );
+}
+
+const useInviteUserFormContext = () => React.useContext(InviteUserFormContext);
+
+export { InviteUserFormProvider, useInviteUserFormContext };
diff --git a/client/src/hooks/query/index.js b/client/src/hooks/query/index.js
index 937a0539b..640214bfd 100644
--- a/client/src/hooks/query/index.js
+++ b/client/src/hooks/query/index.js
@@ -16,4 +16,5 @@ export * from './estimates';
export * from './receipts';
export * from './paymentReceives';
export * from './paymentMades';
-export * from './settings';
\ No newline at end of file
+export * from './settings';
+export * from './users';
\ No newline at end of file
diff --git a/client/src/hooks/query/users.js b/client/src/hooks/query/users.js
new file mode 100644
index 000000000..875cdf507
--- /dev/null
+++ b/client/src/hooks/query/users.js
@@ -0,0 +1,73 @@
+import { useMutation, useQueryClient, useQuery } from 'react-query';
+import { defaultTo } from 'lodash';
+import ApiService from 'services/ApiService';
+
+/**
+ * Create a new invite user.
+ */
+export function useCreateInviteUser(props) {
+ const queryClient = useQueryClient();
+ return useMutation((values) => ApiService.post('invite/send', values), {
+ onSuccess: () => {
+ queryClient.invalidateQueries('USERS');
+ },
+ ...props,
+ });
+}
+
+/**
+ * Edits the given user.
+ *
+ */
+export function useEditUser(props) {
+ const queryClient = useQueryClient();
+
+ return useMutation(([id, values]) => ApiService.post(`users/${id}`, values), {
+ onSuccess: () => {
+ queryClient.invalidateQueries('USERS');
+ },
+ ...props,
+ });
+}
+
+/**
+ * Deletes the given user.
+ */
+export function useDeleteUser(props) {
+ const queryClient = useQueryClient();
+
+ return useMutation((id) => ApiService.delete(`users/${id}`), {
+ onSuccess: () => {
+ queryClient.invalidateQueries('USERS');
+ queryClient.invalidateQueries('USER');
+ },
+ ...props,
+ });
+}
+
+/**
+ * Retrieves users list.
+ */
+export function useUsers(props) {
+ const result = useQuery(
+ ['USERS'],
+ () => ApiService.get(`USERS`).then((response) => response.data.users),
+ props,
+ );
+
+ return {
+ ...result,
+ data: defaultTo(result.data, {}),
+ };
+}
+
+/**
+ * Retrieve details of the given user.
+ */
+export function useUser(id, props) {
+ return useQuery(
+ ['USER', id],
+ () => ApiService.get(`users/${id}`).then((response) => response.data.item),
+ props,
+ );
+}