Add warehouse stock edit prototype
This commit is contained in:
parent
65dedb4263
commit
f94fdba7b9
7 changed files with 211 additions and 5 deletions
|
@ -64,6 +64,7 @@ export interface ProductUpdatePageProps extends ListActions {
|
|||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
fetchCategories: (query: string) => void;
|
||||
fetchCollections: (query: string) => void;
|
||||
onWarehousesEdit: () => void;
|
||||
onVariantsAdd: () => void;
|
||||
onVariantShow: (id: string) => () => void;
|
||||
onImageDelete: (id: string) => () => void;
|
||||
|
@ -109,6 +110,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
|||
onVariantAdd,
|
||||
onVariantsAdd,
|
||||
onVariantShow,
|
||||
onWarehousesEdit,
|
||||
isChecked,
|
||||
selected,
|
||||
toggle,
|
||||
|
@ -252,6 +254,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
|||
stocks={stocks}
|
||||
onChange={changeStockData}
|
||||
onFormDataChange={change}
|
||||
onWarehousesEdit={onWarehousesEdit}
|
||||
/>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
|
|
@ -7,6 +7,7 @@ import Typography from "@material-ui/core/Typography";
|
|||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||
import { diff, DiffData } from "fast-array-diff";
|
||||
|
||||
import ConfirmButton, {
|
||||
ConfirmButtonTransitionState
|
||||
|
@ -45,7 +46,7 @@ export interface ProductWarehousesDialogProps {
|
|||
stocks: Product_variants_stocks[];
|
||||
warehouses: SearchWarehouses_search_edges_node[];
|
||||
onClose: () => void;
|
||||
onConfirm: (data: string[]) => void;
|
||||
onConfirm: (data: DiffData<string>) => void;
|
||||
}
|
||||
|
||||
const ProductWarehousesDialog: React.FC<ProductWarehousesDialogProps> = ({
|
||||
|
@ -61,11 +62,12 @@ const ProductWarehousesDialog: React.FC<ProductWarehousesDialogProps> = ({
|
|||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
|
||||
const initial = stocks?.map(stock => stock.warehouse.id) || [];
|
||||
const [selectedWarehouses, setSelectedWarehouses] = useStateFromProps(
|
||||
stocks?.map(stock => stock.warehouse.id) || []
|
||||
initial
|
||||
);
|
||||
|
||||
const handleConfirm = () => onConfirm(selectedWarehouses);
|
||||
const handleConfirm = () => onConfirm(diff(initial, selectedWarehouses));
|
||||
|
||||
return (
|
||||
<Dialog onClose={onClose} maxWidth="sm" fullWidth open={open}>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import gql from "graphql-tag";
|
||||
|
||||
import { productErrorFragment } from "@saleor/attributes/mutations";
|
||||
import makeMutation from "@saleor/hooks/makeMutation";
|
||||
import { TypedMutation } from "../mutations";
|
||||
import { ProductCreate, ProductCreateVariables } from "./types/ProductCreate";
|
||||
import { ProductDelete, ProductDeleteVariables } from "./types/ProductDelete";
|
||||
|
@ -37,7 +38,11 @@ import {
|
|||
} from "./types/VariantImageUnassign";
|
||||
import { VariantUpdate, VariantUpdateVariables } from "./types/VariantUpdate";
|
||||
|
||||
import { fragmentVariant, productFragmentDetails } from "./queries";
|
||||
import {
|
||||
fragmentVariant,
|
||||
productFragmentDetails,
|
||||
stockFragment
|
||||
} from "./queries";
|
||||
import {
|
||||
productBulkDelete,
|
||||
productBulkDeleteVariables
|
||||
|
@ -54,6 +59,10 @@ import {
|
|||
ProductVariantBulkDelete,
|
||||
ProductVariantBulkDeleteVariables
|
||||
} from "./types/ProductVariantBulkDelete";
|
||||
import {
|
||||
AddOrRemoveStocks,
|
||||
AddOrRemoveStocksVariables
|
||||
} from "./types/AddOrRemoveStocks";
|
||||
|
||||
export const bulkProductErrorFragment = gql`
|
||||
fragment BulkProductErrorFragment on BulkProductError {
|
||||
|
@ -488,3 +497,42 @@ export const TypedProductVariantBulkDeleteMutation = TypedMutation<
|
|||
ProductVariantBulkDelete,
|
||||
ProductVariantBulkDeleteVariables
|
||||
>(ProductVariantBulkDeleteMutation);
|
||||
|
||||
const addOrRemoveStocks = gql`
|
||||
${stockFragment}
|
||||
mutation AddOrRemoveStocks(
|
||||
$variantId: ID!
|
||||
$add: [StockInput!]!
|
||||
$remove: [ID!]!
|
||||
) {
|
||||
productVariantStocksCreate(stocks: $add, variantId: $variantId) {
|
||||
bulkStockErrors {
|
||||
code
|
||||
field
|
||||
index
|
||||
}
|
||||
productVariant {
|
||||
id
|
||||
stocks {
|
||||
...StockFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
productVariantStocksDelete(warehouseIds: $remove, variantId: $variantId) {
|
||||
stockErrors {
|
||||
code
|
||||
field
|
||||
}
|
||||
productVariant {
|
||||
id
|
||||
stocks {
|
||||
...StockFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const useAddOrRemoveStocks = makeMutation<
|
||||
AddOrRemoveStocks,
|
||||
AddOrRemoveStocksVariables
|
||||
>(addOrRemoveStocks);
|
||||
|
|
83
src/products/types/AddOrRemoveStocks.ts
Normal file
83
src/products/types/AddOrRemoveStocks.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { StockInput, ProductErrorCode, StockErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AddOrRemoveStocks
|
||||
// ====================================================
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksCreate_bulkStockErrors {
|
||||
__typename: "BulkStockError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
index: number | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksCreate_productVariant_stocks_warehouse {
|
||||
__typename: "Warehouse";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksCreate_productVariant_stocks {
|
||||
__typename: "Stock";
|
||||
id: string;
|
||||
quantity: number;
|
||||
warehouse: AddOrRemoveStocks_productVariantStocksCreate_productVariant_stocks_warehouse;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksCreate_productVariant {
|
||||
__typename: "ProductVariant";
|
||||
id: string;
|
||||
stocks: (AddOrRemoveStocks_productVariantStocksCreate_productVariant_stocks | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksCreate {
|
||||
__typename: "ProductVariantStocksCreate";
|
||||
bulkStockErrors: AddOrRemoveStocks_productVariantStocksCreate_bulkStockErrors[];
|
||||
productVariant: AddOrRemoveStocks_productVariantStocksCreate_productVariant | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksDelete_stockErrors {
|
||||
__typename: "StockError";
|
||||
code: StockErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksDelete_productVariant_stocks_warehouse {
|
||||
__typename: "Warehouse";
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksDelete_productVariant_stocks {
|
||||
__typename: "Stock";
|
||||
id: string;
|
||||
quantity: number;
|
||||
warehouse: AddOrRemoveStocks_productVariantStocksDelete_productVariant_stocks_warehouse;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksDelete_productVariant {
|
||||
__typename: "ProductVariant";
|
||||
id: string;
|
||||
stocks: (AddOrRemoveStocks_productVariantStocksDelete_productVariant_stocks | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks_productVariantStocksDelete {
|
||||
__typename: "ProductVariantStocksDelete";
|
||||
stockErrors: AddOrRemoveStocks_productVariantStocksDelete_stockErrors[];
|
||||
productVariant: AddOrRemoveStocks_productVariantStocksDelete_productVariant | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocks {
|
||||
productVariantStocksCreate: AddOrRemoveStocks_productVariantStocksCreate | null;
|
||||
productVariantStocksDelete: AddOrRemoveStocks_productVariantStocksDelete | null;
|
||||
}
|
||||
|
||||
export interface AddOrRemoveStocksVariables {
|
||||
variantId: string;
|
||||
add: StockInput[];
|
||||
remove: string[];
|
||||
}
|
|
@ -66,7 +66,11 @@ export const productListUrl = (params?: ProductListUrlQueryParams): string =>
|
|||
productListPath + "?" + stringifyQs(params);
|
||||
|
||||
export const productPath = (id: string) => urlJoin(productSection + id);
|
||||
export type ProductUrlDialog = "create-variants" | "remove" | "remove-variants";
|
||||
export type ProductUrlDialog =
|
||||
| "create-variants"
|
||||
| "edit-stocks"
|
||||
| "remove"
|
||||
| "remove-variants";
|
||||
export type ProductUrlQueryParams = BulkAction & Dialog<ProductUrlDialog>;
|
||||
export const productUrl = (id: string, params?: ProductUrlQueryParams) =>
|
||||
productPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||
|
|
|
@ -19,6 +19,9 @@ import useCategorySearch from "@saleor/searches/useCategorySearch";
|
|||
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import NotFoundPage from "@saleor/components/NotFoundPage";
|
||||
import ProductWarehousesDialog from "@saleor/products/components/ProductWarehousesDialog";
|
||||
import useWarehouseSearch from "@saleor/searches/useWarehouseSearch";
|
||||
import { useAddOrRemoveStocks } from "@saleor/products/mutations";
|
||||
import { getMutationState, maybe } from "../../../misc";
|
||||
import ProductUpdatePage from "../../components/ProductUpdatePage";
|
||||
import ProductUpdateOperations from "../../containers/ProductUpdateOperations";
|
||||
|
@ -71,6 +74,30 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
|||
} = useCollectionSearch({
|
||||
variables: DEFAULT_INITIAL_SEARCH_DATA
|
||||
});
|
||||
const {
|
||||
loadMore: loadMoreWarehouses,
|
||||
search: searchWarehouses,
|
||||
result: searchWarehousesOpts
|
||||
} = useWarehouseSearch({
|
||||
variables: {
|
||||
...DEFAULT_INITIAL_SEARCH_DATA,
|
||||
first: 20
|
||||
}
|
||||
});
|
||||
|
||||
const [addOrRemoveStocks, addOrRemoveStocksOpts] = useAddOrRemoveStocks({
|
||||
onCompleted: data => {
|
||||
if (
|
||||
data.productVariantStocksCreate.bulkStockErrors.length === 0 &&
|
||||
data.productVariantStocksDelete.stockErrors.length === 0
|
||||
) {
|
||||
notify({
|
||||
text: intl.formatMessage(commonMessages.savedChanges)
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const [openModal, closeModal] = createDialogActionHandlers<
|
||||
ProductUrlDialog,
|
||||
|
@ -273,6 +300,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
|||
loading: searchCollectionsOpts.loading,
|
||||
onFetchMore: loadMoreCollections
|
||||
}}
|
||||
onWarehousesEdit={() => openModal("edit-stocks")}
|
||||
/>
|
||||
<ActionDialog
|
||||
open={params.action === "remove"}
|
||||
|
@ -345,6 +373,35 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
|
|||
})
|
||||
}
|
||||
/>
|
||||
{!product?.productType?.hasVariants && (
|
||||
<ProductWarehousesDialog
|
||||
confirmButtonState={addOrRemoveStocksOpts.status}
|
||||
errors={[
|
||||
...(addOrRemoveStocksOpts.data
|
||||
?.productVariantStocksCreate.bulkStockErrors || []),
|
||||
addOrRemoveStocksOpts.data?.productVariantStocksDelete
|
||||
.stockErrors || []
|
||||
]}
|
||||
onClose={closeModal}
|
||||
stocks={product?.variants[0].stocks || []}
|
||||
open={params.action === "edit-stocks"}
|
||||
warehouses={searchWarehousesOpts.data?.search.edges.map(
|
||||
edge => edge.node
|
||||
)}
|
||||
onConfirm={data =>
|
||||
addOrRemoveStocks({
|
||||
variables: {
|
||||
add: data.added.map(id => ({
|
||||
quantity: 0,
|
||||
warehouse: id
|
||||
})),
|
||||
remove: data.removed,
|
||||
variantId: product.variants[0].id
|
||||
}
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
|
|
|
@ -689,6 +689,15 @@ export enum StockAvailability {
|
|||
OUT_OF_STOCK = "OUT_OF_STOCK",
|
||||
}
|
||||
|
||||
export enum StockErrorCode {
|
||||
ALREADY_EXISTS = "ALREADY_EXISTS",
|
||||
GRAPHQL_ERROR = "GRAPHQL_ERROR",
|
||||
INVALID = "INVALID",
|
||||
NOT_FOUND = "NOT_FOUND",
|
||||
REQUIRED = "REQUIRED",
|
||||
UNIQUE = "UNIQUE",
|
||||
}
|
||||
|
||||
export enum TaxRateType {
|
||||
ACCOMMODATION = "ACCOMMODATION",
|
||||
ADMISSION_TO_CULTURAL_EVENTS = "ADMISSION_TO_CULTURAL_EVENTS",
|
||||
|
|
Loading…
Reference in a new issue