Use mutation hooks

This commit is contained in:
dominik-zeglen 2019-11-13 17:46:08 +01:00
parent 8170f9e14e
commit 1dd0488c62
6 changed files with 506 additions and 490 deletions

View file

@ -47,7 +47,7 @@
"moment-timezone": "^0.5.26",
"qs": "^6.9.0",
"react": "^16.9.0",
"react-apollo": "^3.0.0",
"react-apollo": "^3.1.3",
"react-dom": "^16.9.0",
"react-dropzone": "^8.2.0",
"react-error-boundary": "^1.2.5",

View file

@ -1,6 +1,6 @@
import gql from "graphql-tag";
import { TypedMutation } from "../mutations";
import makeMutation from "@saleor/hooks/makeMutation";
import { categoryDetailsFragment } from "./queries";
import {
CategoryBulkDelete,
@ -29,7 +29,7 @@ export const categoryDeleteMutation = gql`
}
}
`;
export const TypedCategoryDeleteMutation = TypedMutation<
export const useCategoryDeleteMutation = makeMutation<
CategoryDelete,
CategoryDeleteVariables
>(categoryDeleteMutation);
@ -48,7 +48,7 @@ export const categoryCreateMutation = gql`
}
}
`;
export const TypedCategoryCreateMutation = TypedMutation<
export const useCategoryCreateMutation = makeMutation<
CategoryCreate,
CategoryCreateVariables
>(categoryCreateMutation);
@ -67,7 +67,7 @@ export const categoryUpdateMutation = gql`
}
}
`;
export const TypedCategoryUpdateMutation = TypedMutation<
export const useCategoryUpdateMutation = makeMutation<
CategoryUpdate,
CategoryUpdateVariables
>(categoryUpdateMutation);
@ -82,7 +82,7 @@ export const categoryBulkDeleteMutation = gql`
}
}
`;
export const TypedCategoryBulkDeleteMutation = TypedMutation<
export const useCategoryBulkDeleteMutation = makeMutation<
CategoryBulkDelete,
CategoryBulkDeleteVariables
>(categoryBulkDeleteMutation);

View file

@ -6,7 +6,7 @@ import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { getMutationState, maybe } from "../../misc";
import CategoryCreatePage from "../components/CategoryCreatePage";
import { TypedCategoryCreateMutation } from "../mutations";
import { useCategoryCreateMutation } from "../mutations";
import { CategoryCreate } from "../types/CategoryCreate";
import { categoryListUrl, categoryUrl } from "../urls";
@ -31,55 +31,54 @@ export const CategoryCreateView: React.FC<CategoryCreateViewProps> = ({
navigate(categoryUrl(data.categoryCreate.category.id));
}
};
const [createCategory, createCategoryResult] = useCategoryCreateMutation({
onCompleted: handleSuccess
});
const errors = maybe(
() => createCategoryResult.data.categoryCreate.errors,
[]
);
const formTransitionState = getMutationState(
createCategoryResult.called,
createCategoryResult.loading,
errors
);
return (
<TypedCategoryCreateMutation onCompleted={handleSuccess}>
{(createCategory, createCategoryResult) => {
const errors = maybe(
() => createCategoryResult.data.categoryCreate.errors,
[]
);
const formTransitionState = getMutationState(
createCategoryResult.called,
createCategoryResult.loading,
errors
);
return (
<>
<WindowTitle
title={intl.formatMessage({
defaultMessage: "Create category",
description: "window title"
})}
/>
<CategoryCreatePage
saveButtonBarState={formTransitionState}
errors={errors}
disabled={createCategoryResult.loading}
onBack={() =>
navigate(parentId ? categoryUrl(parentId) : categoryListUrl())
}
onSubmit={formData =>
createCategory({
variables: {
input: {
descriptionJson: JSON.stringify(formData.description),
name: formData.name,
seo: {
description: formData.seoDescription,
title: formData.seoTitle
}
},
parent: parentId || null
}
})
}
/>
</>
);
}}
</TypedCategoryCreateMutation>
<>
<WindowTitle
title={intl.formatMessage({
defaultMessage: "Create category",
description: "window title"
})}
/>
<CategoryCreatePage
saveButtonBarState={formTransitionState}
errors={errors}
disabled={createCategoryResult.loading}
onBack={() =>
navigate(parentId ? categoryUrl(parentId) : categoryListUrl())
}
onSubmit={formData =>
createCategory({
variables: {
input: {
descriptionJson: JSON.stringify(formData.description),
name: formData.name,
seo: {
description: formData.seoDescription,
title: formData.seoTitle
}
},
parent: parentId || null
}
})
}
/>
</>
);
};
export default CategoryCreateView;

