Add ability to create stock in multiple warehouses
This commit is contained in:
parent
b776321e0a
commit
715303e025
6 changed files with 133 additions and 99 deletions
|
@ -24,16 +24,15 @@ export interface ProductVariantCreatorContentProps {
|
||||||
warehouses: WarehouseFragment[];
|
warehouses: WarehouseFragment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps> = props => {
|
const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps> = ({
|
||||||
const {
|
attributes,
|
||||||
attributes,
|
currencySymbol,
|
||||||
currencySymbol,
|
data,
|
||||||
data,
|
dispatchFormDataAction,
|
||||||
dispatchFormDataAction,
|
errors,
|
||||||
errors,
|
step,
|
||||||
step,
|
warehouses
|
||||||
warehouses
|
}) => {
|
||||||
} = props;
|
|
||||||
const selectedAttributes = attributes.filter(attribute =>
|
const selectedAttributes = attributes.filter(attribute =>
|
||||||
isSelected(
|
isSelected(
|
||||||
attribute.id,
|
attribute.id,
|
||||||
|
@ -104,17 +103,26 @@ const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps>
|
||||||
: ProductVariantCreateReducerActionType.changeApplyStockToAttributeId
|
: ProductVariantCreateReducerActionType.changeApplyStockToAttributeId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onAttributeValueChange={(valueId, price, type) =>
|
onAttributePriceChange={(valueId, price) =>
|
||||||
dispatchFormDataAction(
|
dispatchFormDataAction({
|
||||||
type === "price" && {
|
changeAttributeValuePrice: {
|
||||||
changeAttributeValuePrice: {
|
price,
|
||||||
price,
|
valueId
|
||||||
valueId
|
},
|
||||||
},
|
type:
|
||||||
type:
|
ProductVariantCreateReducerActionType.changeAttributeValuePrice
|
||||||
ProductVariantCreateReducerActionType.changeAttributeValuePrice
|
})
|
||||||
}
|
}
|
||||||
)
|
onAttributeStockChange={(valueId, quantity, warehouseIndex) =>
|
||||||
|
dispatchFormDataAction({
|
||||||
|
changeAttributeValueStock: {
|
||||||
|
quantity,
|
||||||
|
valueId,
|
||||||
|
warehouseIndex
|
||||||
|
},
|
||||||
|
type:
|
||||||
|
ProductVariantCreateReducerActionType.changeAttributeValueStock
|
||||||
|
})
|
||||||
}
|
}
|
||||||
onWarehouseToggle={warehouseId =>
|
onWarehouseToggle={warehouseId =>
|
||||||
dispatchFormDataAction({
|
dispatchFormDataAction({
|
||||||
|
|
|
@ -50,11 +50,9 @@ function canHitNext(
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.stock.mode === "attribute" || data.stock.attribute) {
|
if (data.stock.mode === "attribute" && data.stock.attribute === "") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ export interface ProductVariantCreatorPriceAndSkuProps {
|
||||||
onApplyToAllPriceChange: (value: string) => void;
|
onApplyToAllPriceChange: (value: string) => void;
|
||||||
onApplyToAllStockChange: (warehouseIndex: number, value: string) => void;
|
onApplyToAllStockChange: (warehouseIndex: number, value: string) => void;
|
||||||
onAttributeSelect: (id: string, type: PriceOrStock) => void;
|
onAttributeSelect: (id: string, type: PriceOrStock) => void;
|
||||||
onAttributeValueChange: (
|
onAttributePriceChange: (id: string, value: string) => void;
|
||||||
|
onAttributeStockChange: (
|
||||||
id: string,
|
id: string,
|
||||||
value: string,
|
quantity: number,
|
||||||
type: PriceOrStock
|
warehouseIndex: number
|
||||||
) => void;
|
) => void;
|
||||||
onWarehouseToggle: (id: string) => void;
|
onWarehouseToggle: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,8 @@ const ProductVariantCreatorPriceAndSku: React.FC<ProductVariantCreatorPriceAndSk
|
||||||
onApplyToAllPriceChange,
|
onApplyToAllPriceChange,
|
||||||
onApplyToAllStockChange,
|
onApplyToAllStockChange,
|
||||||
onAttributeSelect,
|
onAttributeSelect,
|
||||||
onAttributeValueChange,
|
onAttributePriceChange,
|
||||||
|
onAttributeStockChange,
|
||||||
onWarehouseToggle
|
onWarehouseToggle
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
|
@ -51,9 +53,7 @@ const ProductVariantCreatorPriceAndSku: React.FC<ProductVariantCreatorPriceAndSk
|
||||||
onApplyToAllChange={value => onApplyToAllChange(value, "price")}
|
onApplyToAllChange={value => onApplyToAllChange(value, "price")}
|
||||||
onApplyToAllPriceChange={onApplyToAllPriceChange}
|
onApplyToAllPriceChange={onApplyToAllPriceChange}
|
||||||
onAttributeSelect={id => onAttributeSelect(id, "price")}
|
onAttributeSelect={id => onAttributeSelect(id, "price")}
|
||||||
onAttributeValueChange={(id, value) =>
|
onAttributeValueChange={onAttributePriceChange}
|
||||||
onAttributeValueChange(id, value, "price")
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<ProductVariantCreatorStock
|
<ProductVariantCreatorStock
|
||||||
|
@ -63,9 +63,7 @@ const ProductVariantCreatorPriceAndSku: React.FC<ProductVariantCreatorPriceAndSk
|
||||||
onApplyToAllChange={value => onApplyToAllChange(value, "stock")}
|
onApplyToAllChange={value => onApplyToAllChange(value, "stock")}
|
||||||
onApplyToAllStockChange={onApplyToAllStockChange}
|
onApplyToAllStockChange={onApplyToAllStockChange}
|
||||||
onAttributeSelect={id => onAttributeSelect(id, "stock")}
|
onAttributeSelect={id => onAttributeSelect(id, "stock")}
|
||||||
onAttributeValueChange={(id, value) =>
|
onAttributeValueChange={onAttributeStockChange}
|
||||||
onAttributeValueChange(id, value, "stock")
|
|
||||||
}
|
|
||||||
onWarehouseToggle={onWarehouseToggle}
|
onWarehouseToggle={onWarehouseToggle}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -27,6 +27,17 @@ import { getStockAttributeValues } from "./utils";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
attributeStockContainer: {
|
||||||
|
columnGap: theme.spacing(3) + "px",
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: ({ data }: ProductVariantCreatorStockProps) =>
|
||||||
|
`150px repeat(${data.warehouses.length}, 288px)`,
|
||||||
|
rowGap: theme.spacing(2) + "px"
|
||||||
|
},
|
||||||
|
attributeStockScroll: {
|
||||||
|
overflowX: "scroll",
|
||||||
|
width: "100%"
|
||||||
|
},
|
||||||
hr: {
|
hr: {
|
||||||
marginBottom: theme.spacing(),
|
marginBottom: theme.spacing(),
|
||||||
marginTop: theme.spacing(0.5)
|
marginTop: theme.spacing(0.5)
|
||||||
|
@ -75,7 +86,11 @@ export interface ProductVariantCreatorStockProps {
|
||||||
onApplyToAllChange: (mode: VariantCreatorPricesAndSkuMode) => void;
|
onApplyToAllChange: (mode: VariantCreatorPricesAndSkuMode) => void;
|
||||||
onApplyToAllStockChange: (warehouseIndex: number, value: string) => void;
|
onApplyToAllStockChange: (warehouseIndex: number, value: string) => void;
|
||||||
onAttributeSelect: (id: string) => void;
|
onAttributeSelect: (id: string) => void;
|
||||||
onAttributeValueChange: (id: string, value: string) => void;
|
onAttributeValueChange: (
|
||||||
|
id: string,
|
||||||
|
quantity: number,
|
||||||
|
warehouseIndex: number
|
||||||
|
) => void;
|
||||||
onWarehouseToggle: (id: string) => void;
|
onWarehouseToggle: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,11 +183,8 @@ const ProductVariantCreatorStock: React.FC<ProductVariantCreatorStockProps> = pr
|
||||||
{data.stock.mode === "all" && (
|
{data.stock.mode === "all" && (
|
||||||
<div className={classes.stockContainer}>
|
<div className={classes.stockContainer}>
|
||||||
{data.warehouses.map((warehouseId, warehouseIndex) => (
|
{data.warehouses.map((warehouseId, warehouseIndex) => (
|
||||||
<div>
|
<div key={warehouseId}>
|
||||||
<Typography
|
<Typography className={classes.warehouseName}>
|
||||||
className={classes.warehouseName}
|
|
||||||
key={warehouseId}
|
|
||||||
>
|
|
||||||
{
|
{
|
||||||
warehouses.find(warehouse => warehouse.id === warehouseId)
|
warehouses.find(warehouse => warehouse.id === warehouseId)
|
||||||
.name
|
.name
|
||||||
|
@ -212,60 +224,74 @@ const ProductVariantCreatorStock: React.FC<ProductVariantCreatorStockProps> = pr
|
||||||
{data.stock.mode === "attribute" && (
|
{data.stock.mode === "attribute" && (
|
||||||
<>
|
<>
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
<Grid variant="uniform">
|
<SingleSelectField
|
||||||
<div className={classes.label}>
|
className={classes.shortInput}
|
||||||
<Typography>
|
choices={attributeChoices}
|
||||||
<FormattedMessage
|
label={intl.formatMessage({
|
||||||
defaultMessage="Choose attribute"
|
defaultMessage: "Select Attribute",
|
||||||
description="variant attribute"
|
description: "variant attribute"
|
||||||
/>
|
})}
|
||||||
</Typography>
|
value={data.stock.attribute}
|
||||||
</div>
|
onChange={event => onAttributeSelect(event.target.value)}
|
||||||
<div>
|
/>
|
||||||
<SingleSelectField
|
{stockAttributeValues && (
|
||||||
choices={attributeChoices}
|
<>
|
||||||
label={intl.formatMessage({
|
<Hr className={classes.hrAttribute} />
|
||||||
defaultMessage: "Attribute",
|
<FormSpacer />
|
||||||
description: "variant attribute"
|
<div className={classes.attributeStockScroll}>
|
||||||
})}
|
<div className={classes.attributeStockContainer}>
|
||||||
value={data.stock.attribute}
|
<div />
|
||||||
onChange={onAttributeSelect}
|
{data.stock.attribute &&
|
||||||
/>
|
data.warehouses.map(warehouseId => (
|
||||||
</div>
|
<Typography
|
||||||
</Grid>
|
className={classes.warehouseName}
|
||||||
{stockAttributeValues &&
|
key={warehouseId}
|
||||||
stockAttributeValues.map(attributeValue => (
|
>
|
||||||
<React.Fragment key={attributeValue.id}>
|
{
|
||||||
<Hr className={classes.hrAttribute} />
|
warehouses.find(
|
||||||
<FormSpacer />
|
warehouse => warehouse.id === warehouseId
|
||||||
<Grid variant="uniform">
|
).name
|
||||||
<div className={classes.label}>
|
}
|
||||||
<Typography>{attributeValue.name}</Typography>
|
</Typography>
|
||||||
</div>
|
))}
|
||||||
<div>
|
{stockAttributeValues.map(attributeValue => (
|
||||||
<TextField
|
<React.Fragment key={attributeValue.id}>
|
||||||
label={intl.formatMessage({
|
<Typography>{attributeValue.name}</Typography>
|
||||||
defaultMessage: "Stock",
|
{data.warehouses.map(
|
||||||
description: "variant stock",
|
(warehouseId, warehouseIndex) => (
|
||||||
id: "productVariantCreatePricesSetStockPlaceholder"
|
<TextField
|
||||||
})}
|
fullWidth
|
||||||
fullWidth
|
inputProps={{
|
||||||
value={
|
min: 0,
|
||||||
data.stock.values.find(
|
type: "number"
|
||||||
value => value.slug === attributeValue.slug
|
}}
|
||||||
).value
|
label={intl.formatMessage({
|
||||||
}
|
defaultMessage: "Stock",
|
||||||
onChange={event =>
|
id:
|
||||||
onAttributeValueChange(
|
"productVariantCreatePricesStockInputLabel"
|
||||||
attributeValue.slug,
|
})}
|
||||||
event.target.value
|
value={
|
||||||
|
data.stock.values.find(
|
||||||
|
value => value.slug === attributeValue.slug
|
||||||
|
).value[warehouseIndex]
|
||||||
|
}
|
||||||
|
onChange={event =>
|
||||||
|
onAttributeValueChange(
|
||||||
|
attributeValue.slug,
|
||||||
|
parseInt(event.target.value, 10),
|
||||||
|
warehouseIndex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
key={warehouseId}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
)}
|
||||||
/>
|
</React.Fragment>
|
||||||
</div>
|
))}
|
||||||
</Grid>
|
</div>
|
||||||
</React.Fragment>
|
</div>
|
||||||
))}
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
|
|
|
@ -92,7 +92,7 @@ const useStyles = makeStyles<
|
||||||
marginTop: theme.spacing(0.5)
|
marginTop: theme.spacing(0.5)
|
||||||
},
|
},
|
||||||
hr: {
|
hr: {
|
||||||
gridColumn: props => `span ${4 + props.data.stock.value.length}`
|
gridColumn: props => `span ${4 + props.data.variants[0].stocks.length}`
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
"& input": {
|
"& input": {
|
||||||
|
@ -103,7 +103,7 @@ const useStyles = makeStyles<
|
||||||
columnGap: theme.spacing(3),
|
columnGap: theme.spacing(3),
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: props =>
|
gridTemplateColumns: props =>
|
||||||
`minmax(240px, auto) 170px repeat(${props.data.stock.value.length}, 140px) 140px 64px`,
|
`minmax(240px, auto) 170px repeat(${props.data.variants[0].stocks.length}, 140px) 140px 64px`,
|
||||||
overflowX: "scroll",
|
overflowX: "scroll",
|
||||||
rowGap: theme.spacing() + "px"
|
rowGap: theme.spacing() + "px"
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,8 +186,8 @@ function changeAttributeValuePrice(
|
||||||
function changeAttributeValueStock(
|
function changeAttributeValueStock(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
attributeValueSlug: string,
|
attributeValueSlug: string,
|
||||||
warehouseIndex: number,
|
quantity: number,
|
||||||
quantity: number
|
warehouseIndex: number
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
const index = state.stock.values.findIndex(
|
const index = state.stock.values.findIndex(
|
||||||
value => value.slug === attributeValueSlug
|
value => value.slug === attributeValueSlug
|
||||||
|
@ -199,8 +199,12 @@ function changeAttributeValueStock(
|
||||||
|
|
||||||
const values = updateAtIndex(
|
const values = updateAtIndex(
|
||||||
{
|
{
|
||||||
slug: attributeValueSlug,
|
...state.stock.values[index],
|
||||||
value: updateAtIndex(quantity, state.stock.value, warehouseIndex)
|
value: updateAtIndex(
|
||||||
|
quantity,
|
||||||
|
state.stock.values[index].value,
|
||||||
|
warehouseIndex
|
||||||
|
)
|
||||||
},
|
},
|
||||||
state.stock.values,
|
state.stock.values,
|
||||||
index
|
index
|
||||||
|
|
Loading…
Reference in a new issue