diff --git a/CHANGELOG.md b/CHANGELOG.md index 44a6c456c..ece7d4fd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ All notable, unreleased changes to this project will be documented in this file. - Add apps and permission groups to navigator - #678 by @dominik-zeglen - Add metadata - #670 by @dominik-zeglen - Update order history information - #680 by @dominik-zeglen +- Add metadata editor to creator views - #684 by @dominik-zeglen ## 2.10.1 diff --git a/src/attributes/components/AttributePage/AttributePage.tsx b/src/attributes/components/AttributePage/AttributePage.tsx index c0195e699..9fe12bdb0 100644 --- a/src/attributes/components/AttributePage/AttributePage.tsx +++ b/src/attributes/components/AttributePage/AttributePage.tsx @@ -82,9 +82,9 @@ const AttributePage: React.FC = ({ filterableInDashboard: true, filterableInStorefront: true, inputType: AttributeInputTypeEnum.DROPDOWN, - metadata: undefined, + metadata: [], name: "", - privateMetadata: undefined, + privateMetadata: [], slug: "", storefrontSearchPosition: "", valueRequired: true, @@ -119,10 +119,12 @@ const AttributePage: React.FC = ({ }; const handleSubmit = (data: AttributePageFormData) => { - const metadata = isMetadataModified ? data.metadata : undefined; - const privateMetadata = isPrivateMetadataModified - ? data.privateMetadata - : undefined; + const metadata = + !attribute || isMetadataModified ? data.metadata : undefined; + const privateMetadata = + !attribute || isPrivateMetadataModified + ? data.privateMetadata + : undefined; onSubmit({ ...data, @@ -170,12 +172,8 @@ const AttributePage: React.FC = ({ onValueReorder={onValueReorder} onValueUpdate={onValueUpdate} /> - {!!attribute && ( - <> - - - - )} + +
= ({ params }) => { } } }); + const [updateMetadata] = useMetadataUpdate({}); + const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const id = params.id ? parseInt(params.id, 0) : undefined; @@ -105,6 +114,31 @@ const AttributeDetails: React.FC = ({ params }) => { const handleValueReorder = ({ newIndex, oldIndex }: ReorderEvent) => setValues(move(values[oldIndex], values, areValuesEqual, newIndex)); + const handleCreate = async (data: AttributePageFormData) => { + const input = { + ...data, + metadata: undefined, + privateMetadata: undefined, + storefrontSearchPosition: parseInt(data.storefrontSearchPosition, 0), + values: values.map(value => ({ + name: value.name + })) + }; + + const result = await attributeCreate({ + variables: { + input + } + }); + + return result.data.attributeCreate?.attribute?.id || null; + }; + const handleSubmit = createMetadataCreateHandler( + handleCreate, + updateMetadata, + updatePrivateMetadata + ); + return ( <> = ({ params }) => { errors={attributeCreateOpts.data?.attributeCreate.errors || []} onBack={() => navigate(attributeListUrl())} onDelete={undefined} - onSubmit={input => - attributeCreate({ - variables: { - input: { - ...input, - storefrontSearchPosition: parseInt( - input.storefrontSearchPosition, - 0 - ), - values: values.map(value => ({ - name: value.name - })) - } - } - }) - } + onSubmit={handleSubmit} onValueAdd={() => openModal("add-value")} onValueDelete={id => openModal("remove-value", { diff --git a/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx b/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx index 4e350ce2a..202abe404 100644 --- a/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx +++ b/src/categories/components/CategoryCreatePage/CategoryCreatePage.tsx @@ -3,18 +3,20 @@ import { CardSpacer } from "@saleor/components/CardSpacer"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; +import Metadata, { MetadataFormData } from "@saleor/components/Metadata"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import { sectionNames } from "@saleor/intl"; +import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import { ContentState, convertToRaw, RawDraftContentState } from "draft-js"; import React from "react"; import { useIntl } from "react-intl"; import CategoryDetailsForm from "../../components/CategoryDetailsForm"; -interface FormData { +export interface FormData extends MetadataFormData { description: RawDraftContentState; name: string; seoTitle: string; @@ -23,7 +25,9 @@ interface FormData { const initialData: FormData = { description: convertToRaw(ContentState.createFromText("")), + metadata: [], name: "", + privateMetadata: [], seoDescription: "", seoTitle: "" }; @@ -44,49 +48,59 @@ export const CategoryCreatePage: React.FC = ({ saveButtonBarState }) => { const intl = useIntl(); + const { + makeChangeHandler: makeMetadataChangeHandler + } = useMetadataChangeTrigger(); + return (
- {({ data, change, submit, hasChanged }) => ( - - - {intl.formatMessage(sectionNames.categories)} - - -
- - - { + const changeMetadata = makeMetadataChangeHandler(change); + + return ( + + + {intl.formatMessage(sectionNames.categories)} + + - -
-
- )} +
+ + + + + + +
+ + ); + }}
); }; diff --git a/src/categories/views/CategoryCreate.tsx b/src/categories/views/CategoryCreate.tsx index aab98691a..606fab85b 100644 --- a/src/categories/views/CategoryCreate.tsx +++ b/src/categories/views/CategoryCreate.tsx @@ -1,11 +1,15 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; +import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; +import { + useMetadataUpdate, + usePrivateMetadataUpdate +} from "@saleor/utils/metadata/updateMetadata"; import React from "react"; import { useIntl } from "react-intl"; -import { maybe } from "../../misc"; -import CategoryCreatePage from "../components/CategoryCreatePage"; +import CategoryCreatePage, { FormData } from "../components/CategoryCreatePage"; import { useCategoryCreateMutation } from "../mutations"; import { CategoryCreate } from "../types/CategoryCreate"; import { categoryListUrl, categoryUrl } from "../urls"; @@ -20,6 +24,8 @@ export const CategoryCreateView: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const [updateMetadata] = useMetadataUpdate({}); + const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const handleSuccess = (data: CategoryCreate) => { if (data.categoryCreate.errors.length === 0) { @@ -37,9 +43,27 @@ export const CategoryCreateView: React.FC = ({ onCompleted: handleSuccess }); - const errors = maybe( - () => createCategoryResult.data.categoryCreate.errors, - [] + const handleCreate = async (formData: FormData) => { + const result = await createCategory({ + variables: { + input: { + descriptionJson: JSON.stringify(formData.description), + name: formData.name, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + } + }, + parent: parentId || null + } + }); + + return result.data?.categoryCreate.category?.id || null; + }; + const handleSubmit = createMetadataCreateHandler( + handleCreate, + updateMetadata, + updatePrivateMetadata ); return ( @@ -52,26 +76,12 @@ export const CategoryCreateView: React.FC = ({ /> navigate(parentId ? categoryUrl(parentId) : categoryListUrl()) } - onSubmit={formData => - createCategory({ - variables: { - input: { - descriptionJson: JSON.stringify(formData.description), - name: formData.name, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - } - }, - parent: parentId || null - } - }) - } + onSubmit={handleSubmit} /> ); diff --git a/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx b/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx index fdea99d5c..4aea831cb 100644 --- a/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx +++ b/src/collections/components/CollectionCreatePage/CollectionCreatePage.tsx @@ -1,19 +1,18 @@ -import Card from "@material-ui/core/Card"; -import CardContent from "@material-ui/core/CardContent"; import AppHeader from "@saleor/components/AppHeader"; import { CardSpacer } from "@saleor/components/CardSpacer"; -import CardTitle from "@saleor/components/CardTitle"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { Container } from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; +import Metadata, { MetadataFormData } from "@saleor/components/Metadata"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; import VisibilityCard from "@saleor/components/VisibilityCard"; import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; -import { commonMessages, sectionNames } from "@saleor/intl"; +import { sectionNames } from "@saleor/intl"; +import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import { ContentState, convertToRaw, RawDraftContentState } from "draft-js"; import React from "react"; import { useIntl } from "react-intl"; @@ -21,7 +20,7 @@ import { useIntl } from "react-intl"; import CollectionDetails from "../CollectionDetails/CollectionDetails"; import { CollectionImage } from "../CollectionImage/CollectionImage"; -export interface CollectionCreatePageFormData { +export interface CollectionCreatePageFormData extends MetadataFormData { backgroundImage: { url: string; value: string; @@ -51,7 +50,9 @@ const initialForm: CollectionCreatePageFormData = { backgroundImageAlt: "", description: convertToRaw(ContentState.createFromText("")), isPublished: false, + metadata: [], name: "", + privateMetadata: [], publicationDate: "", seoDescription: "", seoTitle: "" @@ -66,122 +67,122 @@ const CollectionCreatePage: React.FC = ({ }: CollectionCreatePageProps) => { const intl = useIntl(); const localizeDate = useDateLocalize(); + const { + makeChangeHandler: makeMetadataChangeHandler + } = useMetadataChangeTrigger(); return (
- {({ change, data, hasChanged, submit }) => ( - - - {intl.formatMessage(sectionNames.collections)} - - - -
- - - - change({ - target: { - name: "backgroundImage", - value: { - url: null, - value: null - } - } - } as any) - } - onImageUpload={file => - change({ - target: { - name: "backgroundImage", - value: { - url: URL.createObjectURL(file), - value: file - } - } - } as any) - } - onChange={change} - data={data} - /> - - -
-
+ {({ change, data, hasChanged, submit }) => { + const changeMetadata = makeMetadataChangeHandler(change); + + return ( + + + {intl.formatMessage(sectionNames.collections)} + + +
- - - - + + + change({ + target: { + name: "backgroundImage", + value: { + url: null, + value: null } - )} - /> - - + } + } as any) + } + onImageUpload={file => + change({ + target: { + name: "backgroundImage", + value: { + url: URL.createObjectURL(file), + value: file + } + } + } as any) + } + onChange={change} + data={data} + /> + + + +
-
-
- -
- )} +
+ +
+ + + + ); + }} ); }; diff --git a/src/collections/views/CollectionCreate.tsx b/src/collections/views/CollectionCreate.tsx index 6e90baf6b..ab2c29615 100644 --- a/src/collections/views/CollectionCreate.tsx +++ b/src/collections/views/CollectionCreate.tsx @@ -2,11 +2,18 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; +import { + useMetadataUpdate, + usePrivateMetadataUpdate +} from "@saleor/utils/metadata/updateMetadata"; import React from "react"; import { useIntl } from "react-intl"; import { CollectionCreateInput } from "../../types/globalTypes"; -import CollectionCreatePage from "../components/CollectionCreatePage/CollectionCreatePage"; +import CollectionCreatePage, { + CollectionCreatePageFormData +} from "../components/CollectionCreatePage/CollectionCreatePage"; import { useCollectionCreateMutation } from "../mutations"; import { collectionListUrl, collectionUrl } from "../urls"; @@ -14,6 +21,8 @@ export const CollectionCreate: React.FC = () => { const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const [updateMetadata] = useMetadataUpdate({}); + const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const [createCollection, createCollectionOpts] = useCollectionCreateMutation({ onCompleted: data => { @@ -38,6 +47,31 @@ export const CollectionCreate: React.FC = () => { } }); + const handleCreate = async (formData: CollectionCreatePageFormData) => { + const result = await createCollection({ + variables: { + input: { + backgroundImage: formData.backgroundImage.value, + backgroundImageAlt: formData.backgroundImageAlt, + descriptionJson: JSON.stringify(formData.description), + isPublished: formData.isPublished, + name: formData.name, + seo: { + description: formData.seoDescription, + title: formData.seoTitle + } + } + } + }); + + return result.data?.collectionCreate.collection?.id || null; + }; + const handleSubmit = createMetadataCreateHandler( + handleCreate, + updateMetadata, + updatePrivateMetadata + ); + return ( <> { errors={createCollectionOpts.data?.collectionCreate.errors || []} onBack={() => navigate(collectionListUrl())} disabled={createCollectionOpts.loading} - onSubmit={formData => - createCollection({ - variables: { - input: { - backgroundImage: formData.backgroundImage.value, - backgroundImageAlt: formData.backgroundImageAlt, - descriptionJson: JSON.stringify(formData.description), - isPublished: formData.isPublished, - name: formData.name, - seo: { - description: formData.seoDescription, - title: formData.seoTitle - } - } - } - }) - } + onSubmit={handleSubmit} saveButtonBarState={createCollectionOpts.status} /> diff --git a/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx b/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx index 93506b17e..79568ae1c 100644 --- a/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx +++ b/src/productTypes/components/ProductTypeCreatePage/ProductTypeCreatePage.tsx @@ -4,6 +4,7 @@ import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; +import Metadata, { MetadataFormData } from "@saleor/components/Metadata"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ChangeEvent, FormChange } from "@saleor/hooks/useForm"; @@ -12,6 +13,7 @@ import { sectionNames } from "@saleor/intl"; import { ProductTypeDetails_taxTypes } from "@saleor/productTypes/types/ProductTypeDetails"; import { UserError } from "@saleor/types"; import { WeightUnitsEnum } from "@saleor/types/globalTypes"; +import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import React from "react"; import { useIntl } from "react-intl"; @@ -19,7 +21,7 @@ import ProductTypeDetails from "../ProductTypeDetails/ProductTypeDetails"; import ProductTypeShipping from "../ProductTypeShipping/ProductTypeShipping"; import ProductTypeTaxes from "../ProductTypeTaxes/ProductTypeTaxes"; -export interface ProductTypeForm { +export interface ProductTypeForm extends MetadataFormData { name: string; isShippingRequired: boolean; taxType: string; @@ -39,7 +41,9 @@ export interface ProductTypeCreatePageProps { const formInitialData: ProductTypeForm = { isShippingRequired: false, + metadata: [], name: "", + privateMetadata: [], taxType: "", weight: 0 }; @@ -68,56 +72,65 @@ const ProductTypeCreatePage: React.FC = ({ }: ProductTypeCreatePageProps) => { const intl = useIntl(); const [taxTypeDisplayName, setTaxTypeDisplayName] = useStateFromProps(""); + const { + makeChangeHandler: makeMetadataChangeHandler + } = useMetadataChangeTrigger(); return (
- {({ change, data, hasChanged, submit }) => ( - - - {intl.formatMessage(sectionNames.productTypes)} - - - -
- - - - handleTaxTypeChange( - event, - taxTypes, - change, - setTaxTypeDisplayName - ) - } - /> -
-
- -
-
- -
- )} + {({ change, data, hasChanged, submit }) => { + const changeMetadata = makeMetadataChangeHandler(change); + + return ( + + + {intl.formatMessage(sectionNames.productTypes)} + + + +
+ + + + handleTaxTypeChange( + event, + taxTypes, + change, + setTaxTypeDisplayName + ) + } + /> + + +
+
+ +
+
+ +
+ ); + }}
); }; diff --git a/src/productTypes/views/ProductTypeCreate.tsx b/src/productTypes/views/ProductTypeCreate.tsx index 0c2c9a70a..80317b77a 100644 --- a/src/productTypes/views/ProductTypeCreate.tsx +++ b/src/productTypes/views/ProductTypeCreate.tsx @@ -1,6 +1,11 @@ import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; +import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; +import { + useMetadataUpdate, + usePrivateMetadataUpdate +} from "@saleor/utils/metadata/updateMetadata"; import React from "react"; import { useIntl } from "react-intl"; @@ -17,6 +22,8 @@ export const ProductTypeCreate: React.FC = () => { const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const [updateMetadata] = useMetadataUpdate({}); + const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const handleCreateSuccess = (updateData: ProductTypeCreateMutation) => { if (updateData.productTypeCreate.errors.length === 0) { @@ -32,8 +39,8 @@ export const ProductTypeCreate: React.FC = () => { return ( {(createProductType, createProductTypeOpts) => { - const handleCreate = (formData: ProductTypeForm) => - createProductType({ + const handleCreate = async (formData: ProductTypeForm) => { + const result = await createProductType({ variables: { input: { hasVariants: false, @@ -44,6 +51,15 @@ export const ProductTypeCreate: React.FC = () => { } } }); + + return result.data?.productTypeCreate.productType?.id || null; + }; + const handleSubmit = createMetadataCreateHandler( + handleCreate, + updateMetadata, + updatePrivateMetadata + ); + return ( {({ data, loading }) => ( @@ -58,19 +74,18 @@ export const ProductTypeCreate: React.FC = () => { data.shop.defaultWeightUnit)} disabled={loading} - errors={maybe( - () => createProductTypeOpts.data.productTypeCreate.errors, - [] - )} + errors={ + createProductTypeOpts.data?.productTypeCreate.errors || [] + } pageTitle={intl.formatMessage({ defaultMessage: "Create Product Type", description: "header", id: "productTypeCreatePageHeader" })} saveButtonBarState={createProductTypeOpts.status} - taxTypes={maybe(() => data.taxTypes, [])} + taxTypes={data?.taxTypes || []} onBack={() => navigate(productTypeListUrl())} - onSubmit={handleCreate} + onSubmit={handleSubmit} /> )} diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 9797ff062..5aeb02678 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -4,6 +4,7 @@ import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; +import Metadata, { MetadataFormData } from "@saleor/components/Metadata"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; @@ -25,6 +26,7 @@ import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/ import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; +import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import { ContentState, convertToRaw, RawDraftContentState } from "draft-js"; import React from "react"; import { useIntl } from "react-intl"; @@ -45,7 +47,7 @@ import ProductPricing from "../ProductPricing"; import ProductShipping from "../ProductShipping/ProductShipping"; import ProductStocks, { ProductStockInput } from "../ProductStocks"; -interface FormData { +interface FormData extends MetadataFormData { basePrice: number; publicationDate: string; category: string; @@ -133,6 +135,11 @@ export const ProductCreatePage: React.FC = ({ const initialDescription = React.useRef( convertToRaw(ContentState.createFromText("")) ); + + const { + makeChangeHandler: makeMetadataChangeHandler + } = useMetadataChangeTrigger(); + const initialData: FormData = { basePrice: 0, category: "", @@ -140,7 +147,9 @@ export const ProductCreatePage: React.FC = ({ collections: [], description: {} as any, isPublished: false, + metadata: [], name: "", + privateMetadata: [], productType: "", publicationDate: "", seoDescription: "", @@ -170,9 +179,9 @@ export const ProductCreatePage: React.FC = ({ const handleSubmit = (data: FormData) => onSubmit({ + ...data, attributes, - stocks, - ...data + stocks }); return ( @@ -212,6 +221,8 @@ export const ProductCreatePage: React.FC = ({ productTypeChoiceList ); + const changeMetadata = makeMetadataChangeHandler(change); + return ( @@ -296,6 +307,8 @@ export const ProductCreatePage: React.FC = ({ loading={disabled} onChange={change} /> + +
= ({ data: stocks, remove: removeStock } = useFormset([]); + const { + makeChangeHandler: makeMetadataChangeHandler + } = useMetadataChangeTrigger(); const initialForm: ProductVariantCreatePageFormData = { costPrice: "", images: maybe(() => product.images.map(image => image.id)), + metadata: [], price: "", + privateMetadata: [], quantity: "0", sku: "", trackInventory: true, @@ -108,6 +115,7 @@ const ProductVariantCreatePage: React.FC = ({ changeAttributeData(id, value); triggerChange(); }; + const changeMetadata = makeMetadataChangeHandler(change); return ( @@ -176,6 +184,8 @@ const ProductVariantCreatePage: React.FC = ({ removeStock(id); }} /> + +
{ first: 50 } }); + const [updateMetadata] = useMetadataUpdate({}); + const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const handleBack = () => navigate(productListUrl()); @@ -66,8 +73,8 @@ export const ProductCreateView: React.FC = () => { } }); - const handleSubmit = (formData: ProductCreatePageSubmitData) => { - productCreate({ + const handleCreate = async (formData: ProductCreatePageSubmitData) => { + const result = await productCreate({ variables: { attributes: formData.attributes.map(attribute => ({ id: attribute.id, @@ -96,7 +103,14 @@ export const ProductCreateView: React.FC = () => { weight: weight(formData.weight) } }); + + return result.data.productCreate?.product?.id || null; }; + const handleSubmit = createMetadataCreateHandler( + handleCreate, + updateMetadata, + updatePrivateMetadata + ); return ( <> diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index 36b821eff..bb52bf67d 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -4,6 +4,11 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; import { commonMessages } from "@saleor/intl"; +import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; +import { + useMetadataUpdate, + usePrivateMetadataUpdate +} from "@saleor/utils/metadata/updateMetadata"; import { useWarehouseList } from "@saleor/warehouses/queries"; import React from "react"; import { useIntl } from "react-intl"; @@ -55,6 +60,8 @@ export const ProductVariant: React.FC = ({ } } }); + const [updateMetadata] = useMetadataUpdate({}); + const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const product = data?.product; @@ -63,8 +70,8 @@ export const ProductVariant: React.FC = ({ } const handleBack = () => navigate(productUrl(productId)); - const handleSubmit = (formData: ProductVariantCreatePageSubmitData) => - variantCreate({ + const handleCreate = async (formData: ProductVariantCreatePageSubmitData) => { + const result = await variantCreate({ variables: { input: { attributes: formData.attributes @@ -86,6 +93,14 @@ export const ProductVariant: React.FC = ({ } } }); + + return result.data.productVariantCreate?.productVariant?.id || null; + }; + const handleSubmit = createMetadataCreateHandler( + handleCreate, + updateMetadata, + updatePrivateMetadata + ); const handleVariantClick = (id: string) => navigate(productVariantEditUrl(productId, id)); diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 4d5cbc8eb..2322219b0 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -21166,6 +21166,134 @@ exports[`Storyshots Views / Attributes / Attribute details create 1`] = ` +
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+
+ + ‌ + +
+
+
+
+
+ + Private Metadata + +
+
+
+
+
+ + ‌ + +
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
@@ -31644,6 +31974,134 @@ Ctrl + K"
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
@@ -32109,6 +32567,134 @@ Ctrl + K"
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
@@ -49919,193 +50505,293 @@ Ctrl + K"
-
-
-
+
+
+ + Metadata +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+ +
+
+
+
+ + Visibility +
+
+
+
+
+
-
- Visibility - -
-
-
-
-
-
-
-
-
+
+ + + - Set publication date -
-
-
+

+ Visible +

+ + + +
+
+ Set publication date +
+
@@ -50671,199 +51357,299 @@ Ctrl + K"
-
-
-
+
+
+ + Metadata +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+ +
+
+
+
+ + Visibility +
+
+
+
+
+
-
- Visibility - -
-
-
-
-
-
-
-
-
+
+ + + - Set publication date -
-
-
-
-
+

+ Visible +

+ + + +
+
+ Set publication date +
+
+
+
@@ -51420,197 +52206,297 @@ Ctrl + K"
-
-
-
+
+
+ + Metadata +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+ +
+
+
+
+ + Visibility +
+
+
+
+
+
-
- Visibility - -
-
-
-
-
-
-
-
-
+
+ + + - Set publication date -
-
-
+

+ Visible +

+ + + +
+
+ Set publication date +
+
@@ -119928,6 +120814,134 @@ exports[`Storyshots Views / Product types / Create product type default 1`] = `
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
@@ -135126,6 +136908,134 @@ exports[`Storyshots Views / Products / Create product variant default 1`] = `
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
@@ -135746,6 +137656,134 @@ exports[`Storyshots Views / Products / Create product variant when loading data
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
@@ -136451,6 +138489,134 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] =
+
+
+
+ + Metadata + +
+
+
+
+ +
+
+
+ + Private Metadata + +
+
+
+
+
diff --git a/src/utils/handlers/metadataCreateHandler.ts b/src/utils/handlers/metadataCreateHandler.ts new file mode 100644 index 000000000..e24491b80 --- /dev/null +++ b/src/utils/handlers/metadataCreateHandler.ts @@ -0,0 +1,68 @@ +import { MetadataFormData } from "@saleor/components/Metadata/types"; +import { MutationFunction } from "react-apollo"; + +import { + UpdateMetadata, + UpdateMetadataVariables +} from "../metadata/types/UpdateMetadata"; +import { + UpdatePrivateMetadata, + UpdatePrivateMetadataVariables +} from "../metadata/types/UpdatePrivateMetadata"; + +function createMetadataCreateHandler( + create: (data: T) => Promise, + setMetadata: MutationFunction, + setPrivateMetadata: MutationFunction< + UpdatePrivateMetadata, + UpdatePrivateMetadataVariables + > +) { + return async (data: T) => { + const id = await create(data); + + if (id === null) { + return null; + } + + if (data.metadata.length > 0) { + const updateMetaResult = await setMetadata({ + variables: { + id, + input: data.metadata, + keysToDelete: [] + } + }); + const updateMetaErrors = [ + ...(updateMetaResult.data.deleteMetadata.errors || []), + ...(updateMetaResult.data.updateMetadata.errors || []) + ]; + + if (updateMetaErrors.length > 0) { + return updateMetaErrors; + } + } + if (data.privateMetadata.length > 0) { + const updatePrivateMetaResult = await setPrivateMetadata({ + variables: { + id, + input: data.privateMetadata, + keysToDelete: [] + } + }); + + const updatePrivateMetaErrors = [ + ...(updatePrivateMetaResult.data.deletePrivateMetadata.errors || []), + ...(updatePrivateMetaResult.data.updatePrivateMetadata.errors || []) + ]; + + if (updatePrivateMetaErrors.length > 0) { + return updatePrivateMetaErrors; + } + } + + return []; + }; +} + +export default createMetadataCreateHandler;