diff --git a/CHANGELOG.md b/CHANGELOG.md index 195c53bca..7e5f49767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ All notable, unreleased changes to this project will be documented in this file. - Fix style of product type attributes empty table - #744 by @orzechdev - Fix order draft back button redirect - #753 by @orzechdev - Add manage product types and attributes permission - #768 by @orzechdev +- Fix isPublished and isAvailable behaviour for products, collections and pages - #780 by @mmarkusik ## 2.10.1 diff --git a/assets/images/close-thin.svg b/assets/images/close-thin.svg new file mode 100644 index 000000000..eebda0b81 --- /dev/null +++ b/assets/images/close-thin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx b/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx index 3127745b3..d2661ed3a 100644 --- a/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx +++ b/src/collections/components/CollectionDetailsPage/CollectionDetailsPage.tsx @@ -83,6 +83,7 @@ const CollectionDetailsPage: React.FC = ({ onSubmit({ ...data, + isPublished: data.isPublished || !!data.publicationDate, metadata, privateMetadata }); diff --git a/src/components/VisibilityCard/DateVisibilitySelector.tsx b/src/components/VisibilityCard/DateVisibilitySelector.tsx new file mode 100644 index 000000000..47bd19336 --- /dev/null +++ b/src/components/VisibilityCard/DateVisibilitySelector.tsx @@ -0,0 +1,83 @@ +import closeIcon from "@assets/images/close-thin.svg"; +import { Typography } from "@material-ui/core"; +import { makeStyles } from "@material-ui/core/styles"; +import React, { useState } from "react"; + +import FormSpacer from "../FormSpacer"; + +const CLOSE_ICON_SIZE = 14; + +const useStyles = makeStyles( + theme => ({ + buttonText: { + color: theme.palette.primary.main, + cursor: "pointer", + fontSize: 14, + marginBottom: theme.spacing(1), + paddingBottom: 10, + paddingTop: 0 + }, + container: { + alignItems: "baseline", + display: "flex", + flexDirection: "row", + justifyContent: "space-between" + }, + icon: { + cursor: "pointer", + marginLeft: theme.spacing(2) + } + }), + { name: "DateVisibilitySelector" } +); + +interface Props { + buttonText: string; + children: React.ReactNode; + onInputClose: () => void; +} + +const DateVisibilitySelector = ({ + buttonText, + children, + onInputClose +}: Props) => { + const classes = useStyles({}); + + const [showInput, setShowInput] = useState(false); + + const handleCloseIconClick = () => { + setShowInput(false); + onInputClose(); + }; + + if (!showInput) { + return ( + setShowInput(true)} + > + {buttonText} + + ); + } + + return ( + <> +
+ {children} +
+ close icon +
+
+ + + ); +}; + +export default DateVisibilitySelector; diff --git a/src/components/VisibilityCard/VisibilityCard.tsx b/src/components/VisibilityCard/VisibilityCard.tsx index a97754e83..95a163555 100644 --- a/src/components/VisibilityCard/VisibilityCard.tsx +++ b/src/components/VisibilityCard/VisibilityCard.tsx @@ -12,11 +12,12 @@ import { ChangeEvent } from "@saleor/hooks/useForm"; import { UserError } from "@saleor/types"; import { getFieldError } from "@saleor/utils/errors"; import classNames from "classnames"; -import React, { useState } from "react"; +import React from "react"; import { useIntl } from "react-intl"; import { DateContext } from "../Date/DateContext"; import FormSpacer from "../FormSpacer"; +import DateVisibilitySelector from "./DateVisibilitySelector"; const useStyles = makeStyles( theme => ({ @@ -36,7 +37,7 @@ const useStyles = makeStyles( "& svg": { fill: theme.palette.primary.main }, - marginTop: theme.spacing(3) + marginTop: theme.spacing(1) }, label: { lineHeight: 1.2, @@ -48,14 +49,11 @@ const useStyles = makeStyles( }, secondLabel: { color: theme.palette.text.hint, - fontSize: 12 + fontSize: 12, + marginBottom: theme.spacing(2) }, - setPublicationDate: { - color: theme.palette.primary.main, - cursor: "pointer", - fontSize: 14, - paddingBottom: 10, - paddingTop: 0 + switchField: { + marginTop: theme.spacing(1) } }), { name: "VisibilityCard" } @@ -71,13 +69,17 @@ interface Message { availableSecondLabel?: string; setAvailabilityDateLabel?: string; } + +export interface DateFields { + publicationDate: string; + availableForPurchase?: string; +} + export interface VisibilityCardProps { children?: React.ReactNode | React.ReactNodeArray; - data: { - availableForPurchase?: string; + data: DateFields & { isAvailableForPurchase?: boolean; isPublished: boolean; - publicationDate: string; visibleInListings?: boolean; }; errors: UserError[]; @@ -108,13 +110,6 @@ export const VisibilityCard: React.FC = props => { const hasAvailableProps = isAvailable !== undefined && availableForPurchase !== undefined; - const [isPublicationDate, setPublicationDate] = useState( - publicationDate === null ? true : false - ); - const [isAvailableDate, setAvailableDate] = useState( - availableForPurchase === null ? true : false - ); - const visibleMessage = (date: string) => intl.formatMessage( { @@ -126,6 +121,21 @@ export const VisibilityCard: React.FC = props => { } ); + const handleRadioFieldChange = (type: keyof DateFields) => ( + e: ChangeEvent + ) => { + const { value } = e.target; + if (!value) { + onChange({ + target: { + name: type, + value: null + } + }); + } + return onChange(e); + }; + return ( = props => { } value={isPublished} - onChange={onChange} + onChange={handleRadioFieldChange("publicationDate")} /> {!isPublished && ( - <> - setPublicationDate(!isPublicationDate)} - > - {intl.formatMessage({ - defaultMessage: "Set publication date" + + onChange({ target: { name: "publicationDate", value: null } }) + } + > + - {isPublicationDate && ( - - )} - + name="publicationDate" + type="date" + fullWidth={true} + helperText={getFieldError(errors, "publicationDate")?.message} + value={publicationDate ? publicationDate : ""} + onChange={onChange} + className={classes.date} + InputLabelProps={{ + shrink: true + }} + /> + )} {getFieldError(errors, "isPublished") && ( <> @@ -211,6 +218,7 @@ export const VisibilityCard: React.FC = props => { <>
= props => { } value={isAvailable} - onChange={e => { - const { value } = e.target; - if (!value) { - onChange({ - target: { - name: "availableForPurchase", - value: null - } - }); - } - return onChange(e); - }} + onChange={handleRadioFieldChange("availableForPurchase")} /> {!isAvailable && ( - <> - setAvailableDate(!isAvailable)} - > - {messages.setAvailabilityDateLabel} - - {isAvailableDate && ( - - )} - + + onChange({ + target: { name: "availableForPurchase", value: null } + }) + } + > + + )} {getFieldError(errors, "isAvailableForPurchase") && ( <> diff --git a/src/pages/components/PageDetailsPage/PageDetailsPage.tsx b/src/pages/components/PageDetailsPage/PageDetailsPage.tsx index 772049b04..3253018d5 100644 --- a/src/pages/components/PageDetailsPage/PageDetailsPage.tsx +++ b/src/pages/components/PageDetailsPage/PageDetailsPage.tsx @@ -70,8 +70,16 @@ const PageDetailsPage: React.FC = ({ slug: maybe(() => page.slug, ""), title: maybe(() => page.title, "") }; + + const handleSubmit = (data: FormData) => onSubmit(getParsedData(data)); + + const getParsedData = (data: FormData) => ({ + ...data, + isPublished: data.isPublished || !!data.publicationDate + }); + return ( -
+ {({ change, data, hasChanged, submit }) => ( diff --git a/src/pages/views/PageCreate.tsx b/src/pages/views/PageCreate.tsx index c9110aaa6..384c80484 100644 --- a/src/pages/views/PageCreate.tsx +++ b/src/pages/views/PageCreate.tsx @@ -53,11 +53,7 @@ export const PageCreate: React.FC = () => { input: { contentJson: JSON.stringify(formData.content), isPublished: formData.isPublished, - publicationDate: formData.isPublished - ? null - : formData.publicationDate === "" - ? null - : formData.publicationDate, + publicationDate: formData.publicationDate, seo: { description: formData.seoDescription, title: formData.seoTitle diff --git a/src/pages/views/PageDetails.tsx b/src/pages/views/PageDetails.tsx index fd9cc58fd..23c1a9c65 100644 --- a/src/pages/views/PageDetails.tsx +++ b/src/pages/views/PageDetails.tsx @@ -23,11 +23,7 @@ export interface PageDetailsProps { const createPageInput = (data: FormData): PageInput => ({ contentJson: JSON.stringify(data.content), isPublished: data.isPublished, - publicationDate: data.isPublished - ? null - : data.publicationDate === "" - ? null - : data.publicationDate, + publicationDate: data.publicationDate, seo: { description: data.seoDescription, title: data.seoTitle diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index a83cca3f4..caaa33ff9 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -187,45 +187,54 @@ export const ProductUpdatePage: React.FC = ({ value: taxType.taxCode })) || []; - const handleSubmit = (data: ProductUpdatePageFormData) => { - const metadata = isMetadataModified ? data.metadata : undefined; - const privateMetadata = isPrivateMetadataModified - ? data.privateMetadata - : undefined; + const getAvailabilityData = ({ + availableForPurchase, + isAvailableForPurchase, + isPublished, + publicationDate + }: ProductUpdatePageFormData) => ({ + isAvailableForPurchase: isAvailableForPurchase || !!availableForPurchase, + isPublished: isPublished || !!publicationDate + }); + const getStocksData = () => { if (product.productType.hasVariants) { - onSubmit({ - ...data, - addStocks: [], - attributes, - metadata, - privateMetadata, - removeStocks: [], - updateStocks: [] - }); - } else { - const dataStocks = stocks.map(stock => stock.id); - const variantStocks = product.variants[0]?.stocks.map( - stock => stock.warehouse.id - ); - const stockDiff = diff(variantStocks, dataStocks); - - onSubmit({ - ...data, - addStocks: stocks.filter(stock => - stockDiff.added.some(addedStock => addedStock === stock.id) - ), - attributes, - metadata, - privateMetadata, - removeStocks: stockDiff.removed, - updateStocks: stocks.filter( - stock => !stockDiff.added.some(addedStock => addedStock === stock.id) - ) - }); + return { removeStocks: [], updateStocks: [] }; } + + const dataStocks = stocks.map(stock => stock.id); + const variantStocks = product.variants[0]?.stocks.map( + stock => stock.warehouse.id + ); + const stockDiff = diff(variantStocks, dataStocks); + + return { + removeStocks: stockDiff.removed, + updateStocks: stocks.filter( + stock => !stockDiff.added.some(addedStock => addedStock === stock.id) + ) + }; }; + const getMetadata = (data: ProductUpdatePageFormData) => ({ + metadata: isMetadataModified ? data.metadata : undefined, + privateMetadata: isPrivateMetadataModified + ? data.privateMetadata + : undefined + }); + + const getParsedData = (data: ProductUpdatePageFormData) => ({ + ...data, + ...getAvailabilityData(data), + ...getStocksData(), + ...getMetadata(data), + addStocks: [], + attributes + }); + + const handleSubmit = (data: ProductUpdatePageFormData) => + onSubmit(getParsedData(data)); + return ( {({ change, data, hasChanged, submit, triggerChange, toggleValue }) => { diff --git a/src/products/utils/handlers.ts b/src/products/utils/handlers.ts index 9f854c40a..d72deb0ed 100644 --- a/src/products/utils/handlers.ts +++ b/src/products/utils/handlers.ts @@ -60,23 +60,12 @@ interface ProductAvailabilityArgs { productId: string; } -export function getProductAvailabilityVariables({ +export const getProductAvailabilityVariables = ({ isAvailableForPurchase, availableForPurchase, productId -}: ProductAvailabilityArgs) { - const isAvailable = - availableForPurchase && !isAvailableForPurchase - ? true - : isAvailableForPurchase; - - return { - isAvailable, - productId, - startDate: isAvailableForPurchase - ? null - : availableForPurchase !== "" - ? availableForPurchase - : null - }; -} +}: ProductAvailabilityArgs) => ({ + isAvailable: isAvailableForPurchase, + productId, + startDate: availableForPurchase +}); diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 79a822a45..c0c8b558a 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -1437,7 +1437,7 @@ exports[`Storyshots Generics / AvailabilityCard default 1`] = ` class="Hr-root-id" />
Set availability date
@@ -47605,7 +47605,7 @@ Ctrl + K"
Set publication date
@@ -51453,7 +51453,7 @@ Ctrl + K"
Set publication date
@@ -52299,7 +52299,7 @@ Ctrl + K"
Set publication date
@@ -53146,7 +53146,7 @@ Ctrl + K"
Set publication date
@@ -113561,7 +113561,7 @@ Ctrl + K"
Set publication date
@@ -114385,7 +114385,7 @@ Ctrl + K"
Set publication date
@@ -115016,7 +115016,7 @@ Ctrl + K"
Set publication date
@@ -138280,7 +138280,7 @@ Ctrl + K"
Set publication date
@@ -138288,7 +138288,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
@@ -139561,7 +139561,7 @@ Ctrl + K"
Set publication date
@@ -139569,7 +139569,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
@@ -140993,7 +140993,7 @@ Ctrl + K"
Set publication date
@@ -141001,7 +141001,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
@@ -147655,7 +147655,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -149938,7 +149903,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -152448,7 +152378,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -154895,7 +154790,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -157539,7 +157399,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -160081,7 +159906,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -161731,7 +161521,7 @@ Ctrl + K"
Set publication date
@@ -164003,7 +163793,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-

@@ -166647,7 +166402,7 @@ Ctrl + K" class="Hr-root-id" />
Set availability date
-
- -
- - -
-