Merge pull request #667 from mirumee/ref/product-update-hooks
Use hooks instead of containers with render props in product mutations
This commit is contained in:
commit
03f03d436b
13 changed files with 1156 additions and 1479 deletions
|
@ -27,6 +27,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
||||||
- Add warehouse choice - #646 by @dominik-zeglen
|
- Add warehouse choice - #646 by @dominik-zeglen
|
||||||
- Fix user management modal actions - #637 by @eaglesemanation
|
- Fix user management modal actions - #637 by @eaglesemanation
|
||||||
- Fix navigator button rendering on safari browser - #656 by @dominik-zeglen
|
- Fix navigator button rendering on safari browser - #656 by @dominik-zeglen
|
||||||
|
- Use hooks instead of containers with render props in product mutations - #667 by @dominik-zeglen
|
||||||
|
|
||||||
## 2.10.1
|
## 2.10.1
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,7 @@ import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { PAGINATE_BY } from "../../config";
|
import { PAGINATE_BY } from "../../config";
|
||||||
import { maybe } from "../../misc";
|
import { maybe } from "../../misc";
|
||||||
import { TypedProductBulkDeleteMutation } from "../../products/mutations";
|
import { useProductBulkDeleteMutation } from "../../products/mutations";
|
||||||
import { productBulkDelete } from "../../products/types/productBulkDelete";
|
|
||||||
import { productAddUrl, productUrl } from "../../products/urls";
|
import { productAddUrl, productUrl } from "../../products/urls";
|
||||||
import { CategoryInput } from "../../types/globalTypes";
|
import { CategoryInput } from "../../types/globalTypes";
|
||||||
import {
|
import {
|
||||||
|
@ -129,6 +128,23 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
|
||||||
onCompleted: handleBulkCategoryDelete
|
onCompleted: handleBulkCategoryDelete
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [
|
||||||
|
productBulkDelete,
|
||||||
|
productBulkDeleteOpts
|
||||||
|
] = useProductBulkDeleteMutation({
|
||||||
|
onCompleted: data => {
|
||||||
|
if (data.productBulkDelete.errors.length === 0) {
|
||||||
|
closeModal();
|
||||||
|
notify({
|
||||||
|
status: "success",
|
||||||
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const changeTab = (tabName: CategoryPageTab) => {
|
const changeTab = (tabName: CategoryPageTab) => {
|
||||||
reset();
|
reset();
|
||||||
navigate(
|
navigate(
|
||||||
|
@ -143,18 +159,6 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
|
||||||
CategoryUrlQueryParams
|
CategoryUrlQueryParams
|
||||||
>(navigate, params => categoryUrl(id, params), params);
|
>(navigate, params => categoryUrl(id, params), params);
|
||||||
|
|
||||||
const handleBulkProductDelete = (data: productBulkDelete) => {
|
|
||||||
if (data.productBulkDelete.errors.length === 0) {
|
|
||||||
closeModal();
|
|
||||||
notify({
|
|
||||||
status: "success",
|
|
||||||
text: intl.formatMessage(commonMessages.savedChanges)
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
params.activeTab === CategoryPageTab.categories
|
params.activeTab === CategoryPageTab.categories
|
||||||
? maybe(() => data.category.children.pageInfo)
|
? maybe(() => data.category.children.pageInfo)
|
||||||
|
@ -166,9 +170,6 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WindowTitle title={maybe(() => data.category.name)} />
|
<WindowTitle title={maybe(() => data.category.name)} />
|
||||||
<TypedProductBulkDeleteMutation onCompleted={handleBulkProductDelete}>
|
|
||||||
{(productBulkDelete, productBulkDeleteOpts) => (
|
|
||||||
<>
|
|
||||||
<CategoryUpdatePage
|
<CategoryUpdatePage
|
||||||
changeTab={changeTab}
|
changeTab={changeTab}
|
||||||
currentTab={params.activeTab}
|
currentTab={params.activeTab}
|
||||||
|
@ -179,10 +180,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
|
||||||
onAddProduct={() => navigate(productAddUrl)}
|
onAddProduct={() => navigate(productAddUrl)}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
maybe(
|
maybe(() => categoryUrl(data.category.parent.id), categoryListUrl())
|
||||||
() => categoryUrl(data.category.parent.id),
|
|
||||||
categoryListUrl()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onCategoryClick={id => () => navigate(categoryUrl(id))}
|
onCategoryClick={id => () => navigate(categoryUrl(id))}
|
||||||
|
@ -311,9 +309,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
|
||||||
defaultMessage="{counter,plural,one{Are you sure you want to delete this category?} other{Are you sure you want to delete {displayQuantity} categories?}}"
|
defaultMessage="{counter,plural,one{Are you sure you want to delete this category?} other{Are you sure you want to delete {displayQuantity} categories?}}"
|
||||||
values={{
|
values={{
|
||||||
counter: maybe(() => params.ids.length),
|
counter: maybe(() => params.ids.length),
|
||||||
displayQuantity: (
|
displayQuantity: <strong>{maybe(() => params.ids.length)}</strong>
|
||||||
<strong>{maybe(() => params.ids.length)}</strong>
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
@ -341,17 +337,12 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
|
||||||
defaultMessage="{counter,plural,one{Are you sure you want to delete this product?} other{Are you sure you want to delete {displayQuantity} products?}}"
|
defaultMessage="{counter,plural,one{Are you sure you want to delete this product?} other{Are you sure you want to delete {displayQuantity} products?}}"
|
||||||
values={{
|
values={{
|
||||||
counter: maybe(() => params.ids.length),
|
counter: maybe(() => params.ids.length),
|
||||||
displayQuantity: (
|
displayQuantity: <strong>{maybe(() => params.ids.length)}</strong>
|
||||||
<strong>{maybe(() => params.ids.length)}</strong>
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
</>
|
</>
|
||||||
)}
|
|
||||||
</TypedProductBulkDeleteMutation>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default CategoryDetails;
|
export default CategoryDetails;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { TypedMutationInnerProps } from "../../mutations";
|
import { TypedMutationInnerProps } from "../../mutations";
|
||||||
import { TypedProductImagesReorder } from "../mutations";
|
import { useProductImagesReorder } from "../mutations";
|
||||||
import {
|
import {
|
||||||
ProductImageReorder,
|
ProductImageReorder,
|
||||||
ProductImageReorderVariables
|
ProductImageReorderVariables
|
||||||
|
@ -24,10 +24,12 @@ const ProductImagesReorderProvider: React.FC<ProductImagesReorderProviderProps>
|
||||||
productId,
|
productId,
|
||||||
productImages,
|
productImages,
|
||||||
...mutationProps
|
...mutationProps
|
||||||
}) => (
|
}) => {
|
||||||
<TypedProductImagesReorder {...mutationProps}>
|
const [mutate, mutationResult] = useProductImagesReorder(mutationProps);
|
||||||
{(mutate, mutationResult) =>
|
|
||||||
children(opts => {
|
return (
|
||||||
|
<>
|
||||||
|
{children(opts => {
|
||||||
const productImagesMap = productImages.reduce((prev, curr) => {
|
const productImagesMap = productImages.reduce((prev, curr) => {
|
||||||
prev[curr.id] = curr;
|
prev[curr.id] = curr;
|
||||||
return prev;
|
return prev;
|
||||||
|
@ -52,9 +54,9 @@ const ProductImagesReorderProvider: React.FC<ProductImagesReorderProviderProps>
|
||||||
...opts,
|
...opts,
|
||||||
optimisticResponse
|
optimisticResponse
|
||||||
});
|
});
|
||||||
}, mutationResult)
|
}, mutationResult)}
|
||||||
}
|
</>
|
||||||
</TypedProductImagesReorder>
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default ProductImagesReorderProvider;
|
export default ProductImagesReorderProvider;
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { getMutationProviderData, maybe } from "../../misc";
|
|
||||||
import { PartialMutationProviderOutput } from "../../types";
|
|
||||||
import {
|
|
||||||
TypedProductDeleteMutation,
|
|
||||||
TypedProductImageCreateMutation,
|
|
||||||
TypedProductImageDeleteMutation,
|
|
||||||
TypedProductUpdateMutation,
|
|
||||||
TypedProductVariantBulkDeleteMutation,
|
|
||||||
TypedSimpleProductUpdateMutation
|
|
||||||
} from "../mutations";
|
|
||||||
import { ProductDelete, ProductDeleteVariables } from "../types/ProductDelete";
|
|
||||||
import { ProductDetails_product } from "../types/ProductDetails";
|
|
||||||
import {
|
|
||||||
ProductImageCreate,
|
|
||||||
ProductImageCreateVariables
|
|
||||||
} from "../types/ProductImageCreate";
|
|
||||||
import {
|
|
||||||
ProductImageDelete,
|
|
||||||
ProductImageDeleteVariables
|
|
||||||
} from "../types/ProductImageDelete";
|
|
||||||
import {
|
|
||||||
ProductImageReorder,
|
|
||||||
ProductImageReorderVariables
|
|
||||||
} from "../types/ProductImageReorder";
|
|
||||||
import { ProductUpdate, ProductUpdateVariables } from "../types/ProductUpdate";
|
|
||||||
import {
|
|
||||||
ProductVariantBulkDelete,
|
|
||||||
ProductVariantBulkDeleteVariables
|
|
||||||
} from "../types/ProductVariantBulkDelete";
|
|
||||||
import {
|
|
||||||
SimpleProductUpdate,
|
|
||||||
SimpleProductUpdateVariables
|
|
||||||
} from "../types/SimpleProductUpdate";
|
|
||||||
import ProductImagesReorderProvider from "./ProductImagesReorder";
|
|
||||||
|
|
||||||
interface ProductUpdateOperationsProps {
|
|
||||||
product: ProductDetails_product;
|
|
||||||
children: (props: {
|
|
||||||
bulkProductVariantDelete: PartialMutationProviderOutput<
|
|
||||||
ProductVariantBulkDelete,
|
|
||||||
ProductVariantBulkDeleteVariables
|
|
||||||
>;
|
|
||||||
createProductImage: PartialMutationProviderOutput<
|
|
||||||
ProductImageCreate,
|
|
||||||
ProductImageCreateVariables
|
|
||||||
>;
|
|
||||||
deleteProduct: PartialMutationProviderOutput<
|
|
||||||
ProductDelete,
|
|
||||||
ProductDeleteVariables
|
|
||||||
>;
|
|
||||||
deleteProductImage: PartialMutationProviderOutput<
|
|
||||||
ProductImageDelete,
|
|
||||||
ProductImageDeleteVariables
|
|
||||||
>;
|
|
||||||
reorderProductImages: PartialMutationProviderOutput<
|
|
||||||
ProductImageReorder,
|
|
||||||
ProductImageReorderVariables
|
|
||||||
>;
|
|
||||||
updateProduct: PartialMutationProviderOutput<
|
|
||||||
ProductUpdate,
|
|
||||||
ProductUpdateVariables
|
|
||||||
>;
|
|
||||||
updateSimpleProduct: PartialMutationProviderOutput<
|
|
||||||
SimpleProductUpdate,
|
|
||||||
SimpleProductUpdateVariables
|
|
||||||
>;
|
|
||||||
}) => React.ReactNode;
|
|
||||||
onBulkProductVariantDelete?: (data: ProductVariantBulkDelete) => void;
|
|
||||||
onDelete?: (data: ProductDelete) => void;
|
|
||||||
onImageCreate?: (data: ProductImageCreate) => void;
|
|
||||||
onImageDelete?: (data: ProductImageDelete) => void;
|
|
||||||
onImageReorder?: (data: ProductImageReorder) => void;
|
|
||||||
onUpdate?: (data: ProductUpdate) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProductUpdateOperations: React.FC<ProductUpdateOperationsProps> = ({
|
|
||||||
product,
|
|
||||||
children,
|
|
||||||
onBulkProductVariantDelete,
|
|
||||||
onDelete,
|
|
||||||
onImageDelete,
|
|
||||||
onImageCreate,
|
|
||||||
onImageReorder,
|
|
||||||
onUpdate
|
|
||||||
}) => {
|
|
||||||
const productId = product ? product.id : "";
|
|
||||||
return (
|
|
||||||
<TypedProductUpdateMutation onCompleted={onUpdate}>
|
|
||||||
{(...updateProduct) => (
|
|
||||||
<ProductImagesReorderProvider
|
|
||||||
productId={productId}
|
|
||||||
productImages={maybe(() => product.images, [])}
|
|
||||||
onCompleted={onImageReorder}
|
|
||||||
>
|
|
||||||
{(...reorderProductImages) => (
|
|
||||||
<TypedProductImageCreateMutation onCompleted={onImageCreate}>
|
|
||||||
{(...createProductImage) => (
|
|
||||||
<TypedProductDeleteMutation onCompleted={onDelete}>
|
|
||||||
{(...deleteProduct) => (
|
|
||||||
<TypedProductImageDeleteMutation
|
|
||||||
onCompleted={onImageDelete}
|
|
||||||
>
|
|
||||||
{(...deleteProductImage) => (
|
|
||||||
<TypedSimpleProductUpdateMutation
|
|
||||||
onCompleted={onUpdate}
|
|
||||||
>
|
|
||||||
{(...updateSimpleProduct) => (
|
|
||||||
<TypedProductVariantBulkDeleteMutation
|
|
||||||
onCompleted={onBulkProductVariantDelete}
|
|
||||||
>
|
|
||||||
{(...bulkProductVariantDelete) =>
|
|
||||||
children({
|
|
||||||
bulkProductVariantDelete: getMutationProviderData(
|
|
||||||
...bulkProductVariantDelete
|
|
||||||
),
|
|
||||||
createProductImage: getMutationProviderData(
|
|
||||||
...createProductImage
|
|
||||||
),
|
|
||||||
deleteProduct: getMutationProviderData(
|
|
||||||
...deleteProduct
|
|
||||||
),
|
|
||||||
deleteProductImage: getMutationProviderData(
|
|
||||||
...deleteProductImage
|
|
||||||
),
|
|
||||||
reorderProductImages: getMutationProviderData(
|
|
||||||
...reorderProductImages
|
|
||||||
),
|
|
||||||
updateProduct: getMutationProviderData(
|
|
||||||
...updateProduct
|
|
||||||
),
|
|
||||||
updateSimpleProduct: getMutationProviderData(
|
|
||||||
...updateSimpleProduct
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TypedProductVariantBulkDeleteMutation>
|
|
||||||
)}
|
|
||||||
</TypedSimpleProductUpdateMutation>
|
|
||||||
)}
|
|
||||||
</TypedProductImageDeleteMutation>
|
|
||||||
)}
|
|
||||||
</TypedProductDeleteMutation>
|
|
||||||
)}
|
|
||||||
</TypedProductImageCreateMutation>
|
|
||||||
)}
|
|
||||||
</ProductImagesReorderProvider>
|
|
||||||
)}
|
|
||||||
</TypedProductUpdateMutation>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default ProductUpdateOperations;
|
|
|
@ -1,77 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { getMutationProviderData } from "../../misc";
|
|
||||||
import { PartialMutationProviderOutput } from "../../types";
|
|
||||||
import {
|
|
||||||
TypedVariantDeleteMutation,
|
|
||||||
TypedVariantImageAssignMutation,
|
|
||||||
TypedVariantImageUnassignMutation,
|
|
||||||
TypedVariantUpdateMutation
|
|
||||||
} from "../mutations";
|
|
||||||
import { VariantDelete, VariantDeleteVariables } from "../types/VariantDelete";
|
|
||||||
import {
|
|
||||||
VariantImageAssign,
|
|
||||||
VariantImageAssignVariables
|
|
||||||
} from "../types/VariantImageAssign";
|
|
||||||
import {
|
|
||||||
VariantImageUnassign,
|
|
||||||
VariantImageUnassignVariables
|
|
||||||
} from "../types/VariantImageUnassign";
|
|
||||||
import { VariantUpdate, VariantUpdateVariables } from "../types/VariantUpdate";
|
|
||||||
|
|
||||||
interface VariantDeleteOperationsProps {
|
|
||||||
children: (props: {
|
|
||||||
deleteVariant: PartialMutationProviderOutput<
|
|
||||||
VariantDelete,
|
|
||||||
VariantDeleteVariables
|
|
||||||
>;
|
|
||||||
updateVariant: PartialMutationProviderOutput<
|
|
||||||
VariantUpdate,
|
|
||||||
VariantUpdateVariables
|
|
||||||
>;
|
|
||||||
assignImage: PartialMutationProviderOutput<
|
|
||||||
VariantImageAssign,
|
|
||||||
VariantImageAssignVariables
|
|
||||||
>;
|
|
||||||
unassignImage: PartialMutationProviderOutput<
|
|
||||||
VariantImageUnassign,
|
|
||||||
VariantImageUnassignVariables
|
|
||||||
>;
|
|
||||||
}) => React.ReactNode;
|
|
||||||
onDelete?: (data: VariantDelete) => void;
|
|
||||||
onImageAssign?: (data: VariantImageAssign) => void;
|
|
||||||
onImageUnassign?: (data: VariantImageUnassign) => void;
|
|
||||||
onUpdate?: (data: VariantUpdate) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const VariantUpdateOperations: React.FC<VariantDeleteOperationsProps> = ({
|
|
||||||
children,
|
|
||||||
onDelete,
|
|
||||||
onUpdate,
|
|
||||||
onImageAssign,
|
|
||||||
onImageUnassign
|
|
||||||
}) => (
|
|
||||||
<TypedVariantImageAssignMutation onCompleted={onImageAssign}>
|
|
||||||
{(...assignImage) => (
|
|
||||||
<TypedVariantImageUnassignMutation onCompleted={onImageUnassign}>
|
|
||||||
{(...unassignImage) => (
|
|
||||||
<TypedVariantUpdateMutation onCompleted={onUpdate}>
|
|
||||||
{(...updateVariant) => (
|
|
||||||
<TypedVariantDeleteMutation onCompleted={onDelete}>
|
|
||||||
{(...deleteVariant) =>
|
|
||||||
children({
|
|
||||||
assignImage: getMutationProviderData(...assignImage),
|
|
||||||
deleteVariant: getMutationProviderData(...deleteVariant),
|
|
||||||
unassignImage: getMutationProviderData(...unassignImage),
|
|
||||||
updateVariant: getMutationProviderData(...updateVariant)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TypedVariantDeleteMutation>
|
|
||||||
)}
|
|
||||||
</TypedVariantUpdateMutation>
|
|
||||||
)}
|
|
||||||
</TypedVariantImageUnassignMutation>
|
|
||||||
)}
|
|
||||||
</TypedVariantImageAssignMutation>
|
|
||||||
);
|
|
||||||
export default VariantUpdateOperations;
|
|
|
@ -13,7 +13,6 @@ import {
|
||||||
import makeMutation from "@saleor/hooks/makeMutation";
|
import makeMutation from "@saleor/hooks/makeMutation";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
import { TypedMutation } from "../mutations";
|
|
||||||
import {
|
import {
|
||||||
productBulkDelete,
|
productBulkDelete,
|
||||||
productBulkDeleteVariables
|
productBulkDeleteVariables
|
||||||
|
@ -80,7 +79,7 @@ export const productImageCreateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductImageCreateMutation = TypedMutation<
|
export const useProductImageCreateMutation = makeMutation<
|
||||||
ProductImageCreate,
|
ProductImageCreate,
|
||||||
ProductImageCreateVariables
|
ProductImageCreateVariables
|
||||||
>(productImageCreateMutation);
|
>(productImageCreateMutation);
|
||||||
|
@ -98,7 +97,7 @@ export const productDeleteMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductDeleteMutation = TypedMutation<
|
export const useProductDeleteMutation = makeMutation<
|
||||||
ProductDelete,
|
ProductDelete,
|
||||||
ProductDeleteVariables
|
ProductDeleteVariables
|
||||||
>(productDeleteMutation);
|
>(productDeleteMutation);
|
||||||
|
@ -122,7 +121,7 @@ export const productImagesReorder = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductImagesReorder = TypedMutation<
|
export const useProductImagesReorder = makeMutation<
|
||||||
ProductImageReorder,
|
ProductImageReorder,
|
||||||
ProductImageReorderVariables
|
ProductImageReorderVariables
|
||||||
>(productImagesReorder);
|
>(productImagesReorder);
|
||||||
|
@ -167,7 +166,7 @@ export const productUpdateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductUpdateMutation = TypedMutation<
|
export const useProductUpdateMutation = makeMutation<
|
||||||
ProductUpdate,
|
ProductUpdate,
|
||||||
ProductUpdateVariables
|
ProductUpdateVariables
|
||||||
>(productUpdateMutation);
|
>(productUpdateMutation);
|
||||||
|
@ -263,7 +262,7 @@ export const simpleProductUpdateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedSimpleProductUpdateMutation = TypedMutation<
|
export const useSimpleProductUpdateMutation = makeMutation<
|
||||||
SimpleProductUpdate,
|
SimpleProductUpdate,
|
||||||
SimpleProductUpdateVariables
|
SimpleProductUpdateVariables
|
||||||
>(simpleProductUpdateMutation);
|
>(simpleProductUpdateMutation);
|
||||||
|
@ -316,7 +315,7 @@ export const productCreateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductCreateMutation = TypedMutation<
|
export const useProductCreateMutation = makeMutation<
|
||||||
ProductCreate,
|
ProductCreate,
|
||||||
ProductCreateVariables
|
ProductCreateVariables
|
||||||
>(productCreateMutation);
|
>(productCreateMutation);
|
||||||
|
@ -334,7 +333,7 @@ export const variantDeleteMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedVariantDeleteMutation = TypedMutation<
|
export const useVariantDeleteMutation = makeMutation<
|
||||||
VariantDelete,
|
VariantDelete,
|
||||||
VariantDeleteVariables
|
VariantDeleteVariables
|
||||||
>(variantDeleteMutation);
|
>(variantDeleteMutation);
|
||||||
|
@ -406,7 +405,7 @@ export const variantUpdateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedVariantUpdateMutation = TypedMutation<
|
export const useVariantUpdateMutation = makeMutation<
|
||||||
VariantUpdate,
|
VariantUpdate,
|
||||||
VariantUpdateVariables
|
VariantUpdateVariables
|
||||||
>(variantUpdateMutation);
|
>(variantUpdateMutation);
|
||||||
|
@ -425,7 +424,7 @@ export const variantCreateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedVariantCreateMutation = TypedMutation<
|
export const useVariantCreateMutation = makeMutation<
|
||||||
VariantCreate,
|
VariantCreate,
|
||||||
VariantCreateVariables
|
VariantCreateVariables
|
||||||
>(variantCreateMutation);
|
>(variantCreateMutation);
|
||||||
|
@ -446,7 +445,7 @@ export const productImageDeleteMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductImageDeleteMutation = TypedMutation<
|
export const useProductImageDeleteMutation = makeMutation<
|
||||||
ProductImageDelete,
|
ProductImageDelete,
|
||||||
ProductImageDeleteVariables
|
ProductImageDeleteVariables
|
||||||
>(productImageDeleteMutation);
|
>(productImageDeleteMutation);
|
||||||
|
@ -465,7 +464,7 @@ export const productImageUpdateMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductImageUpdateMutation = TypedMutation<
|
export const useProductImageUpdateMutation = makeMutation<
|
||||||
ProductImageUpdate,
|
ProductImageUpdate,
|
||||||
ProductImageUpdateVariables
|
ProductImageUpdateVariables
|
||||||
>(productImageUpdateMutation);
|
>(productImageUpdateMutation);
|
||||||
|
@ -484,7 +483,7 @@ export const variantImageAssignMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedVariantImageAssignMutation = TypedMutation<
|
export const useVariantImageAssignMutation = makeMutation<
|
||||||
VariantImageAssign,
|
VariantImageAssign,
|
||||||
VariantImageAssignVariables
|
VariantImageAssignVariables
|
||||||
>(variantImageAssignMutation);
|
>(variantImageAssignMutation);
|
||||||
|
@ -503,7 +502,7 @@ export const variantImageUnassignMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedVariantImageUnassignMutation = TypedMutation<
|
export const useVariantImageUnassignMutation = makeMutation<
|
||||||
VariantImageUnassign,
|
VariantImageUnassign,
|
||||||
VariantImageUnassignVariables
|
VariantImageUnassignVariables
|
||||||
>(variantImageUnassignMutation);
|
>(variantImageUnassignMutation);
|
||||||
|
@ -518,7 +517,7 @@ export const productBulkDeleteMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductBulkDeleteMutation = TypedMutation<
|
export const useProductBulkDeleteMutation = makeMutation<
|
||||||
productBulkDelete,
|
productBulkDelete,
|
||||||
productBulkDeleteVariables
|
productBulkDeleteVariables
|
||||||
>(productBulkDeleteMutation);
|
>(productBulkDeleteMutation);
|
||||||
|
@ -533,7 +532,7 @@ export const productBulkPublishMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductBulkPublishMutation = TypedMutation<
|
export const useProductBulkPublishMutation = makeMutation<
|
||||||
productBulkPublish,
|
productBulkPublish,
|
||||||
productBulkPublishVariables
|
productBulkPublishVariables
|
||||||
>(productBulkPublishMutation);
|
>(productBulkPublishMutation);
|
||||||
|
@ -566,7 +565,7 @@ export const ProductVariantBulkDeleteMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductVariantBulkDeleteMutation = TypedMutation<
|
export const useProductVariantBulkDeleteMutation = makeMutation<
|
||||||
ProductVariantBulkDelete,
|
ProductVariantBulkDelete,
|
||||||
ProductVariantBulkDeleteVariables
|
ProductVariantBulkDeleteVariables
|
||||||
>(ProductVariantBulkDeleteMutation);
|
>(ProductVariantBulkDeleteMutation);
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { warehouseFragment } from "@saleor/fragments/warehouses";
|
||||||
import makeQuery from "@saleor/hooks/makeQuery";
|
import makeQuery from "@saleor/hooks/makeQuery";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
import { TypedQuery } from "../queries";
|
|
||||||
import { CountAllProducts } from "./types/CountAllProducts";
|
import { CountAllProducts } from "./types/CountAllProducts";
|
||||||
import {
|
import {
|
||||||
CreateMultipleVariantsData,
|
CreateMultipleVariantsData,
|
||||||
|
@ -150,10 +149,9 @@ const productListQuery = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductListQuery = TypedQuery<
|
export const useProductListQuery = makeQuery<ProductList, ProductListVariables>(
|
||||||
ProductList,
|
productListQuery
|
||||||
ProductListVariables
|
);
|
||||||
>(productListQuery);
|
|
||||||
|
|
||||||
const countAllProductsQuery = gql`
|
const countAllProductsQuery = gql`
|
||||||
query CountAllProducts {
|
query CountAllProducts {
|
||||||
|
@ -174,7 +172,7 @@ const productDetailsQuery = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductDetailsQuery = TypedQuery<
|
export const useProductDetails = makeQuery<
|
||||||
ProductDetails,
|
ProductDetails,
|
||||||
ProductDetailsVariables
|
ProductDetailsVariables
|
||||||
>(productDetailsQuery);
|
>(productDetailsQuery);
|
||||||
|
@ -187,7 +185,7 @@ const productVariantQuery = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductVariantQuery = TypedQuery<
|
export const useProductVariantQuery = makeQuery<
|
||||||
ProductVariantDetails,
|
ProductVariantDetails,
|
||||||
ProductVariantDetailsVariables
|
ProductVariantDetailsVariables
|
||||||
>(productVariantQuery);
|
>(productVariantQuery);
|
||||||
|
@ -231,7 +229,7 @@ const productVariantCreateQuery = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductVariantCreateQuery = TypedQuery<
|
export const useProductVariantCreateQuery = makeQuery<
|
||||||
ProductVariantCreateData,
|
ProductVariantCreateData,
|
||||||
ProductVariantCreateDataVariables
|
ProductVariantCreateDataVariables
|
||||||
>(productVariantCreateQuery);
|
>(productVariantCreateQuery);
|
||||||
|
@ -253,7 +251,7 @@ const productImageQuery = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedProductImageQuery = TypedQuery<
|
export const useProductImageQuery = makeQuery<
|
||||||
ProductImageById,
|
ProductImageById,
|
||||||
ProductImageByIdVariables
|
ProductImageByIdVariables
|
||||||
>(productImageQuery);
|
>(productImageQuery);
|
||||||
|
@ -288,7 +286,7 @@ const availableInGridAttributes = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const AvailableInGridAttributesQuery = TypedQuery<
|
export const useAvailableInGridAttributesQuery = makeQuery<
|
||||||
GridAttributes,
|
GridAttributes,
|
||||||
GridAttributesVariables
|
GridAttributesVariables
|
||||||
>(availableInGridAttributes);
|
>(availableInGridAttributes);
|
||||||
|
|
|
@ -10,12 +10,11 @@ import { useWarehouseList } from "@saleor/warehouses/queries";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { decimal, maybe, weight } from "../../misc";
|
import { decimal, weight } from "../../misc";
|
||||||
import ProductCreatePage, {
|
import ProductCreatePage, {
|
||||||
ProductCreatePageSubmitData
|
ProductCreatePageSubmitData
|
||||||
} from "../components/ProductCreatePage";
|
} from "../components/ProductCreatePage";
|
||||||
import { TypedProductCreateMutation } from "../mutations";
|
import { useProductCreateMutation } from "../mutations";
|
||||||
import { ProductCreate } from "../types/ProductCreate";
|
|
||||||
import { productListUrl, productUrl } from "../urls";
|
import { productListUrl, productUrl } from "../urls";
|
||||||
|
|
||||||
export const ProductCreateView: React.FC = () => {
|
export const ProductCreateView: React.FC = () => {
|
||||||
|
@ -53,7 +52,8 @@ export const ProductCreateView: React.FC = () => {
|
||||||
|
|
||||||
const handleBack = () => navigate(productListUrl());
|
const handleBack = () => navigate(productListUrl());
|
||||||
|
|
||||||
const handleSuccess = (data: ProductCreate) => {
|
const [productCreate, productCreateOpts] = useProductCreateMutation({
|
||||||
|
onCompleted: data => {
|
||||||
if (data.productCreate.errors.length === 0) {
|
if (data.productCreate.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
|
@ -63,11 +63,9 @@ export const ProductCreateView: React.FC = () => {
|
||||||
});
|
});
|
||||||
navigate(productUrl(data.productCreate.product.id));
|
navigate(productUrl(data.productCreate.product.id));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
|
||||||
<TypedProductCreateMutation onCompleted={handleSuccess}>
|
|
||||||
{(productCreate, productCreateOpts) => {
|
|
||||||
const handleSubmit = (formData: ProductCreatePageSubmitData) => {
|
const handleSubmit = (formData: ProductCreatePageSubmitData) => {
|
||||||
productCreate({
|
productCreate({
|
||||||
variables: {
|
variables: {
|
||||||
|
@ -84,9 +82,7 @@ export const ProductCreateView: React.FC = () => {
|
||||||
name: formData.name,
|
name: formData.name,
|
||||||
productType: formData.productType,
|
productType: formData.productType,
|
||||||
publicationDate:
|
publicationDate:
|
||||||
formData.publicationDate !== ""
|
formData.publicationDate !== "" ? formData.publicationDate : null,
|
||||||
? formData.publicationDate
|
|
||||||
: null,
|
|
||||||
seo: {
|
seo: {
|
||||||
description: formData.seoDescription,
|
description: formData.seoDescription,
|
||||||
title: formData.seoTitle
|
title: formData.seoTitle
|
||||||
|
@ -111,15 +107,13 @@ export const ProductCreateView: React.FC = () => {
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<ProductCreatePage
|
<ProductCreatePage
|
||||||
currency={maybe(() => shop.defaultCurrency)}
|
currency={shop?.defaultCurrency}
|
||||||
categories={maybe(
|
categories={(searchCategoryOpts.data?.search.edges || []).map(
|
||||||
() => searchCategoryOpts.data.search.edges,
|
edge => edge.node
|
||||||
[]
|
)}
|
||||||
).map(edge => edge.node)}
|
collections={(searchCollectionOpts.data?.search.edges || []).map(
|
||||||
collections={maybe(
|
edge => edge.node
|
||||||
() => searchCollectionOpts.data.search.edges,
|
)}
|
||||||
[]
|
|
||||||
).map(edge => edge.node)}
|
|
||||||
disabled={productCreateOpts.loading}
|
disabled={productCreateOpts.loading}
|
||||||
errors={productCreateOpts.data?.productCreate.errors || []}
|
errors={productCreateOpts.data?.productCreate.errors || []}
|
||||||
fetchCategories={searchCategory}
|
fetchCategories={searchCategory}
|
||||||
|
@ -129,30 +123,24 @@ export const ProductCreateView: React.FC = () => {
|
||||||
defaultMessage: "New Product",
|
defaultMessage: "New Product",
|
||||||
description: "page header"
|
description: "page header"
|
||||||
})}
|
})}
|
||||||
productTypes={maybe(() =>
|
productTypes={searchProductTypesOpts.data?.search.edges.map(
|
||||||
searchProductTypesOpts.data.search.edges.map(edge => edge.node)
|
edge => edge.node
|
||||||
)}
|
)}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
saveButtonBarState={productCreateOpts.status}
|
saveButtonBarState={productCreateOpts.status}
|
||||||
fetchMoreCategories={{
|
fetchMoreCategories={{
|
||||||
hasMore: maybe(
|
hasMore: searchCategoryOpts.data?.search.pageInfo.hasNextPage,
|
||||||
() => searchCategoryOpts.data.search.pageInfo.hasNextPage
|
|
||||||
),
|
|
||||||
loading: searchCategoryOpts.loading,
|
loading: searchCategoryOpts.loading,
|
||||||
onFetchMore: loadMoreCategories
|
onFetchMore: loadMoreCategories
|
||||||
}}
|
}}
|
||||||
fetchMoreCollections={{
|
fetchMoreCollections={{
|
||||||
hasMore: maybe(
|
hasMore: searchCollectionOpts.data?.search.pageInfo.hasNextPage,
|
||||||
() => searchCollectionOpts.data.search.pageInfo.hasNextPage
|
|
||||||
),
|
|
||||||
loading: searchCollectionOpts.loading,
|
loading: searchCollectionOpts.loading,
|
||||||
onFetchMore: loadMoreCollections
|
onFetchMore: loadMoreCollections
|
||||||
}}
|
}}
|
||||||
fetchMoreProductTypes={{
|
fetchMoreProductTypes={{
|
||||||
hasMore: maybe(
|
hasMore: searchProductTypesOpts.data?.search.pageInfo.hasNextPage,
|
||||||
() => searchProductTypesOpts.data.search.pageInfo.hasNextPage
|
|
||||||
),
|
|
||||||
loading: searchProductTypesOpts.loading,
|
loading: searchProductTypesOpts.loading,
|
||||||
onFetchMore: loadMoreProductTypes
|
onFetchMore: loadMoreProductTypes
|
||||||
}}
|
}}
|
||||||
|
@ -163,8 +151,5 @@ export const ProductCreateView: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</TypedProductCreateMutation>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
export default ProductCreateView;
|
export default ProductCreateView;
|
||||||
|
|
|
@ -7,14 +7,12 @@ import { commonMessages } from "@saleor/intl";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { maybe } from "../../misc";
|
|
||||||
import ProductImagePage from "../components/ProductImagePage";
|
import ProductImagePage from "../components/ProductImagePage";
|
||||||
import {
|
import {
|
||||||
TypedProductImageDeleteMutation,
|
useProductImageDeleteMutation,
|
||||||
TypedProductImageUpdateMutation
|
useProductImageUpdateMutation
|
||||||
} from "../mutations";
|
} from "../mutations";
|
||||||
import { TypedProductImageQuery } from "../queries";
|
import { useProductImageQuery } from "../queries";
|
||||||
import { ProductImageUpdate } from "../types/ProductImageUpdate";
|
|
||||||
import {
|
import {
|
||||||
productImageUrl,
|
productImageUrl,
|
||||||
ProductImageUrlQueryParams,
|
ProductImageUrlQueryParams,
|
||||||
|
@ -38,36 +36,37 @@ export const ProductImage: React.FC<ProductImageProps> = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const handleBack = () => navigate(productUrl(productId));
|
const handleBack = () => navigate(productUrl(productId));
|
||||||
const handleUpdateSuccess = (data: ProductImageUpdate) => {
|
|
||||||
|
const { data, loading } = useProductImageQuery({
|
||||||
|
displayLoader: true,
|
||||||
|
variables: {
|
||||||
|
imageId,
|
||||||
|
productId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [updateImage, updateResult] = useProductImageUpdateMutation({
|
||||||
|
onCompleted: data => {
|
||||||
if (data.productImageUpdate.errors.length === 0) {
|
if (data.productImageUpdate.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
text: intl.formatMessage(commonMessages.savedChanges)
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
return (
|
});
|
||||||
<TypedProductImageQuery
|
|
||||||
displayLoader
|
const [deleteImage, deleteResult] = useProductImageDeleteMutation({
|
||||||
variables={{
|
onCompleted: handleBack
|
||||||
imageId,
|
});
|
||||||
productId
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
|
||||||
const product = data?.product;
|
const product = data?.product;
|
||||||
|
|
||||||
if (product === null) {
|
if (product === null) {
|
||||||
return <NotFoundPage onBack={() => navigate(productListUrl())} />;
|
return <NotFoundPage onBack={() => navigate(productListUrl())} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const handleDelete = () => deleteImage({ variables: { id: imageId } });
|
||||||
<TypedProductImageUpdateMutation onCompleted={handleUpdateSuccess}>
|
|
||||||
{(updateImage, updateResult) => (
|
|
||||||
<TypedProductImageDeleteMutation onCompleted={handleBack}>
|
|
||||||
{(deleteImage, deleteResult) => {
|
|
||||||
const handleDelete = () =>
|
|
||||||
deleteImage({ variables: { id: imageId } });
|
|
||||||
const handleImageClick = (id: string) => () =>
|
const handleImageClick = (id: string) => () =>
|
||||||
navigate(productImageUrl(productId, id));
|
navigate(productImageUrl(productId, id));
|
||||||
const handleUpdate = (formData: { description: string }) => {
|
const handleUpdate = (formData: { description: string }) => {
|
||||||
|
@ -78,15 +77,15 @@ export const ProductImage: React.FC<ProductImageProps> = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const image = data && data.product && data.product.mainImage;
|
const image = data?.product?.mainImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ProductImagePage
|
<ProductImagePage
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
product={maybe(() => data.product.name)}
|
product={data?.product?.name}
|
||||||
image={image || null}
|
image={image || null}
|
||||||
images={maybe(() => data.product.images)}
|
images={data?.product?.images}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onDelete={() =>
|
onDelete={() =>
|
||||||
navigate(
|
navigate(
|
||||||
|
@ -100,9 +99,7 @@ export const ProductImage: React.FC<ProductImageProps> = ({
|
||||||
saveButtonBarState={updateResult.status}
|
saveButtonBarState={updateResult.status}
|
||||||
/>
|
/>
|
||||||
<ActionDialog
|
<ActionDialog
|
||||||
onClose={() =>
|
onClose={() => navigate(productImageUrl(productId, imageId), true)}
|
||||||
navigate(productImageUrl(productId, imageId), true)
|
|
||||||
}
|
|
||||||
onConfirm={handleDelete}
|
onConfirm={handleDelete}
|
||||||
open={params.action === "remove"}
|
open={params.action === "remove"}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
|
@ -118,13 +115,5 @@ export const ProductImage: React.FC<ProductImageProps> = ({
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</TypedProductImageDeleteMutation>
|
|
||||||
)}
|
|
||||||
</TypedProductImageUpdateMutation>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TypedProductImageQuery>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
export default ProductImage;
|
export default ProductImage;
|
||||||
|
|
|
@ -45,18 +45,16 @@ import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ProductListPage from "../../components/ProductListPage";
|
import ProductListPage from "../../components/ProductListPage";
|
||||||
import {
|
import {
|
||||||
TypedProductBulkDeleteMutation,
|
useProductBulkDeleteMutation,
|
||||||
TypedProductBulkPublishMutation,
|
useProductBulkPublishMutation,
|
||||||
useProductExport
|
useProductExport
|
||||||
} from "../../mutations";
|
} from "../../mutations";
|
||||||
import {
|
import {
|
||||||
AvailableInGridAttributesQuery,
|
useAvailableInGridAttributesQuery,
|
||||||
TypedProductListQuery,
|
|
||||||
useCountAllProducts,
|
useCountAllProducts,
|
||||||
useInitialProductFilterDataQuery
|
useInitialProductFilterDataQuery,
|
||||||
|
useProductListQuery
|
||||||
} from "../../queries";
|
} from "../../queries";
|
||||||
import { productBulkDelete } from "../../types/productBulkDelete";
|
|
||||||
import { productBulkPublish } from "../../types/productBulkPublish";
|
|
||||||
import {
|
import {
|
||||||
productAddUrl,
|
productAddUrl,
|
||||||
productListUrl,
|
productListUrl,
|
||||||
|
@ -235,6 +233,53 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
}),
|
}),
|
||||||
[params, settings.rowNumber]
|
[params, settings.rowNumber]
|
||||||
);
|
);
|
||||||
|
const { data, loading, refetch } = useProductListQuery({
|
||||||
|
displayLoader: true,
|
||||||
|
variables: queryVariables
|
||||||
|
});
|
||||||
|
|
||||||
|
function filterColumnIds(columns: ProductListColumns[]) {
|
||||||
|
return columns
|
||||||
|
.filter(isAttributeColumnValue)
|
||||||
|
.map(getAttributeIdFromColumnValue);
|
||||||
|
}
|
||||||
|
const attributes = useAvailableInGridAttributesQuery({
|
||||||
|
variables: { first: 6, ids: filterColumnIds(settings.columns) }
|
||||||
|
});
|
||||||
|
|
||||||
|
const [
|
||||||
|
productBulkDelete,
|
||||||
|
productBulkDeleteOpts
|
||||||
|
] = useProductBulkDeleteMutation({
|
||||||
|
onCompleted: data => {
|
||||||
|
if (data.productBulkDelete.errors.length === 0) {
|
||||||
|
closeModal();
|
||||||
|
notify({
|
||||||
|
status: "success",
|
||||||
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
|
});
|
||||||
|
reset();
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [
|
||||||
|
productBulkPublish,
|
||||||
|
productBulkPublishOpts
|
||||||
|
] = useProductBulkPublishMutation({
|
||||||
|
onCompleted: data => {
|
||||||
|
if (data.productBulkPublish.errors.length === 0) {
|
||||||
|
closeModal();
|
||||||
|
notify({
|
||||||
|
status: "success",
|
||||||
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
|
});
|
||||||
|
reset();
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const filterOpts = getFilterOpts(
|
const filterOpts = getFilterOpts(
|
||||||
params,
|
params,
|
||||||
|
@ -262,56 +307,13 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function filterColumnIds(columns: ProductListColumns[]) {
|
|
||||||
return columns
|
|
||||||
.filter(isAttributeColumnValue)
|
|
||||||
.map(getAttributeIdFromColumnValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AvailableInGridAttributesQuery
|
|
||||||
variables={{ first: 6, ids: filterColumnIds(settings.columns) }}
|
|
||||||
>
|
|
||||||
{attributes => (
|
|
||||||
<TypedProductListQuery displayLoader variables={queryVariables}>
|
|
||||||
{({ data, loading, refetch }) => {
|
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.products.pageInfo),
|
maybe(() => data.products.pageInfo),
|
||||||
paginationState,
|
paginationState,
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleBulkDelete = (data: productBulkDelete) => {
|
|
||||||
if (data.productBulkDelete.errors.length === 0) {
|
|
||||||
closeModal();
|
|
||||||
notify({
|
|
||||||
status: "success",
|
|
||||||
text: intl.formatMessage(commonMessages.savedChanges)
|
|
||||||
});
|
|
||||||
reset();
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBulkPublish = (data: productBulkPublish) => {
|
|
||||||
if (data.productBulkPublish.errors.length === 0) {
|
|
||||||
closeModal();
|
|
||||||
notify({
|
|
||||||
status: "success",
|
|
||||||
text: intl.formatMessage(commonMessages.savedChanges)
|
|
||||||
});
|
|
||||||
reset();
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedProductBulkDeleteMutation onCompleted={handleBulkDelete}>
|
|
||||||
{(productBulkDelete, productBulkDeleteOpts) => (
|
|
||||||
<TypedProductBulkPublishMutation
|
|
||||||
onCompleted={handleBulkPublish}
|
|
||||||
>
|
|
||||||
{(productBulkPublish, productBulkPublishOpts) => (
|
|
||||||
<>
|
<>
|
||||||
<ProductListPage
|
<ProductListPage
|
||||||
activeAttributeSortId={params.attributeId}
|
activeAttributeSortId={params.attributeId}
|
||||||
|
@ -321,21 +323,15 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
}}
|
}}
|
||||||
onSort={handleSort}
|
onSort={handleSort}
|
||||||
availableInGridAttributes={maybe(
|
availableInGridAttributes={maybe(
|
||||||
() =>
|
() => attributes.data.availableInGrid.edges.map(edge => edge.node),
|
||||||
attributes.data.availableInGrid.edges.map(
|
|
||||||
edge => edge.node
|
|
||||||
),
|
|
||||||
[]
|
[]
|
||||||
)}
|
)}
|
||||||
currencySymbol={currencySymbol}
|
currencySymbol={currencySymbol}
|
||||||
currentTab={currentTab}
|
currentTab={currentTab}
|
||||||
defaultSettings={
|
defaultSettings={defaultListSettings[ListViews.PRODUCT_LIST]}
|
||||||
defaultListSettings[ListViews.PRODUCT_LIST]
|
|
||||||
}
|
|
||||||
filterOpts={filterOpts}
|
filterOpts={filterOpts}
|
||||||
gridAttributes={maybe(
|
gridAttributes={maybe(
|
||||||
() =>
|
() => attributes.data.grid.edges.map(edge => edge.node),
|
||||||
attributes.data.grid.edges.map(edge => edge.node),
|
|
||||||
[]
|
[]
|
||||||
)}
|
)}
|
||||||
totalGridAttributes={maybe(
|
totalGridAttributes={maybe(
|
||||||
|
@ -345,16 +341,12 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
settings={settings}
|
settings={settings}
|
||||||
loading={attributes.loading}
|
loading={attributes.loading}
|
||||||
hasMore={maybe(
|
hasMore={maybe(
|
||||||
() =>
|
() => attributes.data.availableInGrid.pageInfo.hasNextPage,
|
||||||
attributes.data.availableInGrid.pageInfo
|
|
||||||
.hasNextPage,
|
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
onAdd={() => navigate(productAddUrl)}
|
onAdd={() => navigate(productAddUrl)}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
products={maybe(() =>
|
products={maybe(() => data.products.edges.map(edge => edge.node))}
|
||||||
data.products.edges.map(edge => edge.node)
|
|
||||||
)}
|
|
||||||
onFetchMore={() =>
|
onFetchMore={() =>
|
||||||
attributes.loadMore(
|
attributes.loadMore(
|
||||||
(prev, next) => {
|
(prev, next) => {
|
||||||
|
@ -377,9 +369,7 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
after:
|
after: attributes.data.availableInGrid.pageInfo.endCursor
|
||||||
attributes.data.availableInGrid.pageInfo
|
|
||||||
.endCursor
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -463,11 +453,7 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
description="dialog content"
|
description="dialog content"
|
||||||
values={{
|
values={{
|
||||||
counter: maybe(() => params.ids.length),
|
counter: maybe(() => params.ids.length),
|
||||||
displayQuantity: (
|
displayQuantity: <strong>{maybe(() => params.ids.length)}</strong>
|
||||||
<strong>
|
|
||||||
{maybe(() => params.ids.length)}
|
|
||||||
</strong>
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
@ -495,11 +481,7 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
description="dialog content"
|
description="dialog content"
|
||||||
values={{
|
values={{
|
||||||
counter: maybe(() => params.ids.length),
|
counter: maybe(() => params.ids.length),
|
||||||
displayQuantity: (
|
displayQuantity: <strong>{maybe(() => params.ids.length)}</strong>
|
||||||
<strong>
|
|
||||||
{maybe(() => params.ids.length)}
|
|
||||||
</strong>
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
@ -527,40 +509,29 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
description="dialog content"
|
description="dialog content"
|
||||||
values={{
|
values={{
|
||||||
counter: maybe(() => params.ids.length),
|
counter: maybe(() => params.ids.length),
|
||||||
displayQuantity: (
|
displayQuantity: <strong>{maybe(() => params.ids.length)}</strong>
|
||||||
<strong>
|
|
||||||
{maybe(() => params.ids.length)}
|
|
||||||
</strong>
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
<ProductExportDialog
|
<ProductExportDialog
|
||||||
attributes={(
|
attributes={(searchAttributes.result.data?.search.edges || []).map(
|
||||||
searchAttributes.result.data?.search.edges || []
|
edge => edge.node
|
||||||
).map(edge => edge.node)}
|
)}
|
||||||
hasMore={
|
hasMore={searchAttributes.result.data?.search.pageInfo.hasNextPage}
|
||||||
searchAttributes.result.data?.search.pageInfo
|
|
||||||
.hasNextPage
|
|
||||||
}
|
|
||||||
loading={searchAttributes.result.loading}
|
loading={searchAttributes.result.loading}
|
||||||
onFetch={searchAttributes.search}
|
onFetch={searchAttributes.search}
|
||||||
onFetchMore={searchAttributes.loadMore}
|
onFetchMore={searchAttributes.loadMore}
|
||||||
open={params.action === "export"}
|
open={params.action === "export"}
|
||||||
confirmButtonState={exportProductsOpts.status}
|
confirmButtonState={exportProductsOpts.status}
|
||||||
errors={
|
errors={exportProductsOpts.data?.exportProducts.errors || []}
|
||||||
exportProductsOpts.data?.exportProducts.errors || []
|
|
||||||
}
|
|
||||||
productQuantity={{
|
productQuantity={{
|
||||||
all: countAllProducts.data?.products.totalCount,
|
all: countAllProducts.data?.products.totalCount,
|
||||||
filter: data?.products.totalCount
|
filter: data?.products.totalCount
|
||||||
}}
|
}}
|
||||||
selectedProducts={listElements.length}
|
selectedProducts={listElements.length}
|
||||||
warehouses={
|
warehouses={
|
||||||
warehouses.data?.warehouses.edges.map(
|
warehouses.data?.warehouses.edges.map(edge => edge.node) || []
|
||||||
edge => edge.node
|
|
||||||
) || []
|
|
||||||
}
|
}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onSubmit={data =>
|
onSubmit={data =>
|
||||||
|
@ -586,21 +557,9 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
confirmButtonState="default"
|
confirmButtonState="default"
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onSubmit={handleFilterTabDelete}
|
onSubmit={handleFilterTabDelete}
|
||||||
tabName={maybe(
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
() => tabs[currentTab - 1].name,
|
|
||||||
"..."
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
|
||||||
</TypedProductBulkPublishMutation>
|
|
||||||
)}
|
|
||||||
</TypedProductBulkDeleteMutation>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TypedProductListQuery>
|
|
||||||
)}
|
|
||||||
</AvailableInGridAttributesQuery>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default ProductList;
|
export default ProductList;
|
||||||
|
|
|
@ -11,6 +11,15 @@ import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useNotifier from "@saleor/hooks/useNotifier";
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import useShop from "@saleor/hooks/useShop";
|
import useShop from "@saleor/hooks/useShop";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
|
import {
|
||||||
|
useProductDeleteMutation,
|
||||||
|
useProductImageCreateMutation,
|
||||||
|
useProductImageDeleteMutation,
|
||||||
|
useProductImagesReorder,
|
||||||
|
useProductUpdateMutation,
|
||||||
|
useProductVariantBulkDeleteMutation,
|
||||||
|
useSimpleProductUpdateMutation
|
||||||
|
} from "@saleor/products/mutations";
|
||||||
import useCategorySearch from "@saleor/searches/useCategorySearch";
|
import useCategorySearch from "@saleor/searches/useCategorySearch";
|
||||||
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
||||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||||
|
@ -20,14 +29,9 @@ import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { getMutationState, maybe } from "../../../misc";
|
import { getMutationState, maybe } from "../../../misc";
|
||||||
import ProductUpdatePage from "../../components/ProductUpdatePage";
|
import ProductUpdatePage from "../../components/ProductUpdatePage";
|
||||||
import ProductUpdateOperations from "../../containers/ProductUpdateOperations";
|
import { useProductDetails } from "../../queries";
|
||||||
import { TypedProductDetailsQuery } from "../../queries";
|
import { ProductImageCreateVariables } from "../../types/ProductImageCreate";
|
||||||
import {
|
|
||||||
ProductImageCreate,
|
|
||||||
ProductImageCreateVariables
|
|
||||||
} from "../../types/ProductImageCreate";
|
|
||||||
import { ProductUpdate as ProductUpdateMutationResult } from "../../types/ProductUpdate";
|
import { ProductUpdate as ProductUpdateMutationResult } from "../../types/ProductUpdate";
|
||||||
import { ProductVariantBulkDelete } from "../../types/ProductVariantBulkDelete";
|
|
||||||
import {
|
import {
|
||||||
productImageUrl,
|
productImageUrl,
|
||||||
productListUrl,
|
productListUrl,
|
||||||
|
@ -78,31 +82,13 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
});
|
});
|
||||||
const shop = useShop();
|
const shop = useShop();
|
||||||
|
|
||||||
const [openModal, closeModal] = createDialogActionHandlers<
|
const { data, loading, refetch } = useProductDetails({
|
||||||
ProductUrlDialog,
|
displayLoader: true,
|
||||||
ProductUrlQueryParams
|
variables: {
|
||||||
>(navigate, params => productUrl(id, params), params);
|
id
|
||||||
|
|
||||||
const handleBack = () => navigate(productListUrl());
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TypedProductDetailsQuery displayLoader variables={{ id }}>
|
|
||||||
{({ data, loading, refetch }) => {
|
|
||||||
const product = data?.product;
|
|
||||||
|
|
||||||
if (product === null) {
|
|
||||||
return <NotFoundPage onBack={handleBack} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
notify({
|
|
||||||
status: "success",
|
|
||||||
text: intl.formatMessage({
|
|
||||||
defaultMessage: "Product removed"
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
navigate(productListUrl());
|
|
||||||
};
|
|
||||||
const handleUpdate = (data: ProductUpdateMutationResult) => {
|
const handleUpdate = (data: ProductUpdateMutationResult) => {
|
||||||
if (data.productUpdate.errors.length === 0) {
|
if (data.productUpdate.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
|
@ -111,11 +97,40 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const [updateProduct, updateProductOpts] = useProductUpdateMutation({
|
||||||
|
onCompleted: handleUpdate
|
||||||
|
});
|
||||||
|
const [
|
||||||
|
updateSimpleProduct,
|
||||||
|
updateSimpleProductOpts
|
||||||
|
] = useSimpleProductUpdateMutation({
|
||||||
|
onCompleted: handleUpdate
|
||||||
|
});
|
||||||
|
|
||||||
const handleImageCreate = (data: ProductImageCreate) => {
|
const [
|
||||||
|
reorderProductImages,
|
||||||
|
reorderProductImagesOpts
|
||||||
|
] = useProductImagesReorder({});
|
||||||
|
|
||||||
|
const [deleteProduct, deleteProductOpts] = useProductDeleteMutation({
|
||||||
|
onCompleted: () => {
|
||||||
|
notify({
|
||||||
|
status: "success",
|
||||||
|
text: intl.formatMessage({
|
||||||
|
defaultMessage: "Product removed"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
navigate(productListUrl());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [
|
||||||
|
createProductImage,
|
||||||
|
createProductImageOpts
|
||||||
|
] = useProductImageCreateMutation({
|
||||||
|
onCompleted: data => {
|
||||||
const imageError = data.productImageCreate.errors.find(
|
const imageError = data.productImageCreate.errors.find(
|
||||||
error =>
|
error => error.field === ("image" as keyof ProductImageCreateVariables)
|
||||||
error.field === ("image" as keyof ProductImageCreateVariables)
|
|
||||||
);
|
);
|
||||||
if (imageError) {
|
if (imageError) {
|
||||||
notify({
|
notify({
|
||||||
|
@ -123,75 +138,73 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
text: intl.formatMessage(commonMessages.somethingWentWrong)
|
text: intl.formatMessage(commonMessages.somethingWentWrong)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
const handleImageDeleteSuccess = () =>
|
});
|
||||||
|
|
||||||
|
const [deleteProductImage] = useProductImageDeleteMutation({
|
||||||
|
onCompleted: () =>
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
text: intl.formatMessage(commonMessages.savedChanges)
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
|
})
|
||||||
});
|
});
|
||||||
const handleVariantAdd = () => navigate(productVariantAddUrl(id));
|
|
||||||
|
|
||||||
const handleBulkProductVariantDelete = (
|
const [
|
||||||
data: ProductVariantBulkDelete
|
bulkProductVariantDelete,
|
||||||
) => {
|
bulkProductVariantDeleteOpts
|
||||||
|
] = useProductVariantBulkDeleteMutation({
|
||||||
|
onCompleted: data => {
|
||||||
if (data.productVariantBulkDelete.errors.length === 0) {
|
if (data.productVariantBulkDelete.errors.length === 0) {
|
||||||
closeModal();
|
closeModal();
|
||||||
reset();
|
reset();
|
||||||
refetch();
|
refetch();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [openModal, closeModal] = createDialogActionHandlers<
|
||||||
|
ProductUrlDialog,
|
||||||
|
ProductUrlQueryParams
|
||||||
|
>(navigate, params => productUrl(id, params), params);
|
||||||
|
|
||||||
|
const handleBack = () => navigate(productListUrl());
|
||||||
|
|
||||||
|
const product = data?.product;
|
||||||
|
|
||||||
|
if (product === null) {
|
||||||
|
return <NotFoundPage onBack={handleBack} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleVariantAdd = () => navigate(productVariantAddUrl(id));
|
||||||
|
|
||||||
return (
|
|
||||||
<ProductUpdateOperations
|
|
||||||
product={product}
|
|
||||||
onBulkProductVariantDelete={handleBulkProductVariantDelete}
|
|
||||||
onDelete={handleDelete}
|
|
||||||
onImageCreate={handleImageCreate}
|
|
||||||
onImageDelete={handleImageDeleteSuccess}
|
|
||||||
onUpdate={handleUpdate}
|
|
||||||
>
|
|
||||||
{({
|
|
||||||
bulkProductVariantDelete,
|
|
||||||
createProductImage,
|
|
||||||
deleteProduct,
|
|
||||||
deleteProductImage,
|
|
||||||
reorderProductImages,
|
|
||||||
updateProduct,
|
|
||||||
updateSimpleProduct
|
|
||||||
}) => {
|
|
||||||
const handleImageDelete = (id: string) => () =>
|
const handleImageDelete = (id: string) => () =>
|
||||||
deleteProductImage.mutate({ id });
|
deleteProductImage({ variables: { id } });
|
||||||
const handleImageEdit = (imageId: string) => () =>
|
const handleImageEdit = (imageId: string) => () =>
|
||||||
navigate(productImageUrl(id, imageId));
|
navigate(productImageUrl(id, imageId));
|
||||||
const handleSubmit = createUpdateHandler(
|
const handleSubmit = createUpdateHandler(
|
||||||
product,
|
product,
|
||||||
updateProduct.mutate,
|
variables => updateProduct({ variables }),
|
||||||
updateSimpleProduct.mutate
|
variables => updateSimpleProduct({ variables })
|
||||||
);
|
);
|
||||||
const handleImageUpload = createImageUploadHandler(
|
const handleImageUpload = createImageUploadHandler(id, variables =>
|
||||||
id,
|
createProductImage({ variables })
|
||||||
createProductImage.mutate
|
|
||||||
);
|
);
|
||||||
const handleImageReorder = createImageReorderHandler(
|
const handleImageReorder = createImageReorderHandler(product, variables =>
|
||||||
product,
|
reorderProductImages({ variables })
|
||||||
reorderProductImages.mutate
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const disableFormSave =
|
const disableFormSave =
|
||||||
createProductImage.opts.loading ||
|
createProductImageOpts.loading ||
|
||||||
deleteProduct.opts.loading ||
|
deleteProductOpts.loading ||
|
||||||
reorderProductImages.opts.loading ||
|
reorderProductImagesOpts.loading ||
|
||||||
updateProduct.opts.loading ||
|
updateProductOpts.loading ||
|
||||||
loading;
|
loading;
|
||||||
const formTransitionState = getMutationState(
|
const formTransitionState = getMutationState(
|
||||||
updateProduct.opts.called || updateSimpleProduct.opts.called,
|
updateProductOpts.called || updateSimpleProductOpts.called,
|
||||||
updateProduct.opts.loading || updateSimpleProduct.opts.loading,
|
updateProductOpts.loading || updateSimpleProductOpts.loading,
|
||||||
maybe(() => updateProduct.opts.data.productUpdate.errors),
|
maybe(() => updateProductOpts.data.productUpdate.errors),
|
||||||
maybe(() => updateSimpleProduct.opts.data.productUpdate.errors),
|
maybe(() => updateSimpleProductOpts.data.productUpdate.errors),
|
||||||
maybe(
|
maybe(() => updateSimpleProductOpts.data.productVariantUpdate.errors)
|
||||||
() =>
|
|
||||||
updateSimpleProduct.opts.data.productVariantUpdate.errors
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const categories = maybe(
|
const categories = maybe(
|
||||||
|
@ -203,14 +216,8 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
[]
|
[]
|
||||||
).map(edge => edge.node);
|
).map(edge => edge.node);
|
||||||
const errors = [
|
const errors = [
|
||||||
...maybe(
|
...maybe(() => updateProductOpts.data.productUpdate.errors, []),
|
||||||
() => updateProduct.opts.data.productUpdate.errors,
|
...maybe(() => updateSimpleProductOpts.data.productUpdate.errors, [])
|
||||||
[]
|
|
||||||
),
|
|
||||||
...maybe(
|
|
||||||
() => updateSimpleProduct.opts.data.productUpdate.errors,
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -230,9 +237,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
placeholderImage={placeholderImg}
|
placeholderImage={placeholderImg}
|
||||||
product={product}
|
product={product}
|
||||||
warehouses={
|
warehouses={
|
||||||
warehouses.data?.warehouses.edges.map(
|
warehouses.data?.warehouses.edges.map(edge => edge.node) || []
|
||||||
edge => edge.node
|
|
||||||
) || []
|
|
||||||
}
|
}
|
||||||
variants={maybe(() => product.variants)}
|
variants={maybe(() => product.variants)}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
|
@ -264,16 +269,14 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
fetchMoreCategories={{
|
fetchMoreCategories={{
|
||||||
hasMore: maybe(
|
hasMore: maybe(
|
||||||
() =>
|
() => searchCategoriesOpts.data.search.pageInfo.hasNextPage
|
||||||
searchCategoriesOpts.data.search.pageInfo.hasNextPage
|
|
||||||
),
|
),
|
||||||
loading: searchCategoriesOpts.loading,
|
loading: searchCategoriesOpts.loading,
|
||||||
onFetchMore: loadMoreCategories
|
onFetchMore: loadMoreCategories
|
||||||
}}
|
}}
|
||||||
fetchMoreCollections={{
|
fetchMoreCollections={{
|
||||||
hasMore: maybe(
|
hasMore: maybe(
|
||||||
() =>
|
() => searchCollectionsOpts.data.search.pageInfo.hasNextPage
|
||||||
searchCollectionsOpts.data.search.pageInfo.hasNextPage
|
|
||||||
),
|
),
|
||||||
loading: searchCollectionsOpts.loading,
|
loading: searchCollectionsOpts.loading,
|
||||||
onFetchMore: loadMoreCollections
|
onFetchMore: loadMoreCollections
|
||||||
|
@ -282,8 +285,8 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
<ActionDialog
|
<ActionDialog
|
||||||
open={params.action === "remove"}
|
open={params.action === "remove"}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
confirmButtonState={deleteProduct.opts.status}
|
confirmButtonState={deleteProductOpts.status}
|
||||||
onConfirm={() => deleteProduct.mutate({ id })}
|
onConfirm={() => deleteProduct({ variables: { id } })}
|
||||||
variant="delete"
|
variant="delete"
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
defaultMessage: "Delete Product",
|
defaultMessage: "Delete Product",
|
||||||
|
@ -303,10 +306,12 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
<ActionDialog
|
<ActionDialog
|
||||||
open={params.action === "remove-variants"}
|
open={params.action === "remove-variants"}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
confirmButtonState={bulkProductVariantDelete.opts.status}
|
confirmButtonState={bulkProductVariantDeleteOpts.status}
|
||||||
onConfirm={() =>
|
onConfirm={() =>
|
||||||
bulkProductVariantDelete.mutate({
|
bulkProductVariantDelete({
|
||||||
|
variables: {
|
||||||
ids: params.ids
|
ids: params.ids
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
variant="delete"
|
variant="delete"
|
||||||
|
@ -321,20 +326,12 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
||||||
description="dialog content"
|
description="dialog content"
|
||||||
values={{
|
values={{
|
||||||
counter: maybe(() => params.ids.length),
|
counter: maybe(() => params.ids.length),
|
||||||
displayQuantity: (
|
displayQuantity: <strong>{maybe(() => params.ids.length)}</strong>
|
||||||
<strong>{maybe(() => params.ids.length)}</strong>
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</ProductUpdateOperations>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TypedProductDetailsQuery>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
export default ProductUpdate;
|
export default ProductUpdate;
|
||||||
|
|
|
@ -15,12 +15,14 @@ import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog
|
||||||
import ProductVariantPage, {
|
import ProductVariantPage, {
|
||||||
ProductVariantPageSubmitData
|
ProductVariantPageSubmitData
|
||||||
} from "../components/ProductVariantPage";
|
} from "../components/ProductVariantPage";
|
||||||
import ProductVariantOperations from "../containers/ProductVariantOperations";
|
|
||||||
import { TypedProductVariantQuery } from "../queries";
|
|
||||||
import {
|
import {
|
||||||
VariantUpdate,
|
useVariantDeleteMutation,
|
||||||
VariantUpdate_productVariantUpdate_errors
|
useVariantImageAssignMutation,
|
||||||
} from "../types/VariantUpdate";
|
useVariantImageUnassignMutation,
|
||||||
|
useVariantUpdateMutation
|
||||||
|
} from "../mutations";
|
||||||
|
import { useProductVariantQuery } from "../queries";
|
||||||
|
import { VariantUpdate_productVariantUpdate_errors } from "../types/VariantUpdate";
|
||||||
import {
|
import {
|
||||||
productUrl,
|
productUrl,
|
||||||
productVariantAddUrl,
|
productVariantAddUrl,
|
||||||
|
@ -59,6 +61,13 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data, loading } = useProductVariantQuery({
|
||||||
|
displayLoader: true,
|
||||||
|
variables: {
|
||||||
|
id: variantId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const [openModal] = createDialogActionHandlers<
|
const [openModal] = createDialogActionHandlers<
|
||||||
ProductVariantEditUrlDialog,
|
ProductVariantEditUrlDialog,
|
||||||
ProductVariantEditUrlQueryParams
|
ProductVariantEditUrlQueryParams
|
||||||
|
@ -70,16 +79,12 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
|
|
||||||
const handleBack = () => navigate(productUrl(productId));
|
const handleBack = () => navigate(productUrl(productId));
|
||||||
|
|
||||||
return (
|
const [assignImage, assignImageOpts] = useVariantImageAssignMutation({});
|
||||||
<TypedProductVariantQuery displayLoader variables={{ id: variantId }}>
|
const [unassignImage, unassignImageOpts] = useVariantImageUnassignMutation(
|
||||||
{({ data, loading }) => {
|
{}
|
||||||
const variant = data?.productVariant;
|
);
|
||||||
|
const [deleteVariant, deleteVariantOpts] = useVariantDeleteMutation({
|
||||||
if (variant === null) {
|
onCompleted: () => {
|
||||||
return <NotFoundPage onBack={handleBack} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
text: intl.formatMessage({
|
text: intl.formatMessage({
|
||||||
|
@ -87,8 +92,10 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
navigate(productUrl(productId));
|
navigate(productUrl(productId));
|
||||||
};
|
}
|
||||||
const handleUpdate = (data: VariantUpdate) => {
|
});
|
||||||
|
const [updateVariant, updateVariantOpts] = useVariantUpdateMutation({
|
||||||
|
onCompleted: data => {
|
||||||
if (data.productVariantUpdate.errors.length === 0) {
|
if (data.productVariantUpdate.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
|
@ -97,35 +104,37 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
} else {
|
} else {
|
||||||
setErrors(data.productVariantUpdate.errors);
|
setErrors(data.productVariantUpdate.errors);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const variant = data?.productVariant;
|
||||||
|
|
||||||
|
if (variant === null) {
|
||||||
|
return <NotFoundPage onBack={handleBack} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<ProductVariantOperations
|
|
||||||
onDelete={handleDelete}
|
|
||||||
onUpdate={handleUpdate}
|
|
||||||
>
|
|
||||||
{({ assignImage, deleteVariant, updateVariant, unassignImage }) => {
|
|
||||||
const disableFormSave =
|
const disableFormSave =
|
||||||
loading ||
|
loading ||
|
||||||
deleteVariant.opts.loading ||
|
deleteVariantOpts.loading ||
|
||||||
updateVariant.opts.loading ||
|
updateVariantOpts.loading ||
|
||||||
assignImage.opts.loading ||
|
assignImageOpts.loading ||
|
||||||
unassignImage.opts.loading;
|
unassignImageOpts.loading;
|
||||||
|
|
||||||
const handleImageSelect = (id: string) => () => {
|
const handleImageSelect = (id: string) => () => {
|
||||||
if (variant) {
|
if (variant) {
|
||||||
if (
|
if (variant?.images?.map(image => image.id).indexOf(id) !== -1) {
|
||||||
variant.images &&
|
unassignImage({
|
||||||
variant.images.map(image => image.id).indexOf(id) !== -1
|
variables: {
|
||||||
) {
|
|
||||||
unassignImage.mutate({
|
|
||||||
imageId: id,
|
imageId: id,
|
||||||
variantId: variant.id
|
variantId: variant.id
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
assignImage.mutate({
|
assignImage({
|
||||||
|
variables: {
|
||||||
imageId: id,
|
imageId: id,
|
||||||
variantId: variant.id
|
variantId: variant.id
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,25 +146,22 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
<ProductVariantPage
|
<ProductVariantPage
|
||||||
defaultWeightUnit={shop?.defaultWeightUnit}
|
defaultWeightUnit={shop?.defaultWeightUnit}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
saveButtonBarState={updateVariant.opts.status}
|
saveButtonBarState={updateVariantOpts.status}
|
||||||
loading={disableFormSave}
|
loading={disableFormSave}
|
||||||
placeholderImage={placeholderImg}
|
placeholderImage={placeholderImg}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
header={variant?.name || variant?.sku}
|
header={variant?.name || variant?.sku}
|
||||||
warehouses={
|
warehouses={
|
||||||
warehouses.data?.warehouses.edges.map(
|
warehouses.data?.warehouses.edges.map(edge => edge.node) || []
|
||||||
edge => edge.node
|
|
||||||
) || []
|
|
||||||
}
|
}
|
||||||
onAdd={() => navigate(productVariantAddUrl(productId))}
|
onAdd={() => navigate(productVariantAddUrl(productId))}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onDelete={() => openModal("remove")}
|
onDelete={() => openModal("remove")}
|
||||||
onImageSelect={handleImageSelect}
|
onImageSelect={handleImageSelect}
|
||||||
onSubmit={(data: ProductVariantPageSubmitData) =>
|
onSubmit={(data: ProductVariantPageSubmitData) =>
|
||||||
updateVariant.mutate({
|
updateVariant({
|
||||||
addStocks: data.addStocks.map(
|
variables: {
|
||||||
mapFormsetStockToStockInput
|
addStocks: data.addStocks.map(mapFormsetStockToStockInput),
|
||||||
),
|
|
||||||
attributes: data.attributes.map(attribute => ({
|
attributes: data.attributes.map(attribute => ({
|
||||||
id: attribute.id,
|
id: attribute.id,
|
||||||
values: [attribute.value]
|
values: [attribute.value]
|
||||||
|
@ -165,11 +171,10 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
price: decimal(data.price),
|
price: decimal(data.price),
|
||||||
removeStocks: data.removeStocks,
|
removeStocks: data.removeStocks,
|
||||||
sku: data.sku,
|
sku: data.sku,
|
||||||
stocks: data.updateStocks.map(
|
stocks: data.updateStocks.map(mapFormsetStockToStockInput),
|
||||||
mapFormsetStockToStockInput
|
|
||||||
),
|
|
||||||
trackInventory: data.trackInventory,
|
trackInventory: data.trackInventory,
|
||||||
weight: weight(data.weight)
|
weight: weight(data.weight)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onVariantClick={variantId => {
|
onVariantClick={variantId => {
|
||||||
|
@ -177,13 +182,13 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ProductVariantDeleteDialog
|
<ProductVariantDeleteDialog
|
||||||
confirmButtonState={deleteVariant.opts.status}
|
confirmButtonState={deleteVariantOpts.status}
|
||||||
onClose={() =>
|
onClose={() => navigate(productVariantEditUrl(productId, variantId))}
|
||||||
navigate(productVariantEditUrl(productId, variantId))
|
|
||||||
}
|
|
||||||
onConfirm={() =>
|
onConfirm={() =>
|
||||||
deleteVariant.mutate({
|
deleteVariant({
|
||||||
|
variables: {
|
||||||
id: variantId
|
id: variantId
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
open={params.action === "remove"}
|
open={params.action === "remove"}
|
||||||
|
@ -191,11 +196,5 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</ProductVariantOperations>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TypedProductVariantQuery>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
export default ProductVariant;
|
export default ProductVariant;
|
||||||
|
|
|
@ -12,9 +12,8 @@ import { decimal, weight } from "../../misc";
|
||||||
import ProductVariantCreatePage, {
|
import ProductVariantCreatePage, {
|
||||||
ProductVariantCreatePageSubmitData
|
ProductVariantCreatePageSubmitData
|
||||||
} from "../components/ProductVariantCreatePage";
|
} from "../components/ProductVariantCreatePage";
|
||||||
import { TypedVariantCreateMutation } from "../mutations";
|
import { useVariantCreateMutation } from "../mutations";
|
||||||
import { TypedProductVariantCreateQuery } from "../queries";
|
import { useProductVariantCreateQuery } from "../queries";
|
||||||
import { VariantCreate } from "../types/VariantCreate";
|
|
||||||
import { productListUrl, productUrl, productVariantEditUrl } from "../urls";
|
import { productListUrl, productUrl, productVariantEditUrl } from "../urls";
|
||||||
|
|
||||||
interface ProductVariantCreateProps {
|
interface ProductVariantCreateProps {
|
||||||
|
@ -35,16 +34,13 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
const { data, loading: productLoading } = useProductVariantCreateQuery({
|
||||||
<TypedProductVariantCreateQuery displayLoader variables={{ id: productId }}>
|
displayLoader: true,
|
||||||
{({ data, loading: productLoading }) => {
|
variables: { id: productId }
|
||||||
const product = data?.product;
|
});
|
||||||
|
|
||||||
if (product === null) {
|
const [variantCreate, variantCreateResult] = useVariantCreateMutation({
|
||||||
return <NotFoundPage onBack={() => navigate(productListUrl())} />;
|
onCompleted: data => {
|
||||||
}
|
|
||||||
|
|
||||||
const handleCreateSuccess = (data: VariantCreate) => {
|
|
||||||
if (data.productVariantCreate.errors.length === 0) {
|
if (data.productVariantCreate.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
|
@ -57,15 +53,17 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const product = data?.product;
|
||||||
|
|
||||||
|
if (product === null) {
|
||||||
|
return <NotFoundPage onBack={() => navigate(productListUrl())} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<TypedVariantCreateMutation onCompleted={handleCreateSuccess}>
|
|
||||||
{(variantCreate, variantCreateResult) => {
|
|
||||||
const handleBack = () => navigate(productUrl(productId));
|
const handleBack = () => navigate(productUrl(productId));
|
||||||
const handleSubmit = (
|
const handleSubmit = (formData: ProductVariantCreatePageSubmitData) =>
|
||||||
formData: ProductVariantCreatePageSubmitData
|
|
||||||
) =>
|
|
||||||
variantCreate({
|
variantCreate({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
|
@ -104,10 +102,7 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
|
||||||
<ProductVariantCreatePage
|
<ProductVariantCreatePage
|
||||||
currencySymbol={shop?.defaultCurrency}
|
currencySymbol={shop?.defaultCurrency}
|
||||||
disabled={disableForm}
|
disabled={disableForm}
|
||||||
errors={
|
errors={variantCreateResult.data?.productVariantCreate.errors || []}
|
||||||
variantCreateResult.data?.productVariantCreate.errors ||
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
header={intl.formatMessage({
|
header={intl.formatMessage({
|
||||||
defaultMessage: "Create Variant",
|
defaultMessage: "Create Variant",
|
||||||
description: "header"
|
description: "header"
|
||||||
|
@ -118,19 +113,11 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
|
||||||
onVariantClick={handleVariantClick}
|
onVariantClick={handleVariantClick}
|
||||||
saveButtonBarState={variantCreateResult.status}
|
saveButtonBarState={variantCreateResult.status}
|
||||||
warehouses={
|
warehouses={
|
||||||
warehouses.data?.warehouses.edges.map(
|
warehouses.data?.warehouses.edges.map(edge => edge.node) || []
|
||||||
edge => edge.node
|
|
||||||
) || []
|
|
||||||
}
|
}
|
||||||
weightUnit={shop?.defaultWeightUnit}
|
weightUnit={shop?.defaultWeightUnit}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</TypedVariantCreateMutation>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TypedProductVariantCreateQuery>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
export default ProductVariant;
|
export default ProductVariant;
|
||||||
|
|
Loading…
Reference in a new issue