Fix product creation flow for simple products (#4081)

* Fix simple product creation

* Fix simple product creation
This commit is contained in:
Patryk Andrzejewski 2023-08-16 10:40:35 +02:00 committed by GitHub
parent 3c1d84f775
commit 498feff0a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 11 deletions

View file

@ -233,7 +233,6 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
assignReferencesAttributeId, assignReferencesAttributeId,
data.attributes, data.attributes,
); );
return ( return (
<DetailPageLayout> <DetailPageLayout>
<TopNav href={productListUrl()} title={header} /> <TopNav href={productListUrl()} title={header} />
@ -275,7 +274,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
/> />
<ProductVariantPrice <ProductVariantPrice
ProductVariantChannelListings={data.channelListings} ProductVariantChannelListings={data.channelListings}
errors={channelsErrors} errors={[...errors, ...channelsErrors]}
loading={loading} loading={loading}
onChange={handlers.changeChannelPrice} onChange={handlers.changeChannelPrice}
/> />

View file

@ -9,11 +9,15 @@ import PriceField from "@dashboard/components/PriceField";
import ResponsiveTable from "@dashboard/components/ResponsiveTable"; import ResponsiveTable from "@dashboard/components/ResponsiveTable";
import Skeleton from "@dashboard/components/Skeleton"; import Skeleton from "@dashboard/components/Skeleton";
import TableRowLink from "@dashboard/components/TableRowLink"; import TableRowLink from "@dashboard/components/TableRowLink";
import { ProductChannelListingErrorFragment } from "@dashboard/graphql"; import {
ProductChannelListingErrorFragment,
ProductErrorFragment,
} from "@dashboard/graphql";
import { renderCollection } from "@dashboard/misc"; import { renderCollection } from "@dashboard/misc";
import { import {
getFormChannelError, getFormChannelError,
getFormChannelErrors, getFormChannelErrors,
getFormErrors,
} from "@dashboard/utils/errors"; } from "@dashboard/utils/errors";
import getProductErrorMessage from "@dashboard/utils/errors/product"; import getProductErrorMessage from "@dashboard/utils/errors/product";
import { TableBody, TableCell, TableHead } from "@material-ui/core"; import { TableBody, TableCell, TableHead } from "@material-ui/core";
@ -23,7 +27,7 @@ import { FormattedMessage, MessageDescriptor, useIntl } from "react-intl";
interface ProductVariantPriceProps { interface ProductVariantPriceProps {
ProductVariantChannelListings?: ChannelData[]; ProductVariantChannelListings?: ChannelData[];
errors?: ProductChannelListingErrorFragment[]; errors: Array<ProductErrorFragment | ProductChannelListingErrorFragment>;
loading?: boolean; loading?: boolean;
disabled?: boolean; disabled?: boolean;
onChange?: ( onChange?: (
@ -47,7 +51,10 @@ export const ProductVariantPrice: React.FC<
disabledMessage, disabledMessage,
} = props; } = props;
const intl = useIntl(); const intl = useIntl();
const formErrors = getFormChannelErrors(["price", "costPrice"], errors); const channelErrors = errors.filter(
e => "channels" in e,
) as ProductChannelListingErrorFragment[];
const apiErrors = getFormChannelErrors(["price", "costPrice"], channelErrors);
if (disabled || !ProductVariantChannelListings.length) { if (disabled || !ProductVariantChannelListings.length) {
return ( return (
@ -120,12 +127,15 @@ export const ProductVariantPrice: React.FC<
{renderCollection( {renderCollection(
ProductVariantChannelListings, ProductVariantChannelListings,
(listing, index) => { (listing, index) => {
const priceError = getFormChannelError( const fieldName = `${listing.id}-channel-price`;
formErrors.price, const formErrors = getFormErrors([fieldName], errors);
listing.id,
); const priceError =
getFormChannelError(apiErrors.price, listing.id) ||
formErrors[fieldName];
const costPriceError = getFormChannelError( const costPriceError = getFormChannelError(
formErrors.costPrice, apiErrors.costPrice,
listing.id, listing.id,
); );
@ -142,7 +152,7 @@ export const ProductVariantPrice: React.FC<
id: "b1zuN9", id: "b1zuN9",
defaultMessage: "Price", defaultMessage: "Price",
})} })}
name={`${listing.id}-channel-price`} name={fieldName}
value={listing.price || ""} value={listing.price || ""}
currencySymbol={listing.currency} currencySymbol={listing.currency}
onChange={e => onChange={e =>

View file

@ -0,0 +1,63 @@
import { ProductCreateData } from "../components/ProductCreatePage";
import { validateProductCreateData } from "./validation";
describe("validateProductCreateData", () => {
it("returns errors when there is no productType or name", () => {
// Arrange
const data = { productType: "" } as unknown as ProductCreateData;
// Act
const errors = validateProductCreateData(data);
// Assert
expect(errors).toEqual([
{
__typename: "ProductError",
attributes: [],
code: "REQUIRED",
field: "productType",
message: null,
},
{
__typename: "ProductError",
attributes: [],
code: "REQUIRED",
field: "name",
message: null,
},
]);
});
it("returns errors when there is no prices for channels", () => {
// Arrange
const data = {
productType: "something",
name: "something",
channelListings: [
{ id: "chann-1", price: "" },
{ id: "chann-2", price: "" },
],
} as unknown as ProductCreateData;
// Act
const errors = validateProductCreateData(data);
// Assert
expect(errors).toEqual([
{
__typename: "ProductError",
attributes: [],
code: "REQUIRED",
field: "chann-1-channel-price",
message: null,
},
{
__typename: "ProductError",
attributes: [],
code: "REQUIRED",
field: "chann-2-channel-price",
message: null,
},
]);
});
});

View file

@ -34,6 +34,14 @@ export const validateProductCreateData = (data: ProductCreateData) => {
errors = [...errors, createEmptyRequiredError("name")]; errors = [...errors, createEmptyRequiredError("name")];
} }
if (data.channelListings) {
const emptyPrices = data.channelListings
.filter(channel => channel.price?.length === 0)
.map(({ id }) => createEmptyRequiredError(`${id}-channel-price`));
errors = [...errors, ...emptyPrices];
}
return errors; return errors;
}; };