Fix undefined and null objects handling

This commit is contained in:
dominik-zeglen 2020-10-22 14:06:13 +02:00
parent 16d9d28033
commit a34d22de8f
5 changed files with 167 additions and 163 deletions

View file

@ -128,151 +128,156 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
taxTypes={taxTypeChoices}
warehouses={warehouses}
>
{({ change, data, handlers, hasChanged, submit }) => (
<Container>
<AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.products)}
</AppHeader>
<PageHeader title={header} />
<Grid>
<div>
<ProductDetailsForm
data={data}
disabled={disabled}
errors={errors}
initialDescription={initialDescription.current}
onChange={change}
/>
<CardSpacer />
{data.attributes.length > 0 && (
<ProductAttributes
attributes={data.attributes}
{({ change, data, handlers, hasChanged, submit }) => {
// Comparing explicitly to false because `hasVariants` can be undefined
const isSimpleProduct = data.productType?.hasVariants === false;
return (
<Container>
<AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.products)}
</AppHeader>
<PageHeader title={header} />
<Grid>
<div>
<ProductDetailsForm
data={data}
disabled={disabled}
errors={errors}
onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple}
initialDescription={initialDescription.current}
onChange={change}
/>
)}
<CardSpacer />
{!data.productType?.hasVariants && (
<>
<ProductShipping
data={data}
<CardSpacer />
{data.attributes.length > 0 && (
<ProductAttributes
attributes={data.attributes}
disabled={disabled}
errors={errors}
weightUnit={weightUnit}
onChange={change}
onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple}
/>
<ProductPricing
currency={currency}
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<ProductStocks
data={data}
disabled={disabled}
hasVariants={false}
onFormDataChange={change}
errors={errors}
stocks={data.stocks}
warehouses={warehouses}
onChange={handlers.changeStock}
onWarehouseStockAdd={handlers.addStock}
onWarehouseStockDelete={handlers.deleteStock}
onWarehouseConfigure={onWarehouseConfigure}
/>
<CardSpacer />
</>
)}
<SeoForm
allowEmptySlug={true}
helperText={intl.formatMessage({
defaultMessage:
"Add search engine title and description to make this product easier to find"
})}
title={data.seoTitle}
slug={data.slug}
slugPlaceholder={data.name}
titlePlaceholder={data.name}
description={data.seoDescription}
descriptionPlaceholder={data.seoTitle}
loading={disabled}
onChange={change}
/>
<CardSpacer />
<Metadata data={data} onChange={handlers.changeMetadata} />
</div>
<div>
<ProductOrganization
canChangeType={true}
categories={categories}
categoryInputDisplayValue={selectedCategory}
collections={collections}
data={data}
disabled={disabled}
errors={errors}
fetchCategories={fetchCategories}
fetchCollections={fetchCollections}
fetchMoreCategories={fetchMoreCategories}
fetchMoreCollections={fetchMoreCollections}
fetchMoreProductTypes={fetchMoreProductTypes}
fetchProductTypes={fetchProductTypes}
productType={data.productType}
productTypeInputDisplayValue={data.productType?.name || ""}
productTypes={productTypes}
onCategoryChange={handlers.selectCategory}
onCollectionChange={handlers.selectCollection}
onProductTypeChange={handlers.selectProductType}
collectionsInputDisplayValue={selectedCollections}
/>
<CardSpacer />
<AvailabilityCard
data={data}
errors={errors}
disabled={disabled}
messages={{
hiddenLabel: intl.formatMessage({
defaultMessage: "Not published",
description: "product label"
}),
hiddenSecondLabel: intl.formatMessage(
{
defaultMessage: "will become published on {date}",
description: "product publication date label"
},
{
date: localizeDate(data.publicationDate, "L")
}
),
visibleLabel: intl.formatMessage({
defaultMessage: "Published",
description: "product label"
})
}}
onChange={change}
/>
<CardSpacer />
<ProductTaxes
data={data}
disabled={disabled}
onChange={change}
onTaxTypeChange={handlers.selectTaxRate}
selectedTaxTypeDisplayName={selectedTaxType}
taxTypes={taxTypes}
/>
</div>
</Grid>
<SaveButtonBar
onCancel={onBack}
onSave={submit}
state={saveButtonBarState}
disabled={disabled || !onSubmit || !hasChanged}
/>
</Container>
)}
)}
<CardSpacer />
{isSimpleProduct && (
<>
<ProductShipping
data={data}
disabled={disabled}
errors={errors}
weightUnit={weightUnit}
onChange={change}
/>
<ProductPricing
currency={currency}
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<ProductStocks
data={data}
disabled={disabled}
hasVariants={false}
onFormDataChange={change}
errors={errors}
stocks={data.stocks}
warehouses={warehouses}
onChange={handlers.changeStock}
onWarehouseStockAdd={handlers.addStock}
onWarehouseStockDelete={handlers.deleteStock}
onWarehouseConfigure={onWarehouseConfigure}
/>
<CardSpacer />
</>
)}
<SeoForm
allowEmptySlug={true}
helperText={intl.formatMessage({
defaultMessage:
"Add search engine title and description to make this product easier to find"
})}
title={data.seoTitle}
slug={data.slug}
slugPlaceholder={data.name}
titlePlaceholder={data.name}
description={data.seoDescription}
descriptionPlaceholder={data.seoTitle}
loading={disabled}
onChange={change}
/>
<CardSpacer />
<Metadata data={data} onChange={handlers.changeMetadata} />
</div>
<div>
<ProductOrganization
canChangeType={true}
categories={categories}
categoryInputDisplayValue={selectedCategory}
collections={collections}
data={data}
disabled={disabled}
errors={errors}
fetchCategories={fetchCategories}
fetchCollections={fetchCollections}
fetchMoreCategories={fetchMoreCategories}
fetchMoreCollections={fetchMoreCollections}
fetchMoreProductTypes={fetchMoreProductTypes}
fetchProductTypes={fetchProductTypes}
productType={data.productType}
productTypeInputDisplayValue={data.productType?.name || ""}
productTypes={productTypes}
onCategoryChange={handlers.selectCategory}
onCollectionChange={handlers.selectCollection}
onProductTypeChange={handlers.selectProductType}
collectionsInputDisplayValue={selectedCollections}
/>
<CardSpacer />
<AvailabilityCard
data={data}
errors={errors}
disabled={disabled}
messages={{
hiddenLabel: intl.formatMessage({
defaultMessage: "Not published",
description: "product label"
}),
hiddenSecondLabel: intl.formatMessage(
{
defaultMessage: "will become published on {date}",
description: "product publication date label"
},
{
date: localizeDate(data.publicationDate, "L")
}
),
visibleLabel: intl.formatMessage({
defaultMessage: "Published",
description: "product label"
})
}}
onChange={change}
/>
<CardSpacer />
<ProductTaxes
data={data}
disabled={disabled}
onChange={change}
onTaxTypeChange={handlers.selectTaxRate}
selectedTaxTypeDisplayName={selectedTaxType}
taxTypes={taxTypes}
/>
</div>
</Grid>
<SaveButtonBar
onCancel={onBack}
onSave={submit}
state={saveButtonBarState}
disabled={disabled || !onSubmit || !hasChanged}
/>
</Container>
);
}}
</ProductCreateForm>
);
};

