Use mutation hooks
This commit is contained in:
parent
8170f9e14e
commit
1dd0488c62
6 changed files with 506 additions and 490 deletions
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
65
src/hooks/makeMutation.ts
Normal 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;
|
Loading…
Reference in a new issue