View file

@ -24,9 +24,9 @@ import {
CategoryUpdatePage
} from "../components/CategoryUpdatePage/CategoryUpdatePage";
import {
TypedCategoryBulkDeleteMutation,
TypedCategoryDeleteMutation,
TypedCategoryUpdateMutation
useCategoryBulkDeleteMutation,
useCategoryDeleteMutation,
useCategoryUpdateMutation
} from "../mutations";
import { TypedCategoryDetailsQuery } from "../queries";
import { CategoryBulkDelete } from "../types/CategoryBulkDelete";
@ -73,6 +73,11 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
navigate(categoryListUrl());
}
};
const [deleteCategory, deleteResult] = useCategoryDeleteMutation({
onCompleted: handleCategoryDelete
});
const handleCategoryUpdate = (data: CategoryUpdate) => {
if (data.categoryUpdate.errors.length > 0) {
const backgroundImageError = data.categoryUpdate.errors.find(
@ -86,6 +91,27 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
}
};
const [updateCategory, updateResult] = useCategoryUpdateMutation({
onCompleted: handleCategoryUpdate
});
const handleBulkCategoryDelete = (data: CategoryBulkDelete) => {
if (data.categoryBulkDelete.errors.length === 0) {
closeModal();
notify({
text: intl.formatMessage(commonMessages.savedChanges)
});
reset();
}
};
const [
categoryBulkDelete,
categoryBulkDeleteOpts
] = useCategoryBulkDeleteMutation({
onCompleted: handleBulkCategoryDelete
});
const changeTab = (tabName: CategoryPageTab) => {
reset();
navigate(
@ -114,329 +140,257 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
})
);
const paginationState = createPaginationState(PAGINATE_BY, params);
const formTransitionState = getMutationState(
updateResult.called,
updateResult.loading,
maybe(() => updateResult.data.categoryUpdate.errors)
);
const removeDialogTransitionState = getMutationState(
deleteResult.called,
deleteResult.loading,
maybe(() => deleteResult.data.categoryDelete.errors)
);
return (
<TypedCategoryDeleteMutation onCompleted={handleCategoryDelete}>
{(deleteCategory, deleteResult) => (
<TypedCategoryUpdateMutation onCompleted={handleCategoryUpdate}>
{(updateCategory, updateResult) => {
const paginationState = createPaginationState(PAGINATE_BY, params);
const formTransitionState = getMutationState(
updateResult.called,
updateResult.loading,
maybe(() => updateResult.data.categoryUpdate.errors)
);
const removeDialogTransitionState = getMutationState(
deleteResult.called,
deleteResult.loading,
maybe(() => deleteResult.data.categoryDelete.errors)
);
return (
<TypedCategoryDetailsQuery
displayLoader
variables={{ ...paginationState, id }}
require={["category"]}
>
{({ data, loading, refetch }) => {
const handleBulkCategoryDelete = (
data: CategoryBulkDelete
) => {
if (data.categoryBulkDelete.errors.length === 0) {
closeModal();
notify({
text: intl.formatMessage(commonMessages.savedChanges)
});
refetch();
reset();
}
};
<TypedCategoryDetailsQuery
displayLoader
variables={{ ...paginationState, id }}
require={["category"]}
>
{({ data, loading, refetch }) => {
const handleBulkProductDelete = (data: productBulkDelete) => {
if (data.productBulkDelete.errors.length === 0) {
closeModal();
notify({
text: intl.formatMessage(commonMessages.savedChanges)
});
refetch();
reset();
}
};
const handleBulkProductDelete = (data: productBulkDelete) => {
if (data.productBulkDelete.errors.length === 0) {
closeModal();
notify({
text: intl.formatMessage(commonMessages.savedChanges)
});
refetch();
reset();
}
};
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
params.activeTab === CategoryPageTab.categories
? maybe(() => data.category.children.pageInfo)
: maybe(() => data.category.products.pageInfo),
paginationState,
params
);
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
params.activeTab === CategoryPageTab.categories
? maybe(() => data.category.children.pageInfo)
: maybe(() => data.category.products.pageInfo),
paginationState,
params
);
return (
<>
<WindowTitle title={maybe(() => data.category.name)} />
<TypedProductBulkDeleteMutation
onCompleted={handleBulkProductDelete}
>
{(productBulkDelete, productBulkDeleteOpts) => {
const categoryBulkDeleteMutationState = getMutationState(
categoryBulkDeleteOpts.called,
categoryBulkDeleteOpts.loading,
maybe(
() => categoryBulkDeleteOpts.data.categoryBulkDelete.errors
)
);
const productBulkDeleteMutationState = getMutationState(
productBulkDeleteOpts.called,
productBulkDeleteOpts.loading,
maybe(
() => productBulkDeleteOpts.data.productBulkDelete.errors
)
);
return (
<>
<WindowTitle title={maybe(() => data.category.name)} />
<TypedCategoryBulkDeleteMutation
onCompleted={handleBulkCategoryDelete}
>
{(categoryBulkDelete, categoryBulkDeleteOpts) => (
<TypedProductBulkDeleteMutation
onCompleted={handleBulkProductDelete}
>
{(productBulkDelete, productBulkDeleteOpts) => {
const categoryBulkDeleteMutationState = getMutationState(
categoryBulkDeleteOpts.called,
categoryBulkDeleteOpts.loading,
maybe(
() =>
categoryBulkDeleteOpts.data
.categoryBulkDelete.errors
)
);
const productBulkDeleteMutationState = getMutationState(
productBulkDeleteOpts.called,
productBulkDeleteOpts.loading,
maybe(
() =>
productBulkDeleteOpts.data.productBulkDelete
.errors
)
);
return (
<>
<CategoryUpdatePage
changeTab={changeTab}
currentTab={params.activeTab}
category={maybe(() => data.category)}
disabled={loading}
errors={maybe(
() =>
updateResult.data.categoryUpdate.errors
)}
onAddCategory={() =>
navigate(categoryAddUrl(id))
}
onAddProduct={() => navigate(productAddUrl)}
onBack={() =>
navigate(
maybe(
() =>
categoryUrl(
data.category.parent.id
),
categoryListUrl()
)
)
}
onCategoryClick={id => () =>
navigate(categoryUrl(id))}
onDelete={() => openModal("delete")}
onImageDelete={() =>
updateCategory({
variables: {
id,
input: {
backgroundImage: null
}
}
})
}
onImageUpload={file =>
updateCategory({
variables: {
id,
input: {
backgroundImage: file
}
}
})
}
onNextPage={loadNextPage}
onPreviousPage={loadPreviousPage}
pageInfo={pageInfo}
onProductClick={id => () =>
navigate(productUrl(id))}
onSubmit={formData =>
updateCategory({
variables: {
id,
input: {
backgroundImageAlt:
formData.backgroundImageAlt,
descriptionJson: JSON.stringify(
formData.description
),
name: formData.name,
seo: {
description:
formData.seoDescription,
title: formData.seoTitle
}
}
}
})
}
products={maybe(() =>
data.category.products.edges.map(
edge => edge.node
)
)}
saveButtonBarState={formTransitionState}
subcategories={maybe(() =>
data.category.children.edges.map(
edge => edge.node
)
)}
subcategoryListToolbar={
<IconButton
color="primary"
onClick={() =>
openModal(
"delete-categories",
listElements
)
}
>
<DeleteIcon />
</IconButton>
}
productListToolbar={
<IconButton
color="primary"
onClick={() =>
openModal(
"delete-products",
listElements
)
}
>
<DeleteIcon />
</IconButton>
}
isChecked={isSelected}
selected={listElements.length}
toggle={toggle}
toggleAll={toggleAll}
/>
<ActionDialog
confirmButtonState={
removeDialogTransitionState
}
onClose={closeModal}
onConfirm={() =>
deleteCategory({ variables: { id } })
}
open={params.action === "delete"}
title={intl.formatMessage({
defaultMessage: "Delete category",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {categoryName}?"
values={{
categoryName: (
<strong>
{maybe(
() => data.category.name,
"..."
)}
</strong>
)
}}
/>
</DialogContentText>
<DialogContentText>
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
</DialogContentText>
</ActionDialog>
<ActionDialog
open={
params.action === "delete-categories" &&
maybe(() => params.ids.length > 0)
}
confirmButtonState={
categoryBulkDeleteMutationState
}
onClose={closeModal}
onConfirm={() =>
categoryBulkDelete({
variables: { ids: params.ids }
})
}
title={intl.formatMessage({
defaultMessage: "Delete categories",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?"
values={{
counter: maybe(
() => params.ids.length
),
displayQuantity: (
<strong>
{maybe(() => params.ids.length)}
</strong>
)
}}
/>
</DialogContentText>
<DialogContentText>
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
</DialogContentText>
</ActionDialog>
<ActionDialog
open={params.action === "delete-products"}
confirmButtonState={
productBulkDeleteMutationState
}
onClose={closeModal}
onConfirm={() =>
productBulkDelete({
variables: { ids: params.ids }
})
}
title={intl.formatMessage({
defaultMessage: "Delete products",
description: "dialog title"
})}
variant="delete"
>
{" "}
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}?"
values={{
counter: maybe(
() => params.ids.length
),
displayQuantity: (
<strong>
{maybe(() => params.ids.length)}
</strong>
)
}}
/>
</DialogContentText>
</ActionDialog>
</>
);
}}
</TypedProductBulkDeleteMutation>
)}
</TypedCategoryBulkDeleteMutation>
</>
);
}}
</TypedCategoryDetailsQuery>
);
}}
</TypedCategoryUpdateMutation>
)}
</TypedCategoryDeleteMutation>
return (
<>
<CategoryUpdatePage
changeTab={changeTab}
currentTab={params.activeTab}
category={maybe(() => data.category)}
disabled={loading}
errors={maybe(
() => updateResult.data.categoryUpdate.errors
)}
onAddCategory={() => navigate(categoryAddUrl(id))}
onAddProduct={() => navigate(productAddUrl)}
onBack={() =>
navigate(
maybe(
() => categoryUrl(data.category.parent.id),
categoryListUrl()
)
)
}
onCategoryClick={id => () => navigate(categoryUrl(id))}
onDelete={() => openModal("delete")}
onImageDelete={() =>
updateCategory({
variables: {
id,
input: {
backgroundImage: null
}
}
})
}
onImageUpload={file =>
updateCategory({
variables: {
id,
input: {
backgroundImage: file
}
}
})
}
onNextPage={loadNextPage}
onPreviousPage={loadPreviousPage}
pageInfo={pageInfo}
onProductClick={id => () => navigate(productUrl(id))}
onSubmit={formData =>
updateCategory({
variables: {
id,
input: {
backgroundImageAlt: formData.backgroundImageAlt,
descriptionJson: JSON.stringify(
formData.description
),
name: formData.name,
seo: {
description: formData.seoDescription,
title: formData.seoTitle
}
}
}
})
}
products={maybe(() =>
data.category.products.edges.map(edge => edge.node)
)}
saveButtonBarState={formTransitionState}
subcategories={maybe(() =>
data.category.children.edges.map(edge => edge.node)
)}
subcategoryListToolbar={
<IconButton
color="primary"
onClick={() =>
openModal("delete-categories", listElements)
}
>
<DeleteIcon />
</IconButton>
}
productListToolbar={
<IconButton
color="primary"
onClick={() =>
openModal("delete-products", listElements)
}
>
<DeleteIcon />
</IconButton>
}
isChecked={isSelected}
selected={listElements.length}
toggle={toggle}
toggleAll={toggleAll}
/>
<ActionDialog
confirmButtonState={removeDialogTransitionState}
onClose={closeModal}
onConfirm={() => deleteCategory({ variables: { id } })}
open={params.action === "delete"}
title={intl.formatMessage({
defaultMessage: "Delete category",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {categoryName}?"
values={{
categoryName: (
<strong>
{maybe(() => data.category.name, "...")}
</strong>
)
}}
/>
</DialogContentText>
<DialogContentText>
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
</DialogContentText>
</ActionDialog>
<ActionDialog
open={
params.action === "delete-categories" &&
maybe(() => params.ids.length > 0)
}
confirmButtonState={categoryBulkDeleteMutationState}
onClose={closeModal}
onConfirm={() =>
categoryBulkDelete({
variables: { ids: params.ids }
}).then(() => refetch())
}
title={intl.formatMessage({
defaultMessage: "Delete categories",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?"
values={{
counter: maybe(() => params.ids.length),
displayQuantity: (
<strong>{maybe(() => params.ids.length)}</strong>
)
}}
/>
</DialogContentText>
<DialogContentText>
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
</DialogContentText>
</ActionDialog>
<ActionDialog
open={params.action === "delete-products"}
confirmButtonState={productBulkDeleteMutationState}
onClose={closeModal}
onConfirm={() =>
productBulkDelete({
variables: { ids: params.ids }
}).then(() => refetch())
}
title={intl.formatMessage({
defaultMessage: "Delete products",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}?"
values={{
counter: maybe(() => params.ids.length),
displayQuantity: (
<strong>{maybe(() => params.ids.length)}</strong>
)
}}
/>
</DialogContentText>
</ActionDialog>
</>
);
}}
</TypedProductBulkDeleteMutation>
</>
);
}}
</TypedCategoryDetailsQuery>
);
};
export default CategoryDetails;

View file

@ -18,7 +18,7 @@ import usePaginator, {
import { getMutationState, maybe } from "@saleor/misc";
import { ListViews } from "@saleor/types";
import { CategoryListPage } from "../../components/CategoryListPage/CategoryListPage";
import { TypedCategoryBulkDeleteMutation } from "../../mutations";
import { useCategoryBulkDeleteMutation } from "../../mutations";
import { TypedRootCategoriesQuery } from "../../queries";
import { CategoryBulkDelete } from "../../types/CategoryBulkDelete";
import {
@ -138,120 +138,118 @@ export const CategoryList: React.FC<CategoryListProps> = ({ params }) => {
reset();
}
};
return (
<TypedCategoryBulkDeleteMutation
onCompleted={handleCategoryBulkDelete}
>
{(categoryBulkDelete, categoryBulkDeleteOpts) => {
const bulkDeleteState = getMutationState(
categoryBulkDeleteOpts.called,
categoryBulkDeleteOpts.loading,
maybe(
() => categoryBulkDeleteOpts.data.categoryBulkDelete.errors
)
);
return (
<>
<CategoryListPage
categories={maybe(
() => data.categories.edges.map(edge => edge.node),
[]
)}
currentTab={currentTab}
initialSearch={params.query || ""}
onSearchChange={query => changeFilterField({ query })}
onAll={() => navigate(categoryListUrl())}
onTabChange={handleTabChange}
onTabDelete={() => openModal("delete-search")}
onTabSave={() => openModal("save-search")}
tabs={tabs.map(tab => tab.name)}
settings={settings}
onAdd={() => navigate(categoryAddUrl())}
onRowClick={id => () => navigate(categoryUrl(id))}
disabled={loading}
onNextPage={loadNextPage}
onPreviousPage={loadPreviousPage}
onUpdateListSettings={updateListSettings}
pageInfo={pageInfo}
isChecked={isSelected}
selected={listElements.length}
toggle={toggle}
toggleAll={toggleAll}
toolbar={
<IconButton
color="primary"
onClick={() =>
navigate(
categoryListUrl({
...params,
action: "delete",
ids: listElements
})
)
}
>
<DeleteIcon />
</IconButton>
}
/>
<ActionDialog
confirmButtonState={bulkDeleteState}
onClose={() =>
navigate(
categoryListUrl({
...params,
action: undefined,
ids: undefined
})
)
}
onConfirm={() =>
categoryBulkDelete({
variables: {
ids: params.ids
}
const [
categoryBulkDelete,
categoryBulkDeleteOpts
] = useCategoryBulkDeleteMutation({
onCompleted: handleCategoryBulkDelete
});
const bulkDeleteState = getMutationState(
categoryBulkDeleteOpts.called,
categoryBulkDeleteOpts.loading,
maybe(() => categoryBulkDeleteOpts.data.categoryBulkDelete.errors)
);
return (
<>
<CategoryListPage
categories={maybe(
() => data.categories.edges.map(edge => edge.node),
[]
)}
currentTab={currentTab}
initialSearch={params.query || ""}
onSearchChange={query => changeFilterField({ query })}
onAll={() => navigate(categoryListUrl())}
onTabChange={handleTabChange}
onTabDelete={() => openModal("delete-search")}
onTabSave={() => openModal("save-search")}
tabs={tabs.map(tab => tab.name)}
settings={settings}
onAdd={() => navigate(categoryAddUrl())}
onRowClick={id => () => navigate(categoryUrl(id))}
disabled={loading}
onNextPage={loadNextPage}
onPreviousPage={loadPreviousPage}
onUpdateListSettings={updateListSettings}
pageInfo={pageInfo}
isChecked={isSelected}
selected={listElements.length}
toggle={toggle}
toggleAll={toggleAll}
toolbar={
<IconButton
color="primary"
onClick={() =>
navigate(
categoryListUrl({
...params,
action: "delete",
ids: listElements
})
}
open={params.action === "delete"}
title={intl.formatMessage({
defaultMessage: "Delete categories",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?"
values={{
counter: maybe(() => params.ids.length),
displayQuantity: (
<strong>{maybe(() => params.ids.length)}</strong>
)
}}
/>
</DialogContentText>
<DialogContentText>
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
</DialogContentText>
</ActionDialog>
<SaveFilterTabDialog
open={params.action === "save-search"}
confirmButtonState="default"
onClose={closeModal}
onSubmit={handleTabSave}
/>
<DeleteFilterTabDialog
open={params.action === "delete-search"}
confirmButtonState="default"
onClose={closeModal}
onSubmit={handleTabDelete}
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
/>
</>
);
}}
</TypedCategoryBulkDeleteMutation>
)
}
>
<DeleteIcon />
</IconButton>
}
/>
<ActionDialog
confirmButtonState={bulkDeleteState}
onClose={() =>
navigate(
categoryListUrl({
...params,
action: undefined,
ids: undefined
})
)
}
onConfirm={() =>
categoryBulkDelete({
variables: {
ids: params.ids
}
})
}
open={params.action === "delete"}
title={intl.formatMessage({
defaultMessage: "Delete categories",
description: "dialog title"
})}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?"
values={{
counter: maybe(() => params.ids.length),
displayQuantity: (
<strong>{maybe(() => params.ids.length)}</strong>
)
}}
/>
</DialogContentText>
<DialogContentText>
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
</DialogContentText>
</ActionDialog>
<SaveFilterTabDialog
open={params.action === "save-search"}
confirmButtonState="default"
onClose={closeModal}
onSubmit={handleTabSave}
/>
<DeleteFilterTabDialog
open={params.action === "delete-search"}
confirmButtonState="default"
onClose={closeModal}
onSubmit={handleTabDelete}
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
/>
</>
);
}}
</TypedRootCategoriesQuery>

65
src/hooks/makeMutation.ts Normal file
View file

@ -0,0 +1,65 @@
import { ApolloError } from "apollo-client";
import { DocumentNode } from "graphql";
import {
MutationFunction,
MutationResult,
useMutation as useBaseMutation
} from "react-apollo";
import { useIntl } from "react-intl";
import { commonMessages } from "@saleor/intl";
import { maybe } from "@saleor/misc";
import useNotifier from "./useNotifier";
type UseMutation<TData, TVariables> = [
MutationFunction<TData, TVariables>,
MutationResult<TData>
];
type UseMutationCbs<TData> = Partial<{
onCompleted: (data: TData) => void;
onError: (error: ApolloError) => void;
}>;
type UseMutationHook<TData, TVariables> = (
cbs: UseMutationCbs<TData>
) => UseMutation<TData, TVariables>;
function makeMutation<TData, TVariables>(
mutation: DocumentNode
): UseMutationHook<TData, TVariables> {
function useMutation<TData, TVariables>({
onCompleted,
onError
}: UseMutationCbs<TData>): UseMutation<TData, TVariables> {
const notify = useNotifier();
const intl = useIntl();
const [mutateFn, result] = useBaseMutation(mutation, {
onCompleted,
onError: (err: ApolloError) => {
if (
maybe(
() =>
err.graphQLErrors[0].extensions.exception.code ===
"ReadOnlyException"
)
) {
notify({
text: intl.formatMessage(commonMessages.readOnly)
});
} else {
notify({
text: intl.formatMessage(commonMessages.somethingWentWrong)
});
}
if (onError) {
onError(err);
}
}
});
return [mutateFn, result];
}
return useMutation;
}
export default makeMutation;