Remove attribute selection
This commit is contained in:
parent
0148bc4527
commit
36396c9d3e
8 changed files with 47 additions and 149 deletions
|
@ -1,77 +0,0 @@
|
|||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import makeStyles from "@material-ui/styles/makeStyles";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import { maybe, renderCollection } from "@saleor/misc";
|
||||
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
|
||||
import { ProductVariantCreateFormData } from "./form";
|
||||
|
||||
export interface ProductVariantCreateAttributesProps {
|
||||
attributes: ProductDetails_product_productType_variantAttributes[];
|
||||
data: ProductVariantCreateFormData;
|
||||
onAttributeClick: (id: string) => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles({
|
||||
checkboxCell: {
|
||||
paddingLeft: 0
|
||||
},
|
||||
wideCell: {
|
||||
width: "100%"
|
||||
}
|
||||
});
|
||||
|
||||
const ProductVariantCreateAttributes: React.FC<
|
||||
ProductVariantCreateAttributesProps
|
||||
> = props => {
|
||||
const { attributes, data, onAttributeClick } = props;
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
<Table key="table">
|
||||
<TableBody>
|
||||
{renderCollection(
|
||||
attributes,
|
||||
attribute => {
|
||||
if (!attribute) {
|
||||
return null;
|
||||
}
|
||||
const isChecked = !!data.attributes.find(
|
||||
selectedAttribute => selectedAttribute.id === attribute.id
|
||||
);
|
||||
|
||||
return (
|
||||
<TableRow key={maybe(() => attribute.id)}>
|
||||
<TableCell padding="checkbox" className={classes.checkboxCell}>
|
||||
<Checkbox
|
||||
checked={isChecked}
|
||||
disableClickPropagation={true}
|
||||
onChange={() => onAttributeClick(attribute.id)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.wideCell}>
|
||||
{attribute.name}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
},
|
||||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={2}>
|
||||
<FormattedMessage defaultMessage="This product type has no variant attributes" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
ProductVariantCreateAttributes.displayName = "ProductVariantCreateAttributes";
|
||||
export default ProductVariantCreateAttributes;
|
|
@ -5,7 +5,6 @@ import { ProductDetails_product_productType_variantAttributes } from "@saleor/pr
|
|||
import { ProductVariantBulkCreate_productVariantBulkCreate_bulkProductErrors } from "@saleor/products/types/ProductVariantBulkCreate";
|
||||
import { isSelected } from "@saleor/utils/lists";
|
||||
import { ProductVariantCreateFormData } from "./form";
|
||||
import ProductVariantCreateAttributes from "./ProductVariantCreateAttributes";
|
||||
import ProductVariantCreatePrices from "./ProductVariantCreatePrices";
|
||||
import ProductVariantCreateSummary from "./ProductVariantCreateSummary";
|
||||
import ProductVariantCreateTabs from "./ProductVariantCreateTabs";
|
||||
|
@ -54,18 +53,6 @@ const ProductVariantCreateContent: React.FC<
|
|||
<div>
|
||||
<ProductVariantCreateTabs step={step} />
|
||||
<div className={classes.root}>
|
||||
{step === "attributes" && (
|
||||
<ProductVariantCreateAttributes
|
||||
attributes={attributes}
|
||||
data={data}
|
||||
onAttributeClick={attributeId =>
|
||||
dispatchFormDataAction({
|
||||
attributeId,
|
||||
type: "selectAttribute"
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{step === "values" && (
|
||||
<ProductVariantCreateValues
|
||||
attributes={selectedAttributes}
|
||||
|
|
|
@ -9,7 +9,7 @@ import React from "react";
|
|||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { ProductVariantBulkCreateInput } from "../../../types/globalTypes";
|
||||
import { initialForm, ProductVariantCreateFormData } from "./form";
|
||||
import { createInitialForm, ProductVariantCreateFormData } from "./form";
|
||||
import ProductVariantCreateContent, {
|
||||
ProductVariantCreateContentProps
|
||||
} from "./ProductVariantCreateContent";
|
||||
|
@ -32,8 +32,6 @@ function canHitNext(
|
|||
data: ProductVariantCreateFormData
|
||||
): boolean {
|
||||
switch (step) {
|
||||
case "attributes":
|
||||
return data.attributes.length > 0;
|
||||
case "values":
|
||||
return data.attributes.every(attribute => attribute.values.length > 0);
|
||||
case "prices":
|
||||
|
@ -77,6 +75,7 @@ export interface ProductVariantCreateDialogProps
|
|||
ProductVariantCreateContentProps,
|
||||
"data" | "dispatchFormDataAction" | "step"
|
||||
> {
|
||||
defaultPrice: string;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: (data: ProductVariantBulkCreateInput[]) => void;
|
||||
|
@ -85,17 +84,19 @@ export interface ProductVariantCreateDialogProps
|
|||
const ProductVariantCreateDialog: React.FC<
|
||||
ProductVariantCreateDialogProps
|
||||
> = props => {
|
||||
const { open, onClose, onSubmit, ...contentProps } = props;
|
||||
const {
|
||||
attributes,
|
||||
defaultPrice,
|
||||
open,
|
||||
onClose,
|
||||
onSubmit,
|
||||
...contentProps
|
||||
} = props;
|
||||
const classes = useStyles(props);
|
||||
const [step, setStep] = React.useState<ProductVariantCreateStep>(
|
||||
"attributes"
|
||||
);
|
||||
const [step, setStep] = React.useState<ProductVariantCreateStep>("values");
|
||||
|
||||
function handleNextStep() {
|
||||
switch (step) {
|
||||
case "attributes":
|
||||
setStep("values");
|
||||
break;
|
||||
case "values":
|
||||
setStep("prices");
|
||||
break;
|
||||
|
@ -107,9 +108,6 @@ const ProductVariantCreateDialog: React.FC<
|
|||
|
||||
function handlePrevStep() {
|
||||
switch (step) {
|
||||
case "values":
|
||||
setStep("attributes");
|
||||
break;
|
||||
case "prices":
|
||||
setStep("values");
|
||||
break;
|
||||
|
@ -121,7 +119,16 @@ const ProductVariantCreateDialog: React.FC<
|
|||
|
||||
const [data, dispatchFormDataAction] = React.useReducer(
|
||||
reduceProductVariantCreateFormData,
|
||||
initialForm
|
||||
createInitialForm(attributes, defaultPrice)
|
||||
);
|
||||
|
||||
React.useEffect(
|
||||
() =>
|
||||
dispatchFormDataAction({
|
||||
data: createInitialForm(attributes, defaultPrice),
|
||||
type: "reload"
|
||||
}),
|
||||
[attributes.length]
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -135,6 +142,7 @@ const ProductVariantCreateDialog: React.FC<
|
|||
<DialogContent className={classes.content}>
|
||||
<ProductVariantCreateContent
|
||||
{...contentProps}
|
||||
attributes={attributes}
|
||||
data={data}
|
||||
dispatchFormDataAction={dispatchFormDataAction}
|
||||
step={step}
|
||||
|
@ -144,7 +152,7 @@ const ProductVariantCreateDialog: React.FC<
|
|||
<Button className={classes.button} onClick={onClose}>
|
||||
<FormattedMessage defaultMessage="Cancel" description="button" />
|
||||
</Button>
|
||||
{step !== "attributes" && (
|
||||
{step !== "values" && (
|
||||
<Button
|
||||
className={classes.button}
|
||||
color="primary"
|
||||
|
|
|
@ -13,13 +13,6 @@ interface Step {
|
|||
}
|
||||
function getSteps(intl: IntlShape): Step[] {
|
||||
return [
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Choose Attributes",
|
||||
description: "variant creation step"
|
||||
}),
|
||||
value: "attributes"
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Select Values",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
|
||||
import { ProductVariantBulkCreateInput } from "../../../types/globalTypes";
|
||||
|
||||
export interface AttributeValue {
|
||||
|
@ -21,12 +22,18 @@ export interface ProductVariantCreateFormData {
|
|||
variants: ProductVariantBulkCreateInput[];
|
||||
}
|
||||
|
||||
export const initialForm: ProductVariantCreateFormData = {
|
||||
attributes: [],
|
||||
export const createInitialForm = (
|
||||
attributes: ProductDetails_product_productType_variantAttributes[],
|
||||
price: string
|
||||
): ProductVariantCreateFormData => ({
|
||||
attributes: attributes.map(attribute => ({
|
||||
id: attribute.id,
|
||||
values: []
|
||||
})),
|
||||
price: {
|
||||
all: true,
|
||||
attribute: undefined,
|
||||
value: "",
|
||||
value: price || "",
|
||||
values: []
|
||||
},
|
||||
stock: {
|
||||
|
@ -36,4 +43,4 @@ export const initialForm: ProductVariantCreateFormData = {
|
|||
values: []
|
||||
},
|
||||
variants: []
|
||||
};
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
updateAtIndex
|
||||
} from "@saleor/utils/lists";
|
||||
import { createVariants } from "./createVariants";
|
||||
import { initialForm, ProductVariantCreateFormData } from "./form";
|
||||
import { ProductVariantCreateFormData } from "./form";
|
||||
|
||||
export type ProductVariantCreateReducerActionType =
|
||||
| "applyPriceToAll"
|
||||
|
@ -21,13 +21,14 @@ export type ProductVariantCreateReducerActionType =
|
|||
| "changeAttributeValueStock"
|
||||
| "changeVariantData"
|
||||
| "deleteVariant"
|
||||
| "selectAttribute"
|
||||
| "reload"
|
||||
| "selectValue";
|
||||
|
||||
export type VariantField = "stock" | "price" | "sku";
|
||||
export interface ProductVariantCreateReducerAction {
|
||||
all?: boolean;
|
||||
attributeId?: string;
|
||||
data?: ProductVariantCreateFormData;
|
||||
field?: VariantField;
|
||||
type: ProductVariantCreateReducerActionType;
|
||||
value?: string;
|
||||
|
@ -35,31 +36,12 @@ export interface ProductVariantCreateReducerAction {
|
|||
variantIndex?: number;
|
||||
}
|
||||
|
||||
function selectAttribute(
|
||||
state: ProductVariantCreateFormData,
|
||||
attributeId: string
|
||||
): ProductVariantCreateFormData {
|
||||
const attributes = toggle(
|
||||
{
|
||||
id: attributeId,
|
||||
values: []
|
||||
},
|
||||
state.attributes,
|
||||
(a, b) => a.id === b.id
|
||||
);
|
||||
|
||||
return {
|
||||
...initialForm,
|
||||
attributes
|
||||
};
|
||||
}
|
||||
|
||||
function selectValue(
|
||||
state: ProductVariantCreateFormData,
|
||||
prevState: ProductVariantCreateFormData,
|
||||
attributeId: string,
|
||||
valueId: string
|
||||
): ProductVariantCreateFormData {
|
||||
const attribute = state.attributes.find(
|
||||
const attribute = prevState.attributes.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
const values = toggle(valueId, attribute.values, (a, b) => a === b);
|
||||
|
@ -68,11 +50,11 @@ function selectValue(
|
|||
id: attributeId,
|
||||
values
|
||||
},
|
||||
remove(attribute, state.attributes, (a, b) => a.id === b.id)
|
||||
remove(attribute, prevState.attributes, (a, b) => a.id === b.id)
|
||||
);
|
||||
|
||||
return {
|
||||
...initialForm,
|
||||
...prevState,
|
||||
attributes: updatedAttributes
|
||||
};
|
||||
}
|
||||
|
@ -310,9 +292,6 @@ function reduceProductVariantCreateFormData(
|
|||
action: ProductVariantCreateReducerAction
|
||||
) {
|
||||
switch (action.type) {
|
||||
case "selectAttribute":
|
||||
return selectAttribute(prevState, action.attributeId);
|
||||
|
||||
case "selectValue":
|
||||
return selectValue(prevState, action.attributeId, action.valueId);
|
||||
|
||||
|
@ -341,6 +320,8 @@ function reduceProductVariantCreateFormData(
|
|||
);
|
||||
case "deleteVariant":
|
||||
return deleteVariant(prevState, action.variantIndex);
|
||||
case "reload":
|
||||
return action.data;
|
||||
default:
|
||||
return prevState;
|
||||
}
|
||||
|
|
|
@ -1,5 +1 @@
|
|||
export type ProductVariantCreateStep =
|
||||
| "attributes"
|
||||
| "values"
|
||||
| "prices"
|
||||
| "summary";
|
||||
export type ProductVariantCreateStep = "values" | "prices" | "summary";
|
||||
|
|
|
@ -353,6 +353,9 @@ export const ProductUpdate: React.StatelessComponent<ProductUpdateProps> = ({
|
|||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
<ProductVariantCreateDialog
|
||||
defaultPrice={maybe(() =>
|
||||
data.product.basePrice.amount.toFixed(2)
|
||||
)}
|
||||
errors={maybe(
|
||||
() =>
|
||||
bulkProductVariantCreate.opts.data
|
||||
|
|
Loading…
Reference in a new issue