Variant selection attributes (#1463)
* Create separate table for variant attributes and handle variant selection state * implemented most required changes * implementation * localize leftover string * implement most cr changes * implemented most of cr changes * add additional comment and fix ci * reorder update mutation for BE consistency Co-authored-by: bonifacy1 <szewczyk134@gmail.com>
This commit is contained in:
parent
19f90d29e8
commit
39dabc8ea2
20 changed files with 757 additions and 32 deletions
|
@ -5727,10 +5727,6 @@
|
||||||
"context": "section header",
|
"context": "section header",
|
||||||
"string": "Product Attributes"
|
"string": "Product Attributes"
|
||||||
},
|
},
|
||||||
"src_dot_productTypes_dot_components_dot_ProductTypeAttributes_dot_888493112": {
|
|
||||||
"context": "section header",
|
|
||||||
"string": "Variant Attributes"
|
|
||||||
},
|
|
||||||
"src_dot_productTypes_dot_components_dot_ProductTypeDetailsPage_dot_1217376589": {
|
"src_dot_productTypes_dot_components_dot_ProductTypeDetailsPage_dot_1217376589": {
|
||||||
"context": "switch button",
|
"context": "switch button",
|
||||||
"string": "Product type uses Variant Attributes"
|
"string": "Product type uses Variant Attributes"
|
||||||
|
@ -5827,6 +5823,31 @@
|
||||||
"src_dot_productTypes_dot_components_dot_ProductTypeShipping_dot_746695941": {
|
"src_dot_productTypes_dot_components_dot_ProductTypeShipping_dot_746695941": {
|
||||||
"string": "Weight"
|
"string": "Weight"
|
||||||
},
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_1192828581": {
|
||||||
|
"string": "No attributes found"
|
||||||
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_1228425832": {
|
||||||
|
"string": "Attribute name"
|
||||||
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_1656462109": {
|
||||||
|
"context": "button",
|
||||||
|
"string": "Assign attribute"
|
||||||
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_1779771890": {
|
||||||
|
"string": "{inputType} attributes cannot be used as variant selection attributes."
|
||||||
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_1835784218": {
|
||||||
|
"context": "variant attribute checkbox",
|
||||||
|
"string": "Variant Selection"
|
||||||
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_3478065224": {
|
||||||
|
"context": "attribute internal name",
|
||||||
|
"string": "Slug"
|
||||||
|
},
|
||||||
|
"src_dot_productTypes_dot_components_dot_ProductTypeVariantAttributes_dot_888493112": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Variant Attributes"
|
||||||
|
},
|
||||||
"src_dot_productTypes_dot_hooks_dot_useProductTypeDelete_dot_title": {
|
"src_dot_productTypes_dot_hooks_dot_useProductTypeDelete_dot_title": {
|
||||||
"context": "ProductTypeDeleteWarningDialog title",
|
"context": "ProductTypeDeleteWarningDialog title",
|
||||||
"string": "Delete product {selectedTypesCount,plural,one{type} other{types}}"
|
"string": "Delete product {selectedTypesCount,plural,one{type} other{types}}"
|
||||||
|
|
|
@ -70,6 +70,7 @@ enum AccountErrorCode {
|
||||||
JWT_INVALID_CSRF_TOKEN
|
JWT_INVALID_CSRF_TOKEN
|
||||||
CHANNEL_INACTIVE
|
CHANNEL_INACTIVE
|
||||||
MISSING_CHANNEL_SLUG
|
MISSING_CHANNEL_SLUG
|
||||||
|
ACCOUNT_NOT_CONFIRMED
|
||||||
}
|
}
|
||||||
|
|
||||||
input AccountInput {
|
input AccountInput {
|
||||||
|
@ -456,6 +457,11 @@ type AssignNavigation {
|
||||||
errors: [MenuError!]!
|
errors: [MenuError!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AssignedVariantAttribute {
|
||||||
|
attribute: Attribute!
|
||||||
|
variantSelection: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
type Attribute implements Node & ObjectWithMetadata {
|
type Attribute implements Node & ObjectWithMetadata {
|
||||||
id: ID!
|
id: ID!
|
||||||
productTypes(before: String, after: String, first: Int, last: Int): ProductTypeCountableConnection!
|
productTypes(before: String, after: String, first: Int, last: Int): ProductTypeCountableConnection!
|
||||||
|
@ -3748,6 +3754,7 @@ type Mutation {
|
||||||
shippingZoneBulkDelete(ids: [ID]!): ShippingZoneBulkDelete
|
shippingZoneBulkDelete(ids: [ID]!): ShippingZoneBulkDelete
|
||||||
shippingZoneUpdate(id: ID!, input: ShippingZoneUpdateInput!): ShippingZoneUpdate
|
shippingZoneUpdate(id: ID!, input: ShippingZoneUpdateInput!): ShippingZoneUpdate
|
||||||
productAttributeAssign(operations: [ProductAttributeAssignInput]!, productTypeId: ID!): ProductAttributeAssign
|
productAttributeAssign(operations: [ProductAttributeAssignInput]!, productTypeId: ID!): ProductAttributeAssign
|
||||||
|
productAttributeAssignmentUpdate(operations: [ProductAttributeAssignmentUpdateInput]!, productTypeId: ID!): ProductAttributeAssignmentUpdate
|
||||||
productAttributeUnassign(attributeIds: [ID]!, productTypeId: ID!): ProductAttributeUnassign
|
productAttributeUnassign(attributeIds: [ID]!, productTypeId: ID!): ProductAttributeUnassign
|
||||||
categoryCreate(input: CategoryInput!, parent: ID): CategoryCreate
|
categoryCreate(input: CategoryInput!, parent: ID): CategoryCreate
|
||||||
categoryDelete(id: ID!): CategoryDelete
|
categoryDelete(id: ID!): CategoryDelete
|
||||||
|
@ -5200,6 +5207,18 @@ type ProductAttributeAssign {
|
||||||
input ProductAttributeAssignInput {
|
input ProductAttributeAssignInput {
|
||||||
id: ID!
|
id: ID!
|
||||||
type: ProductAttributeType!
|
type: ProductAttributeType!
|
||||||
|
variantSelection: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductAttributeAssignmentUpdate {
|
||||||
|
productType: ProductType
|
||||||
|
productErrors: [ProductError!]! @deprecated(reason: "This field will be removed in Saleor 4.0. Use `errors` field instead.")
|
||||||
|
errors: [ProductError!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
input ProductAttributeAssignmentUpdateInput {
|
||||||
|
id: ID!
|
||||||
|
variantSelection: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ProductAttributeType {
|
enum ProductAttributeType {
|
||||||
|
@ -5527,7 +5546,8 @@ type ProductType implements Node & ObjectWithMetadata {
|
||||||
kind: ProductTypeKindEnum!
|
kind: ProductTypeKindEnum!
|
||||||
products(channel: String, before: String, after: String, first: Int, last: Int): ProductCountableConnection @deprecated(reason: "This field will be removed in Saleor 4.0. Use the top-level `products` query with the `productTypes` filter.")
|
products(channel: String, before: String, after: String, first: Int, last: Int): ProductCountableConnection @deprecated(reason: "This field will be removed in Saleor 4.0. Use the top-level `products` query with the `productTypes` filter.")
|
||||||
taxType: TaxType
|
taxType: TaxType
|
||||||
variantAttributes(variantSelection: VariantAttributeScope): [Attribute]
|
variantAttributes(variantSelection: VariantAttributeScope): [Attribute] @deprecated(reason: "This field will be removed in Saleor 4.0. use `assignedVariantAttributes` instead.")
|
||||||
|
assignedVariantAttributes(variantSelection: VariantAttributeScope): [AssignedVariantAttribute]
|
||||||
productAttributes: [Attribute]
|
productAttributes: [Attribute]
|
||||||
availableAttributes(filter: AttributeFilterInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection
|
availableAttributes(filter: AttributeFilterInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,12 @@ export const productTypeDetailsFragment = gql`
|
||||||
variantAttributes {
|
variantAttributes {
|
||||||
...AttributeFragment
|
...AttributeFragment
|
||||||
}
|
}
|
||||||
|
assignedVariantAttributes {
|
||||||
|
attribute {
|
||||||
|
...AttributeFragment
|
||||||
|
}
|
||||||
|
variantSelection
|
||||||
|
}
|
||||||
weight {
|
weight {
|
||||||
unit
|
unit
|
||||||
value
|
value
|
||||||
|
|
|
@ -53,6 +53,25 @@ export interface ProductTypeDetailsFragment_variantAttributes {
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeDetailsFragment_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeDetailsFragment_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: ProductTypeDetailsFragment_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductTypeDetailsFragment_weight {
|
export interface ProductTypeDetailsFragment_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -71,5 +90,6 @@ export interface ProductTypeDetailsFragment {
|
||||||
privateMetadata: (ProductTypeDetailsFragment_privateMetadata | null)[];
|
privateMetadata: (ProductTypeDetailsFragment_privateMetadata | null)[];
|
||||||
productAttributes: (ProductTypeDetailsFragment_productAttributes | null)[] | null;
|
productAttributes: (ProductTypeDetailsFragment_productAttributes | null)[] | null;
|
||||||
variantAttributes: (ProductTypeDetailsFragment_variantAttributes | null)[] | null;
|
variantAttributes: (ProductTypeDetailsFragment_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (ProductTypeDetailsFragment_assignedVariantAttributes | null)[] | null;
|
||||||
weight: ProductTypeDetailsFragment_weight | null;
|
weight: ProductTypeDetailsFragment_weight | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,25 +89,12 @@ const ProductTypeAttributes: React.FC<ProductTypeAttributesProps> = props => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card data-test="product-attributes">
|
||||||
data-test={
|
|
||||||
type === ProductAttributeType.PRODUCT
|
|
||||||
? "product-attributes"
|
|
||||||
: "variant-attributes"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={
|
title={intl.formatMessage({
|
||||||
type === ProductAttributeType.PRODUCT
|
defaultMessage: "Product Attributes",
|
||||||
? intl.formatMessage({
|
description: "section header"
|
||||||
defaultMessage: "Product Attributes",
|
})}
|
||||||
description: "section header"
|
|
||||||
})
|
|
||||||
: intl.formatMessage({
|
|
||||||
defaultMessage: "Variant Attributes",
|
|
||||||
description: "section header"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
toolbar={
|
toolbar={
|
||||||
<Button
|
<Button
|
||||||
data-test-id={testId}
|
data-test-id={testId}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ProductTypeAttributes from "../ProductTypeAttributes/ProductTypeAttribute
|
||||||
import ProductTypeDetails from "../ProductTypeDetails/ProductTypeDetails";
|
import ProductTypeDetails from "../ProductTypeDetails/ProductTypeDetails";
|
||||||
import ProductTypeShipping from "../ProductTypeShipping/ProductTypeShipping";
|
import ProductTypeShipping from "../ProductTypeShipping/ProductTypeShipping";
|
||||||
import ProductTypeTaxes from "../ProductTypeTaxes/ProductTypeTaxes";
|
import ProductTypeTaxes from "../ProductTypeTaxes/ProductTypeTaxes";
|
||||||
|
import ProductTypeVariantAttributes from "../ProductTypeVariantAttributes/ProductTypeVariantAttributes";
|
||||||
|
|
||||||
interface ChoiceType {
|
interface ChoiceType {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -67,6 +68,8 @@ export interface ProductTypeDetailsPageProps {
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
onHasVariantsToggle: (hasVariants: boolean) => void;
|
onHasVariantsToggle: (hasVariants: boolean) => void;
|
||||||
onSubmit: (data: ProductTypeForm) => SubmitPromise;
|
onSubmit: (data: ProductTypeForm) => SubmitPromise;
|
||||||
|
setSelectedVariantAttributes: (data: string[]) => void;
|
||||||
|
selectedVariantAttributes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTaxTypeChange(
|
function handleTaxTypeChange(
|
||||||
|
@ -98,7 +101,9 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
|
||||||
onBack,
|
onBack,
|
||||||
onDelete,
|
onDelete,
|
||||||
onHasVariantsToggle,
|
onHasVariantsToggle,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
setSelectedVariantAttributes,
|
||||||
|
selectedVariantAttributes
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const {
|
const {
|
||||||
|
@ -156,7 +161,7 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form initial={formInitialData} onSubmit={handleSubmit} confirmLeave>
|
<Form initial={formInitialData} onSubmit={handleSubmit} confirmLeave>
|
||||||
{({ change, data, hasChanged, submit }) => {
|
{({ change, data, hasChanged, submit, setChanged }) => {
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -217,9 +222,11 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
|
||||||
{data.hasVariants && (
|
{data.hasVariants && (
|
||||||
<>
|
<>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<ProductTypeAttributes
|
<ProductTypeVariantAttributes
|
||||||
testId="assignVariantsAttributes"
|
testId="assignVariantsAttributes"
|
||||||
attributes={maybe(() => productType.variantAttributes)}
|
assignedVariantAttributes={
|
||||||
|
productType?.assignedVariantAttributes
|
||||||
|
}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
type={ProductAttributeType.VARIANT}
|
type={ProductAttributeType.VARIANT}
|
||||||
onAttributeAssign={onAttributeAdd}
|
onAttributeAssign={onAttributeAdd}
|
||||||
|
@ -228,6 +235,11 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
|
||||||
onAttributeReorder(event, ProductAttributeType.VARIANT)
|
onAttributeReorder(event, ProductAttributeType.VARIANT)
|
||||||
}
|
}
|
||||||
onAttributeUnassign={onAttributeUnassign}
|
onAttributeUnassign={onAttributeUnassign}
|
||||||
|
onAttributeVariantSelection={setChanged}
|
||||||
|
setSelectedVariantAttributes={
|
||||||
|
setSelectedVariantAttributes
|
||||||
|
}
|
||||||
|
selectedVariantAttributes={selectedVariantAttributes}
|
||||||
{...variantAttributeList}
|
{...variantAttributeList}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
IconButton,
|
||||||
|
TableCell,
|
||||||
|
TableRow,
|
||||||
|
Tooltip
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
|
import HelpOutline from "@material-ui/icons/HelpOutline";
|
||||||
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
|
import Checkbox from "@saleor/components/Checkbox";
|
||||||
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
|
import {
|
||||||
|
SortableTableBody,
|
||||||
|
SortableTableRow
|
||||||
|
} from "@saleor/components/SortableTable";
|
||||||
|
import TableHead from "@saleor/components/TableHead";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { maybe, renderCollection, stopPropagation } from "@saleor/misc";
|
||||||
|
import { ListActions, ReorderAction } from "@saleor/types";
|
||||||
|
import { ProductAttributeType } from "@saleor/types/globalTypes";
|
||||||
|
import capitalize from "lodash/capitalize";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ProductTypeDetails_productType_assignedVariantAttributes,
|
||||||
|
ProductTypeDetails_productType_variantAttributes
|
||||||
|
} from "../../types/ProductTypeDetails";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
colAction: {
|
||||||
|
"&:last-child": {
|
||||||
|
paddingRight: 0
|
||||||
|
},
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
colGrab: {
|
||||||
|
width: 60
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
colSlug: {
|
||||||
|
width: 200
|
||||||
|
},
|
||||||
|
colVariant: {
|
||||||
|
width: 150
|
||||||
|
},
|
||||||
|
colVariantContent: {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center"
|
||||||
|
},
|
||||||
|
colVariantDisabled: {
|
||||||
|
fill: "#28234A",
|
||||||
|
fillOpacity: 0.6,
|
||||||
|
"&:hover": {
|
||||||
|
fillOpacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
cursor: "pointer"
|
||||||
|
},
|
||||||
|
textLeft: {
|
||||||
|
textAlign: "left"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ name: "ProductTypeAttributes" }
|
||||||
|
);
|
||||||
|
|
||||||
|
interface ProductTypeVariantAttributesProps extends ListActions {
|
||||||
|
assignedVariantAttributes: ProductTypeDetails_productType_assignedVariantAttributes[];
|
||||||
|
disabled: boolean;
|
||||||
|
type: string;
|
||||||
|
testId?: string;
|
||||||
|
selectedVariantAttributes: string[];
|
||||||
|
onAttributeAssign: (type: ProductAttributeType) => void;
|
||||||
|
onAttributeClick: (id: string) => void;
|
||||||
|
onAttributeReorder: ReorderAction;
|
||||||
|
onAttributeUnassign: (id: string) => void;
|
||||||
|
onAttributeVariantSelection?: (isActive: boolean) => void;
|
||||||
|
setSelectedVariantAttributes?: (data: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleContainerAssign(
|
||||||
|
variantID: string,
|
||||||
|
isSelected: boolean,
|
||||||
|
selectedAttributes: string[],
|
||||||
|
setSelectedAttributes: (data: string[]) => void
|
||||||
|
) {
|
||||||
|
if (isSelected) {
|
||||||
|
setSelectedAttributes(
|
||||||
|
selectedAttributes.filter(
|
||||||
|
selectedContainer => selectedContainer !== variantID
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setSelectedAttributes([...selectedAttributes, variantID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberOfColumns = 6;
|
||||||
|
|
||||||
|
const ProductTypeVariantAttributes: React.FC<ProductTypeVariantAttributesProps> = props => {
|
||||||
|
const {
|
||||||
|
assignedVariantAttributes,
|
||||||
|
disabled,
|
||||||
|
isChecked,
|
||||||
|
selected,
|
||||||
|
toggle,
|
||||||
|
toggleAll,
|
||||||
|
toolbar,
|
||||||
|
type,
|
||||||
|
testId,
|
||||||
|
onAttributeAssign,
|
||||||
|
onAttributeClick,
|
||||||
|
onAttributeReorder,
|
||||||
|
onAttributeUnassign,
|
||||||
|
onAttributeVariantSelection,
|
||||||
|
setSelectedVariantAttributes,
|
||||||
|
selectedVariantAttributes
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Populate initial selection - populated inside this component to preserve it's state between data reloads
|
||||||
|
setSelectedVariantAttributes(
|
||||||
|
assignedVariantAttributes
|
||||||
|
.map(elem => (elem.variantSelection ? elem.attribute.id : undefined))
|
||||||
|
.filter(Boolean) || []
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card data-test="variant-attributes">
|
||||||
|
<CardTitle
|
||||||
|
title={intl.formatMessage({
|
||||||
|
defaultMessage: "Variant Attributes",
|
||||||
|
description: "section header"
|
||||||
|
})}
|
||||||
|
toolbar={
|
||||||
|
<Button
|
||||||
|
data-test-id={testId}
|
||||||
|
color="primary"
|
||||||
|
variant="text"
|
||||||
|
onClick={() => onAttributeAssign(ProductAttributeType[type])}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Assign attribute"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ResponsiveTable>
|
||||||
|
<colgroup>
|
||||||
|
<col className={classes.colGrab} />
|
||||||
|
<col />
|
||||||
|
<col className={classes.colName} />
|
||||||
|
<col className={classes.colSlug} />
|
||||||
|
<col className={classes.colVariant} />
|
||||||
|
<col className={classes.colAction} />
|
||||||
|
</colgroup>
|
||||||
|
{assignedVariantAttributes?.length > 0 && (
|
||||||
|
<TableHead
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
disabled={disabled}
|
||||||
|
dragRows
|
||||||
|
selected={selected}
|
||||||
|
items={
|
||||||
|
(assignedVariantAttributes as unknown) as ProductTypeDetails_productType_variantAttributes[]
|
||||||
|
}
|
||||||
|
toggleAll={toggleAll}
|
||||||
|
toolbar={toolbar}
|
||||||
|
>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<FormattedMessage defaultMessage="Attribute name" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Slug"
|
||||||
|
description="attribute internal name"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Variant Selection"
|
||||||
|
description="variant attribute checkbox"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell />
|
||||||
|
</TableHead>
|
||||||
|
)}
|
||||||
|
<SortableTableBody onSortEnd={onAttributeReorder}>
|
||||||
|
{renderCollection(
|
||||||
|
assignedVariantAttributes,
|
||||||
|
(assignedVariantAttribute, attributeIndex) => {
|
||||||
|
const { attribute } = assignedVariantAttribute;
|
||||||
|
const isVariantSelected = assignedVariantAttribute
|
||||||
|
? isChecked(attribute.id)
|
||||||
|
: false;
|
||||||
|
const isSelected = !!selectedVariantAttributes.find(
|
||||||
|
selectedAttribute => selectedAttribute === attribute.id
|
||||||
|
);
|
||||||
|
const variantSelectionDisabled = ![
|
||||||
|
"DROPDOWN",
|
||||||
|
"BOOLEAN",
|
||||||
|
"SWATCH",
|
||||||
|
"NUMERIC"
|
||||||
|
].includes(attribute.inputType);
|
||||||
|
const readableAttributeInputType = capitalize(
|
||||||
|
attribute.inputType.split("_").join(" ")
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SortableTableRow
|
||||||
|
selected={isVariantSelected}
|
||||||
|
className={!!attribute ? classes.link : undefined}
|
||||||
|
hover={!!attribute}
|
||||||
|
onClick={
|
||||||
|
!!attribute
|
||||||
|
? () => onAttributeClick(attribute.id)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
key={maybe(() => attribute.id)}
|
||||||
|
index={attributeIndex || 0}
|
||||||
|
data-test="id"
|
||||||
|
data-test-id={maybe(() => attribute.id)}
|
||||||
|
>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={isVariantSelected}
|
||||||
|
disabled={disabled}
|
||||||
|
disableClickPropagation
|
||||||
|
onChange={() => toggle(attribute.id)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colName} data-test="name">
|
||||||
|
{attribute.name ?? <Skeleton />}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colSlug} data-test="slug">
|
||||||
|
{maybe(() => attribute.slug) ? (
|
||||||
|
attribute.slug
|
||||||
|
) : (
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
className={classes.colVariant}
|
||||||
|
data-test="variant-selection"
|
||||||
|
>
|
||||||
|
<div className={classes.colVariantContent}>
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
disabled={disabled || variantSelectionDisabled}
|
||||||
|
disableClickPropagation
|
||||||
|
onChange={() => {
|
||||||
|
onAttributeVariantSelection(true);
|
||||||
|
handleContainerAssign(
|
||||||
|
attribute.id,
|
||||||
|
isSelected,
|
||||||
|
selectedVariantAttributes,
|
||||||
|
setSelectedVariantAttributes
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{!!variantSelectionDisabled && (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage={
|
||||||
|
"{inputType} attributes cannot be used as variant selection attributes."
|
||||||
|
}
|
||||||
|
values={{ inputType: readableAttributeInputType }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<HelpOutline className={classes.colVariantDisabled} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colAction}>
|
||||||
|
<IconButton
|
||||||
|
onClick={stopPropagation(() =>
|
||||||
|
onAttributeUnassign(attribute.id)
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<DeleteIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</SortableTableRow>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
() => (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={numberOfColumns}>
|
||||||
|
<FormattedMessage defaultMessage="No attributes found" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</SortableTableBody>
|
||||||
|
</ResponsiveTable>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
ProductTypeVariantAttributes.displayName = "ProductTypeVariantAttributes";
|
||||||
|
export default ProductTypeVariantAttributes;
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./ProductTypeVariantAttributes";
|
||||||
|
export * from "./ProductTypeVariantAttributes";
|
|
@ -1140,6 +1140,24 @@ export const productType: ProductTypeDetails_productType = {
|
||||||
unit: null
|
unit: null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
assignedVariantAttributes: [
|
||||||
|
{
|
||||||
|
__typename: "AssignedVariantAttribute" as "AssignedVariantAttribute",
|
||||||
|
attribute: {
|
||||||
|
__typename: "Attribute" as "Attribute",
|
||||||
|
filterableInDashboard: true,
|
||||||
|
filterableInStorefront: false,
|
||||||
|
id: "UHJvZHVjdEF0dHJpYnV0ATo5",
|
||||||
|
name: "Author",
|
||||||
|
slug: "author",
|
||||||
|
type: AttributeTypeEnum.PRODUCT_TYPE,
|
||||||
|
inputType: AttributeInputTypeEnum.DROPDOWN,
|
||||||
|
visibleInStorefront: true,
|
||||||
|
unit: null
|
||||||
|
},
|
||||||
|
variantSelection: true
|
||||||
|
}
|
||||||
|
],
|
||||||
weight: {
|
weight: {
|
||||||
__typename: "Weight",
|
__typename: "Weight",
|
||||||
unit: WeightUnitsEnum.KG,
|
unit: WeightUnitsEnum.KG,
|
||||||
|
|
|
@ -7,6 +7,10 @@ import {
|
||||||
AssignProductAttribute,
|
AssignProductAttribute,
|
||||||
AssignProductAttributeVariables
|
AssignProductAttributeVariables
|
||||||
} from "./types/AssignProductAttribute";
|
} from "./types/AssignProductAttribute";
|
||||||
|
import {
|
||||||
|
ProductAttributeAssignmentUpdate,
|
||||||
|
ProductAttributeAssignmentUpdateVariables
|
||||||
|
} from "./types/ProductAttributeAssignmentUpdate";
|
||||||
import {
|
import {
|
||||||
ProductTypeAttributeReorder,
|
ProductTypeAttributeReorder,
|
||||||
ProductTypeAttributeReorderVariables
|
ProductTypeAttributeReorderVariables
|
||||||
|
@ -170,3 +174,30 @@ export const ProductTypeAttributeReorderMutation = TypedMutation<
|
||||||
ProductTypeAttributeReorder,
|
ProductTypeAttributeReorder,
|
||||||
ProductTypeAttributeReorderVariables
|
ProductTypeAttributeReorderVariables
|
||||||
>(productTypeAttributeReorder);
|
>(productTypeAttributeReorder);
|
||||||
|
|
||||||
|
export const productAttributeAssignmentUpdate = gql`
|
||||||
|
${productTypeDetailsFragment}
|
||||||
|
mutation ProductAttributeAssignmentUpdate(
|
||||||
|
$operations: [ProductAttributeAssignmentUpdateInput]!
|
||||||
|
$productTypeId: ID!
|
||||||
|
) {
|
||||||
|
productAttributeAssignmentUpdate(
|
||||||
|
operations: $operations
|
||||||
|
productTypeId: $productTypeId
|
||||||
|
) {
|
||||||
|
errors {
|
||||||
|
field
|
||||||
|
message
|
||||||
|
attributes
|
||||||
|
}
|
||||||
|
productType {
|
||||||
|
...ProductTypeDetailsFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const useProductAttributeAssignmentUpdateMutation = makeMutation<
|
||||||
|
ProductAttributeAssignmentUpdate,
|
||||||
|
ProductAttributeAssignmentUpdateVariables
|
||||||
|
>(productAttributeAssignmentUpdate);
|
||||||
|
|
|
@ -59,6 +59,25 @@ export interface AssignProductAttribute_productAttributeAssign_productType_varia
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AssignProductAttribute_productAttributeAssign_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssignProductAttribute_productAttributeAssign_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: AssignProductAttribute_productAttributeAssign_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AssignProductAttribute_productAttributeAssign_productType_weight {
|
export interface AssignProductAttribute_productAttributeAssign_productType_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -77,6 +96,7 @@ export interface AssignProductAttribute_productAttributeAssign_productType {
|
||||||
privateMetadata: (AssignProductAttribute_productAttributeAssign_productType_privateMetadata | null)[];
|
privateMetadata: (AssignProductAttribute_productAttributeAssign_productType_privateMetadata | null)[];
|
||||||
productAttributes: (AssignProductAttribute_productAttributeAssign_productType_productAttributes | null)[] | null;
|
productAttributes: (AssignProductAttribute_productAttributeAssign_productType_productAttributes | null)[] | null;
|
||||||
variantAttributes: (AssignProductAttribute_productAttributeAssign_productType_variantAttributes | null)[] | null;
|
variantAttributes: (AssignProductAttribute_productAttributeAssign_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (AssignProductAttribute_productAttributeAssign_productType_assignedVariantAttributes | null)[] | null;
|
||||||
weight: AssignProductAttribute_productAttributeAssign_productType_weight | null;
|
weight: AssignProductAttribute_productAttributeAssign_productType_weight | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
116
src/productTypes/types/ProductAttributeAssignmentUpdate.ts
Normal file
116
src/productTypes/types/ProductAttributeAssignmentUpdate.ts
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { ProductAttributeAssignmentUpdateInput, ProductTypeKindEnum, AttributeTypeEnum, MeasurementUnitsEnum, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL mutation operation: ProductAttributeAssignmentUpdate
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_errors {
|
||||||
|
__typename: "ProductError";
|
||||||
|
field: string | null;
|
||||||
|
message: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_taxType {
|
||||||
|
__typename: "TaxType";
|
||||||
|
description: string | null;
|
||||||
|
taxCode: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_metadata {
|
||||||
|
__typename: "MetadataItem";
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_privateMetadata {
|
||||||
|
__typename: "MetadataItem";
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_productAttributes {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_variantAttributes {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_weight {
|
||||||
|
__typename: "Weight";
|
||||||
|
unit: WeightUnitsEnum;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType {
|
||||||
|
__typename: "ProductType";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
kind: ProductTypeKindEnum;
|
||||||
|
hasVariants: boolean;
|
||||||
|
isShippingRequired: boolean;
|
||||||
|
taxType: ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_taxType | null;
|
||||||
|
metadata: (ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_metadata | null)[];
|
||||||
|
privateMetadata: (ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_privateMetadata | null)[];
|
||||||
|
productAttributes: (ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_productAttributes | null)[] | null;
|
||||||
|
variantAttributes: (ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_assignedVariantAttributes | null)[] | null;
|
||||||
|
weight: ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType_weight | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate {
|
||||||
|
__typename: "ProductAttributeAssignmentUpdate";
|
||||||
|
errors: ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_errors[];
|
||||||
|
productType: ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate_productType | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdate {
|
||||||
|
productAttributeAssignmentUpdate: ProductAttributeAssignmentUpdate_productAttributeAssignmentUpdate | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdateVariables {
|
||||||
|
operations: (ProductAttributeAssignmentUpdateInput | null)[];
|
||||||
|
productTypeId: string;
|
||||||
|
}
|
|
@ -59,6 +59,25 @@ export interface ProductTypeAttributeReorder_productTypeReorderAttributes_produc
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeAttributeReorder_productTypeReorderAttributes_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeAttributeReorder_productTypeReorderAttributes_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: ProductTypeAttributeReorder_productTypeReorderAttributes_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductTypeAttributeReorder_productTypeReorderAttributes_productType_weight {
|
export interface ProductTypeAttributeReorder_productTypeReorderAttributes_productType_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -77,6 +96,7 @@ export interface ProductTypeAttributeReorder_productTypeReorderAttributes_produc
|
||||||
privateMetadata: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_privateMetadata | null)[];
|
privateMetadata: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_privateMetadata | null)[];
|
||||||
productAttributes: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_productAttributes | null)[] | null;
|
productAttributes: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_productAttributes | null)[] | null;
|
||||||
variantAttributes: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_variantAttributes | null)[] | null;
|
variantAttributes: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (ProductTypeAttributeReorder_productTypeReorderAttributes_productType_assignedVariantAttributes | null)[] | null;
|
||||||
weight: ProductTypeAttributeReorder_productTypeReorderAttributes_productType_weight | null;
|
weight: ProductTypeAttributeReorder_productTypeReorderAttributes_productType_weight | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,25 @@ export interface ProductTypeCreate_productTypeCreate_productType_variantAttribut
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeCreate_productTypeCreate_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeCreate_productTypeCreate_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: ProductTypeCreate_productTypeCreate_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductTypeCreate_productTypeCreate_productType_weight {
|
export interface ProductTypeCreate_productTypeCreate_productType_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -77,6 +96,7 @@ export interface ProductTypeCreate_productTypeCreate_productType {
|
||||||
privateMetadata: (ProductTypeCreate_productTypeCreate_productType_privateMetadata | null)[];
|
privateMetadata: (ProductTypeCreate_productTypeCreate_productType_privateMetadata | null)[];
|
||||||
productAttributes: (ProductTypeCreate_productTypeCreate_productType_productAttributes | null)[] | null;
|
productAttributes: (ProductTypeCreate_productTypeCreate_productType_productAttributes | null)[] | null;
|
||||||
variantAttributes: (ProductTypeCreate_productTypeCreate_productType_variantAttributes | null)[] | null;
|
variantAttributes: (ProductTypeCreate_productTypeCreate_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (ProductTypeCreate_productTypeCreate_productType_assignedVariantAttributes | null)[] | null;
|
||||||
weight: ProductTypeCreate_productTypeCreate_productType_weight | null;
|
weight: ProductTypeCreate_productTypeCreate_productType_weight | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,25 @@ export interface ProductTypeDetails_productType_variantAttributes {
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeDetails_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeDetails_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: ProductTypeDetails_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductTypeDetails_productType_weight {
|
export interface ProductTypeDetails_productType_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -71,6 +90,7 @@ export interface ProductTypeDetails_productType {
|
||||||
privateMetadata: (ProductTypeDetails_productType_privateMetadata | null)[];
|
privateMetadata: (ProductTypeDetails_productType_privateMetadata | null)[];
|
||||||
productAttributes: (ProductTypeDetails_productType_productAttributes | null)[] | null;
|
productAttributes: (ProductTypeDetails_productType_productAttributes | null)[] | null;
|
||||||
variantAttributes: (ProductTypeDetails_productType_variantAttributes | null)[] | null;
|
variantAttributes: (ProductTypeDetails_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (ProductTypeDetails_productType_assignedVariantAttributes | null)[] | null;
|
||||||
weight: ProductTypeDetails_productType_weight | null;
|
weight: ProductTypeDetails_productType_weight | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,25 @@ export interface ProductTypeUpdate_productTypeUpdate_productType_variantAttribut
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeUpdate_productTypeUpdate_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeUpdate_productTypeUpdate_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: ProductTypeUpdate_productTypeUpdate_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductTypeUpdate_productTypeUpdate_productType_weight {
|
export interface ProductTypeUpdate_productTypeUpdate_productType_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -77,6 +96,7 @@ export interface ProductTypeUpdate_productTypeUpdate_productType {
|
||||||
privateMetadata: (ProductTypeUpdate_productTypeUpdate_productType_privateMetadata | null)[];
|
privateMetadata: (ProductTypeUpdate_productTypeUpdate_productType_privateMetadata | null)[];
|
||||||
productAttributes: (ProductTypeUpdate_productTypeUpdate_productType_productAttributes | null)[] | null;
|
productAttributes: (ProductTypeUpdate_productTypeUpdate_productType_productAttributes | null)[] | null;
|
||||||
variantAttributes: (ProductTypeUpdate_productTypeUpdate_productType_variantAttributes | null)[] | null;
|
variantAttributes: (ProductTypeUpdate_productTypeUpdate_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (ProductTypeUpdate_productTypeUpdate_productType_assignedVariantAttributes | null)[] | null;
|
||||||
weight: ProductTypeUpdate_productTypeUpdate_productType_weight | null;
|
weight: ProductTypeUpdate_productTypeUpdate_productType_weight | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,25 @@ export interface UnassignProductAttribute_productAttributeUnassign_productType_v
|
||||||
inputType: AttributeInputTypeEnum | null;
|
inputType: AttributeInputTypeEnum | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UnassignProductAttribute_productAttributeUnassign_productType_assignedVariantAttributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
type: AttributeTypeEnum | null;
|
||||||
|
visibleInStorefront: boolean;
|
||||||
|
filterableInDashboard: boolean;
|
||||||
|
filterableInStorefront: boolean;
|
||||||
|
unit: MeasurementUnitsEnum | null;
|
||||||
|
inputType: AttributeInputTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UnassignProductAttribute_productAttributeUnassign_productType_assignedVariantAttributes {
|
||||||
|
__typename: "AssignedVariantAttribute";
|
||||||
|
attribute: UnassignProductAttribute_productAttributeUnassign_productType_assignedVariantAttributes_attribute;
|
||||||
|
variantSelection: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface UnassignProductAttribute_productAttributeUnassign_productType_weight {
|
export interface UnassignProductAttribute_productAttributeUnassign_productType_weight {
|
||||||
__typename: "Weight";
|
__typename: "Weight";
|
||||||
unit: WeightUnitsEnum;
|
unit: WeightUnitsEnum;
|
||||||
|
@ -77,6 +96,7 @@ export interface UnassignProductAttribute_productAttributeUnassign_productType {
|
||||||
privateMetadata: (UnassignProductAttribute_productAttributeUnassign_productType_privateMetadata | null)[];
|
privateMetadata: (UnassignProductAttribute_productAttributeUnassign_productType_privateMetadata | null)[];
|
||||||
productAttributes: (UnassignProductAttribute_productAttributeUnassign_productType_productAttributes | null)[] | null;
|
productAttributes: (UnassignProductAttribute_productAttributeUnassign_productType_productAttributes | null)[] | null;
|
||||||
variantAttributes: (UnassignProductAttribute_productAttributeUnassign_productType_variantAttributes | null)[] | null;
|
variantAttributes: (UnassignProductAttribute_productAttributeUnassign_productType_variantAttributes | null)[] | null;
|
||||||
|
assignedVariantAttributes: (UnassignProductAttribute_productAttributeUnassign_productType_assignedVariantAttributes | null)[] | null;
|
||||||
weight: UnassignProductAttribute_productAttributeUnassign_productType_weight | null;
|
weight: UnassignProductAttribute_productAttributeUnassign_productType_weight | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,10 @@ import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { getStringOrPlaceholder, maybe } from "@saleor/misc";
|
import { getStringOrPlaceholder, maybe } from "@saleor/misc";
|
||||||
import useProductTypeDelete from "@saleor/productTypes/hooks/useProductTypeDelete";
|
import useProductTypeDelete from "@saleor/productTypes/hooks/useProductTypeDelete";
|
||||||
import { useProductTypeUpdateMutation } from "@saleor/productTypes/mutations";
|
import {
|
||||||
|
useProductAttributeAssignmentUpdateMutation,
|
||||||
|
useProductTypeUpdateMutation
|
||||||
|
} from "@saleor/productTypes/mutations";
|
||||||
import { ReorderEvent } from "@saleor/types";
|
import { ReorderEvent } from "@saleor/types";
|
||||||
import { ProductAttributeType } from "@saleor/types/globalTypes";
|
import { ProductAttributeType } from "@saleor/types/globalTypes";
|
||||||
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
|
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
|
||||||
|
@ -90,13 +93,47 @@ export const ProductTypeUpdate: React.FC<ProductTypeUpdateProps> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const [
|
||||||
|
updateProductAttributes,
|
||||||
|
updateProductAttributesOpts
|
||||||
|
] = useProductAttributeAssignmentUpdateMutation({
|
||||||
|
onCompleted: updateData => {
|
||||||
|
if (
|
||||||
|
updateData.productAttributeAssignmentUpdate.errors !== null &&
|
||||||
|
updateData.productAttributeAssignmentUpdate.errors.length > 0
|
||||||
|
) {
|
||||||
|
setErrors(prevErrors => ({
|
||||||
|
...prevErrors,
|
||||||
|
formErrors: updateData.productAttributeAssignmentUpdate.errors
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const [updateMetadata] = useMetadataUpdate({});
|
const [updateMetadata] = useMetadataUpdate({});
|
||||||
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
|
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
|
||||||
|
|
||||||
const handleBack = () => navigate(productTypeListUrl());
|
const handleBack = () => navigate(productTypeListUrl());
|
||||||
|
const [
|
||||||
|
selectedVariantAttributes,
|
||||||
|
setSelectedVariantAttributes
|
||||||
|
] = React.useState<string[]>([]);
|
||||||
|
|
||||||
const handleProductTypeUpdate = async (formData: ProductTypeForm) => {
|
const handleProductTypeUpdate = async (formData: ProductTypeForm) => {
|
||||||
|
const operations = formData.variantAttributes.map(variantAttribute => ({
|
||||||
|
id: variantAttribute.value,
|
||||||
|
variantSelection: selectedVariantAttributes.includes(
|
||||||
|
variantAttribute.value
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
|
||||||
|
const productAttributeUpdateResult = await updateProductAttributes({
|
||||||
|
variables: {
|
||||||
|
productTypeId: id,
|
||||||
|
operations
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const result = await updateProductType({
|
const result = await updateProductType({
|
||||||
variables: {
|
variables: {
|
||||||
id,
|
id,
|
||||||
|
@ -117,7 +154,11 @@ export const ProductTypeUpdate: React.FC<ProductTypeUpdateProps> = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return result.data.productTypeUpdate.errors;
|
return [
|
||||||
|
...result.data.productTypeUpdate.errors,
|
||||||
|
...productAttributeUpdateResult.data.productAttributeAssignmentUpdate
|
||||||
|
.errors
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const productTypeDeleteData = useProductTypeDelete({
|
const productTypeDeleteData = useProductTypeDelete({
|
||||||
|
@ -232,7 +273,10 @@ export const ProductTypeUpdate: React.FC<ProductTypeUpdateProps> = ({
|
||||||
ids: params.ids
|
ids: params.ids
|
||||||
});
|
});
|
||||||
|
|
||||||
const loading = updateProductTypeOpts.loading || dataLoading;
|
const loading =
|
||||||
|
updateProductTypeOpts.loading ||
|
||||||
|
updateProductAttributesOpts.loading ||
|
||||||
|
dataLoading;
|
||||||
|
|
||||||
const handleAttributeReorder = (
|
const handleAttributeReorder = (
|
||||||
event: ReorderEvent,
|
event: ReorderEvent,
|
||||||
|
@ -262,8 +306,13 @@ export const ProductTypeUpdate: React.FC<ProductTypeUpdateProps> = ({
|
||||||
errors={errors.formErrors}
|
errors={errors.formErrors}
|
||||||
pageTitle={maybe(() => data.productType.name)}
|
pageTitle={maybe(() => data.productType.name)}
|
||||||
productType={maybe(() => data.productType)}
|
productType={maybe(() => data.productType)}
|
||||||
saveButtonBarState={updateProductTypeOpts.status}
|
saveButtonBarState={
|
||||||
|
updateProductTypeOpts.status ||
|
||||||
|
updateProductAttributesOpts.status
|
||||||
|
}
|
||||||
taxTypes={maybe(() => data.taxTypes, [])}
|
taxTypes={maybe(() => data.taxTypes, [])}
|
||||||
|
selectedVariantAttributes={selectedVariantAttributes}
|
||||||
|
setSelectedVariantAttributes={setSelectedVariantAttributes}
|
||||||
onAttributeAdd={type =>
|
onAttributeAdd={type =>
|
||||||
navigate(
|
navigate(
|
||||||
productTypeUrl(id, {
|
productTypeUrl(id, {
|
||||||
|
|
|
@ -28,7 +28,9 @@ const props: Omit<ProductTypeDetailsPageProps, "classes"> = {
|
||||||
productType,
|
productType,
|
||||||
saveButtonBarState: "default",
|
saveButtonBarState: "default",
|
||||||
taxTypes: [],
|
taxTypes: [],
|
||||||
variantAttributeList: listActionsProps
|
variantAttributeList: listActionsProps,
|
||||||
|
setSelectedVariantAttributes: () => undefined,
|
||||||
|
selectedVariantAttributes: []
|
||||||
};
|
};
|
||||||
|
|
||||||
storiesOf("Views / Product types / Product type details", module)
|
storiesOf("Views / Product types / Product type details", module)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
//==============================================================
|
//==============================================================
|
||||||
|
|
||||||
export enum AccountErrorCode {
|
export enum AccountErrorCode {
|
||||||
|
ACCOUNT_NOT_CONFIRMED = "ACCOUNT_NOT_CONFIRMED",
|
||||||
ACTIVATE_OWN_ACCOUNT = "ACTIVATE_OWN_ACCOUNT",
|
ACTIVATE_OWN_ACCOUNT = "ACTIVATE_OWN_ACCOUNT",
|
||||||
ACTIVATE_SUPERUSER_ACCOUNT = "ACTIVATE_SUPERUSER_ACCOUNT",
|
ACTIVATE_SUPERUSER_ACCOUNT = "ACTIVATE_SUPERUSER_ACCOUNT",
|
||||||
CHANNEL_INACTIVE = "CHANNEL_INACTIVE",
|
CHANNEL_INACTIVE = "CHANNEL_INACTIVE",
|
||||||
|
@ -2528,6 +2529,12 @@ export interface PriceRangeInput {
|
||||||
export interface ProductAttributeAssignInput {
|
export interface ProductAttributeAssignInput {
|
||||||
id: string;
|
id: string;
|
||||||
type: ProductAttributeType;
|
type: ProductAttributeType;
|
||||||
|
variantSelection?: boolean | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductAttributeAssignmentUpdateInput {
|
||||||
|
id: string;
|
||||||
|
variantSelection: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductChannelListingAddInput {
|
export interface ProductChannelListingAddInput {
|
||||||
|
|
Loading…
Reference in a new issue