From 419525f49378b536ed414788d7632690e060e1f4 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 24 Aug 2020 12:29:54 +0200 Subject: [PATCH] Use query hooks in product variant view --- .../containers/ProductImagesReorder.tsx | 20 +- .../containers/ProductVariantOperations.tsx | 77 ------ src/products/queries.ts | 3 +- src/products/views/ProductCreate.tsx | 212 +++++++-------- src/products/views/ProductVariant.tsx | 256 +++++++++--------- 5 files changed, 243 insertions(+), 325 deletions(-) delete mode 100644 src/products/containers/ProductVariantOperations.tsx diff --git a/src/products/containers/ProductImagesReorder.tsx b/src/products/containers/ProductImagesReorder.tsx index c4f019d74..8fcbfd93a 100644 --- a/src/products/containers/ProductImagesReorder.tsx +++ b/src/products/containers/ProductImagesReorder.tsx @@ -1,7 +1,7 @@ import React from "react"; import { TypedMutationInnerProps } from "../../mutations"; -import { TypedProductImagesReorder } from "../mutations"; +import { useProductImagesReorder } from "../mutations"; import { ProductImageReorder, ProductImageReorderVariables @@ -24,10 +24,12 @@ const ProductImagesReorderProvider: React.FC productId, productImages, ...mutationProps -}) => ( - - {(mutate, mutationResult) => - children(opts => { +}) => { + const [mutate, mutationResult] = useProductImagesReorder(mutationProps); + + return ( + <> + {children(opts => { const productImagesMap = productImages.reduce((prev, curr) => { prev[curr.id] = curr; return prev; @@ -52,9 +54,9 @@ const ProductImagesReorderProvider: React.FC ...opts, optimisticResponse }); - }, mutationResult) - } - -); + }, mutationResult)} + + ); +}; export default ProductImagesReorderProvider; diff --git a/src/products/containers/ProductVariantOperations.tsx b/src/products/containers/ProductVariantOperations.tsx deleted file mode 100644 index fdb9a4a8b..000000000 --- a/src/products/containers/ProductVariantOperations.tsx +++ /dev/null @@ -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 = ({ - children, - onDelete, - onUpdate, - onImageAssign, - onImageUnassign -}) => ( - - {(...assignImage) => ( - - {(...unassignImage) => ( - - {(...updateVariant) => ( - - {(...deleteVariant) => - children({ - assignImage: getMutationProviderData(...assignImage), - deleteVariant: getMutationProviderData(...deleteVariant), - unassignImage: getMutationProviderData(...unassignImage), - updateVariant: getMutationProviderData(...updateVariant) - }) - } - - )} - - )} - - )} - -); -export default VariantUpdateOperations; diff --git a/src/products/queries.ts b/src/products/queries.ts index 3fbbaef8f..e94ea7379 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -10,7 +10,6 @@ import { warehouseFragment } from "@saleor/fragments/warehouses"; import makeQuery from "@saleor/hooks/makeQuery"; import gql from "graphql-tag"; -import { TypedQuery } from "../queries"; import { CountAllProducts } from "./types/CountAllProducts"; import { CreateMultipleVariantsData, @@ -186,7 +185,7 @@ const productVariantQuery = gql` } } `; -export const TypedProductVariantQuery = TypedQuery< +export const useProductVariantQuery = makeQuery< ProductVariantDetails, ProductVariantDetailsVariables >(productVariantQuery); diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 342596a34..030d7640c 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -14,8 +14,7 @@ import { decimal, maybe, weight } from "../../misc"; import ProductCreatePage, { ProductCreatePageSubmitData } from "../components/ProductCreatePage"; -import { TypedProductCreateMutation } from "../mutations"; -import { ProductCreate } from "../types/ProductCreate"; +import { useProductCreateMutation } from "../mutations"; import { productListUrl, productUrl } from "../urls"; export const ProductCreateView: React.FC = () => { @@ -53,118 +52,111 @@ export const ProductCreateView: React.FC = () => { const handleBack = () => navigate(productListUrl()); - const handleSuccess = (data: ProductCreate) => { - if (data.productCreate.errors.length === 0) { - notify({ - status: "success", - text: intl.formatMessage({ - defaultMessage: "Product created" - }) - }); - navigate(productUrl(data.productCreate.product.id)); + const [productCreate, productCreateOpts] = useProductCreateMutation({ + onCompleted: data => { + if (data.productCreate.errors.length === 0) { + notify({ + status: "success", + text: intl.formatMessage({ + defaultMessage: "Product created" + }) + }); + navigate(productUrl(data.productCreate.product.id)); + } } + }); + + const handleSubmit = (formData: ProductCreatePageSubmitData) => { + productCreate({ + variables: { + attributes: formData.attributes.map(attribute => ({ + id: attribute.id, + values: attribute.value + })), + basePrice: decimal(formData.basePrice), + category: formData.category, + chargeTaxes: formData.chargeTaxes, + collections: formData.collections, + descriptionJson: JSON.stringify(formData.description), + isPublished: formData.isPublished, + name: formData.name, + productType: formData.productType, + publicationDate: + formData.publicationDate !== "" ? formData.publicationDate : null, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + }, + sku: formData.sku, + stocks: formData.stocks.map(stock => ({ + quantity: parseInt(stock.value, 0), + warehouse: stock.id + })), + trackInventory: formData.trackInventory, + weight: weight(formData.weight) + } + }); }; return ( - - {(productCreate, productCreateOpts) => { - const handleSubmit = (formData: ProductCreatePageSubmitData) => { - productCreate({ - variables: { - attributes: formData.attributes.map(attribute => ({ - id: attribute.id, - values: attribute.value - })), - basePrice: decimal(formData.basePrice), - category: formData.category, - chargeTaxes: formData.chargeTaxes, - collections: formData.collections, - descriptionJson: JSON.stringify(formData.description), - isPublished: formData.isPublished, - name: formData.name, - productType: formData.productType, - publicationDate: - formData.publicationDate !== "" - ? formData.publicationDate - : null, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - }, - sku: formData.sku, - stocks: formData.stocks.map(stock => ({ - quantity: parseInt(stock.value, 0), - warehouse: stock.id - })), - trackInventory: formData.trackInventory, - weight: weight(formData.weight) - } - }); - }; - - return ( - <> - - shop.defaultCurrency)} - categories={maybe( - () => searchCategoryOpts.data.search.edges, - [] - ).map(edge => edge.node)} - collections={maybe( - () => searchCollectionOpts.data.search.edges, - [] - ).map(edge => edge.node)} - disabled={productCreateOpts.loading} - errors={productCreateOpts.data?.productCreate.errors || []} - fetchCategories={searchCategory} - fetchCollections={searchCollection} - fetchProductTypes={searchProductTypes} - header={intl.formatMessage({ - defaultMessage: "New Product", - description: "page header" - })} - productTypes={maybe(() => - searchProductTypesOpts.data.search.edges.map(edge => edge.node) - )} - onBack={handleBack} - onSubmit={handleSubmit} - saveButtonBarState={productCreateOpts.status} - fetchMoreCategories={{ - hasMore: maybe( - () => searchCategoryOpts.data.search.pageInfo.hasNextPage - ), - loading: searchCategoryOpts.loading, - onFetchMore: loadMoreCategories - }} - fetchMoreCollections={{ - hasMore: maybe( - () => searchCollectionOpts.data.search.pageInfo.hasNextPage - ), - loading: searchCollectionOpts.loading, - onFetchMore: loadMoreCollections - }} - fetchMoreProductTypes={{ - hasMore: maybe( - () => searchProductTypesOpts.data.search.pageInfo.hasNextPage - ), - loading: searchProductTypesOpts.loading, - onFetchMore: loadMoreProductTypes - }} - warehouses={ - warehouses.data?.warehouses.edges.map(edge => edge.node) || [] - } - weightUnit={shop?.defaultWeightUnit} - /> - - ); - }} - + <> + + shop.defaultCurrency)} + categories={maybe(() => searchCategoryOpts.data.search.edges, []).map( + edge => edge.node + )} + collections={maybe( + () => searchCollectionOpts.data.search.edges, + [] + ).map(edge => edge.node)} + disabled={productCreateOpts.loading} + errors={productCreateOpts.data?.productCreate.errors || []} + fetchCategories={searchCategory} + fetchCollections={searchCollection} + fetchProductTypes={searchProductTypes} + header={intl.formatMessage({ + defaultMessage: "New Product", + description: "page header" + })} + productTypes={maybe(() => + searchProductTypesOpts.data.search.edges.map(edge => edge.node) + )} + onBack={handleBack} + onSubmit={handleSubmit} + saveButtonBarState={productCreateOpts.status} + fetchMoreCategories={{ + hasMore: maybe( + () => searchCategoryOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCategoryOpts.loading, + onFetchMore: loadMoreCategories + }} + fetchMoreCollections={{ + hasMore: maybe( + () => searchCollectionOpts.data.search.pageInfo.hasNextPage + ), + loading: searchCollectionOpts.loading, + onFetchMore: loadMoreCollections + }} + fetchMoreProductTypes={{ + hasMore: maybe( + () => searchProductTypesOpts.data.search.pageInfo.hasNextPage + ), + loading: searchProductTypesOpts.loading, + onFetchMore: loadMoreProductTypes + }} + warehouses={ + warehouses.data?.warehouses.edges.map(edge => edge.node) || [] + } + weightUnit={shop?.defaultWeightUnit} + /> + ); }; export default ProductCreateView; diff --git a/src/products/views/ProductVariant.tsx b/src/products/views/ProductVariant.tsx index 15150049d..bd8308134 100644 --- a/src/products/views/ProductVariant.tsx +++ b/src/products/views/ProductVariant.tsx @@ -15,12 +15,14 @@ import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog import ProductVariantPage, { ProductVariantPageSubmitData } from "../components/ProductVariantPage"; -import ProductVariantOperations from "../containers/ProductVariantOperations"; -import { TypedProductVariantQuery } from "../queries"; import { - VariantUpdate, - VariantUpdate_productVariantUpdate_errors -} from "../types/VariantUpdate"; + useVariantDeleteMutation, + useVariantImageAssignMutation, + useVariantImageUnassignMutation, + useVariantUpdateMutation +} from "../mutations"; +import { useProductVariantQuery } from "../queries"; +import { VariantUpdate_productVariantUpdate_errors } from "../types/VariantUpdate"; import { productUrl, productVariantAddUrl, @@ -59,6 +61,13 @@ export const ProductVariant: React.FC = ({ } }); + const { data, loading } = useProductVariantQuery({ + displayLoader: true, + variables: { + id: variantId + } + }); + const [openModal] = createDialogActionHandlers< ProductVariantEditUrlDialog, ProductVariantEditUrlQueryParams @@ -70,132 +79,125 @@ export const ProductVariant: React.FC = ({ const handleBack = () => navigate(productUrl(productId)); - return ( - - {({ data, loading }) => { - const variant = data?.productVariant; + const [assignImage, assignImageOpts] = useVariantImageAssignMutation({}); + const [unassignImage, unassignImageOpts] = useVariantImageUnassignMutation( + {} + ); + const [deleteVariant, deleteVariantOpts] = useVariantDeleteMutation({ + onCompleted: () => { + notify({ + status: "success", + text: intl.formatMessage({ + defaultMessage: "Variant removed" + }) + }); + navigate(productUrl(productId)); + } + }); + const [updateVariant, updateVariantOpts] = useVariantUpdateMutation({ + onCompleted: data => { + if (data.productVariantUpdate.errors.length === 0) { + notify({ + status: "success", + text: intl.formatMessage(commonMessages.savedChanges) + }); + } else { + setErrors(data.productVariantUpdate.errors); + } + } + }); - if (variant === null) { - return ; - } + const variant = data?.productVariant; - const handleDelete = () => { - notify({ - status: "success", - text: intl.formatMessage({ - defaultMessage: "Variant removed" - }) - }); - navigate(productUrl(productId)); - }; - const handleUpdate = (data: VariantUpdate) => { - if (data.productVariantUpdate.errors.length === 0) { - notify({ - status: "success", - text: intl.formatMessage(commonMessages.savedChanges) - }); - } else { - setErrors(data.productVariantUpdate.errors); + if (variant === null) { + return ; + } + + const disableFormSave = + loading || + deleteVariantOpts.loading || + updateVariantOpts.loading || + assignImageOpts.loading || + unassignImageOpts.loading; + + const handleImageSelect = (id: string) => () => { + if (variant) { + if ( + variant.images && + variant.images.map(image => image.id).indexOf(id) !== -1 + ) { + unassignImage({ + variables: { + imageId: id, + variantId: variant.id } - }; + }); + } else { + assignImage({ + variables: { + imageId: id, + variantId: variant.id + } + }); + } + } + }; - return ( - - {({ assignImage, deleteVariant, updateVariant, unassignImage }) => { - const disableFormSave = - loading || - deleteVariant.opts.loading || - updateVariant.opts.loading || - assignImage.opts.loading || - unassignImage.opts.loading; - - const handleImageSelect = (id: string) => () => { - if (variant) { - if ( - variant.images && - variant.images.map(image => image.id).indexOf(id) !== -1 - ) { - unassignImage.mutate({ - imageId: id, - variantId: variant.id - }); - } else { - assignImage.mutate({ - imageId: id, - variantId: variant.id - }); - } - } - }; - - return ( - <> - - edge.node - ) || [] - } - onAdd={() => navigate(productVariantAddUrl(productId))} - onBack={handleBack} - onDelete={() => openModal("remove")} - onImageSelect={handleImageSelect} - onSubmit={(data: ProductVariantPageSubmitData) => - updateVariant.mutate({ - addStocks: data.addStocks.map( - mapFormsetStockToStockInput - ), - attributes: data.attributes.map(attribute => ({ - id: attribute.id, - values: [attribute.value] - })), - costPrice: decimal(data.costPrice), - id: variantId, - price: decimal(data.price), - removeStocks: data.removeStocks, - sku: data.sku, - stocks: data.updateStocks.map( - mapFormsetStockToStockInput - ), - trackInventory: data.trackInventory, - weight: weight(data.weight) - }) - } - onVariantClick={variantId => { - navigate(productVariantEditUrl(productId, variantId)); - }} - /> - - navigate(productVariantEditUrl(productId, variantId)) - } - onConfirm={() => - deleteVariant.mutate({ - id: variantId - }) - } - open={params.action === "remove"} - name={data?.productVariant?.name} - /> - - ); - }} - - ); - }} - + return ( + <> + + edge.node) || [] + } + onAdd={() => navigate(productVariantAddUrl(productId))} + onBack={handleBack} + onDelete={() => openModal("remove")} + onImageSelect={handleImageSelect} + onSubmit={(data: ProductVariantPageSubmitData) => + updateVariant({ + variables: { + addStocks: data.addStocks.map(mapFormsetStockToStockInput), + attributes: data.attributes.map(attribute => ({ + id: attribute.id, + values: [attribute.value] + })), + costPrice: decimal(data.costPrice), + id: variantId, + price: decimal(data.price), + removeStocks: data.removeStocks, + sku: data.sku, + stocks: data.updateStocks.map(mapFormsetStockToStockInput), + trackInventory: data.trackInventory, + weight: weight(data.weight) + } + }) + } + onVariantClick={variantId => { + navigate(productVariantEditUrl(productId, variantId)); + }} + /> + navigate(productVariantEditUrl(productId, variantId))} + onConfirm={() => + deleteVariant({ + variables: { + id: variantId + } + }) + } + open={params.action === "remove"} + name={data?.productVariant?.name} + /> + ); }; export default ProductVariant;