Use query hooks in product variant view

This commit is contained in:
dominik-zeglen 2020-08-24 12:29:54 +02:00
parent 0fc4d1afb2
commit 419525f493
5 changed files with 243 additions and 325 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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,
@ -186,7 +185,7 @@ const productVariantQuery = gql`
} }
} }
`; `;
export const TypedProductVariantQuery = TypedQuery< export const useProductVariantQuery = makeQuery<
ProductVariantDetails, ProductVariantDetails,
ProductVariantDetailsVariables ProductVariantDetailsVariables
>(productVariantQuery); >(productVariantQuery);

View file

@ -14,8 +14,7 @@ import { decimal, maybe, 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
@ -112,10 +108,9 @@ export const ProductCreateView: React.FC = () => {
/> />
<ProductCreatePage <ProductCreatePage
currency={maybe(() => shop.defaultCurrency)} currency={maybe(() => shop.defaultCurrency)}
categories={maybe( categories={maybe(() => searchCategoryOpts.data.search.edges, []).map(
() => searchCategoryOpts.data.search.edges, edge => edge.node
[] )}
).map(edge => edge.node)}
collections={maybe( collections={maybe(
() => searchCollectionOpts.data.search.edges, () => searchCollectionOpts.data.search.edges,
[] []
@ -163,8 +158,5 @@ export const ProductCreateView: React.FC = () => {
/> />
</> </>
); );
}}
</TypedProductCreateMutation>
);
}; };
export default ProductCreateView; export default ProductCreateView;

View file

@ -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,20 +104,21 @@ 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) {
@ -118,14 +126,18 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
variant.images && variant.images &&
variant.images.map(image => image.id).indexOf(id) !== -1 variant.images.map(image => image.id).indexOf(id) !== -1
) { ) {
unassignImage.mutate({ unassignImage({
variables: {
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 +149,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 +174,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 +185,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 +199,5 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
/> />
</> </>
); );
}}
</ProductVariantOperations>
);
}}
</TypedProductVariantQuery>
);
}; };
export default ProductVariant; export default ProductVariant;