View file

@ -1,2 +1,3 @@
export { default } from "./ProductCreatePage";
export * from "./ProductCreatePage";
export * from "./form";

View file

@ -127,9 +127,10 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
const anchor = React.useRef<HTMLDivElement>();
const [isExpanded, setExpansionState] = React.useState(false);
const warehousesToAssign = warehouses.filter(
warehouse => !stocks.some(stock => stock.id === warehouse.id)
);
const warehousesToAssign =
warehouses?.filter(
warehouse => !stocks.some(stock => stock.id === warehouse.id)
) || [];
const formErrors = getFormErrors(["sku"], errors);
return (
@ -187,7 +188,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
</span>
</div>
</Typography>
{!warehouses.length && (
{!warehouses?.length && (
<Typography color="textSecondary" className={classes.noWarehouseInfo}>
{hasVariants ? (
<>
@ -219,7 +220,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
</Typography>
)}
</CardContent>
{warehouses.length > 0 && (
{warehouses?.length > 0 && (
<Table>
<TableHead>
<TableRow>

View file

@ -90,13 +90,12 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
const [isModalOpened, setModalStatus] = React.useState(false);
const toggleModal = () => setModalStatus(!isModalOpened);
const variantImages = variant?.images?.map(image => image.id) || [];
const productImages =
variant?.product?.images?.sort((prev, next) =>
prev.sortOrder > next.sortOrder ? 1 : -1
) || [];
const variantImages = variant?.images?.map(image => image.id);
const productImages = variant?.product?.images?.sort((prev, next) =>
prev.sortOrder > next.sortOrder ? 1 : -1
);
const images = productImages
.filter(image => variantImages.indexOf(image.id) !== -1)
?.filter(image => variantImages.indexOf(image.id) !== -1)
.sort((prev, next) => (prev.sortOrder > next.sortOrder ? 1 : -1));
return (

View file

@ -5,7 +5,7 @@ import { storiesOf } from "@storybook/react";
import React from "react";
import ProductCreatePage, {
ProductCreatePageSubmitData
ProductCreateFormData
} from "../../../products/components/ProductCreatePage";
import { product as productFixture } from "../../../products/fixtures";
import { productTypes } from "../../../productTypes/fixtures";
@ -74,17 +74,15 @@ storiesOf("Views / Products / Create product", module)
"productType",
"category",
"sku"
] as Array<keyof ProductCreatePageSubmitData | "attributes">).map(
field => ({
__typename: "ProductError",
attributes:
field === "attributes"
? [productTypes[0].productAttributes[0].id]
: null,
code: ProductErrorCode.INVALID,
field
})
)}
] as Array<keyof ProductCreateFormData | "attributes">).map(field => ({
__typename: "ProductError",
attributes:
field === "attributes"
? [productTypes[0].productAttributes[0].id]
: null,
code: ProductErrorCode.INVALID,
field
}))}
header="Add product"
collections={product.collections}
fetchCategories={() => undefined}
@ -94,7 +92,7 @@ storiesOf("Views / Products / Create product", module)
fetchMoreCollections={fetchMoreProps}
fetchMoreProductTypes={fetchMoreProps}
initial={{
productType: productTypes[0].id
productType: productTypes[0]
}}
productTypes={productTypes}
categories={[product.category]}