From 1ff350a2283836173768f2983078e2fa58386b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chy=C5=82a?= Date: Wed, 9 Oct 2024 11:04:05 +0200 Subject: [PATCH] Preventing crash when assigning product to shipping rate (#5188) * Fix reading id of undefined products * Add changeset --- .changeset/loud-weeks-tap.md | 5 ++ .../ShippingMethodProductsAddDialog.tsx | 24 ++++----- .../ShippingMethodProductsAddDialog/types.ts | 5 ++ .../utils.test.ts | 52 +++++++++++++++++++ .../ShippingMethodProductsAddDialog/utils.ts | 7 +++ 5 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 .changeset/loud-weeks-tap.md create mode 100644 src/shipping/components/ShippingMethodProductsAddDialog/types.ts create mode 100644 src/shipping/components/ShippingMethodProductsAddDialog/utils.test.ts create mode 100644 src/shipping/components/ShippingMethodProductsAddDialog/utils.ts diff --git a/.changeset/loud-weeks-tap.md b/.changeset/loud-weeks-tap.md new file mode 100644 index 00000000000..549811684a5 --- /dev/null +++ b/.changeset/loud-weeks-tap.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +Assigning product to shipping method weight rate no more cause error diff --git a/src/shipping/components/ShippingMethodProductsAddDialog/ShippingMethodProductsAddDialog.tsx b/src/shipping/components/ShippingMethodProductsAddDialog/ShippingMethodProductsAddDialog.tsx index f6087747f8d..df989c72e79 100644 --- a/src/shipping/components/ShippingMethodProductsAddDialog/ShippingMethodProductsAddDialog.tsx +++ b/src/shipping/components/ShippingMethodProductsAddDialog/ShippingMethodProductsAddDialog.tsx @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { FetchResult } from "@apollo/client"; import { Channel, isAvailableInChannel } from "@dashboard/channels/utils"; import BackButton from "@dashboard/components/BackButton"; @@ -8,10 +7,11 @@ import { DashboardModal } from "@dashboard/components/Modal"; import ResponsiveTable from "@dashboard/components/ResponsiveTable"; import TableCellAvatar from "@dashboard/components/TableCellAvatar"; import TableRowLink from "@dashboard/components/TableRowLink"; -import { SearchProductsQuery, ShippingPriceExcludeProductMutation } from "@dashboard/graphql"; +import { ShippingPriceExcludeProductMutation } from "@dashboard/graphql"; import useSearchQuery from "@dashboard/hooks/useSearchQuery"; import { renderCollection } from "@dashboard/misc"; -import { FetchMoreProps, RelayToFlat } from "@dashboard/types"; +import { isProductSelected } from "@dashboard/shipping/components/ShippingMethodProductsAddDialog/utils"; +import { FetchMoreProps } from "@dashboard/types"; import { CircularProgress, TableBody, TableCell, TextField } from "@material-ui/core"; import { makeStyles } from "@saleor/macaw-ui"; import { Box, Skeleton, Text } from "@saleor/macaw-ui-next"; @@ -19,6 +19,8 @@ import React from "react"; import InfiniteScroll from "react-infinite-scroll-component"; import { FormattedMessage, useIntl } from "react-intl"; +import { Product, Products } from "./types"; + const useStyles = makeStyles( () => ({ avatar: { @@ -41,7 +43,7 @@ const useStyles = makeStyles( export interface ShippingMethodProductsAddDialogProps extends FetchMoreProps { confirmButtonState: ConfirmButtonTransitionState; open: boolean; - products: RelayToFlat; + products: Products; onClose: () => void; onFetch: (query: string) => void; onSubmit: (ids: string[]) => Promise>; @@ -49,10 +51,10 @@ export interface ShippingMethodProductsAddDialogProps extends FetchMoreProps { } const handleProductAssign = ( - product: RelayToFlat[0], + product: Product, isSelected: boolean, - selectedProducts: RelayToFlat, - setSelectedProducts: (data: RelayToFlat) => void, + selectedProducts: Products, + setSelectedProducts: (data: Products) => void, ) => { if (isSelected) { setSelectedProducts( @@ -80,9 +82,7 @@ const ShippingMethodProductsAddDialog: React.FC - >([]); + const [selectedProducts, setSelectedProducts] = React.useState([]); const handleSubmit = () => { onSubmit(selectedProducts.map(product => product.id)).then(() => { setSelectedProducts([]); @@ -153,9 +153,7 @@ const ShippingMethodProductsAddDialog: React.FC { - const isSelected = selectedProducts.some( - selectedProduct => selectedProduct.id === product.id, - ); + const isSelected = isProductSelected(selectedProducts, product?.id); const isProductAvailable = isAvailableInChannel({ availableChannels, diff --git a/src/shipping/components/ShippingMethodProductsAddDialog/types.ts b/src/shipping/components/ShippingMethodProductsAddDialog/types.ts new file mode 100644 index 00000000000..15d1012b72c --- /dev/null +++ b/src/shipping/components/ShippingMethodProductsAddDialog/types.ts @@ -0,0 +1,5 @@ +import { SearchProductsQuery } from "@dashboard/graphql"; +import { RelayToFlat } from "@dashboard/types"; + +export type Products = NonNullable>; +export type Product = Products[0]; diff --git a/src/shipping/components/ShippingMethodProductsAddDialog/utils.test.ts b/src/shipping/components/ShippingMethodProductsAddDialog/utils.test.ts new file mode 100644 index 00000000000..8fb36125d70 --- /dev/null +++ b/src/shipping/components/ShippingMethodProductsAddDialog/utils.test.ts @@ -0,0 +1,52 @@ +import { Products } from "./types"; +import { isProductSelected } from "./utils"; + +describe("isProductSelected", () => { + it("should return false if product id is not provided", () => { + // Arrange + const selectedProducts = [{ id: "1" }, { id: "2" }] as Products; + const productId = undefined; + + // Act + const result = isProductSelected(selectedProducts, productId); + + // Assert + expect(result).toEqual(false); + }); + + it("should return false if product id is not in selected products", () => { + // Arrange + const selectedProducts = [{ id: "1" }, { id: "2" }] as Products; + const productId = "3"; + + // Act + const result = isProductSelected(selectedProducts, productId); + + // Assert + expect(result).toEqual(false); + }); + + it("should return false if no selected product", () => { + // Arrange + const selectedProducts = [] as Products; + const productId = "1"; + + // Act + const result = isProductSelected(selectedProducts, productId); + + // Assert + expect(result).toEqual(false); + }); + + it("should return true if product id is in selected products", () => { + // Arrange + const selectedProducts = [{ id: "1" }, { id: "2" }] as Products; + const productId = "2"; + + // Act + const result = isProductSelected(selectedProducts, productId); + + // Assert + expect(result).toEqual(true); + }); +}); diff --git a/src/shipping/components/ShippingMethodProductsAddDialog/utils.ts b/src/shipping/components/ShippingMethodProductsAddDialog/utils.ts new file mode 100644 index 00000000000..6168c3b8345 --- /dev/null +++ b/src/shipping/components/ShippingMethodProductsAddDialog/utils.ts @@ -0,0 +1,7 @@ +import { Products } from "./types"; + +export const isProductSelected = (selectedProducts: Products, productId?: string) => { + if (!productId) return false; + + return selectedProducts.some(selectedProduct => selectedProduct.id === productId); +};