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

View file

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

View file

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

View file

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