Add variant stock management
This commit is contained in:
parent
4b661c9bff
commit
0eb7750321
7 changed files with 274 additions and 38 deletions
|
@ -180,6 +180,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
|
||||||
<TableCell className={classes.colQuantity}>
|
<TableCell className={classes.colQuantity}>
|
||||||
<TextField
|
<TextField
|
||||||
className={classes.inputComponent}
|
className={classes.inputComponent}
|
||||||
|
disabled={disabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
inputProps={{
|
inputProps={{
|
||||||
className: classes.input,
|
className: classes.input,
|
||||||
|
|
|
@ -13,7 +13,10 @@ import useFormset, {
|
||||||
FormsetData
|
FormsetData
|
||||||
} from "@saleor/hooks/useFormset";
|
} from "@saleor/hooks/useFormset";
|
||||||
import { VariantUpdate_productVariantUpdate_errors } from "@saleor/products/types/VariantUpdate";
|
import { VariantUpdate_productVariantUpdate_errors } from "@saleor/products/types/VariantUpdate";
|
||||||
import { getAttributeInputFromVariant } from "@saleor/products/utils/data";
|
import {
|
||||||
|
getAttributeInputFromVariant,
|
||||||
|
getStockInputFromVariant
|
||||||
|
} from "@saleor/products/utils/data";
|
||||||
import { maybe } from "../../../misc";
|
import { maybe } from "../../../misc";
|
||||||
import { ProductVariant } from "../../types/ProductVariant";
|
import { ProductVariant } from "../../types/ProductVariant";
|
||||||
import ProductVariantAttributes, {
|
import ProductVariantAttributes, {
|
||||||
|
@ -23,18 +26,19 @@ import ProductVariantImages from "../ProductVariantImages";
|
||||||
import ProductVariantImageSelectDialog from "../ProductVariantImageSelectDialog";
|
import ProductVariantImageSelectDialog from "../ProductVariantImageSelectDialog";
|
||||||
import ProductVariantNavigation from "../ProductVariantNavigation";
|
import ProductVariantNavigation from "../ProductVariantNavigation";
|
||||||
import ProductVariantPrice from "../ProductVariantPrice";
|
import ProductVariantPrice from "../ProductVariantPrice";
|
||||||
import ProductVariantStock from "../ProductVariantStock";
|
import ProductStocks, { ProductStockInput } from "../ProductStocks";
|
||||||
|
|
||||||
export interface ProductVariantPageFormData {
|
export interface ProductVariantPageFormData {
|
||||||
costPrice: string;
|
costPrice: string;
|
||||||
priceOverride: string;
|
priceOverride: string;
|
||||||
quantity: string;
|
|
||||||
sku: string;
|
sku: string;
|
||||||
|
trackInventory: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductVariantPageSubmitData
|
export interface ProductVariantPageSubmitData
|
||||||
extends ProductVariantPageFormData {
|
extends ProductVariantPageFormData {
|
||||||
attributes: FormsetData<VariantAttributeInputData, string>;
|
attributes: FormsetData<VariantAttributeInputData, string>;
|
||||||
|
stocks: ProductStockInput[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProductVariantPageProps {
|
interface ProductVariantPageProps {
|
||||||
|
@ -44,6 +48,7 @@ interface ProductVariantPageProps {
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
placeholderImage?: string;
|
placeholderImage?: string;
|
||||||
header: string;
|
header: string;
|
||||||
|
onWarehousesEdit: () => void;
|
||||||
onAdd();
|
onAdd();
|
||||||
onBack();
|
onBack();
|
||||||
onDelete();
|
onDelete();
|
||||||
|
@ -64,15 +69,20 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
||||||
onDelete,
|
onDelete,
|
||||||
onImageSelect,
|
onImageSelect,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
onWarehousesEdit,
|
||||||
onVariantClick
|
onVariantClick
|
||||||
}) => {
|
}) => {
|
||||||
const attributeInput = React.useMemo(
|
const attributeInput = React.useMemo(
|
||||||
() => getAttributeInputFromVariant(variant),
|
() => getAttributeInputFromVariant(variant),
|
||||||
[variant]
|
[variant]
|
||||||
);
|
);
|
||||||
|
const stockInput = React.useMemo(() => getStockInputFromVariant(variant), [
|
||||||
|
variant
|
||||||
|
]);
|
||||||
const { change: changeAttributeData, data: attributes } = useFormset(
|
const { change: changeAttributeData, data: attributes } = useFormset(
|
||||||
attributeInput
|
attributeInput
|
||||||
);
|
);
|
||||||
|
const { change: changeStockData, data: stocks } = useFormset(stockInput);
|
||||||
|
|
||||||
const [isModalOpened, setModalStatus] = React.useState(false);
|
const [isModalOpened, setModalStatus] = React.useState(false);
|
||||||
const toggleModal = () => setModalStatus(!isModalOpened);
|
const toggleModal = () => setModalStatus(!isModalOpened);
|
||||||
|
@ -92,14 +102,15 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
||||||
const initialForm: ProductVariantPageFormData = {
|
const initialForm: ProductVariantPageFormData = {
|
||||||
costPrice: maybe(() => variant.costPrice.amount.toString(), ""),
|
costPrice: maybe(() => variant.costPrice.amount.toString(), ""),
|
||||||
priceOverride: maybe(() => variant.priceOverride.amount.toString(), ""),
|
priceOverride: maybe(() => variant.priceOverride.amount.toString(), ""),
|
||||||
quantity: maybe(() => variant.quantity.toString(), "0"),
|
sku: maybe(() => variant.sku, ""),
|
||||||
sku: maybe(() => variant.sku, "")
|
trackInventory: variant?.trackInventory
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (data: ProductVariantPageFormData) =>
|
const handleSubmit = (data: ProductVariantPageFormData) =>
|
||||||
onSubmit({
|
onSubmit({
|
||||||
...data,
|
...data,
|
||||||
attributes
|
attributes,
|
||||||
|
stocks
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -164,15 +175,17 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<ProductVariantStock
|
<ProductStocks
|
||||||
|
data={data}
|
||||||
|
disabled={loading}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
sku={data.sku}
|
stocks={stocks}
|
||||||
quantity={data.quantity}
|
onChange={(id, value) => {
|
||||||
stockAllocated={
|
triggerChange();
|
||||||
variant ? variant.quantityAllocated : undefined
|
changeStockData(id, value);
|
||||||
}
|
}}
|
||||||
loading={loading}
|
onFormDataChange={change}
|
||||||
onChange={change}
|
onWarehousesEdit={onWarehousesEdit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -355,6 +355,7 @@ export const TypedVariantDeleteMutation = TypedMutation<
|
||||||
>(variantDeleteMutation);
|
>(variantDeleteMutation);
|
||||||
|
|
||||||
export const variantUpdateMutation = gql`
|
export const variantUpdateMutation = gql`
|
||||||
|
${bulkStockErrorFragment}
|
||||||
${fragmentVariant}
|
${fragmentVariant}
|
||||||
${productErrorFragment}
|
${productErrorFragment}
|
||||||
mutation VariantUpdate(
|
mutation VariantUpdate(
|
||||||
|
@ -365,6 +366,7 @@ export const variantUpdateMutation = gql`
|
||||||
$sku: String
|
$sku: String
|
||||||
$quantity: Int
|
$quantity: Int
|
||||||
$trackInventory: Boolean!
|
$trackInventory: Boolean!
|
||||||
|
$stocks: [StockInput!]!
|
||||||
) {
|
) {
|
||||||
productVariantUpdate(
|
productVariantUpdate(
|
||||||
id: $id
|
id: $id
|
||||||
|
@ -384,6 +386,14 @@ export const variantUpdateMutation = gql`
|
||||||
...ProductVariant
|
...ProductVariant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
productVariantStocksUpdate(stocks: $stocks, variantId: $id) {
|
||||||
|
errors: bulkStockErrors {
|
||||||
|
...BulkStockErrorFragment
|
||||||
|
}
|
||||||
|
productVariant {
|
||||||
|
...ProductVariant
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TypedVariantUpdateMutation = TypedMutation<
|
export const TypedVariantUpdateMutation = TypedMutation<
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { AttributeValueInput, ProductErrorCode } from "./../../types/globalTypes";
|
import { AttributeValueInput, StockInput, ProductErrorCode } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL mutation operation: VariantUpdate
|
// GraphQL mutation operation: VariantUpdate
|
||||||
|
@ -130,8 +130,132 @@ export interface VariantUpdate_productVariantUpdate {
|
||||||
productVariant: VariantUpdate_productVariantUpdate_productVariant | null;
|
productVariant: VariantUpdate_productVariantUpdate_productVariant | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_errors {
|
||||||
|
__typename: "BulkStockError";
|
||||||
|
code: ProductErrorCode;
|
||||||
|
field: string | null;
|
||||||
|
index: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values {
|
||||||
|
__typename: "AttributeValue";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute {
|
||||||
|
__typename: "Attribute";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
valueRequired: boolean;
|
||||||
|
values: (VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values | null)[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes_values {
|
||||||
|
__typename: "AttributeValue";
|
||||||
|
id: string;
|
||||||
|
name: string | null;
|
||||||
|
slug: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes {
|
||||||
|
__typename: "SelectedAttribute";
|
||||||
|
attribute: VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute;
|
||||||
|
values: (VariantUpdate_productVariantStocksUpdate_productVariant_attributes_values | null)[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_costPrice {
|
||||||
|
__typename: "Money";
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_images {
|
||||||
|
__typename: "ProductImage";
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_priceOverride {
|
||||||
|
__typename: "Money";
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_product_images {
|
||||||
|
__typename: "ProductImage";
|
||||||
|
id: string;
|
||||||
|
alt: string;
|
||||||
|
sortOrder: number | null;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_product_thumbnail {
|
||||||
|
__typename: "Image";
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_product_variants_images {
|
||||||
|
__typename: "ProductImage";
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_product_variants {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
sku: string;
|
||||||
|
images: (VariantUpdate_productVariantStocksUpdate_productVariant_product_variants_images | null)[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_product {
|
||||||
|
__typename: "Product";
|
||||||
|
id: string;
|
||||||
|
images: (VariantUpdate_productVariantStocksUpdate_productVariant_product_images | null)[] | null;
|
||||||
|
name: string;
|
||||||
|
thumbnail: VariantUpdate_productVariantStocksUpdate_productVariant_product_thumbnail | null;
|
||||||
|
variants: (VariantUpdate_productVariantStocksUpdate_productVariant_product_variants | null)[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse {
|
||||||
|
__typename: "Warehouse";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant_stocks {
|
||||||
|
__typename: "Stock";
|
||||||
|
id: string;
|
||||||
|
quantity: number;
|
||||||
|
warehouse: VariantUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate_productVariant {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
attributes: VariantUpdate_productVariantStocksUpdate_productVariant_attributes[];
|
||||||
|
costPrice: VariantUpdate_productVariantStocksUpdate_productVariant_costPrice | null;
|
||||||
|
images: (VariantUpdate_productVariantStocksUpdate_productVariant_images | null)[] | null;
|
||||||
|
name: string;
|
||||||
|
priceOverride: VariantUpdate_productVariantStocksUpdate_productVariant_priceOverride | null;
|
||||||
|
product: VariantUpdate_productVariantStocksUpdate_productVariant_product;
|
||||||
|
sku: string;
|
||||||
|
stocks: (VariantUpdate_productVariantStocksUpdate_productVariant_stocks | null)[] | null;
|
||||||
|
trackInventory: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariantUpdate_productVariantStocksUpdate {
|
||||||
|
__typename: "ProductVariantStocksUpdate";
|
||||||
|
errors: VariantUpdate_productVariantStocksUpdate_errors[];
|
||||||
|
productVariant: VariantUpdate_productVariantStocksUpdate_productVariant | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface VariantUpdate {
|
export interface VariantUpdate {
|
||||||
productVariantUpdate: VariantUpdate_productVariantUpdate | null;
|
productVariantUpdate: VariantUpdate_productVariantUpdate | null;
|
||||||
|
productVariantStocksUpdate: VariantUpdate_productVariantStocksUpdate | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariantUpdateVariables {
|
export interface VariantUpdateVariables {
|
||||||
|
@ -142,4 +266,5 @@ export interface VariantUpdateVariables {
|
||||||
sku?: string | null;
|
sku?: string | null;
|
||||||
quantity?: number | null;
|
quantity?: number | null;
|
||||||
trackInventory: boolean;
|
trackInventory: boolean;
|
||||||
|
stocks: StockInput[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,10 @@ export const productUrl = (id: string, params?: ProductUrlQueryParams) =>
|
||||||
|
|
||||||
export const productVariantEditPath = (productId: string, variantId: string) =>
|
export const productVariantEditPath = (productId: string, variantId: string) =>
|
||||||
urlJoin(productSection, productId, "variant", variantId);
|
urlJoin(productSection, productId, "variant", variantId);
|
||||||
export type ProductVariantEditUrlDialog = "remove";
|
export type ProductVariantEditUrlDialog = "edit-stocks" | "remove";
|
||||||
export type ProductVariantEditUrlQueryParams = Dialog<"remove">;
|
export type ProductVariantEditUrlQueryParams = Dialog<
|
||||||
|
ProductVariantEditUrlDialog
|
||||||
|
>;
|
||||||
export const productVariantEditUrl = (
|
export const productVariantEditUrl = (
|
||||||
productId: string,
|
productId: string,
|
||||||
variantId: string,
|
variantId: string,
|
||||||
|
|
|
@ -103,6 +103,19 @@ export function getAttributeInputFromVariant(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getStockInputFromVariant(
|
||||||
|
variant: ProductVariant
|
||||||
|
): ProductStockInput[] {
|
||||||
|
return (
|
||||||
|
variant?.stocks.map(stock => ({
|
||||||
|
data: null,
|
||||||
|
id: stock.warehouse.id,
|
||||||
|
label: stock.warehouse.name,
|
||||||
|
value: stock.quantity.toString()
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function getVariantAttributeInputFromProduct(
|
export function getVariantAttributeInputFromProduct(
|
||||||
product: ProductVariantCreateData_product
|
product: ProductVariantCreateData_product
|
||||||
): VariantAttributeInput[] {
|
): VariantAttributeInput[] {
|
||||||
|
|
|
@ -7,7 +7,10 @@ import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useNotifier from "@saleor/hooks/useNotifier";
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import NotFoundPage from "@saleor/components/NotFoundPage";
|
import NotFoundPage from "@saleor/components/NotFoundPage";
|
||||||
import { decimal, maybe } from "../../misc";
|
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||||
|
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
|
||||||
|
import useWarehouseSearch from "@saleor/searches/useWarehouseSearch";
|
||||||
|
import { decimal } from "../../misc";
|
||||||
import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog";
|
import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog";
|
||||||
import ProductVariantPage, {
|
import ProductVariantPage, {
|
||||||
ProductVariantPageSubmitData
|
ProductVariantPageSubmitData
|
||||||
|
@ -22,8 +25,11 @@ import {
|
||||||
productUrl,
|
productUrl,
|
||||||
productVariantAddUrl,
|
productVariantAddUrl,
|
||||||
productVariantEditUrl,
|
productVariantEditUrl,
|
||||||
ProductVariantEditUrlQueryParams
|
ProductVariantEditUrlQueryParams,
|
||||||
|
ProductVariantEditUrlDialog
|
||||||
} from "../urls";
|
} from "../urls";
|
||||||
|
import ProductWarehousesDialog from "../components/ProductWarehousesDialog";
|
||||||
|
import { useAddOrRemoveStocks } from "../mutations";
|
||||||
|
|
||||||
interface ProductUpdateProps {
|
interface ProductUpdateProps {
|
||||||
variantId: string;
|
variantId: string;
|
||||||
|
@ -46,6 +52,40 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
setErrors([]);
|
setErrors([]);
|
||||||
}, [variantId]);
|
}, [variantId]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
loadMore: loadMoreWarehouses,
|
||||||
|
search: searchWarehouses,
|
||||||
|
result: searchWarehousesOpts
|
||||||
|
} = useWarehouseSearch({
|
||||||
|
variables: {
|
||||||
|
...DEFAULT_INITIAL_SEARCH_DATA,
|
||||||
|
first: 20
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [addOrRemoveStocks, addOrRemoveStocksOpts] = useAddOrRemoveStocks({
|
||||||
|
onCompleted: data => {
|
||||||
|
if (
|
||||||
|
data.productVariantStocksCreate.errors.length === 0 &&
|
||||||
|
data.productVariantStocksDelete.errors.length === 0
|
||||||
|
) {
|
||||||
|
notify({
|
||||||
|
text: intl.formatMessage(commonMessages.savedChanges)
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [openModal, closeModal] = createDialogActionHandlers<
|
||||||
|
ProductVariantEditUrlDialog,
|
||||||
|
ProductVariantEditUrlQueryParams
|
||||||
|
>(
|
||||||
|
navigate,
|
||||||
|
params => productVariantEditUrl(productId, variantId, params),
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
const handleBack = () => navigate(productUrl(productId));
|
const handleBack = () => navigate(productUrl(productId));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -107,14 +147,14 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WindowTitle title={maybe(() => data.productVariant.name)} />
|
<WindowTitle title={data?.productVariant?.name} />
|
||||||
<ProductVariantPage
|
<ProductVariantPage
|
||||||
errors={errors}
|
errors={errors}
|
||||||
saveButtonBarState={updateVariant.opts.status}
|
saveButtonBarState={updateVariant.opts.status}
|
||||||
loading={disableFormSave}
|
loading={disableFormSave}
|
||||||
placeholderImage={placeholderImg}
|
placeholderImage={placeholderImg}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
header={variant ? variant.name || variant.sku : undefined}
|
header={variant?.name || variant?.sku}
|
||||||
onAdd={() => navigate(productVariantAddUrl(productId))}
|
onAdd={() => navigate(productVariantAddUrl(productId))}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onDelete={() =>
|
onDelete={() =>
|
||||||
|
@ -125,8 +165,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onImageSelect={handleImageSelect}
|
onImageSelect={handleImageSelect}
|
||||||
onSubmit={(data: ProductVariantPageSubmitData) => {
|
onSubmit={(data: ProductVariantPageSubmitData) =>
|
||||||
if (variant) {
|
|
||||||
updateVariant.mutate({
|
updateVariant.mutate({
|
||||||
attributes: data.attributes.map(attribute => ({
|
attributes: data.attributes.map(attribute => ({
|
||||||
id: attribute.id,
|
id: attribute.id,
|
||||||
|
@ -135,15 +174,18 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
costPrice: decimal(data.costPrice),
|
costPrice: decimal(data.costPrice),
|
||||||
id: variantId,
|
id: variantId,
|
||||||
priceOverride: decimal(data.priceOverride),
|
priceOverride: decimal(data.priceOverride),
|
||||||
quantity: parseInt(data.quantity, 0),
|
|
||||||
sku: data.sku,
|
sku: data.sku,
|
||||||
trackInventory: true // FIXME: missing in UI
|
stocks: data.stocks.map(stock => ({
|
||||||
});
|
quantity: parseInt(stock.value, 10),
|
||||||
|
warehouse: stock.id
|
||||||
|
})),
|
||||||
|
trackInventory: data.trackInventory
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}}
|
|
||||||
onVariantClick={variantId => {
|
onVariantClick={variantId => {
|
||||||
navigate(productVariantEditUrl(productId, variantId));
|
navigate(productVariantEditUrl(productId, variantId));
|
||||||
}}
|
}}
|
||||||
|
onWarehousesEdit={() => openModal("edit-stocks")}
|
||||||
/>
|
/>
|
||||||
<ProductVariantDeleteDialog
|
<ProductVariantDeleteDialog
|
||||||
confirmButtonState={deleteVariant.opts.status}
|
confirmButtonState={deleteVariant.opts.status}
|
||||||
|
@ -156,7 +198,37 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
open={params.action === "remove"}
|
open={params.action === "remove"}
|
||||||
name={maybe(() => data.productVariant.name)}
|
name={data?.productVariant?.name}
|
||||||
|
/>
|
||||||
|
<ProductWarehousesDialog
|
||||||
|
confirmButtonState={addOrRemoveStocksOpts.status}
|
||||||
|
disabled={addOrRemoveStocksOpts.loading}
|
||||||
|
errors={[
|
||||||
|
...(addOrRemoveStocksOpts.data?.productVariantStocksCreate
|
||||||
|
.errors || []),
|
||||||
|
...(addOrRemoveStocksOpts.data?.productVariantStocksDelete
|
||||||
|
.errors || [])
|
||||||
|
]}
|
||||||
|
onClose={closeModal}
|
||||||
|
open={params.action === "edit-stocks"}
|
||||||
|
warehouses={searchWarehousesOpts.data?.search.edges.map(
|
||||||
|
edge => edge.node
|
||||||
|
)}
|
||||||
|
warehousesWithStocks={
|
||||||
|
variant?.stocks.map(stock => stock.warehouse.id) || []
|
||||||
|
}
|
||||||
|
onConfirm={data =>
|
||||||
|
addOrRemoveStocks({
|
||||||
|
variables: {
|
||||||
|
add: data.added.map(id => ({
|
||||||
|
quantity: 0,
|
||||||
|
warehouse: id
|
||||||
|
})),
|
||||||
|
remove: data.removed,
|
||||||
|
variantId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue