From 414f6d7a3d87283eb0700692587f4bbd136b310c Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 12:46:35 +0100 Subject: [PATCH 01/88] Add warehouse list view --- .../Navigator/modes/default/views.ts | 5 + src/config.ts | 4 + src/configuration/index.tsx | 39 +++- src/hooks/useListSettings.ts | 10 + src/icons/Warehouses.tsx | 16 ++ src/index.tsx | 7 + src/intl.ts | 4 + src/products/types/StockFragment.ts | 22 +++ src/types.ts | 1 + src/types/globalTypes.ts | 13 ++ .../WarehouseList/WarehouseList.tsx | 178 ++++++++++++++++++ .../components/WarehouseList/index.ts | 2 + .../WarehouseListPage.stories.tsx | 36 ++++ .../WarehouseListPage/WarehouseListPage.tsx | 104 ++++++++++ .../components/WarehouseListPage/index.ts | 2 + src/warehouses/fixtures.ts | 53 ++++++ src/warehouses/index.tsx | 66 +++++++ src/warehouses/queries.ts | 55 ++++++ src/warehouses/types/WarehouseFragment.ts | 30 +++ src/warehouses/types/WarehouseList.ts | 64 +++++++ src/warehouses/urls.ts | 42 +++++ .../views/WarehouseList/WarehouseList.tsx | 160 ++++++++++++++++ src/warehouses/views/WarehouseList/filters.ts | 31 +++ src/warehouses/views/WarehouseList/index.ts | 2 + src/warehouses/views/WarehouseList/sort.ts | 18 ++ 25 files changed, 954 insertions(+), 10 deletions(-) create mode 100644 src/icons/Warehouses.tsx create mode 100644 src/products/types/StockFragment.ts create mode 100644 src/warehouses/components/WarehouseList/WarehouseList.tsx create mode 100644 src/warehouses/components/WarehouseList/index.ts create mode 100644 src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx create mode 100644 src/warehouses/components/WarehouseListPage/WarehouseListPage.tsx create mode 100644 src/warehouses/components/WarehouseListPage/index.ts create mode 100644 src/warehouses/fixtures.ts create mode 100644 src/warehouses/index.tsx create mode 100644 src/warehouses/queries.ts create mode 100644 src/warehouses/types/WarehouseFragment.ts create mode 100644 src/warehouses/types/WarehouseList.ts create mode 100644 src/warehouses/urls.ts create mode 100644 src/warehouses/views/WarehouseList/WarehouseList.tsx create mode 100644 src/warehouses/views/WarehouseList/filters.ts create mode 100644 src/warehouses/views/WarehouseList/index.ts create mode 100644 src/warehouses/views/WarehouseList/sort.ts diff --git a/src/components/Navigator/modes/default/views.ts b/src/components/Navigator/modes/default/views.ts index c2cea32c5..c489ce6fb 100644 --- a/src/components/Navigator/modes/default/views.ts +++ b/src/components/Navigator/modes/default/views.ts @@ -21,6 +21,7 @@ import { staffListUrl } from "@saleor/staff/urls"; import { countryListUrl } from "@saleor/taxes/urls"; import { languageListUrl } from "@saleor/translations/urls"; import { webhookListUrl } from "@saleor/webhooks/urls"; +import { warehouseListUrl } from "@saleor/warehouses/urls"; import { QuickSearchActionInput } from "../../types"; interface View { @@ -116,6 +117,10 @@ function searchInViews( { label: intl.formatMessage(sectionNames.webhooks), url: webhookListUrl() + }, + { + label: intl.formatMessage(sectionNames.warehouses), + url: warehouseListUrl() } ]; diff --git a/src/config.ts b/src/config.ts index 83d7fcd5a..90b81e7c8 100644 --- a/src/config.ts +++ b/src/config.ts @@ -34,6 +34,7 @@ export interface AppListViewSettings { [ListViews.STAFF_MEMBERS_LIST]: ListSettings; [ListViews.PERMISSION_GROUP_LIST]: ListSettings; [ListViews.VOUCHER_LIST]: ListSettings; + [ListViews.WAREHOUSE_LIST]: ListSettings; [ListViews.WEBHOOK_LIST]: ListSettings; } export const defaultListSettings: AppListViewSettings = { @@ -80,6 +81,9 @@ export const defaultListSettings: AppListViewSettings = { [ListViews.VOUCHER_LIST]: { rowNumber: PAGINATE_BY }, + [ListViews.WAREHOUSE_LIST]: { + rowNumber: PAGINATE_BY + }, [ListViews.WEBHOOK_LIST]: { rowNumber: PAGINATE_BY } diff --git a/src/configuration/index.tsx b/src/configuration/index.tsx index 6b1c17a84..e597ad17c 100644 --- a/src/configuration/index.tsx +++ b/src/configuration/index.tsx @@ -31,6 +31,8 @@ import { permissionGroupListUrl } from "@saleor/permissionGroups/urls"; import { taxSection } from "@saleor/taxes/urls"; import { PermissionEnum } from "@saleor/types/globalTypes"; import { webhookListUrl } from "@saleor/webhooks/urls"; +import Warehouses from "@saleor/icons/Warehouses"; +import { warehouseSection } from "@saleor/warehouses/urls"; import ConfigurationPage, { MenuSection } from "./ConfigurationPage"; export function createConfigurationMenu(intl: IntlShape): MenuSection[] { @@ -67,16 +69,6 @@ export function createConfigurationMenu(intl: IntlShape): MenuSection[] { defaultMessage: "Product Settings" }), menuItems: [ - { - description: intl.formatMessage({ - defaultMessage: "Manage how you ship out orders", - id: "configurationMenuShipping" - }), - icon: , - permission: PermissionEnum.MANAGE_SHIPPING, - title: intl.formatMessage(sectionNames.shipping), - url: shippingZonesListUrl() - }, { description: intl.formatMessage({ defaultMessage: "Manage how your store charges tax", @@ -117,6 +109,33 @@ export function createConfigurationMenu(intl: IntlShape): MenuSection[] { } ] }, + { + label: intl.formatMessage({ + defaultMessage: "Product Settings" + }), + menuItems: [ + { + description: intl.formatMessage({ + defaultMessage: "Manage how you ship out orders", + id: "configurationMenuShipping" + }), + icon: , + permission: PermissionEnum.MANAGE_SHIPPING, + title: intl.formatMessage(sectionNames.shipping), + url: shippingZonesListUrl() + }, + { + description: intl.formatMessage({ + defaultMessage: "Manage and update your warehouse information", + id: "configurationMenuWarehouses" + }), + icon: , + permission: PermissionEnum.MANAGE_PRODUCTS, + title: intl.formatMessage(sectionNames.warehouses), + url: warehouseSection + } + ] + }, { label: intl.formatMessage({ defaultMessage: "Miscellaneous" diff --git a/src/hooks/useListSettings.ts b/src/hooks/useListSettings.ts index 75c1afd86..cac29fca9 100644 --- a/src/hooks/useListSettings.ts +++ b/src/hooks/useListSettings.ts @@ -1,3 +1,4 @@ +import { useEffect } from "react"; import useLocalStorage from "@saleor/hooks/useLocalStorage"; import { AppListViewSettings, defaultListSettings } from "./../config"; import { ListSettings, ListViews } from "./../types"; @@ -14,6 +15,15 @@ export default function useListSettings( defaultListSettings ); + useEffect(() => { + if (settings[listName] === undefined) { + setListSettings(settings => ({ + ...settings, + [listName]: defaultListSettings[listName] + })); + } + }, []); + const updateListSettings = (key: keyof ListSettings, value: any) => setListSettings(settings => ({ ...settings, diff --git a/src/icons/Warehouses.tsx b/src/icons/Warehouses.tsx new file mode 100644 index 000000000..56170523f --- /dev/null +++ b/src/icons/Warehouses.tsx @@ -0,0 +1,16 @@ +import createSvgIcon from "@material-ui/icons/utils/createSvgIcon"; +import React from "react"; + +const Warehouses = createSvgIcon( + <> + + , + "Warehouses" +); + +export default Warehouses; diff --git a/src/index.tsx b/src/index.tsx index db050df08..12279e63b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -55,6 +55,8 @@ import TaxesSection from "./taxes"; import TranslationsSection from "./translations"; import { PermissionEnum } from "./types/globalTypes"; import WebhooksSection from "./webhooks"; +import { warehouseSection } from "./warehouses/urls"; +import WarehouseSection from "./warehouses"; interface ResponseError extends ErrorResponse { networkError?: Error & { @@ -263,6 +265,11 @@ const Routes: React.FC = () => { path={serviceSection} component={ServiceSection} /> + {createConfigurationMenu(intl).filter(menu => menu.menuItems.map(item => hasPermission(item.permission, user) diff --git a/src/intl.ts b/src/intl.ts index 8b7328cff..2f8841205 100644 --- a/src/intl.ts +++ b/src/intl.ts @@ -224,6 +224,10 @@ export const sectionNames = defineMessages({ defaultMessage: "Vouchers", description: "vouchers section name" }, + warehouses: { + defaultMessage: "Warehouses", + description: "warehouses section name" + }, webhooks: { defaultMessage: "Webhooks", description: "webhooks section name" diff --git a/src/products/types/StockFragment.ts b/src/products/types/StockFragment.ts new file mode 100644 index 000000000..7aba2f87d --- /dev/null +++ b/src/products/types/StockFragment.ts @@ -0,0 +1,22 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL fragment: StockFragment +// ==================================================== + +export interface StockFragment_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface StockFragment { + __typename: "Stock"; + id: string; + quantity: number; + quantityAllocated: number; + stockQuantity: number; + warehouse: StockFragment_warehouse; +} diff --git a/src/types.ts b/src/types.ts index 3db6bcc62..e3f2014a8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -37,6 +37,7 @@ export enum ListViews { SHIPPING_METHODS_LIST = "SHIPPING_METHODS_LIST", STAFF_MEMBERS_LIST = "STAFF_MEMBERS_LIST", VOUCHER_LIST = "VOUCHER_LIST", + WAREHOUSE_LIST = "WAREHOUSE_LIST", WEBHOOK_LIST = "WEBHOOK_LIST" } diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 72cec5cbe..48507817e 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -746,6 +746,10 @@ export enum VoucherTypeEnum { SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT", } +export enum WarehouseSortField { + NAME = "NAME", +} + export enum WebhookErrorCode { GRAPHQL_ERROR = "GRAPHQL_ERROR", INVALID = "INVALID", @@ -1415,6 +1419,15 @@ export interface VoucherSortingInput { field: VoucherSortField; } +export interface WarehouseFilterInput { + search?: string | null; +} + +export interface WarehouseSortingInput { + direction: OrderDirection; + field: WarehouseSortField; +} + export interface WebhookCreateInput { name?: string | null; targetUrl?: string | null; diff --git a/src/warehouses/components/WarehouseList/WarehouseList.tsx b/src/warehouses/components/WarehouseList/WarehouseList.tsx new file mode 100644 index 000000000..6220a8951 --- /dev/null +++ b/src/warehouses/components/WarehouseList/WarehouseList.tsx @@ -0,0 +1,178 @@ +import { makeStyles } from "@material-ui/core/styles"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableFooter from "@material-ui/core/TableFooter"; +import TableRow from "@material-ui/core/TableRow"; +import TableHead from "@material-ui/core/TableHead"; +import React from "react"; +import { FormattedMessage } from "react-intl"; +import IconButton from "@material-ui/core/IconButton"; +import DeleteIcon from "@material-ui/icons/Delete"; +import EditIcon from "@material-ui/icons/Edit"; + +import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; +import ResponsiveTable from "@saleor/components/ResponsiveTable"; +import Skeleton from "@saleor/components/Skeleton"; +import TablePagination from "@saleor/components/TablePagination"; +import { maybe, renderCollection } from "@saleor/misc"; +import { ListProps, SortPage } from "@saleor/types"; +import { WarehouseListUrlSortField } from "@saleor/warehouses/urls"; +import TableCellHeader from "@saleor/components/TableCellHeader"; +import { getArrowDirection } from "@saleor/utils/sort"; + +const useStyles = makeStyles( + theme => ({ + [theme.breakpoints.up("lg")]: { + colActions: { + width: 160 + }, + colName: { + width: 400 + }, + colZones: { + width: "auto" + } + }, + actions: { + alignItems: "center", + display: "flex", + justifyContent: "flex-end", + position: "relative", + right: -theme.spacing(2) + }, + colActions: { + textAlign: "right" + }, + colName: { + paddingLeft: 0 + }, + colZones: { + paddingLeft: 0 + }, + tableRow: { + cursor: "pointer" + } + }), + { name: "WarehouseList" } +); + +interface WarehouseListProps + extends ListProps, + SortPage { + warehouses: WarehouseFragment[]; + onAdd: () => void; + onRemove: (id: string) => void; +} + +const numberOfColumns = 3; + +const WarehouseList: React.FC = props => { + const { + warehouses, + disabled, + settings, + sort, + pageInfo, + onNextPage, + onPreviousPage, + onUpdateListSettings, + onRemove, + onRowClick, + onSort + } = props; + + const classes = useStyles(props); + + return ( + + + + onSort(WarehouseListUrlSortField.name)} + > + + + + + + + + + + + + + + + + + {renderCollection( + warehouses, + warehouse => ( + warehouse.id)} + > + + {maybe(() => warehouse.name, )} + + + {maybe( + () => + warehouse.shippingZones.edges + .map(edge => edge.node.name) + .join(", "), + + )} + + +
+ + + + onRemove(warehouse.id)} + > + + +
+
+
+ ), + () => ( + + + + + + ) + )} +
+
+ ); +}; + +WarehouseList.displayName = "WarehouseList"; +export default WarehouseList; diff --git a/src/warehouses/components/WarehouseList/index.ts b/src/warehouses/components/WarehouseList/index.ts new file mode 100644 index 000000000..4c64e0c2c --- /dev/null +++ b/src/warehouses/components/WarehouseList/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseList"; +export * from "./WarehouseList"; diff --git a/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx b/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx new file mode 100644 index 000000000..7b163fd66 --- /dev/null +++ b/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx @@ -0,0 +1,36 @@ +import { storiesOf } from "@storybook/react"; +import React from "react"; + +import { + pageListProps, + tabPageProps, + sortPageProps, + searchPageProps +} from "@saleor/fixtures"; +import WarehouseListPage, { + WarehouseListPageProps +} from "@saleor/warehouses/components/WarehouseListPage"; +import Decorator from "@saleor/storybook/Decorator"; +import { WarehouseListUrlSortField } from "@saleor/warehouses/urls"; +import { warehouseList } from "../../fixtures"; + +const props: WarehouseListPageProps = { + ...pageListProps.default, + ...searchPageProps, + ...sortPageProps, + ...tabPageProps, + onBack: () => undefined, + sort: { + ...sortPageProps.sort, + sort: WarehouseListUrlSortField.name + }, + warehouses: warehouseList +}; + +storiesOf("Views / Warehouses / Warehouse list", module) + .addDecorator(Decorator) + .add("default", () => ) + .add("loading", () => ( + + )) + .add("no data", () => ); diff --git a/src/warehouses/components/WarehouseListPage/WarehouseListPage.tsx b/src/warehouses/components/WarehouseListPage/WarehouseListPage.tsx new file mode 100644 index 000000000..05c66b060 --- /dev/null +++ b/src/warehouses/components/WarehouseListPage/WarehouseListPage.tsx @@ -0,0 +1,104 @@ +import Button from "@material-ui/core/Button"; +import Card from "@material-ui/core/Card"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; +import Container from "@saleor/components/Container"; +import PageHeader from "@saleor/components/PageHeader"; +import SearchBar from "@saleor/components/SearchBar"; +import { sectionNames } from "@saleor/intl"; +import { + PageListProps, + SearchPageProps, + TabPageProps, + SortPage +} from "@saleor/types"; +import { WarehouseListUrlSortField } from "@saleor/warehouses/urls"; +import AppHeader from "@saleor/components/AppHeader"; +import WarehouseList from "../WarehouseList"; + +export interface WarehouseListPageProps + extends PageListProps, + SearchPageProps, + SortPage, + TabPageProps { + warehouses: WarehouseFragment[]; + onBack: () => void; + onRemove: (id: string) => void; +} + +export const WarehouseListPage: React.FC = ({ + warehouses, + currentTab, + disabled, + initialSearch, + pageInfo, + settings, + tabs, + onAdd, + onAll, + onBack, + onNextPage, + onPreviousPage, + onRemove, + onRowClick, + onSearchChange, + onTabChange, + onTabDelete, + onTabSave, + onUpdateListSettings, + ...listProps +}) => { + const intl = useIntl(); + + return ( + + + + + + + + + + + + + ); +}; +WarehouseListPage.displayName = "WarehouseListPage"; +export default WarehouseListPage; diff --git a/src/warehouses/components/WarehouseListPage/index.ts b/src/warehouses/components/WarehouseListPage/index.ts new file mode 100644 index 000000000..1bce1dd38 --- /dev/null +++ b/src/warehouses/components/WarehouseListPage/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseListPage"; +export * from "./WarehouseListPage"; diff --git a/src/warehouses/fixtures.ts b/src/warehouses/fixtures.ts new file mode 100644 index 000000000..e393c9c11 --- /dev/null +++ b/src/warehouses/fixtures.ts @@ -0,0 +1,53 @@ +import { shippingZones } from "../shipping/fixtures"; +import { WarehouseList_warehouses_edges_node } from "./types/WarehouseList"; + +export const warehouseList: WarehouseList_warehouses_edges_node[] = [ + { + __typename: "Warehouse", + id: "V2FyZWhvdXNlOmEzMThmMGZlLTcwMmYtNDNjYy1hYmFjLWZmZmMzN2Y3ZTliYw==", + name: "C our wares", + shippingZones: { + __typename: "ShippingZoneCountableConnection", + edges: shippingZones.map(node => ({ + __typename: "ShippingZoneCountableEdge", + node + })) + } + }, + { + __typename: "Warehouse", + id: "V2FyZWhvdXNlOjJmN2UyOTlmLWEwMzMtNDhjZS1iYmM5LTFkZDM4NjU2ZjMwYw==", + name: "Be stocked", + shippingZones: { + __typename: "ShippingZoneCountableConnection", + edges: shippingZones.map(node => ({ + __typename: "ShippingZoneCountableEdge", + node + })) + } + }, + { + __typename: "Warehouse", + id: "V2FyZWhvdXNlOmM0ZmQ3Nzc0LWZlMjYtNDE1YS1hYjk1LWFlYTFjMjI0NTgwNg==", + name: "A Warehouse", + shippingZones: { + __typename: "ShippingZoneCountableConnection", + edges: shippingZones.map(node => ({ + __typename: "ShippingZoneCountableEdge", + node + })) + } + }, + { + __typename: "Warehouse", + id: "V2FyZWhvdXNlOmNlMmNiZDhhLWRkYmQtNDhiNS1hM2UxLTNmZGVkZGI5MWZkMg==", + name: "Darkwares", + shippingZones: { + __typename: "ShippingZoneCountableConnection", + edges: shippingZones.map(node => ({ + __typename: "ShippingZoneCountableEdge", + node + })) + } + } +]; diff --git a/src/warehouses/index.tsx b/src/warehouses/index.tsx new file mode 100644 index 000000000..8d06f0040 --- /dev/null +++ b/src/warehouses/index.tsx @@ -0,0 +1,66 @@ +import { parse as parseQs } from "qs"; +import React from "react"; +import { Route, RouteComponentProps, Switch } from "react-router-dom"; + +import { sectionNames } from "@saleor/intl"; +import { useIntl } from "react-intl"; +import { asSortParams } from "@saleor/utils/sort"; +import { WindowTitle } from "../components/WindowTitle"; +import { + // warehouseAddPath, + // WarehouseAddUrlQueryParams, + warehouseListPath, + WarehouseListUrlQueryParams, + // warehousePath, + // WarehouseUrlQueryParams, + WarehouseListUrlSortField +} from "./urls"; +// import WarehouseCreateComponent from "./views/WarehouseCreate"; +// import WarehouseDetailsComponent from "./views/WarehouseDetails"; +import WarehouseListComponent from "./views/WarehouseList"; + +const WarehouseList: React.FC = ({ location }) => { + const qs = parseQs(location.search.substr(1)); + const params: WarehouseListUrlQueryParams = asSortParams( + qs, + WarehouseListUrlSortField + ); + + return ; +}; + +// const WarehouseCreate: React.FC> = ({ location }) => { +// const qs = parseQs(location.search.substr(1)); +// const params: WarehouseAddUrlQueryParams = qs; +// return ; +// }; + +// const WarehouseDetails: React.FC> = ({ +// location, +// match +// }) => { +// const qs = parseQs(location.search.substr(1)); +// const params: WarehouseUrlQueryParams = qs; +// return ( +// +// ); +// }; + +export const WarehouseSection: React.FC = () => { + const intl = useIntl(); + + return ( + <> + + + + {/* + */} + + + ); +}; +export default WarehouseSection; diff --git a/src/warehouses/queries.ts b/src/warehouses/queries.ts new file mode 100644 index 000000000..1cfd8b5ac --- /dev/null +++ b/src/warehouses/queries.ts @@ -0,0 +1,55 @@ +import gql from "graphql-tag"; + +import makeQuery from "@saleor/hooks/makeQuery"; +import { pageInfoFragment } from "@saleor/queries"; +import { WarehouseList, WarehouseListVariables } from "./types/WarehouseList"; + +export const warehouseFragment = gql` + fragment WarehouseFragment on Warehouse { + id + name + shippingZones(first: 100) { + edges { + node { + id + name + } + } + } + } +`; + +const warehouseList = gql` + ${warehouseFragment} + ${pageInfoFragment} + query WarehouseList( + $first: Int + $after: String + $last: Int + $before: String + $filter: WarehouseFilterInput + $sort: WarehouseSortingInput + ) { + warehouses( + before: $before + after: $after + first: $first + last: $last + filter: $filter + sortBy: $sort + ) { + edges { + node { + ...WarehouseFragment + } + } + pageInfo { + ...PageInfoFragment + } + } + } +`; +export const useWarehouseList = makeQuery< + WarehouseList, + WarehouseListVariables +>(warehouseList); diff --git a/src/warehouses/types/WarehouseFragment.ts b/src/warehouses/types/WarehouseFragment.ts new file mode 100644 index 000000000..1f6e19e37 --- /dev/null +++ b/src/warehouses/types/WarehouseFragment.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL fragment: WarehouseFragment +// ==================================================== + +export interface WarehouseFragment_shippingZones_edges_node { + __typename: "ShippingZone"; + id: string; + name: string; +} + +export interface WarehouseFragment_shippingZones_edges { + __typename: "ShippingZoneCountableEdge"; + node: WarehouseFragment_shippingZones_edges_node; +} + +export interface WarehouseFragment_shippingZones { + __typename: "ShippingZoneCountableConnection"; + edges: WarehouseFragment_shippingZones_edges[]; +} + +export interface WarehouseFragment { + __typename: "Warehouse"; + id: string; + name: string; + shippingZones: WarehouseFragment_shippingZones; +} diff --git a/src/warehouses/types/WarehouseList.ts b/src/warehouses/types/WarehouseList.ts new file mode 100644 index 000000000..00e3b29e4 --- /dev/null +++ b/src/warehouses/types/WarehouseList.ts @@ -0,0 +1,64 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { WarehouseFilterInput, WarehouseSortingInput } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL query operation: WarehouseList +// ==================================================== + +export interface WarehouseList_warehouses_edges_node_shippingZones_edges_node { + __typename: "ShippingZone"; + id: string; + name: string; +} + +export interface WarehouseList_warehouses_edges_node_shippingZones_edges { + __typename: "ShippingZoneCountableEdge"; + node: WarehouseList_warehouses_edges_node_shippingZones_edges_node; +} + +export interface WarehouseList_warehouses_edges_node_shippingZones { + __typename: "ShippingZoneCountableConnection"; + edges: WarehouseList_warehouses_edges_node_shippingZones_edges[]; +} + +export interface WarehouseList_warehouses_edges_node { + __typename: "Warehouse"; + id: string; + name: string; + shippingZones: WarehouseList_warehouses_edges_node_shippingZones; +} + +export interface WarehouseList_warehouses_edges { + __typename: "WarehouseCountableEdge"; + node: WarehouseList_warehouses_edges_node; +} + +export interface WarehouseList_warehouses_pageInfo { + __typename: "PageInfo"; + endCursor: string | null; + hasNextPage: boolean; + hasPreviousPage: boolean; + startCursor: string | null; +} + +export interface WarehouseList_warehouses { + __typename: "WarehouseCountableConnection"; + edges: WarehouseList_warehouses_edges[]; + pageInfo: WarehouseList_warehouses_pageInfo; +} + +export interface WarehouseList { + warehouses: WarehouseList_warehouses | null; +} + +export interface WarehouseListVariables { + first?: number | null; + after?: string | null; + last?: number | null; + before?: string | null; + filter?: WarehouseFilterInput | null; + sort?: WarehouseSortingInput | null; +} diff --git a/src/warehouses/urls.ts b/src/warehouses/urls.ts new file mode 100644 index 000000000..9864e5077 --- /dev/null +++ b/src/warehouses/urls.ts @@ -0,0 +1,42 @@ +import { stringify as stringifyQs } from "qs"; +import urlJoin from "url-join"; + +import { + ActiveTab, + Dialog, + Filters, + Pagination, + SingleAction, + TabActionDialog, + Sort +} from "../types"; + +export const warehouseSection = "/warehouses/"; + +export const warehouseListPath = warehouseSection; +export enum WarehouseListUrlFiltersEnum { + query = "query" +} +export type WarehouseListUrlFilters = Filters; +export type WarehouseListUrlDialog = "remove" | TabActionDialog; +export enum WarehouseListUrlSortField { + name = "name" +} +export type WarehouseListUrlSort = Sort; +export type WarehouseListUrlQueryParams = ActiveTab & + Dialog & + Pagination & + WarehouseListUrlFilters & + WarehouseListUrlSort & + SingleAction; +export const warehouseListUrl = (params?: WarehouseListUrlQueryParams) => + warehouseListPath + "?" + stringifyQs(params); + +export const warehousePath = (id: string) => urlJoin(warehouseSection, id); +export type WarehouseUrlDialog = "remove"; +export type WarehouseUrlQueryParams = Dialog & SingleAction; +export const warehouseUrl = (id: string, params?: WarehouseUrlQueryParams) => + warehousePath(encodeURIComponent(id)) + "?" + stringifyQs(params); + +export const warehouseAddPath = urlJoin(warehouseSection, "add"); +export const warehouseAddUrl = warehouseAddPath; diff --git a/src/warehouses/views/WarehouseList/WarehouseList.tsx b/src/warehouses/views/WarehouseList/WarehouseList.tsx new file mode 100644 index 000000000..bc119d669 --- /dev/null +++ b/src/warehouses/views/WarehouseList/WarehouseList.tsx @@ -0,0 +1,160 @@ +import React from "react"; +import { useIntl } from "react-intl"; + +import { + WarehouseListUrlQueryParams, + warehouseUrl, + WarehouseListUrlDialog, + warehouseListUrl, + warehouseAddUrl +} from "@saleor/warehouses/urls"; +import useNavigator from "@saleor/hooks/useNavigator"; +import { useWarehouseList } from "@saleor/warehouses/queries"; +import usePaginator, { + createPaginationState +} from "@saleor/hooks/usePaginator"; +import useNotifier from "@saleor/hooks/useNotifier"; +import useListSettings from "@saleor/hooks/useListSettings"; +import { ListViews } from "@saleor/types"; +import { WindowTitle } from "@saleor/components/WindowTitle"; +import { sectionNames } from "@saleor/intl"; +import WarehouseListPage from "@saleor/warehouses/components/WarehouseListPage"; +import SaveFilterTabDialog, { + SaveFilterTabDialogFormData +} from "@saleor/components/SaveFilterTabDialog"; +import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; +import { maybe } from "@saleor/misc"; +import { getSortParams } from "@saleor/utils/sort"; +import createSortHandler from "@saleor/utils/handlers/sortHandler"; +import createFilterHandlers from "@saleor/utils/handlers/filterHandlers"; +import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import { configurationMenuUrl } from "@saleor/configuration"; +import { getSortQueryVariables } from "./sort"; +import { + getFilterVariables, + getFilterTabs, + areFiltersApplied, + deleteFilterTab, + saveFilterTab, + getActiveFilters +} from "./filters"; + +export interface WarehouseListProps { + params: WarehouseListUrlQueryParams; +} + +const WarehouseList: React.FC = ({ params }) => { + const navigate = useNavigator(); + const notify = useNotifier(); + const paginate = usePaginator(); + const { updateListSettings, settings } = useListSettings( + ListViews.SALES_LIST + ); + const intl = useIntl(); + + const paginationState = createPaginationState(settings.rowNumber, params); + const queryVariables = React.useMemo( + () => ({ + ...paginationState, + filter: getFilterVariables(params), + sort: getSortQueryVariables(params) + }), + [params] + ); + const { data, loading, refetch } = useWarehouseList({ + displayLoader: true, + variables: queryVariables + }); + + const tabs = getFilterTabs(); + + const currentTab = + params.activeTab === undefined + ? areFiltersApplied(params) + ? tabs.length + 1 + : 0 + : parseInt(params.activeTab, 0); + + const [, resetFilters, handleSearchChange] = createFilterHandlers({ + createUrl: warehouseListUrl, + getFilterQueryParam: () => undefined, + navigate, + params + }); + + const [openModal, closeModal] = createDialogActionHandlers< + WarehouseListUrlDialog, + WarehouseListUrlQueryParams + >(navigate, warehouseListUrl, params); + + const handleTabChange = (tab: number) => + navigate( + warehouseListUrl({ + activeTab: tab.toString(), + ...getFilterTabs()[tab - 1].data + }) + ); + + const handleTabDelete = () => { + deleteFilterTab(currentTab); + navigate(warehouseListUrl()); + }; + + const handleTabSave = (data: SaveFilterTabDialogFormData) => { + saveFilterTab(data.name, getActiveFilters(params)); + handleTabChange(tabs.length + 1); + }; + + const { loadNextPage, loadPreviousPage, pageInfo } = paginate( + maybe(() => data.warehouses.pageInfo), + paginationState, + params + ); + + const handleSort = createSortHandler(navigate, warehouseListUrl, params); + + return ( + <> + + navigate(configurationMenuUrl)} + onTabChange={handleTabChange} + onTabDelete={() => openModal("delete-search")} + onTabSave={() => openModal("save-search")} + tabs={tabs.map(tab => tab.name)} + warehouses={maybe(() => data.warehouses.edges.map(edge => edge.node))} + settings={settings} + disabled={loading} + pageInfo={pageInfo} + onAdd={() => navigate(warehouseAddUrl)} + onNextPage={loadNextPage} + onPreviousPage={loadPreviousPage} + onRemove={() => undefined} + onSort={handleSort} + onUpdateListSettings={updateListSettings} + onRowClick={id => () => navigate(warehouseUrl(id))} + sort={getSortParams(params)} + /> + + tabs[currentTab - 1].name, "...")} + /> + + ); +}; + +WarehouseList.displayName = "WarehouseList"; +export default WarehouseList; diff --git a/src/warehouses/views/WarehouseList/filters.ts b/src/warehouses/views/WarehouseList/filters.ts new file mode 100644 index 000000000..f0e6a19f3 --- /dev/null +++ b/src/warehouses/views/WarehouseList/filters.ts @@ -0,0 +1,31 @@ +import { WarehouseFilterInput } from "@saleor/types/globalTypes"; +import { + createFilterTabUtils, + createFilterUtils +} from "../../../utils/filters"; +import { + WarehouseListUrlFilters, + WarehouseListUrlFiltersEnum, + WarehouseListUrlQueryParams +} from "../../urls"; + +export const WAREHOUSE_FILTERS_KEY = "warehouseFilters"; + +export function getFilterVariables( + params: WarehouseListUrlFilters +): WarehouseFilterInput { + return { + search: params.query + }; +} + +export const { + deleteFilterTab, + getFilterTabs, + saveFilterTab +} = createFilterTabUtils(WAREHOUSE_FILTERS_KEY); + +export const { areFiltersApplied, getActiveFilters } = createFilterUtils< + WarehouseListUrlQueryParams, + WarehouseListUrlFilters +>(WarehouseListUrlFiltersEnum); diff --git a/src/warehouses/views/WarehouseList/index.ts b/src/warehouses/views/WarehouseList/index.ts new file mode 100644 index 000000000..4c64e0c2c --- /dev/null +++ b/src/warehouses/views/WarehouseList/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseList"; +export * from "./WarehouseList"; diff --git a/src/warehouses/views/WarehouseList/sort.ts b/src/warehouses/views/WarehouseList/sort.ts new file mode 100644 index 000000000..ccf74b0fb --- /dev/null +++ b/src/warehouses/views/WarehouseList/sort.ts @@ -0,0 +1,18 @@ +import { WarehouseListUrlSortField } from "@saleor/warehouses/urls"; +import { WarehouseSortField } from "@saleor/types/globalTypes"; +import { createGetSortQueryVariables } from "@saleor/utils/sort"; + +export function getSortQueryField( + sort: WarehouseListUrlSortField +): WarehouseSortField { + switch (sort) { + case WarehouseListUrlSortField.name: + return WarehouseSortField.NAME; + default: + return undefined; + } +} + +export const getSortQueryVariables = createGetSortQueryVariables( + getSortQueryField +); From fd1f728415a4cd2258edb1a4b458b5b3c6c81ae3 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 13:06:24 +0100 Subject: [PATCH 02/88] Add warehouse delete action --- .../WarehouseDeleteDialog.tsx | 51 +++++++++++++++++++ .../components/WarehouseDeleteDialog/index.ts | 2 + .../WarehouseList/WarehouseList.tsx | 4 +- src/warehouses/mutations.ts | 22 ++++++++ src/warehouses/types/WarehouseDelete.ts | 26 ++++++++++ src/warehouses/urls.ts | 4 +- .../views/WarehouseList/WarehouseList.tsx | 38 ++++++++++++-- 7 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 src/warehouses/components/WarehouseDeleteDialog/WarehouseDeleteDialog.tsx create mode 100644 src/warehouses/components/WarehouseDeleteDialog/index.ts create mode 100644 src/warehouses/mutations.ts create mode 100644 src/warehouses/types/WarehouseDelete.ts diff --git a/src/warehouses/components/WarehouseDeleteDialog/WarehouseDeleteDialog.tsx b/src/warehouses/components/WarehouseDeleteDialog/WarehouseDeleteDialog.tsx new file mode 100644 index 000000000..224a2c36e --- /dev/null +++ b/src/warehouses/components/WarehouseDeleteDialog/WarehouseDeleteDialog.tsx @@ -0,0 +1,51 @@ +import DialogContentText from "@material-ui/core/DialogContentText"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import ActionDialog from "@saleor/components/ActionDialog"; +import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; + +export interface WarehouseDeleteDialogProps { + confirmButtonState: ConfirmButtonTransitionState; + open: boolean; + onConfirm: () => void; + onClose: () => void; + name: string; +} + +const WarehouseDeleteDialog: React.FC = ({ + name, + confirmButtonState, + onClose, + onConfirm, + open +}) => { + const intl = useIntl(); + + return ( + + + {name} + }} + /> + + + ); +}; + +WarehouseDeleteDialog.displayName = "WarehouseDeleteDialog"; +export default WarehouseDeleteDialog; diff --git a/src/warehouses/components/WarehouseDeleteDialog/index.ts b/src/warehouses/components/WarehouseDeleteDialog/index.ts new file mode 100644 index 000000000..f8f68537d --- /dev/null +++ b/src/warehouses/components/WarehouseDeleteDialog/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseDeleteDialog"; +export * from "./WarehouseDeleteDialog"; diff --git a/src/warehouses/components/WarehouseList/WarehouseList.tsx b/src/warehouses/components/WarehouseList/WarehouseList.tsx index 6220a8951..c8e7c4e3a 100644 --- a/src/warehouses/components/WarehouseList/WarehouseList.tsx +++ b/src/warehouses/components/WarehouseList/WarehouseList.tsx @@ -14,7 +14,7 @@ import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import Skeleton from "@saleor/components/Skeleton"; import TablePagination from "@saleor/components/TablePagination"; -import { maybe, renderCollection } from "@saleor/misc"; +import { maybe, renderCollection, stopPropagation } from "@saleor/misc"; import { ListProps, SortPage } from "@saleor/types"; import { WarehouseListUrlSortField } from "@saleor/warehouses/urls"; import TableCellHeader from "@saleor/components/TableCellHeader"; @@ -153,7 +153,7 @@ const WarehouseList: React.FC = props => { onRemove(warehouse.id)} + onClick={stopPropagation(() => onRemove(warehouse.id))} > diff --git a/src/warehouses/mutations.ts b/src/warehouses/mutations.ts new file mode 100644 index 000000000..fa1da647b --- /dev/null +++ b/src/warehouses/mutations.ts @@ -0,0 +1,22 @@ +import gql from "graphql-tag"; + +import makeMutation from "@saleor/hooks/makeMutation"; +import { + WarehouseDelete, + WarehouseDeleteVariables +} from "./types/WarehouseDelete"; + +const deleteWarehouse = gql` + mutation WarehouseDelete($id: ID!) { + deleteWarehouse(id: $id) { + errors { + field + message + } + } + } +`; +export const useWarehouseDelete = makeMutation< + WarehouseDelete, + WarehouseDeleteVariables +>(deleteWarehouse); diff --git a/src/warehouses/types/WarehouseDelete.ts b/src/warehouses/types/WarehouseDelete.ts new file mode 100644 index 000000000..0e2aa5efa --- /dev/null +++ b/src/warehouses/types/WarehouseDelete.ts @@ -0,0 +1,26 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL mutation operation: WarehouseDelete +// ==================================================== + +export interface WarehouseDelete_deleteWarehouse_errors { + __typename: "Error"; + field: string | null; + message: string | null; +} + +export interface WarehouseDelete_deleteWarehouse { + __typename: "WarehouseDelete"; + errors: WarehouseDelete_deleteWarehouse_errors[] | null; +} + +export interface WarehouseDelete { + deleteWarehouse: WarehouseDelete_deleteWarehouse | null; +} + +export interface WarehouseDeleteVariables { + id: string; +} diff --git a/src/warehouses/urls.ts b/src/warehouses/urls.ts index 9864e5077..d84d2266a 100644 --- a/src/warehouses/urls.ts +++ b/src/warehouses/urls.ts @@ -18,7 +18,7 @@ export enum WarehouseListUrlFiltersEnum { query = "query" } export type WarehouseListUrlFilters = Filters; -export type WarehouseListUrlDialog = "remove" | TabActionDialog; +export type WarehouseListUrlDialog = "delete" | TabActionDialog; export enum WarehouseListUrlSortField { name = "name" } @@ -33,7 +33,7 @@ export const warehouseListUrl = (params?: WarehouseListUrlQueryParams) => warehouseListPath + "?" + stringifyQs(params); export const warehousePath = (id: string) => urlJoin(warehouseSection, id); -export type WarehouseUrlDialog = "remove"; +export type WarehouseUrlDialog = "delete"; export type WarehouseUrlQueryParams = Dialog & SingleAction; export const warehouseUrl = (id: string, params?: WarehouseUrlQueryParams) => warehousePath(encodeURIComponent(id)) + "?" + stringifyQs(params); diff --git a/src/warehouses/views/WarehouseList/WarehouseList.tsx b/src/warehouses/views/WarehouseList/WarehouseList.tsx index bc119d669..4609456a6 100644 --- a/src/warehouses/views/WarehouseList/WarehouseList.tsx +++ b/src/warehouses/views/WarehouseList/WarehouseList.tsx @@ -17,18 +17,20 @@ import useNotifier from "@saleor/hooks/useNotifier"; import useListSettings from "@saleor/hooks/useListSettings"; import { ListViews } from "@saleor/types"; import { WindowTitle } from "@saleor/components/WindowTitle"; -import { sectionNames } from "@saleor/intl"; +import { sectionNames, commonMessages } from "@saleor/intl"; import WarehouseListPage from "@saleor/warehouses/components/WarehouseListPage"; import SaveFilterTabDialog, { SaveFilterTabDialogFormData } from "@saleor/components/SaveFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; -import { maybe } from "@saleor/misc"; +import { maybe, getMutationStatus } from "@saleor/misc"; import { getSortParams } from "@saleor/utils/sort"; import createSortHandler from "@saleor/utils/handlers/sortHandler"; import createFilterHandlers from "@saleor/utils/handlers/filterHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import { configurationMenuUrl } from "@saleor/configuration"; +import WarehouseDeleteDialog from "@saleor/warehouses/components/WarehouseDeleteDialog"; +import { useWarehouseDelete } from "@saleor/warehouses/mutations"; import { getSortQueryVariables } from "./sort"; import { getFilterVariables, @@ -65,6 +67,17 @@ const WarehouseList: React.FC = ({ params }) => { displayLoader: true, variables: queryVariables }); + const [deleteWarehouse, deleteWarehouseOpts] = useWarehouseDelete({ + onCompleted: data => { + if (data.deleteWarehouse.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + refetch(); + closeModal(); + } + } + }); const tabs = getFilterTabs(); @@ -113,6 +126,8 @@ const WarehouseList: React.FC = ({ params }) => { const handleSort = createSortHandler(navigate, warehouseListUrl, params); + const deleteTransitionState = getMutationStatus(deleteWarehouseOpts); + return ( <> @@ -133,12 +148,29 @@ const WarehouseList: React.FC = ({ params }) => { onAdd={() => navigate(warehouseAddUrl)} onNextPage={loadNextPage} onPreviousPage={loadPreviousPage} - onRemove={() => undefined} + onRemove={id => openModal("delete", { id })} onSort={handleSort} onUpdateListSettings={updateListSettings} onRowClick={id => () => navigate(warehouseUrl(id))} sort={getSortParams(params)} /> + + data.warehouses.edges.find(edge => edge.node.id === params.id).node + .name + )} + open={params.action === "delete"} + onClose={closeModal} + onConfirm={() => + deleteWarehouse({ + variables: { + id: params.id + } + }) + } + /> Date: Thu, 30 Jan 2020 13:11:21 +0100 Subject: [PATCH 03/88] Fix stories --- .../components/WarehouseListPage/WarehouseListPage.stories.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx b/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx index 7b163fd66..6fbaaeac5 100644 --- a/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx +++ b/src/warehouses/components/WarehouseListPage/WarehouseListPage.stories.tsx @@ -20,6 +20,7 @@ const props: WarehouseListPageProps = { ...sortPageProps, ...tabPageProps, onBack: () => undefined, + onRemove: () => undefined, sort: { ...sortPageProps.sort, sort: WarehouseListUrlSortField.name From 74ea0998249cf0629d53775dc242696557f89d0e Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 14:17:29 +0100 Subject: [PATCH 04/88] Make company address shared component --- .../CompanyAddressInput.tsx} | 39 +++++++++---------- src/components/CompanyAddressInput/index.ts | 2 + .../components/SiteSettingsAddress/index.ts | 2 - .../SiteSettingsPage/SiteSettingsPage.tsx | 8 +++- 4 files changed, 26 insertions(+), 25 deletions(-) rename src/{siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx => components/CompanyAddressInput/CompanyAddressInput.tsx} (84%) create mode 100644 src/components/CompanyAddressInput/index.ts delete mode 100644 src/siteSettings/components/SiteSettingsAddress/index.ts diff --git a/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx b/src/components/CompanyAddressInput/CompanyAddressInput.tsx similarity index 84% rename from src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx rename to src/components/CompanyAddressInput/CompanyAddressInput.tsx index bbf07bee7..927a12d25 100644 --- a/src/siteSettings/components/SiteSettingsAddress/SiteSettingsAddress.tsx +++ b/src/components/CompanyAddressInput/CompanyAddressInput.tsx @@ -17,14 +17,15 @@ import { ShopErrorFragment } from "@saleor/siteSettings/types/ShopErrorFragment" import getShopErrorMessage from "@saleor/utils/errors/shop"; import { AccountErrorFragment } from "@saleor/customers/types/AccountErrorFragment"; import getAccountErrorMessage from "@saleor/utils/errors/account"; -import { SiteSettingsPageFormData } from "../SiteSettingsPage"; +import { AddressTypeInput } from "@saleor/customers/types"; -interface SiteSettingsAddressProps { +interface CompanyAddressInputProps { countries: SingleAutocompleteChoiceType[]; - data: SiteSettingsPageFormData; + data: AddressTypeInput; displayCountry: string; errors: Array; disabled: boolean; + header: string; onChange: (event: ChangeEvent) => void; onCountryChange: (event: ChangeEvent) => void; } @@ -35,7 +36,7 @@ const useStyles = makeStyles( overflow: "visible" } }, - { name: "SiteSettingsAddress" } + { name: "CompanyAddressInput" } ); function getErrorMessage( @@ -49,13 +50,14 @@ function getErrorMessage( return getShopErrorMessage(err, intl); } -const SiteSettingsAddress: React.FC = props => { +const CompanyAddressInput: React.FC = props => { const { countries, data, disabled, displayCountry, errors, + header, onChange, onCountryChange } = props; @@ -77,12 +79,7 @@ const SiteSettingsAddress: React.FC = props => { return ( - + = props => { label={intl.formatMessage({ defaultMessage: "Company" })} - name={"companyName" as keyof SiteSettingsPageFormData} + name={"companyName" as keyof AddressTypeInput} onChange={onChange} value={data.companyName} fullWidth @@ -104,7 +101,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "Address line 1" })} - name={"streetAddress1" as keyof SiteSettingsPageFormData} + name={"streetAddress1" as keyof AddressTypeInput} onChange={onChange} value={data.streetAddress1} fullWidth @@ -117,7 +114,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "Address line 2" })} - name={"streetAddress2" as keyof SiteSettingsPageFormData} + name={"streetAddress2" as keyof AddressTypeInput} onChange={onChange} value={data.streetAddress2} fullWidth @@ -131,7 +128,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "City" })} - name={"city" as keyof SiteSettingsPageFormData} + name={"city" as keyof AddressTypeInput} onChange={onChange} value={data.city} fullWidth @@ -143,7 +140,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "ZIP / Postal code" })} - name={"postalCode" as keyof SiteSettingsPageFormData} + name={"postalCode" as keyof AddressTypeInput} onChange={onChange} value={data.postalCode} fullWidth @@ -159,7 +156,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "Country" })} - name={"country" as keyof SiteSettingsPageFormData} + name={"country" as keyof AddressTypeInput} onChange={onCountryChange} value={data.country} choices={countries} @@ -174,7 +171,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "Country area" })} - name={"countryArea" as keyof SiteSettingsPageFormData} + name={"countryArea" as keyof AddressTypeInput} onChange={onChange} value={data.countryArea} fullWidth @@ -189,7 +186,7 @@ const SiteSettingsAddress: React.FC = props => { label={intl.formatMessage({ defaultMessage: "Phone" })} - name={"phone" as keyof SiteSettingsPageFormData} + name={"phone" as keyof AddressTypeInput} value={data.phone} onChange={onChange} /> @@ -197,5 +194,5 @@ const SiteSettingsAddress: React.FC = props => { ); }; -SiteSettingsAddress.displayName = "SiteSettingsAddress"; -export default SiteSettingsAddress; +CompanyAddressInput.displayName = "CompanyAddressInput"; +export default CompanyAddressInput; diff --git a/src/components/CompanyAddressInput/index.ts b/src/components/CompanyAddressInput/index.ts new file mode 100644 index 000000000..9abca5b78 --- /dev/null +++ b/src/components/CompanyAddressInput/index.ts @@ -0,0 +1,2 @@ +export { default } from "./CompanyAddressInput"; +export * from "./CompanyAddressInput"; diff --git a/src/siteSettings/components/SiteSettingsAddress/index.ts b/src/siteSettings/components/SiteSettingsAddress/index.ts deleted file mode 100644 index b15a23918..000000000 --- a/src/siteSettings/components/SiteSettingsAddress/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./SiteSettingsAddress"; -export * from "./SiteSettingsAddress"; diff --git a/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx b/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx index dab35c263..7fa681fa7 100644 --- a/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx +++ b/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.tsx @@ -17,10 +17,10 @@ import { commonMessages, sectionNames } from "@saleor/intl"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { mapCountriesToChoices } from "@saleor/utils/maps"; import { ShopErrorFragment } from "@saleor/siteSettings/types/ShopErrorFragment"; +import CompanyAddressInput from "@saleor/components/CompanyAddressInput"; import { maybe } from "../../../misc"; import { AuthorizationKeyType } from "../../../types/globalTypes"; import { SiteSettings_shop } from "../../types/SiteSettings"; -import SiteSettingsAddress from "../SiteSettingsAddress/SiteSettingsAddress"; import SiteSettingsDetails from "../SiteSettingsDetails/SiteSettingsDetails"; import SiteSettingsKeys from "../SiteSettingsKeys/SiteSettingsKeys"; import SiteSettingsMailing, { @@ -200,12 +200,16 @@ const SiteSettingsPage: React.FC = props => { - From 2a7829c0f76de998d8ae45190c2cc835e0a27126 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 15:34:27 +0100 Subject: [PATCH 05/88] Add warehouse create --- src/fixtures.ts | 20 +++ src/types/globalTypes.ts | 19 +++ .../WarehouseCreatePage.stories.tsx | 48 +++++++ .../WarehouseCreatePage.tsx | 119 ++++++++++++++++++ .../components/WarehouseCreatePage/index.ts | 2 + .../WarehouseInfo/WarehouseInfo.tsx | 50 ++++++++ .../components/WarehouseInfo/index.ts | 2 + src/warehouses/index.tsx | 14 +-- src/warehouses/mutations.ts | 24 ++++ src/warehouses/queries.ts | 12 ++ src/warehouses/types/WarehouseCreate.ts | 75 +++++++++++ .../types/WarehouseDetailsFragment.ts | 53 ++++++++ .../views/WarehouseCreate/WarehouseCreate.tsx | 60 +++++++++ src/warehouses/views/WarehouseCreate/index.ts | 2 + 14 files changed, 491 insertions(+), 9 deletions(-) create mode 100644 src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx create mode 100644 src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx create mode 100644 src/warehouses/components/WarehouseCreatePage/index.ts create mode 100644 src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx create mode 100644 src/warehouses/components/WarehouseInfo/index.ts create mode 100644 src/warehouses/types/WarehouseCreate.ts create mode 100644 src/warehouses/types/WarehouseDetailsFragment.ts create mode 100644 src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx create mode 100644 src/warehouses/views/WarehouseCreate/index.ts diff --git a/src/fixtures.ts b/src/fixtures.ts index ebb678030..3394f4a92 100644 --- a/src/fixtures.ts +++ b/src/fixtures.ts @@ -485,3 +485,23 @@ export const adminUserPermissions: User_userPermissions[] = [ name: "Manage customers." } ]; + +export const address = { + __typename: "Address", + city: "Port Danielshire", + cityArea: "", + companyName: "", + country: { + __typename: "CountryDisplay", + code: "SE", + country: "Szwecja" + }, + countryArea: "", + firstName: "Elizabeth", + id: "QWRkcmVzczoy", + lastName: "Vaughn", + phone: "", + postalCode: "52203", + streetAddress1: "419 Ruiz Orchard Apt. 199", + streetAddress2: "0238 Cremin Freeway" +}; diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 48507817e..53faacc0a 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -1419,6 +1419,25 @@ export interface VoucherSortingInput { field: VoucherSortField; } +export interface WarehouseAddressInput { + streetAddress1: string; + streetAddress2?: string | null; + city: string; + cityArea?: string | null; + postalCode?: string | null; + country: CountryCode; + countryArea?: string | null; + phone?: string | null; +} + +export interface WarehouseCreateInput { + name: string; + companyName?: string | null; + shippingZones?: (string | null)[] | null; + email?: string | null; + address: WarehouseAddressInput; +} + export interface WarehouseFilterInput { search?: string | null; } diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx new file mode 100644 index 000000000..9f25b855b --- /dev/null +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx @@ -0,0 +1,48 @@ +import { storiesOf } from "@storybook/react"; +import React from "react"; + +import { address, permissions } from "@saleor/fixtures"; +import Decorator from "@saleor/storybook/Decorator"; +import { formError } from "@saleor/storybook/misc"; +import { warehouseList } from "../../fixtures"; +import WarehouseCreatePage, { + WarehouseCreatePageProps, + WarehouseCreatePageFormData +} from "./WarehouseCreatePage"; + +const props: WarehouseCreatePageProps = { + disabled: false, + errors: [], + saveButtonBarState: "default", + onBack: () => undefined, + onSubmit: () => undefined, + warehouse: { + ...warehouseList[0], + address + } +}; +storiesOf("Views / Warehouses / Create warehouse", module) + .addDecorator(Decorator) + .add("default", () => ) + .add("loading", () => ( + + )) + .add("form errors", () => ( + ).map(field => + formError(field) + )} + /> + )); diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx new file mode 100644 index 000000000..2024cca42 --- /dev/null +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx @@ -0,0 +1,119 @@ +import React from "react"; +import { useIntl } from "react-intl"; + +import Container from "@saleor/components/Container"; +import Form from "@saleor/components/Form"; +import SaveButtonBar from "@saleor/components/SaveButtonBar"; +import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; +import { UserError } from "@saleor/types"; +import Grid from "@saleor/components/Grid"; +import CardSpacer from "@saleor/components/CardSpacer"; +import CompanyAddressInput from "@saleor/components/CompanyAddressInput"; +import { AddressTypeInput } from "@saleor/customers/types"; +import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; +import { mapCountriesToChoices } from "@saleor/utils/maps"; +import useAddressValidation from "@saleor/hooks/useAddressValidation"; +import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { maybe } from "@saleor/misc"; +import { ShopInfo_shop } from "@saleor/components/Shop/types/ShopInfo"; +import WarehouseInfo from "../WarehouseInfo"; + +export interface WarehouseCreatePageFormData extends AddressTypeInput { + name: string; +} +export interface WarehouseCreatePageProps { + disabled: boolean; + errors: UserError[]; + saveButtonBarState: ConfirmButtonTransitionState; + shop: ShopInfo_shop; + onBack: () => void; + onSubmit: (data: WarehouseCreatePageFormData) => void; +} + +const initialForm: WarehouseCreatePageFormData = { + city: "", + companyName: "", + country: "", + countryArea: "", + name: "", + phone: "", + postalCode: "", + streetAddress1: "", + streetAddress2: "" +}; + +const WarehouseCreatePage: React.FC = ({ + disabled, + errors: apiErrors, + saveButtonBarState, + shop, + onBack, + onSubmit +}) => { + const intl = useIntl(); + const [displayCountry, setDisplayCountry] = useStateFromProps( + maybe(() => shop.companyAddress.country.code, "") + ); + + const { + errors: validationErrors, + submit: handleSubmit + } = useAddressValidation(onSubmit); + + return ( +
+ {({ change, data, errors, submit }) => { + const countryChoices = mapCountriesToChoices( + maybe(() => shop.countries, []) + ); + const handleCountryChange = createSingleAutocompleteSelectHandler( + change, + setDisplayCountry, + countryChoices + ); + + return ( + + +
+ + + +
+
+ +
+ ); + }} +
+ ); +}; + +WarehouseCreatePage.displayName = "WarehouseCreatePage"; +export default WarehouseCreatePage; diff --git a/src/warehouses/components/WarehouseCreatePage/index.ts b/src/warehouses/components/WarehouseCreatePage/index.ts new file mode 100644 index 000000000..b9bd23b20 --- /dev/null +++ b/src/warehouses/components/WarehouseCreatePage/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseCreatePage"; +export * from "./WarehouseCreatePage"; diff --git a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx new file mode 100644 index 000000000..56b402e08 --- /dev/null +++ b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import TextField from "@material-ui/core/TextField"; +import { useIntl } from "react-intl"; +import CardTitle from "@saleor/components/CardTitle"; +import { commonMessages } from "@saleor/intl"; +import { FormChange } from "@saleor/hooks/useForm"; +import { FormErrors } from "@saleor/types"; + +export interface WarehouseInfoProps { + data: Record<"name", string>; + disabled: boolean; + errors: FormErrors<"name">; + onChange: FormChange; +} + +const WarehouseInfo: React.FC = ({ + data, + disabled, + errors, + onChange +}) => { + const intl = useIntl(); + + return ( + + + + + + + ); +}; + +WarehouseInfo.displayName = "WarehouseInfo"; +export default WarehouseInfo; diff --git a/src/warehouses/components/WarehouseInfo/index.ts b/src/warehouses/components/WarehouseInfo/index.ts new file mode 100644 index 000000000..3296772d7 --- /dev/null +++ b/src/warehouses/components/WarehouseInfo/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseInfo"; +export * from "./WarehouseInfo"; diff --git a/src/warehouses/index.tsx b/src/warehouses/index.tsx index 8d06f0040..0b37a9da5 100644 --- a/src/warehouses/index.tsx +++ b/src/warehouses/index.tsx @@ -13,11 +13,13 @@ import { WarehouseListUrlQueryParams, // warehousePath, // WarehouseUrlQueryParams, - WarehouseListUrlSortField + WarehouseListUrlSortField, + warehouseAddPath } from "./urls"; // import WarehouseCreateComponent from "./views/WarehouseCreate"; // import WarehouseDetailsComponent from "./views/WarehouseDetails"; import WarehouseListComponent from "./views/WarehouseList"; +import WarehouseCreate from "./views/WarehouseCreate"; const WarehouseList: React.FC = ({ location }) => { const qs = parseQs(location.search.substr(1)); @@ -29,12 +31,6 @@ const WarehouseList: React.FC = ({ location }) => { return ; }; -// const WarehouseCreate: React.FC> = ({ location }) => { -// const qs = parseQs(location.search.substr(1)); -// const params: WarehouseAddUrlQueryParams = qs; -// return ; -// }; - // const WarehouseDetails: React.FC> = ({ // location, // match @@ -57,8 +53,8 @@ export const WarehouseSection: React.FC = () => { - {/* - */} + + {/* */} ); diff --git a/src/warehouses/mutations.ts b/src/warehouses/mutations.ts index fa1da647b..9611cac88 100644 --- a/src/warehouses/mutations.ts +++ b/src/warehouses/mutations.ts @@ -1,10 +1,15 @@ import gql from "graphql-tag"; import makeMutation from "@saleor/hooks/makeMutation"; +import { + WarehouseCreate, + WarehouseCreateVariables +} from "./types/WarehouseCreate"; import { WarehouseDelete, WarehouseDeleteVariables } from "./types/WarehouseDelete"; +import { warehouseDetailsFragment } from "./queries"; const deleteWarehouse = gql` mutation WarehouseDelete($id: ID!) { @@ -20,3 +25,22 @@ export const useWarehouseDelete = makeMutation< WarehouseDelete, WarehouseDeleteVariables >(deleteWarehouse); + +const createWarehouse = gql` + ${warehouseDetailsFragment} + mutation WarehouseCreate($input: WarehouseCreateInput!) { + createWarehouse(input: $input) { + errors { + field + message + } + warehouse { + ...WarehouseDetailsFragment + } + } + } +`; +export const useWarehouseCreate = makeMutation< + WarehouseCreate, + WarehouseCreateVariables +>(createWarehouse); diff --git a/src/warehouses/queries.ts b/src/warehouses/queries.ts index 1cfd8b5ac..d75984c68 100644 --- a/src/warehouses/queries.ts +++ b/src/warehouses/queries.ts @@ -2,6 +2,7 @@ import gql from "graphql-tag"; import makeQuery from "@saleor/hooks/makeQuery"; import { pageInfoFragment } from "@saleor/queries"; +import { fragmentAddress } from "@saleor/orders/queries"; import { WarehouseList, WarehouseListVariables } from "./types/WarehouseList"; export const warehouseFragment = gql` @@ -19,6 +20,17 @@ export const warehouseFragment = gql` } `; +export const warehouseDetailsFragment = gql` + ${fragmentAddress} + ${warehouseFragment} + fragment WarehouseDetailsFragment on Warehouse { + ...WarehouseFragment + address { + ...AddressFragment + } + } +`; + const warehouseList = gql` ${warehouseFragment} ${pageInfoFragment} diff --git a/src/warehouses/types/WarehouseCreate.ts b/src/warehouses/types/WarehouseCreate.ts new file mode 100644 index 000000000..5caeb87b9 --- /dev/null +++ b/src/warehouses/types/WarehouseCreate.ts @@ -0,0 +1,75 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { WarehouseCreateInput } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL mutation operation: WarehouseCreate +// ==================================================== + +export interface WarehouseCreate_createWarehouse_errors { + __typename: "Error"; + field: string | null; + message: string | null; +} + +export interface WarehouseCreate_createWarehouse_warehouse_shippingZones_edges_node { + __typename: "ShippingZone"; + id: string; + name: string; +} + +export interface WarehouseCreate_createWarehouse_warehouse_shippingZones_edges { + __typename: "ShippingZoneCountableEdge"; + node: WarehouseCreate_createWarehouse_warehouse_shippingZones_edges_node; +} + +export interface WarehouseCreate_createWarehouse_warehouse_shippingZones { + __typename: "ShippingZoneCountableConnection"; + edges: WarehouseCreate_createWarehouse_warehouse_shippingZones_edges[]; +} + +export interface WarehouseCreate_createWarehouse_warehouse_address_country { + __typename: "CountryDisplay"; + code: string; + country: string; +} + +export interface WarehouseCreate_createWarehouse_warehouse_address { + __typename: "Address"; + city: string; + cityArea: string; + companyName: string; + country: WarehouseCreate_createWarehouse_warehouse_address_country; + countryArea: string; + firstName: string; + id: string; + lastName: string; + phone: string | null; + postalCode: string; + streetAddress1: string; + streetAddress2: string; +} + +export interface WarehouseCreate_createWarehouse_warehouse { + __typename: "Warehouse"; + id: string; + name: string; + shippingZones: WarehouseCreate_createWarehouse_warehouse_shippingZones; + address: WarehouseCreate_createWarehouse_warehouse_address; +} + +export interface WarehouseCreate_createWarehouse { + __typename: "WarehouseCreate"; + errors: WarehouseCreate_createWarehouse_errors[] | null; + warehouse: WarehouseCreate_createWarehouse_warehouse | null; +} + +export interface WarehouseCreate { + createWarehouse: WarehouseCreate_createWarehouse | null; +} + +export interface WarehouseCreateVariables { + input: WarehouseCreateInput; +} diff --git a/src/warehouses/types/WarehouseDetailsFragment.ts b/src/warehouses/types/WarehouseDetailsFragment.ts new file mode 100644 index 000000000..fae00ac31 --- /dev/null +++ b/src/warehouses/types/WarehouseDetailsFragment.ts @@ -0,0 +1,53 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL fragment: WarehouseDetailsFragment +// ==================================================== + +export interface WarehouseDetailsFragment_shippingZones_edges_node { + __typename: "ShippingZone"; + id: string; + name: string; +} + +export interface WarehouseDetailsFragment_shippingZones_edges { + __typename: "ShippingZoneCountableEdge"; + node: WarehouseDetailsFragment_shippingZones_edges_node; +} + +export interface WarehouseDetailsFragment_shippingZones { + __typename: "ShippingZoneCountableConnection"; + edges: WarehouseDetailsFragment_shippingZones_edges[]; +} + +export interface WarehouseDetailsFragment_address_country { + __typename: "CountryDisplay"; + code: string; + country: string; +} + +export interface WarehouseDetailsFragment_address { + __typename: "Address"; + city: string; + cityArea: string; + companyName: string; + country: WarehouseDetailsFragment_address_country; + countryArea: string; + firstName: string; + id: string; + lastName: string; + phone: string | null; + postalCode: string; + streetAddress1: string; + streetAddress2: string; +} + +export interface WarehouseDetailsFragment { + __typename: "Warehouse"; + id: string; + name: string; + shippingZones: WarehouseDetailsFragment_shippingZones; + address: WarehouseDetailsFragment_address; +} diff --git a/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx b/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx new file mode 100644 index 000000000..921a0ee8f --- /dev/null +++ b/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { useIntl } from "react-intl"; + +import WarehouseCreatePage from "@saleor/warehouses/components/WarehouseCreatePage"; +import useNavigator from "@saleor/hooks/useNavigator"; +import { warehouseListUrl, warehouseUrl } from "@saleor/warehouses/urls"; +import { useWarehouseCreate } from "@saleor/warehouses/mutations"; +import { commonMessages } from "@saleor/intl"; +import useNotifier from "@saleor/hooks/useNotifier"; +import { maybe, findValueInEnum, getMutationStatus } from "@saleor/misc"; +import { CountryCode } from "@saleor/types/globalTypes"; +import useShop from "@saleor/hooks/useShop"; + +const WarehouseCreate: React.FC = () => { + const intl = useIntl(); + const navigate = useNavigator(); + const notify = useNotifier(); + const shop = useShop(); + const [createWarehouse, createWarehouseOpts] = useWarehouseCreate({ + onCompleted: data => { + if (data.createWarehouse.errors.length === 0) { + navigate(warehouseUrl(data.createWarehouse.warehouse.id)); + notify({ text: intl.formatMessage(commonMessages.savedChanges) }); + } + } + }); + const createWarehouseTransitionState = getMutationStatus(createWarehouseOpts); + + return ( + navigate(warehouseListUrl())} + disabled={createWarehouseOpts.loading} + errors={maybe(() => createWarehouseOpts.data.createWarehouse.errors, [])} + shop={shop} + onSubmit={data => + createWarehouse({ + variables: { + input: { + address: { + city: data.city, + cityArea: data.cityArea, + country: findValueInEnum(data.country, CountryCode), + countryArea: data.countryArea, + phone: data.phone, + postalCode: data.postalCode, + streetAddress1: data.streetAddress1, + streetAddress2: data.streetAddress2 + }, + name: data.name + } + } + }) + } + saveButtonBarState={createWarehouseTransitionState} + /> + ); +}; + +WarehouseCreate.displayName = "WarehouseCreate"; +export default WarehouseCreate; diff --git a/src/warehouses/views/WarehouseCreate/index.ts b/src/warehouses/views/WarehouseCreate/index.ts new file mode 100644 index 000000000..d73de272c --- /dev/null +++ b/src/warehouses/views/WarehouseCreate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseCreate"; +export * from "./WarehouseCreate"; From c9afddd050f11979bf6de3df946fb4800312d811 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 15:39:55 +0100 Subject: [PATCH 06/88] Improve headers --- .../WarehouseCreatePage.tsx | 18 ++++-- .../views/WarehouseCreate/WarehouseCreate.tsx | 62 +++++++++++-------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx index 2024cca42..64bde0713 100644 --- a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { useIntl } from "react-intl"; +import { useIntl, FormattedMessage } from "react-intl"; import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; @@ -16,6 +16,9 @@ import useAddressValidation from "@saleor/hooks/useAddressValidation"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { maybe } from "@saleor/misc"; import { ShopInfo_shop } from "@saleor/components/Shop/types/ShopInfo"; +import AppHeader from "@saleor/components/AppHeader"; +import PageHeader from "@saleor/components/PageHeader"; +import { sectionNames } from "@saleor/intl"; import WarehouseInfo from "../WarehouseInfo"; export interface WarehouseCreatePageFormData extends AddressTypeInput { @@ -51,9 +54,7 @@ const WarehouseCreatePage: React.FC = ({ onSubmit }) => { const intl = useIntl(); - const [displayCountry, setDisplayCountry] = useStateFromProps( - maybe(() => shop.companyAddress.country.code, "") - ); + const [displayCountry, setDisplayCountry] = useStateFromProps(""); const { errors: validationErrors, @@ -78,6 +79,15 @@ const WarehouseCreatePage: React.FC = ({ return ( + + + +
{ const intl = useIntl(); @@ -27,32 +28,43 @@ const WarehouseCreate: React.FC = () => { const createWarehouseTransitionState = getMutationStatus(createWarehouseOpts); return ( - navigate(warehouseListUrl())} - disabled={createWarehouseOpts.loading} - errors={maybe(() => createWarehouseOpts.data.createWarehouse.errors, [])} - shop={shop} - onSubmit={data => - createWarehouse({ - variables: { - input: { - address: { - city: data.city, - cityArea: data.cityArea, - country: findValueInEnum(data.country, CountryCode), - countryArea: data.countryArea, - phone: data.phone, - postalCode: data.postalCode, - streetAddress1: data.streetAddress1, - streetAddress2: data.streetAddress2 - }, - name: data.name + <> + + navigate(warehouseListUrl())} + disabled={createWarehouseOpts.loading} + errors={maybe( + () => createWarehouseOpts.data.createWarehouse.errors, + [] + )} + shop={shop} + onSubmit={data => + createWarehouse({ + variables: { + input: { + address: { + city: data.city, + cityArea: data.cityArea, + country: findValueInEnum(data.country, CountryCode), + countryArea: data.countryArea, + phone: data.phone, + postalCode: data.postalCode, + streetAddress1: data.streetAddress1, + streetAddress2: data.streetAddress2 + }, + name: data.name + } } - } - }) - } - saveButtonBarState={createWarehouseTransitionState} - /> + }) + } + saveButtonBarState={createWarehouseTransitionState} + /> + ); }; From 8445d2d815a3fbb988dab660d24b8672f0d5f5ee Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 16:37:22 +0100 Subject: [PATCH 07/88] Add warehouse details --- src/fixtures.ts | 4 +- src/types/globalTypes.ts | 8 + .../WarehouseCreatePage.stories.tsx | 14 +- .../WarehouseDetailsPage.stories.tsx | 48 ++++++ .../WarehouseDetailsPage.tsx | 141 ++++++++++++++++++ .../components/WarehouseDetailsPage/index.ts | 2 + .../WarehouseInfo/WarehouseInfo.tsx | 1 + .../WarehouseZones/WarehouseZones.tsx | 73 +++++++++ .../components/WarehouseZones/index.ts | 2 + src/warehouses/index.tsx | 37 +++-- src/warehouses/mutations.ts | 23 +++ src/warehouses/queries.ts | 17 +++ src/warehouses/types/WarehouseDetails.ts | 61 ++++++++ src/warehouses/types/WarehouseUpdate.ts | 76 ++++++++++ .../WarehouseDetails/WarehouseDetails.tsx | 84 +++++++++++ .../views/WarehouseDetails/index.ts | 2 + 16 files changed, 561 insertions(+), 32 deletions(-) create mode 100644 src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx create mode 100644 src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx create mode 100644 src/warehouses/components/WarehouseDetailsPage/index.ts create mode 100644 src/warehouses/components/WarehouseZones/WarehouseZones.tsx create mode 100644 src/warehouses/components/WarehouseZones/index.ts create mode 100644 src/warehouses/types/WarehouseDetails.ts create mode 100644 src/warehouses/types/WarehouseUpdate.ts create mode 100644 src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx create mode 100644 src/warehouses/views/WarehouseDetails/index.ts diff --git a/src/fixtures.ts b/src/fixtures.ts index 3394f4a92..037506378 100644 --- a/src/fixtures.ts +++ b/src/fixtures.ts @@ -487,12 +487,12 @@ export const adminUserPermissions: User_userPermissions[] = [ ]; export const address = { - __typename: "Address", + __typename: "Address" as "Address", city: "Port Danielshire", cityArea: "", companyName: "", country: { - __typename: "CountryDisplay", + __typename: "CountryDisplay" as "CountryDisplay", code: "SE", country: "Szwecja" }, diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 53faacc0a..e6066af22 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -1447,6 +1447,14 @@ export interface WarehouseSortingInput { field: WarehouseSortField; } +export interface WarehouseUpdateInput { + name: string; + companyName?: string | null; + shippingZones?: (string | null)[] | null; + email?: string | null; + address?: WarehouseAddressInput | null; +} + export interface WebhookCreateInput { name?: string | null; targetUrl?: string | null; diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx index 9f25b855b..87ef6f4d4 100644 --- a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx @@ -1,10 +1,9 @@ import { storiesOf } from "@storybook/react"; import React from "react"; -import { address, permissions } from "@saleor/fixtures"; import Decorator from "@saleor/storybook/Decorator"; import { formError } from "@saleor/storybook/misc"; -import { warehouseList } from "../../fixtures"; +import { shop } from "@saleor/siteSettings/fixtures"; import WarehouseCreatePage, { WarehouseCreatePageProps, WarehouseCreatePageFormData @@ -13,20 +12,15 @@ import WarehouseCreatePage, { const props: WarehouseCreatePageProps = { disabled: false, errors: [], - saveButtonBarState: "default", onBack: () => undefined, onSubmit: () => undefined, - warehouse: { - ...warehouseList[0], - address - } + saveButtonBarState: "default", + shop }; storiesOf("Views / Warehouses / Create warehouse", module) .addDecorator(Decorator) .add("default", () => ) - .add("loading", () => ( - - )) + .add("loading", () => ) .add("form errors", () => ( undefined, + onSubmit: () => undefined, + saveButtonBarState: "default", + warehouse: { + ...warehouseList[0], + address + } +}; +storiesOf("Views / Warehouses / Warehouse details", module) + .addDecorator(Decorator) + .add("default", () => ) + .add("loading", () => ( + + )) + .add("form errors", () => ( + ).map(field => + formError(field) + )} + /> + )); diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx new file mode 100644 index 000000000..1d6b02689 --- /dev/null +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx @@ -0,0 +1,141 @@ +import React from "react"; +import { useIntl, FormattedMessage } from "react-intl"; + +import Container from "@saleor/components/Container"; +import Form from "@saleor/components/Form"; +import SaveButtonBar from "@saleor/components/SaveButtonBar"; +import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; +import { UserError } from "@saleor/types"; +import Grid from "@saleor/components/Grid"; +import CardSpacer from "@saleor/components/CardSpacer"; +import CompanyAddressInput from "@saleor/components/CompanyAddressInput"; +import { AddressTypeInput } from "@saleor/customers/types"; +import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; +import { mapCountriesToChoices } from "@saleor/utils/maps"; +import useAddressValidation from "@saleor/hooks/useAddressValidation"; +import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { maybe, findValueInEnum } from "@saleor/misc"; +import { ShopInfo_shop } from "@saleor/components/Shop/types/ShopInfo"; +import AppHeader from "@saleor/components/AppHeader"; +import PageHeader from "@saleor/components/PageHeader"; +import { sectionNames } from "@saleor/intl"; +import { CountryCode } from "@saleor/types/globalTypes"; +import WarehouseInfo from "../WarehouseInfo"; +import WarehouseZones from "../WarehouseZones"; +import { WarehouseDetails_warehouse } from "../../types/WarehouseDetails"; + +export interface WarehouseDetailsPageFormData extends AddressTypeInput { + name: string; +} +export interface WarehouseDetailsPageProps { + disabled: boolean; + errors: UserError[]; + saveButtonBarState: ConfirmButtonTransitionState; + shop: ShopInfo_shop; + warehouse: WarehouseDetails_warehouse; + onBack: () => void; + onShippingZoneClick: (id: string) => void; + onSubmit: (data: WarehouseDetailsPageFormData) => void; +} + +const WarehouseDetailsPage: React.FC = ({ + disabled, + errors: apiErrors, + saveButtonBarState, + shop, + warehouse, + onBack, + onShippingZoneClick, + onSubmit +}) => { + const intl = useIntl(); + const [displayCountry, setDisplayCountry] = useStateFromProps(""); + + const { + errors: validationErrors, + submit: handleSubmit + } = useAddressValidation(onSubmit); + + const initialForm: WarehouseDetailsPageFormData = { + city: maybe(() => warehouse.address.city, ""), + companyName: maybe(() => warehouse.address.companyName, ""), + country: maybe(() => + findValueInEnum(warehouse.address.country.code, CountryCode) + ), + countryArea: maybe(() => warehouse.address.countryArea, ""), + name: maybe(() => warehouse.name, ""), + phone: maybe(() => warehouse.address.phone, ""), + postalCode: maybe(() => warehouse.address.postalCode, ""), + streetAddress1: maybe(() => warehouse.address.streetAddress1, ""), + streetAddress2: maybe(() => warehouse.address.streetAddress2, "") + }; + + return ( +
+ {({ change, data, errors, submit }) => { + const countryChoices = mapCountriesToChoices( + maybe(() => shop.countries, []) + ); + const handleCountryChange = createSingleAutocompleteSelectHandler( + change, + setDisplayCountry, + countryChoices + ); + + return ( + + + + + warehouse.name)} /> + +
+ + + +
+
+ + warehouse.shippingZones.edges.map(edge => edge.node) + )} + onShippingZoneClick={onShippingZoneClick} + /> +
+
+ +
+ ); + }} +
+ ); +}; + +WarehouseDetailsPage.displayName = "WarehouseDetailsPage"; +export default WarehouseDetailsPage; diff --git a/src/warehouses/components/WarehouseDetailsPage/index.ts b/src/warehouses/components/WarehouseDetailsPage/index.ts new file mode 100644 index 000000000..c5fea07a8 --- /dev/null +++ b/src/warehouses/components/WarehouseDetailsPage/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseDetailsPage"; +export * from "./WarehouseDetailsPage"; diff --git a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx index 56b402e08..7b31cc2ea 100644 --- a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx +++ b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx @@ -3,6 +3,7 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import TextField from "@material-ui/core/TextField"; import { useIntl } from "react-intl"; + import CardTitle from "@saleor/components/CardTitle"; import { commonMessages } from "@saleor/intl"; import { FormChange } from "@saleor/hooks/useForm"; diff --git a/src/warehouses/components/WarehouseZones/WarehouseZones.tsx b/src/warehouses/components/WarehouseZones/WarehouseZones.tsx new file mode 100644 index 000000000..b4fe1cb2d --- /dev/null +++ b/src/warehouses/components/WarehouseZones/WarehouseZones.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import Typography from "@material-ui/core/Typography"; +import { useIntl, FormattedMessage } from "react-intl"; +import makeStyles from "@material-ui/core/styles/makeStyles"; + +import CardTitle from "@saleor/components/CardTitle"; +import { WarehouseDetails_warehouse_shippingZones_edges_node } from "@saleor/warehouses/types/WarehouseDetails"; +import { renderCollection, maybe } from "@saleor/misc"; +import Link from "@saleor/components/Link"; +import Skeleton from "@saleor/components/Skeleton"; + +export interface WarehouseInfoProps { + zones: WarehouseDetails_warehouse_shippingZones_edges_node[]; + onShippingZoneClick: (id: string) => void; +} + +const useStyles = makeStyles( + theme => ({ + link: { + "&:not(:last-of-type)": { + marginBottom: theme.spacing() + } + } + }), + { + name: "WarehouseInfoProps" + } +); + +const WarehouseInfo: React.FC = ({ + zones, + onShippingZoneClick +}) => { + const classes = useStyles({}); + const intl = useIntl(); + + return ( + + + + {renderCollection( + zones, + zone => + maybe( + () => ( +
+ onShippingZoneClick(zone.id)}> + {zone.name} + +
+ ), + + ), + () => ( + + + + ) + )} +
+
+ ); +}; + +WarehouseInfo.displayName = "WarehouseInfo"; +export default WarehouseInfo; diff --git a/src/warehouses/components/WarehouseZones/index.ts b/src/warehouses/components/WarehouseZones/index.ts new file mode 100644 index 000000000..c0a280252 --- /dev/null +++ b/src/warehouses/components/WarehouseZones/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseZones"; +export * from "./WarehouseZones"; diff --git a/src/warehouses/index.tsx b/src/warehouses/index.tsx index 0b37a9da5..b94af8c1a 100644 --- a/src/warehouses/index.tsx +++ b/src/warehouses/index.tsx @@ -7,17 +7,14 @@ import { useIntl } from "react-intl"; import { asSortParams } from "@saleor/utils/sort"; import { WindowTitle } from "../components/WindowTitle"; import { - // warehouseAddPath, - // WarehouseAddUrlQueryParams, warehouseListPath, WarehouseListUrlQueryParams, - // warehousePath, - // WarehouseUrlQueryParams, + warehousePath, + WarehouseUrlQueryParams, WarehouseListUrlSortField, warehouseAddPath } from "./urls"; -// import WarehouseCreateComponent from "./views/WarehouseCreate"; -// import WarehouseDetailsComponent from "./views/WarehouseDetails"; +import WarehouseDetailsComponent from "./views/WarehouseDetails"; import WarehouseListComponent from "./views/WarehouseList"; import WarehouseCreate from "./views/WarehouseCreate"; @@ -31,19 +28,19 @@ const WarehouseList: React.FC = ({ location }) => { return ; }; -// const WarehouseDetails: React.FC> = ({ -// location, -// match -// }) => { -// const qs = parseQs(location.search.substr(1)); -// const params: WarehouseUrlQueryParams = qs; -// return ( -// -// ); -// }; +const WarehouseDetails: React.FC> = ({ + location, + match +}) => { + const qs = parseQs(location.search.substr(1)); + const params: WarehouseUrlQueryParams = qs; + return ( + + ); +}; export const WarehouseSection: React.FC = () => { const intl = useIntl(); @@ -54,7 +51,7 @@ export const WarehouseSection: React.FC = () => { - {/* */} + ); diff --git a/src/warehouses/mutations.ts b/src/warehouses/mutations.ts index 9611cac88..26a9b2805 100644 --- a/src/warehouses/mutations.ts +++ b/src/warehouses/mutations.ts @@ -5,6 +5,10 @@ import { WarehouseCreate, WarehouseCreateVariables } from "./types/WarehouseCreate"; +import { + WarehouseUpdate, + WarehouseUpdateVariables +} from "./types/WarehouseUpdate"; import { WarehouseDelete, WarehouseDeleteVariables @@ -44,3 +48,22 @@ export const useWarehouseCreate = makeMutation< WarehouseCreate, WarehouseCreateVariables >(createWarehouse); + +const updateWarehouse = gql` + ${warehouseDetailsFragment} + mutation WarehouseUpdate($id: ID!, $input: WarehouseUpdateInput!) { + updateWarehouse(id: $id, input: $input) { + errors { + field + message + } + warehouse { + ...WarehouseDetailsFragment + } + } + } +`; +export const useWarehouseUpdate = makeMutation< + WarehouseUpdate, + WarehouseUpdateVariables +>(updateWarehouse); diff --git a/src/warehouses/queries.ts b/src/warehouses/queries.ts index d75984c68..6eeefdeb4 100644 --- a/src/warehouses/queries.ts +++ b/src/warehouses/queries.ts @@ -4,6 +4,10 @@ import makeQuery from "@saleor/hooks/makeQuery"; import { pageInfoFragment } from "@saleor/queries"; import { fragmentAddress } from "@saleor/orders/queries"; import { WarehouseList, WarehouseListVariables } from "./types/WarehouseList"; +import { + WarehouseDetails, + WarehouseDetailsVariables +} from "./types/WarehouseDetails"; export const warehouseFragment = gql` fragment WarehouseFragment on Warehouse { @@ -65,3 +69,16 @@ export const useWarehouseList = makeQuery< WarehouseList, WarehouseListVariables >(warehouseList); + +const warehouseDetails = gql` + ${warehouseDetailsFragment} + query WarehouseDetails($id: ID!) { + warehouse(id: $id) { + ...WarehouseDetailsFragment + } + } +`; +export const useWarehouseDetails = makeQuery< + WarehouseDetails, + WarehouseDetailsVariables +>(warehouseDetails); diff --git a/src/warehouses/types/WarehouseDetails.ts b/src/warehouses/types/WarehouseDetails.ts new file mode 100644 index 000000000..b48eb255a --- /dev/null +++ b/src/warehouses/types/WarehouseDetails.ts @@ -0,0 +1,61 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: WarehouseDetails +// ==================================================== + +export interface WarehouseDetails_warehouse_shippingZones_edges_node { + __typename: "ShippingZone"; + id: string; + name: string; +} + +export interface WarehouseDetails_warehouse_shippingZones_edges { + __typename: "ShippingZoneCountableEdge"; + node: WarehouseDetails_warehouse_shippingZones_edges_node; +} + +export interface WarehouseDetails_warehouse_shippingZones { + __typename: "ShippingZoneCountableConnection"; + edges: WarehouseDetails_warehouse_shippingZones_edges[]; +} + +export interface WarehouseDetails_warehouse_address_country { + __typename: "CountryDisplay"; + code: string; + country: string; +} + +export interface WarehouseDetails_warehouse_address { + __typename: "Address"; + city: string; + cityArea: string; + companyName: string; + country: WarehouseDetails_warehouse_address_country; + countryArea: string; + firstName: string; + id: string; + lastName: string; + phone: string | null; + postalCode: string; + streetAddress1: string; + streetAddress2: string; +} + +export interface WarehouseDetails_warehouse { + __typename: "Warehouse"; + id: string; + name: string; + shippingZones: WarehouseDetails_warehouse_shippingZones; + address: WarehouseDetails_warehouse_address; +} + +export interface WarehouseDetails { + warehouse: WarehouseDetails_warehouse | null; +} + +export interface WarehouseDetailsVariables { + id: string; +} diff --git a/src/warehouses/types/WarehouseUpdate.ts b/src/warehouses/types/WarehouseUpdate.ts new file mode 100644 index 000000000..345f6f9fb --- /dev/null +++ b/src/warehouses/types/WarehouseUpdate.ts @@ -0,0 +1,76 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { WarehouseUpdateInput } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL mutation operation: WarehouseUpdate +// ==================================================== + +export interface WarehouseUpdate_updateWarehouse_errors { + __typename: "Error"; + field: string | null; + message: string | null; +} + +export interface WarehouseUpdate_updateWarehouse_warehouse_shippingZones_edges_node { + __typename: "ShippingZone"; + id: string; + name: string; +} + +export interface WarehouseUpdate_updateWarehouse_warehouse_shippingZones_edges { + __typename: "ShippingZoneCountableEdge"; + node: WarehouseUpdate_updateWarehouse_warehouse_shippingZones_edges_node; +} + +export interface WarehouseUpdate_updateWarehouse_warehouse_shippingZones { + __typename: "ShippingZoneCountableConnection"; + edges: WarehouseUpdate_updateWarehouse_warehouse_shippingZones_edges[]; +} + +export interface WarehouseUpdate_updateWarehouse_warehouse_address_country { + __typename: "CountryDisplay"; + code: string; + country: string; +} + +export interface WarehouseUpdate_updateWarehouse_warehouse_address { + __typename: "Address"; + city: string; + cityArea: string; + companyName: string; + country: WarehouseUpdate_updateWarehouse_warehouse_address_country; + countryArea: string; + firstName: string; + id: string; + lastName: string; + phone: string | null; + postalCode: string; + streetAddress1: string; + streetAddress2: string; +} + +export interface WarehouseUpdate_updateWarehouse_warehouse { + __typename: "Warehouse"; + id: string; + name: string; + shippingZones: WarehouseUpdate_updateWarehouse_warehouse_shippingZones; + address: WarehouseUpdate_updateWarehouse_warehouse_address; +} + +export interface WarehouseUpdate_updateWarehouse { + __typename: "WarehouseUpdate"; + errors: WarehouseUpdate_updateWarehouse_errors[] | null; + warehouse: WarehouseUpdate_updateWarehouse_warehouse | null; +} + +export interface WarehouseUpdate { + updateWarehouse: WarehouseUpdate_updateWarehouse | null; +} + +export interface WarehouseUpdateVariables { + id: string; + input: WarehouseUpdateInput; +} diff --git a/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx b/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx new file mode 100644 index 000000000..792ee6715 --- /dev/null +++ b/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx @@ -0,0 +1,84 @@ +import React from "react"; +import { useIntl } from "react-intl"; + +import WarehouseDetailsPage from "@saleor/warehouses/components/WarehouseDetailsPage"; +import useNavigator from "@saleor/hooks/useNavigator"; +import { + warehouseListUrl, + WarehouseUrlQueryParams +} from "@saleor/warehouses/urls"; +import { useWarehouseDetails } from "@saleor/warehouses/queries"; +import { commonMessages } from "@saleor/intl"; +import useNotifier from "@saleor/hooks/useNotifier"; +import { maybe, findValueInEnum, getMutationStatus } from "@saleor/misc"; +import { CountryCode } from "@saleor/types/globalTypes"; +import useShop from "@saleor/hooks/useShop"; +import { WindowTitle } from "@saleor/components/WindowTitle"; +import { useWarehouseUpdate } from "@saleor/warehouses/mutations"; +import { shippingZoneUrl } from "@saleor/shipping/urls"; + +export interface WarehouseDetailsProps { + id: string; + params: WarehouseUrlQueryParams; +} + +const WarehouseDetails: React.FC = ({ id, params }) => { + const intl = useIntl(); + const navigate = useNavigator(); + const notify = useNotifier(); + const shop = useShop(); + const { data, loading } = useWarehouseDetails({ + displayLoader: true, + require: ["warehouse"], + variables: { id } + }); + const [updateWarehouse, updateWarehouseOpts] = useWarehouseUpdate({ + onCompleted: data => { + if (data.updateWarehouse.errors.length === 0) { + notify({ text: intl.formatMessage(commonMessages.savedChanges) }); + } + } + }); + const updateWarehouseTransitionState = getMutationStatus(updateWarehouseOpts); + + return ( + <> + data.warehouse.name)} /> + navigate(warehouseListUrl())} + disabled={loading || updateWarehouseOpts.loading} + errors={maybe( + () => updateWarehouseOpts.data.updateWarehouse.errors, + [] + )} + saveButtonBarState={updateWarehouseTransitionState} + shop={shop} + warehouse={maybe(() => data.warehouse)} + onShippingZoneClick={id => navigate(shippingZoneUrl(id))} + onSubmit={data => + updateWarehouse({ + variables: { + id, + input: { + address: { + city: data.city, + cityArea: data.cityArea, + country: findValueInEnum(data.country, CountryCode), + countryArea: data.countryArea, + phone: data.phone, + postalCode: data.postalCode, + streetAddress1: data.streetAddress1, + streetAddress2: data.streetAddress2 + }, + name: data.name + } + } + }) + } + /> + + ); +}; + +WarehouseDetails.displayName = "WarehouseDetails"; +export default WarehouseDetails; diff --git a/src/warehouses/views/WarehouseDetails/index.ts b/src/warehouses/views/WarehouseDetails/index.ts new file mode 100644 index 000000000..a8e1f03bc --- /dev/null +++ b/src/warehouses/views/WarehouseDetails/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WarehouseDetails"; +export * from "./WarehouseDetails"; From e5274afa6420c86295c8db3b57e45f557bd5f554 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 16:43:55 +0100 Subject: [PATCH 08/88] Add warehouse deleting --- .../WarehouseDetailsPage.tsx | 3 ++ .../WarehouseDetails/WarehouseDetails.tsx | 40 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx index 1d6b02689..97e09ee5c 100644 --- a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx @@ -34,6 +34,7 @@ export interface WarehouseDetailsPageProps { shop: ShopInfo_shop; warehouse: WarehouseDetails_warehouse; onBack: () => void; + onDelete: () => void; onShippingZoneClick: (id: string) => void; onSubmit: (data: WarehouseDetailsPageFormData) => void; } @@ -45,6 +46,7 @@ const WarehouseDetailsPage: React.FC = ({ shop, warehouse, onBack, + onDelete, onShippingZoneClick, onSubmit }) => { @@ -127,6 +129,7 @@ const WarehouseDetailsPage: React.FC = ({ diff --git a/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx b/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx index 792ee6715..a59481e35 100644 --- a/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx +++ b/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx @@ -5,7 +5,8 @@ import WarehouseDetailsPage from "@saleor/warehouses/components/WarehouseDetails import useNavigator from "@saleor/hooks/useNavigator"; import { warehouseListUrl, - WarehouseUrlQueryParams + WarehouseUrlQueryParams, + warehouseUrl } from "@saleor/warehouses/urls"; import { useWarehouseDetails } from "@saleor/warehouses/queries"; import { commonMessages } from "@saleor/intl"; @@ -14,8 +15,13 @@ import { maybe, findValueInEnum, getMutationStatus } from "@saleor/misc"; import { CountryCode } from "@saleor/types/globalTypes"; import useShop from "@saleor/hooks/useShop"; import { WindowTitle } from "@saleor/components/WindowTitle"; -import { useWarehouseUpdate } from "@saleor/warehouses/mutations"; +import { + useWarehouseUpdate, + useWarehouseDelete +} from "@saleor/warehouses/mutations"; import { shippingZoneUrl } from "@saleor/shipping/urls"; +import WarehouseDeleteDialog from "@saleor/warehouses/components/WarehouseDeleteDialog"; +import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; export interface WarehouseDetailsProps { id: string; @@ -41,6 +47,24 @@ const WarehouseDetails: React.FC = ({ id, params }) => { }); const updateWarehouseTransitionState = getMutationStatus(updateWarehouseOpts); + const [deleteWarehouse, deleteWarehouseOpts] = useWarehouseDelete({ + onCompleted: data => { + if (data.deleteWarehouse.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + navigate(warehouseListUrl()); + } + } + }); + const deleteWarehouseTransitionState = getMutationStatus(deleteWarehouseOpts); + + const [openModal, closeModal] = createDialogActionHandlers( + navigate, + params => warehouseUrl(id, params), + params + ); + return ( <> data.warehouse.name)} /> @@ -54,6 +78,7 @@ const WarehouseDetails: React.FC = ({ id, params }) => { saveButtonBarState={updateWarehouseTransitionState} shop={shop} warehouse={maybe(() => data.warehouse)} + onDelete={() => openModal("delete")} onShippingZoneClick={id => navigate(shippingZoneUrl(id))} onSubmit={data => updateWarehouse({ @@ -76,6 +101,17 @@ const WarehouseDetails: React.FC = ({ id, params }) => { }) } /> + data.warehouse.name)} + onClose={closeModal} + onConfirm={() => + deleteWarehouse({ + variables: { id } + }) + } + open={params.action === "delete"} + /> ); }; From 34698b7d6fab453e12a7b06dca99389b198db6fd Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 30 Jan 2020 17:11:34 +0100 Subject: [PATCH 09/88] Fix rtypes --- .../CompanyAddressInput/CompanyAddressInput.tsx | 4 +++- .../WarehouseCreatePage.stories.tsx | 10 +++++++--- .../WarehouseCreatePage/WarehouseCreatePage.tsx | 11 ++++------- .../WarehouseDetailsPage.stories.tsx | 9 ++++++++- .../WarehouseDetailsPage/WarehouseDetailsPage.tsx | 10 ++++------ .../views/WarehouseCreate/WarehouseCreate.tsx | 6 +++--- .../views/WarehouseDetails/WarehouseDetails.tsx | 4 ++-- 7 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/components/CompanyAddressInput/CompanyAddressInput.tsx b/src/components/CompanyAddressInput/CompanyAddressInput.tsx index 927a12d25..bdd2374a4 100644 --- a/src/components/CompanyAddressInput/CompanyAddressInput.tsx +++ b/src/components/CompanyAddressInput/CompanyAddressInput.tsx @@ -161,7 +161,9 @@ const CompanyAddressInput: React.FC = props => { value={data.country} choices={countries} InputProps={{ - autoComplete: "off" + inputProps: { + autocomplete: "plsdontautocomplete" // Somehow it shuts it down + } }} /> ({ + __typename: "CountryDisplay", + code: c.code, + country: c.name + })), disabled: false, errors: [], onBack: () => undefined, onSubmit: () => undefined, - saveButtonBarState: "default", - shop + saveButtonBarState: "default" }; storiesOf("Views / Warehouses / Create warehouse", module) .addDecorator(Decorator) diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx index 64bde0713..ec50f6a61 100644 --- a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx @@ -14,8 +14,7 @@ import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/single import { mapCountriesToChoices } from "@saleor/utils/maps"; import useAddressValidation from "@saleor/hooks/useAddressValidation"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; -import { maybe } from "@saleor/misc"; -import { ShopInfo_shop } from "@saleor/components/Shop/types/ShopInfo"; +import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo"; import AppHeader from "@saleor/components/AppHeader"; import PageHeader from "@saleor/components/PageHeader"; import { sectionNames } from "@saleor/intl"; @@ -25,10 +24,10 @@ export interface WarehouseCreatePageFormData extends AddressTypeInput { name: string; } export interface WarehouseCreatePageProps { + countries: ShopInfo_shop_countries[]; disabled: boolean; errors: UserError[]; saveButtonBarState: ConfirmButtonTransitionState; - shop: ShopInfo_shop; onBack: () => void; onSubmit: (data: WarehouseCreatePageFormData) => void; } @@ -46,10 +45,10 @@ const initialForm: WarehouseCreatePageFormData = { }; const WarehouseCreatePage: React.FC = ({ + countries, disabled, errors: apiErrors, saveButtonBarState, - shop, onBack, onSubmit }) => { @@ -68,9 +67,7 @@ const WarehouseCreatePage: React.FC = ({ onSubmit={handleSubmit} > {({ change, data, errors, submit }) => { - const countryChoices = mapCountriesToChoices( - maybe(() => shop.countries, []) - ); + const countryChoices = mapCountriesToChoices(countries); const handleCountryChange = createSingleAutocompleteSelectHandler( change, setDisplayCountry, diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx index e42d88ad7..5a3dd646b 100644 --- a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx @@ -1,7 +1,7 @@ import { storiesOf } from "@storybook/react"; import React from "react"; -import { address } from "@saleor/fixtures"; +import { address, countries } from "@saleor/fixtures"; import Decorator from "@saleor/storybook/Decorator"; import { formError } from "@saleor/storybook/misc"; import { warehouseList } from "../../fixtures"; @@ -11,9 +11,16 @@ import WarehouseDetailsPage, { } from "./WarehouseDetailsPage"; const props: WarehouseDetailsPageProps = { + countries: countries.map(c => ({ + __typename: "CountryDisplay", + code: c.code, + country: c.name + })), disabled: false, errors: [], onBack: () => undefined, + onDelete: () => undefined, + onShippingZoneClick: () => undefined, onSubmit: () => undefined, saveButtonBarState: "default", warehouse: { diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx index 97e09ee5c..148dda244 100644 --- a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx @@ -15,7 +15,7 @@ import { mapCountriesToChoices } from "@saleor/utils/maps"; import useAddressValidation from "@saleor/hooks/useAddressValidation"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { maybe, findValueInEnum } from "@saleor/misc"; -import { ShopInfo_shop } from "@saleor/components/Shop/types/ShopInfo"; +import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo"; import AppHeader from "@saleor/components/AppHeader"; import PageHeader from "@saleor/components/PageHeader"; import { sectionNames } from "@saleor/intl"; @@ -28,10 +28,10 @@ export interface WarehouseDetailsPageFormData extends AddressTypeInput { name: string; } export interface WarehouseDetailsPageProps { + countries: ShopInfo_shop_countries[]; disabled: boolean; errors: UserError[]; saveButtonBarState: ConfirmButtonTransitionState; - shop: ShopInfo_shop; warehouse: WarehouseDetails_warehouse; onBack: () => void; onDelete: () => void; @@ -40,10 +40,10 @@ export interface WarehouseDetailsPageProps { } const WarehouseDetailsPage: React.FC = ({ + countries, disabled, errors: apiErrors, saveButtonBarState, - shop, warehouse, onBack, onDelete, @@ -79,9 +79,7 @@ const WarehouseDetailsPage: React.FC = ({ onSubmit={handleSubmit} > {({ change, data, errors, submit }) => { - const countryChoices = mapCountriesToChoices( - maybe(() => shop.countries, []) - ); + const countryChoices = mapCountriesToChoices(countries); const handleCountryChange = createSingleAutocompleteSelectHandler( change, setDisplayCountry, diff --git a/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx b/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx index 758592db0..4698713ce 100644 --- a/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx +++ b/src/warehouses/views/WarehouseCreate/WarehouseCreate.tsx @@ -36,13 +36,14 @@ const WarehouseCreate: React.FC = () => { })} /> navigate(warehouseListUrl())} + countries={maybe(() => shop.countries, [])} disabled={createWarehouseOpts.loading} errors={maybe( () => createWarehouseOpts.data.createWarehouse.errors, [] )} - shop={shop} + saveButtonBarState={createWarehouseTransitionState} + onBack={() => navigate(warehouseListUrl())} onSubmit={data => createWarehouse({ variables: { @@ -62,7 +63,6 @@ const WarehouseCreate: React.FC = () => { } }) } - saveButtonBarState={createWarehouseTransitionState} /> ); diff --git a/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx b/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx index a59481e35..5cd0ec2f4 100644 --- a/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx +++ b/src/warehouses/views/WarehouseDetails/WarehouseDetails.tsx @@ -69,15 +69,15 @@ const WarehouseDetails: React.FC = ({ id, params }) => { <> data.warehouse.name)} /> navigate(warehouseListUrl())} + countries={maybe(() => shop.countries, [])} disabled={loading || updateWarehouseOpts.loading} errors={maybe( () => updateWarehouseOpts.data.updateWarehouse.errors, [] )} saveButtonBarState={updateWarehouseTransitionState} - shop={shop} warehouse={maybe(() => data.warehouse)} + onBack={() => navigate(warehouseListUrl())} onDelete={() => openModal("delete")} onShippingZoneClick={id => navigate(shippingZoneUrl(id))} onSubmit={data => From ed3e9fbc45d83f3abca3ba45fc6da219ea8d13e6 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 3 Feb 2020 12:01:18 +0100 Subject: [PATCH 10/88] wip --- src/searches/types/SearchWarehouses.ts | 42 ++++ src/searches/useWarehouseSearch.ts | 33 +++ .../ShippingZoneDetailsPage.tsx | 198 +++++++++++------- .../ShippingZoneWarehouses.tsx | 60 ++++++ .../ShippingZoneWarehouses/index.ts | 2 + src/shipping/queries.ts | 4 + src/shipping/types/CreateShippingRate.ts | 7 + src/shipping/types/DeleteShippingRate.ts | 7 + src/shipping/types/ShippingZone.ts | 7 + .../types/ShippingZoneDetailsFragment.ts | 7 + .../views/ShippingZoneDetails/index.tsx | 29 ++- 11 files changed, 316 insertions(+), 80 deletions(-) create mode 100644 src/searches/types/SearchWarehouses.ts create mode 100644 src/searches/useWarehouseSearch.ts create mode 100644 src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx create mode 100644 src/shipping/components/ShippingZoneWarehouses/index.ts diff --git a/src/searches/types/SearchWarehouses.ts b/src/searches/types/SearchWarehouses.ts new file mode 100644 index 000000000..beab7185b --- /dev/null +++ b/src/searches/types/SearchWarehouses.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: SearchWarehouses +// ==================================================== + +export interface SearchWarehouses_search_edges_node { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface SearchWarehouses_search_edges { + __typename: "WarehouseCountableEdge"; + node: SearchWarehouses_search_edges_node; +} + +export interface SearchWarehouses_search_pageInfo { + __typename: "PageInfo"; + endCursor: string | null; + hasNextPage: boolean; + hasPreviousPage: boolean; + startCursor: string | null; +} + +export interface SearchWarehouses_search { + __typename: "WarehouseCountableConnection"; + edges: SearchWarehouses_search_edges[]; + pageInfo: SearchWarehouses_search_pageInfo; +} + +export interface SearchWarehouses { + search: SearchWarehouses_search | null; +} + +export interface SearchWarehousesVariables { + after?: string | null; + first: number; + query: string; +} diff --git a/src/searches/useWarehouseSearch.ts b/src/searches/useWarehouseSearch.ts new file mode 100644 index 000000000..b5b0e6048 --- /dev/null +++ b/src/searches/useWarehouseSearch.ts @@ -0,0 +1,33 @@ +import gql from "graphql-tag"; + +import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; +import { pageInfoFragment } from "@saleor/queries"; +import { + SearchWarehouses, + SearchWarehousesVariables +} from "./types/SearchWarehouses"; + +export const searchWarehouses = gql` + ${pageInfoFragment} + query SearchWarehouses($after: String, $first: Int!, $query: String!) { + search: warehouses( + after: $after + first: $first + filter: { search: $query } + ) { + edges { + node { + id + name + } + } + pageInfo { + ...PageInfoFragment + } + } + } +`; + +export default makeTopLevelSearch( + searchWarehouses +); diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index fa48d8624..f08002d62 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -11,14 +11,21 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; +import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; +import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import { maybe, getStringOrPlaceholder } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; -import { ShippingZoneDetailsFragment } from "../../types/ShippingZoneDetailsFragment"; +import { + ShippingZoneDetailsFragment, + ShippingZoneDetailsFragment_warehouses +} from "../../types/ShippingZoneDetailsFragment"; import ShippingZoneInfo from "../ShippingZoneInfo"; import ShippingZoneRates from "../ShippingZoneRates"; +import ShippingZoneWarehouses from "../ShippingZoneWarehouses"; export interface FormData { name: string; + warehouses: string[]; } export interface ShippingZoneDetailsPageProps { @@ -26,6 +33,7 @@ export interface ShippingZoneDetailsPageProps { errors: ShippingErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; shippingZone: ShippingZoneDetailsFragment; + warehouses: ShippingZoneDetailsFragment_warehouses[]; onBack: () => void; onCountryAdd: () => void; onCountryRemove: (code: string) => void; @@ -38,6 +46,15 @@ export interface ShippingZoneDetailsPageProps { onWeightRateEdit: (id: string) => void; } +function warehouseToChoice( + warehouse: Record<"id" | "name", string> +): MultiAutocompleteChoiceType { + return { + label: warehouse.name, + value: warehouse.id + }; +} + const ShippingZoneDetailsPage: React.FC = ({ disabled, errors, @@ -52,90 +69,117 @@ const ShippingZoneDetailsPage: React.FC = ({ onWeightRateAdd, onWeightRateEdit, saveButtonBarState, - shippingZone + shippingZone, + warehouses }) => { const intl = useIntl(); const initialForm: FormData = { - name: shippingZone?.name || "" + name: shippingZone?.name || "", + warehouses: shippingZone?.warehouses.map(warehouse => warehouse.id) || [] }; + const [warehouseDisplayValues, setWarehouseDisplayValues] = React.useState( + shippingZone?.warehouses.map(warehouseToChoice) + ); + + const warehouseChoices = warehouses.map(warehouseToChoice); return (
- {({ change, data, hasChanged, submit }) => ( - - - - - - -
- - - - shippingZone.default - ? intl.formatMessage({ - defaultMessage: - "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" - }) - : intl.formatMessage({ - defaultMessage: - "Currently, there are no countries assigned to this shipping zone" - }), - "..." - )} - onCountryAssign={onCountryAdd} - onCountryUnassign={onCountryRemove} - title={intl.formatMessage({ - defaultMessage: "Countries" - })} - /> - - - shippingZone.shippingMethods.filter( - method => method.type === ShippingMethodTypeEnum.PRICE - ) - )} - variant="price" - /> - - - shippingZone.shippingMethods.filter( - method => method.type === ShippingMethodTypeEnum.WEIGHT - ) - )} - variant="weight" - /> -
-
- -
- )} + {({ change, data, hasChanged, submit }) => { + const handleWarehouseChange = createMultiAutocompleteSelectHandler( + change, + setWarehouseDisplayValues, + warehouseDisplayValues, + warehouseChoices + ); + + return ( + + + + + + +
+ + + + shippingZone.default + ? intl.formatMessage({ + defaultMessage: + "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" + }) + : intl.formatMessage({ + defaultMessage: + "Currently, there are no countries assigned to this shipping zone" + }), + "..." + )} + onCountryAssign={onCountryAdd} + onCountryUnassign={onCountryRemove} + title={intl.formatMessage({ + defaultMessage: "Countries" + })} + /> + + + shippingZone.shippingMethods.filter( + method => method.type === ShippingMethodTypeEnum.PRICE + ) + )} + variant="price" + /> + + + shippingZone.shippingMethods.filter( + method => method.type === ShippingMethodTypeEnum.WEIGHT + ) + )} + variant="weight" + /> +
+
+ undefined} + warehouses={warehouseChoices} + /> +
+
+ +
+ ); + }}
); }; diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx new file mode 100644 index 000000000..6e1eeffcb --- /dev/null +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -0,0 +1,60 @@ +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import React from "react"; +import { useIntl } from "react-intl"; + +import CardTitle from "@saleor/components/CardTitle"; +import { FetchMoreProps } from "@saleor/types"; +import { FormChange } from "@saleor/hooks/useForm"; +import MultiAutocompleteSelectField, { + MultiAutocompleteChoiceType +} from "@saleor/components/MultiAutocompleteSelectField"; + +interface ShippingZoneWarehousesFormData { + warehouses: string[]; +} +interface ShippingZonewWarehousesProps extends FetchMoreProps { + data: ShippingZoneWarehousesFormData; + displayValue: MultiAutocompleteChoiceType[]; + warehouses: MultiAutocompleteChoiceType[]; + onChange: FormChange; +} + +export const ShippingZoneWarehouses: React.FC = props => { + const { + data, + displayValue, + hasMore, + loading, + onChange, + onFetchMore, + warehouses + } = props; + const intl = useIntl(); + + return ( + + + + undefined} + hasMore={hasMore} + loading={loading} + name="warehouse" + onChange={onChange} + onFetchMore={onFetchMore} + value={data.warehouses} + /> + + + ); +}; +ShippingZoneWarehouses.displayName = "ShippingZoneWarehouses"; +export default ShippingZoneWarehouses; diff --git a/src/shipping/components/ShippingZoneWarehouses/index.ts b/src/shipping/components/ShippingZoneWarehouses/index.ts new file mode 100644 index 000000000..9719aa5e7 --- /dev/null +++ b/src/shipping/components/ShippingZoneWarehouses/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ShippingZoneWarehouses"; +export * from "./ShippingZoneWarehouses"; diff --git a/src/shipping/queries.ts b/src/shipping/queries.ts index 9a4a1b4e9..8215a50bb 100644 --- a/src/shipping/queries.ts +++ b/src/shipping/queries.ts @@ -50,6 +50,10 @@ export const shippingZoneDetailsFragment = gql` shippingMethods { ...ShippingMethodFragment } + warehouses { + id + name + } } `; diff --git a/src/shipping/types/CreateShippingRate.ts b/src/shipping/types/CreateShippingRate.ts index c0d3a1e4a..7a29f3395 100644 --- a/src/shipping/types/CreateShippingRate.ts +++ b/src/shipping/types/CreateShippingRate.ts @@ -62,6 +62,12 @@ export interface CreateShippingRate_shippingPriceCreate_shippingZone_shippingMet type: ShippingMethodTypeEnum | null; } +export interface CreateShippingRate_shippingPriceCreate_shippingZone_warehouses { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface CreateShippingRate_shippingPriceCreate_shippingZone { __typename: "ShippingZone"; id: string; @@ -69,6 +75,7 @@ export interface CreateShippingRate_shippingPriceCreate_shippingZone { name: string; default: boolean; shippingMethods: (CreateShippingRate_shippingPriceCreate_shippingZone_shippingMethods | null)[] | null; + warehouses: (CreateShippingRate_shippingPriceCreate_shippingZone_warehouses | null)[] | null; } export interface CreateShippingRate_shippingPriceCreate { diff --git a/src/shipping/types/DeleteShippingRate.ts b/src/shipping/types/DeleteShippingRate.ts index b4ffa0352..d3fafa9b6 100644 --- a/src/shipping/types/DeleteShippingRate.ts +++ b/src/shipping/types/DeleteShippingRate.ts @@ -62,6 +62,12 @@ export interface DeleteShippingRate_shippingPriceDelete_shippingZone_shippingMet type: ShippingMethodTypeEnum | null; } +export interface DeleteShippingRate_shippingPriceDelete_shippingZone_warehouses { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface DeleteShippingRate_shippingPriceDelete_shippingZone { __typename: "ShippingZone"; id: string; @@ -69,6 +75,7 @@ export interface DeleteShippingRate_shippingPriceDelete_shippingZone { name: string; default: boolean; shippingMethods: (DeleteShippingRate_shippingPriceDelete_shippingZone_shippingMethods | null)[] | null; + warehouses: (DeleteShippingRate_shippingPriceDelete_shippingZone_warehouses | null)[] | null; } export interface DeleteShippingRate_shippingPriceDelete { diff --git a/src/shipping/types/ShippingZone.ts b/src/shipping/types/ShippingZone.ts index 7b8dc090b..091776cd3 100644 --- a/src/shipping/types/ShippingZone.ts +++ b/src/shipping/types/ShippingZone.ts @@ -56,6 +56,12 @@ export interface ShippingZone_shippingZone_shippingMethods { type: ShippingMethodTypeEnum | null; } +export interface ShippingZone_shippingZone_warehouses { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ShippingZone_shippingZone { __typename: "ShippingZone"; id: string; @@ -63,6 +69,7 @@ export interface ShippingZone_shippingZone { name: string; default: boolean; shippingMethods: (ShippingZone_shippingZone_shippingMethods | null)[] | null; + warehouses: (ShippingZone_shippingZone_warehouses | null)[] | null; } export interface ShippingZone { diff --git a/src/shipping/types/ShippingZoneDetailsFragment.ts b/src/shipping/types/ShippingZoneDetailsFragment.ts index 981e085a9..13bf1a398 100644 --- a/src/shipping/types/ShippingZoneDetailsFragment.ts +++ b/src/shipping/types/ShippingZoneDetailsFragment.ts @@ -56,6 +56,12 @@ export interface ShippingZoneDetailsFragment_shippingMethods { type: ShippingMethodTypeEnum | null; } +export interface ShippingZoneDetailsFragment_warehouses { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ShippingZoneDetailsFragment { __typename: "ShippingZone"; id: string; @@ -63,4 +69,5 @@ export interface ShippingZoneDetailsFragment { name: string; default: boolean; shippingMethods: (ShippingZoneDetailsFragment_shippingMethods | null)[] | null; + warehouses: (ShippingZoneDetailsFragment_warehouses | null)[] | null; } diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index bf03ddef6..ec889f9bc 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -4,6 +4,9 @@ import { useIntl } from "react-intl"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import useWarehouseSearch from "@saleor/searches/useWarehouseSearch"; +import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; +import { useWarehouseUpdate } from "@saleor/warehouses/mutations"; import { maybe } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import ShippingZoneDetailsPage from "../../components/ShippingZoneDetailsPage"; @@ -33,6 +36,14 @@ const ShippingZoneDetails: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); + const [updateWarehouse, updateWarehouseOpts] = useWarehouseUpdate({}); + + const { + search: searchWarehouses, + result: searchWarehousesOpts + } = useWarehouseSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA + }); const closeModal = () => navigate(shippingZoneUrl(id), true); @@ -146,14 +157,19 @@ const ShippingZoneDetails: React.FC = ({ }) ) } - onSubmit={formData => + onSubmit={formData => { ops.shippingZoneUpdate.mutate({ id, input: { name: formData.name } - }) - } + }); + updateWarehouse({ + variables: { + id: formData.warehouse + } + }); + }} onWeightRateAdd={() => navigate( shippingZoneUrl(id, { @@ -172,6 +188,13 @@ const ShippingZoneDetails: React.FC = ({ } saveButtonBarState={ops.shippingZoneUpdate.opts.status} shippingZone={maybe(() => data.shippingZone)} + warehouses={maybe( + () => + searchWarehousesOpts.data.search.edges.map( + edge => edge.node + ), + [] + )} /> Date: Wed, 5 Feb 2020 15:11:37 +0100 Subject: [PATCH 11/88] Use apollo hooks --- .../ShippingZoneDetailsPage.tsx | 2 +- src/shipping/mutations.ts | 70 ++- src/shipping/queries.ts | 8 +- .../types/AssignShippingZoneToWarehouse.ts | 29 ++ .../types/UnassignShippingZoneToWarehouse.ts | 29 ++ .../ShippingZoneDetailsDialogs.tsx | 244 --------- .../views/ShippingZoneDetails/data.ts | 62 +++ .../views/ShippingZoneDetails/index.tsx | 488 +++++++++++------- src/types/globalTypes.ts | 18 +- 9 files changed, 503 insertions(+), 447 deletions(-) create mode 100644 src/shipping/types/AssignShippingZoneToWarehouse.ts create mode 100644 src/shipping/types/UnassignShippingZoneToWarehouse.ts delete mode 100644 src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx create mode 100644 src/shipping/views/ShippingZoneDetails/data.ts diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index f08002d62..afaa9a798 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -13,7 +13,7 @@ import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; -import { maybe, getStringOrPlaceholder } from "../../../misc"; +import { maybe } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import { ShippingZoneDetailsFragment, diff --git a/src/shipping/mutations.ts b/src/shipping/mutations.ts index ab550e936..6408f1a3d 100644 --- a/src/shipping/mutations.ts +++ b/src/shipping/mutations.ts @@ -1,6 +1,6 @@ import gql from "graphql-tag"; -import { TypedMutation } from "../mutations"; +import makeMutation from "@saleor/hooks/makeMutation"; import { countryFragment } from "../taxes/queries"; import { shippingMethodFragment, shippingZoneDetailsFragment } from "./queries"; import { @@ -39,6 +39,14 @@ import { UpdateShippingZone, UpdateShippingZoneVariables } from "./types/UpdateShippingZone"; +import { + AssignShippingZoneToWarehouse, + AssignShippingZoneToWarehouseVariables +} from "./types/AssignShippingZoneToWarehouse"; +import { + UnassignShippingZoneToWarehouse, + UnassignShippingZoneToWarehouseVariables +} from "./types/UnassignShippingZoneToWarehouse"; export const shippingErrorFragment = gql` fragment ShippingErrorFragment on ShippingError { @@ -57,7 +65,7 @@ const deleteShippingZone = gql` } } `; -export const TypedDeleteShippingZone = TypedMutation< +export const useShippingZoneDelete = makeMutation< DeleteShippingZone, DeleteShippingZoneVariables >(deleteShippingZone); @@ -72,7 +80,7 @@ const bulkDeleteShippingZone = gql` } } `; -export const TypedBulkDeleteShippingZone = TypedMutation< +export const useShippingZoneBulkDelete = makeMutation< BulkDeleteShippingZone, BulkDeleteShippingZoneVariables >(bulkDeleteShippingZone); @@ -90,7 +98,7 @@ const updateDefaultWeightUnit = gql` } } `; -export const TypedUpdateDefaultWeightUnit = TypedMutation< +export const useDefaultWeightUnitUpdate = makeMutation< UpdateDefaultWeightUnit, UpdateDefaultWeightUnitVariables >(updateDefaultWeightUnit); @@ -114,7 +122,7 @@ const createShippingZone = gql` } } `; -export const TypedCreateShippingZone = TypedMutation< +export const useShippingZoneCreate = makeMutation< CreateShippingZone, CreateShippingZoneVariables >(createShippingZone); @@ -138,7 +146,7 @@ const updateShippingZone = gql` } } `; -export const TypedUpdateShippingZone = TypedMutation< +export const useShippingZoneUpdate = makeMutation< UpdateShippingZone, UpdateShippingZoneVariables >(updateShippingZone); @@ -157,7 +165,7 @@ const updateShippingRate = gql` } } `; -export const TypedUpdateShippingRate = TypedMutation< +export const useShippingRateUpdate = makeMutation< UpdateShippingRate, UpdateShippingRateVariables >(updateShippingRate); @@ -176,7 +184,7 @@ const createShippingRate = gql` } } `; -export const TypedCreateShippingRate = TypedMutation< +export const useShippingRateCreate = makeMutation< CreateShippingRate, CreateShippingRateVariables >(createShippingRate); @@ -195,7 +203,7 @@ const deleteShippingRate = gql` } } `; -export const TypedDeleteShippingRate = TypedMutation< +export const useShippingRateDelete = makeMutation< DeleteShippingRate, DeleteShippingRateVariables >(deleteShippingRate); @@ -210,7 +218,49 @@ const bulkDeleteShippingRate = gql` } } `; -export const TypedBulkDeleteShippingRate = TypedMutation< +export const useShippingRateBulkDelete = makeMutation< BulkDeleteShippingRate, BulkDeleteShippingRateVariables >(bulkDeleteShippingRate); + +const assignShippingZoneToWarehouse = gql` + mutation AssignShippingZoneToWarehouse( + $warehouseId: ID! + $shippingZoneId: ID! + ) { + assignWarehouseShippingZone( + id: $warehouseId + shippingZoneIds: [$shippingZoneId] + ) { + warehouseErrors { + code + field + } + } + } +`; +export const useAassignShippingZoneToWarehouse = makeMutation< + AssignShippingZoneToWarehouse, + AssignShippingZoneToWarehouseVariables +>(assignShippingZoneToWarehouse); + +const unassignShippingZoneToWarehouse = gql` + mutation UnassignShippingZoneToWarehouse( + $warehouseId: ID! + $shippingZoneId: ID! + ) { + unassignWarehouseShippingZone( + id: $warehouseId + shippingZoneIds: [$shippingZoneId] + ) { + warehouseErrors { + code + field + } + } + } +`; +export const useUnassignShippingZoneToWarehouse = makeMutation< + UnassignShippingZoneToWarehouse, + UnassignShippingZoneToWarehouseVariables +>(unassignShippingZoneToWarehouse); diff --git a/src/shipping/queries.ts b/src/shipping/queries.ts index 8215a50bb..9779655e2 100644 --- a/src/shipping/queries.ts +++ b/src/shipping/queries.ts @@ -1,5 +1,6 @@ import gql from "graphql-tag"; +import makeQuery from "@saleor/hooks/makeQuery"; import { pageInfoFragment, TypedQuery } from "../queries"; import { ShippingZone, ShippingZoneVariables } from "./types/ShippingZone"; import { ShippingZones, ShippingZonesVariables } from "./types/ShippingZones"; @@ -91,7 +92,6 @@ const shippingZone = gql` } } `; -export const TypedShippingZone = TypedQuery< - ShippingZone, - ShippingZoneVariables ->(shippingZone); +export const useShippingZone = makeQuery( + shippingZone +); diff --git a/src/shipping/types/AssignShippingZoneToWarehouse.ts b/src/shipping/types/AssignShippingZoneToWarehouse.ts new file mode 100644 index 000000000..378d365c7 --- /dev/null +++ b/src/shipping/types/AssignShippingZoneToWarehouse.ts @@ -0,0 +1,29 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { WarehouseErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL mutation operation: AssignShippingZoneToWarehouse +// ==================================================== + +export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors { + __typename: "WarehouseError"; + code: WarehouseErrorCode | null; + field: string | null; +} + +export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone { + __typename: "WarehouseShippingZoneAssign"; + warehouseErrors: AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors[] | null; +} + +export interface AssignShippingZoneToWarehouse { + assignWarehouseShippingZone: AssignShippingZoneToWarehouse_assignWarehouseShippingZone | null; +} + +export interface AssignShippingZoneToWarehouseVariables { + warehouseId: string; + shippingZoneId: string; +} diff --git a/src/shipping/types/UnassignShippingZoneToWarehouse.ts b/src/shipping/types/UnassignShippingZoneToWarehouse.ts new file mode 100644 index 000000000..a8f8e1721 --- /dev/null +++ b/src/shipping/types/UnassignShippingZoneToWarehouse.ts @@ -0,0 +1,29 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { WarehouseErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL mutation operation: UnassignShippingZoneToWarehouse +// ==================================================== + +export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors { + __typename: "WarehouseError"; + code: WarehouseErrorCode | null; + field: string | null; +} + +export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone { + __typename: "WarehouseShippingZoneUnassign"; + warehouseErrors: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors[] | null; +} + +export interface UnassignShippingZoneToWarehouse { + unassignWarehouseShippingZone: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone | null; +} + +export interface UnassignShippingZoneToWarehouseVariables { + warehouseId: string; + shippingZoneId: string; +} diff --git a/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx b/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx deleted file mode 100644 index 36f346b39..000000000 --- a/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx +++ /dev/null @@ -1,244 +0,0 @@ -import DialogContentText from "@material-ui/core/DialogContentText"; -import React from "react"; -import { FormattedMessage, useIntl } from "react-intl"; - -import ActionDialog from "@saleor/components/ActionDialog"; -import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import useNavigator from "@saleor/hooks/useNavigator"; -import useShop from "@saleor/hooks/useShop"; -import { getStringOrPlaceholder } from "../../../misc"; -import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; -import ShippingZoneCountriesAssignDialog from "../../components/ShippingZoneCountriesAssignDialog"; -import ShippingZoneRateDialog from "../../components/ShippingZoneRateDialog"; -import { ShippingZoneDetailsFragment } from "../../types/ShippingZoneDetailsFragment"; -import { shippingZoneUrl, ShippingZoneUrlQueryParams } from "../../urls"; -import { ShippingZoneOperationsOutput } from "./ShippingZoneOperations"; - -export interface ShippingZoneDetailsDialogsProps { - assignCountryTransitionState: ConfirmButtonTransitionState; - createRateTransitionState: ConfirmButtonTransitionState; - deleteRateTransitionState: ConfirmButtonTransitionState; - deleteZoneTransitionState: ConfirmButtonTransitionState; - id: string; - ops: ShippingZoneOperationsOutput; - params: ShippingZoneUrlQueryParams; - shippingZone: ShippingZoneDetailsFragment; - unassignCountryTransitionState: ConfirmButtonTransitionState; - updateRateTransitionState: ConfirmButtonTransitionState; -} - -const ShippingZoneDetailsDialogs: React.FC = ({ - assignCountryTransitionState, - createRateTransitionState, - deleteRateTransitionState, - deleteZoneTransitionState, - id, - ops, - params, - shippingZone, - unassignCountryTransitionState, - updateRateTransitionState -}) => { - const navigate = useNavigator(); - const shop = useShop(); - const intl = useIntl(); - - const closeModal = () => navigate(shippingZoneUrl(id), true); - - const rate = shippingZone?.shippingMethods?.find( - rate => rate.id === params.id - ); - - return ( - <> - - ops.shippingRateUpdate.mutate({ - id: params.id, - input: { - maximumOrderPrice: formData.noLimits - ? null - : parseFloat(formData.maxValue), - minimumOrderPrice: formData.noLimits - ? null - : parseFloat(formData.minValue), - name: formData.name, - price: formData.isFree ? 0 : parseFloat(formData.price), - shippingZone: id, - type: rate?.type - } - }) - } - open={params.action === "edit-rate"} - rate={rate} - variant={rate?.type} - /> - - ops.shippingRateDelete.mutate({ - id: params.id - }) - } - open={params.action === "remove-rate"} - title={intl.formatMessage({ - defaultMessage: "Delete Shipping Method", - description: "dialog header" - })} - variant="delete" - > - - - - - - ops.shippingRateCreate.mutate({ - input: { - maximumOrderPrice: - params.type === ShippingMethodTypeEnum.PRICE - ? formData.noLimits - ? null - : parseFloat(formData.maxValue) - : null, - maximumOrderWeight: - params.type === ShippingMethodTypeEnum.WEIGHT - ? formData.noLimits - ? null - : parseFloat(formData.maxValue) - : null, - - minimumOrderPrice: - params.type === ShippingMethodTypeEnum.PRICE - ? formData.noLimits - ? null - : parseFloat(formData.minValue) - : null, - minimumOrderWeight: - params.type === ShippingMethodTypeEnum.WEIGHT - ? formData.noLimits - ? null - : parseFloat(formData.minValue) - : null, - name: formData.name, - price: formData.isFree ? 0 : parseFloat(formData.price), - shippingZone: id, - type: params.type - } - }) - } - open={params.action === "add-rate"} - rate={undefined} - variant={params.type} - /> - - ops.shippingZoneDelete.mutate({ - id - }) - } - open={params.action === "remove"} - title={intl.formatMessage({ - defaultMessage: "Delete Shipping Zone", - description: "dialog header" - })} - variant="delete" - > - - {getStringOrPlaceholder(shippingZone?.name)} - ) - }} - /> - - - country.code) || []} - isDefault={!!shippingZone?.default} - onClose={closeModal} - onConfirm={formData => - ops.shippingZoneUpdate.mutate({ - id, - input: { - countries: formData.countries, - default: formData.restOfTheWorld - } - }) - } - open={params.action === "assign-country"} - /> - - ops.shippingZoneUpdate.mutate({ - id, - input: { - countries: shippingZone.countries - .filter(country => country.code !== params.id) - .map(country => country.code) - } - }) - } - open={params.action === "unassign-country"} - title={intl.formatMessage({ - defaultMessage: "Delete from Shipping Zone", - description: "unassign country, dialog header" - })} - variant="delete" - > - - - {getStringOrPlaceholder( - shippingZone?.countries.find( - country => country.code === params.id - )?.country - )} - - ) - }} - /> - - - - ); -}; -export default ShippingZoneDetailsDialogs; diff --git a/src/shipping/views/ShippingZoneDetails/data.ts b/src/shipping/views/ShippingZoneDetails/data.ts new file mode 100644 index 000000000..0aadca15c --- /dev/null +++ b/src/shipping/views/ShippingZoneDetails/data.ts @@ -0,0 +1,62 @@ +import { ShippingZoneUrlQueryParams } from "@saleor/shipping/urls"; +import { ShippingMethodTypeEnum } from "@saleor/types/globalTypes"; +import { UpdateShippingRateVariables } from "@saleor/shipping/types/UpdateShippingRate"; +import { CreateShippingRateVariables } from "@saleor/shipping/types/CreateShippingRate"; +import { FormData as ShippingZoneRateDialogFormData } from "../../components/ShippingZoneRateDialog"; + +export function getCreateShippingRateVariables( + data: ShippingZoneRateDialogFormData, + params: ShippingZoneUrlQueryParams, + id: string +): CreateShippingRateVariables { + return { + input: { + maximumOrderPrice: + params.type === ShippingMethodTypeEnum.PRICE + ? data.noLimits + ? null + : parseFloat(data.maxValue) + : null, + maximumOrderWeight: + params.type === ShippingMethodTypeEnum.WEIGHT + ? data.noLimits + ? null + : parseFloat(data.maxValue) + : null, + + minimumOrderPrice: + params.type === ShippingMethodTypeEnum.PRICE + ? data.noLimits + ? null + : parseFloat(data.minValue) + : null, + minimumOrderWeight: + params.type === ShippingMethodTypeEnum.WEIGHT + ? data.noLimits + ? null + : parseFloat(data.minValue) + : null, + name: data.name, + price: data.isFree ? 0 : parseFloat(data.price), + shippingZone: id, + type: params.type + } + }; +} + +export function getUpdateShippingRateVariables( + data: ShippingZoneRateDialogFormData, + params: ShippingZoneUrlQueryParams, + id: string +): UpdateShippingRateVariables { + return { + id: params.id, + input: { + maximumOrderPrice: data.noLimits ? null : parseFloat(data.maxValue), + minimumOrderPrice: data.noLimits ? null : parseFloat(data.minValue), + name: data.name, + price: data.isFree ? 0 : parseFloat(data.price), + shippingZone: id + } + }; +} diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index ec889f9bc..b5cb55b7d 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -1,28 +1,41 @@ +import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; -import { useIntl } from "react-intl"; +import { FormattedMessage, useIntl } from "react-intl"; +import ActionDialog from "@saleor/components/ActionDialog"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; import useWarehouseSearch from "@saleor/searches/useWarehouseSearch"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; -import { useWarehouseUpdate } from "@saleor/warehouses/mutations"; -import { maybe } from "../../../misc"; +import { + useShippingRateCreate, + useShippingRateUpdate, + useShippingRateDelete, + useShippingZoneDelete, + useShippingZoneUpdate +} from "@saleor/shipping/mutations"; +import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import ShippingZoneRateDialog from "@saleor/shipping/components/ShippingZoneRateDialog"; +import useShop from "@saleor/hooks/useShop"; +import ShippingZoneCountriesAssignDialog from "@saleor/shipping/components/ShippingZoneCountriesAssignDialog"; +import NotFoundPage from "@saleor/components/NotFoundPage"; +import { getStringOrPlaceholder } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; -import ShippingZoneDetailsPage from "../../components/ShippingZoneDetailsPage"; -import { TypedShippingZone } from "../../queries"; -import { CreateShippingRate } from "../../types/CreateShippingRate"; -import { DeleteShippingRate } from "../../types/DeleteShippingRate"; -import { DeleteShippingZone } from "../../types/DeleteShippingZone"; -import { UpdateShippingRate } from "../../types/UpdateShippingRate"; -import { UpdateShippingZone } from "../../types/UpdateShippingZone"; +import ShippingZoneDetailsPage, { + FormData +} from "../../components/ShippingZoneDetailsPage"; +import { useShippingZone } from "../../queries"; import { shippingZonesListUrl, shippingZoneUrl, - ShippingZoneUrlQueryParams + ShippingZoneUrlQueryParams, + ShippingZoneUrlDialog } from "../../urls"; -import ShippingZoneDetailsDialogs from "./ShippingZoneDetailsDialogs"; -import ShippingZoneOperations from "./ShippingZoneOperations"; +import { + getCreateShippingRateVariables, + getUpdateShippingRateVariables +} from "./data"; export interface ShippingZoneDetailsProps { id: string; @@ -36,187 +49,294 @@ const ShippingZoneDetails: React.FC = ({ const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); - const [updateWarehouse, updateWarehouseOpts] = useWarehouseUpdate({}); + const shop = useShop(); - const { - search: searchWarehouses, - result: searchWarehousesOpts - } = useWarehouseSearch({ + const { result: searchWarehousesOpts } = useWarehouseSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); - const closeModal = () => navigate(shippingZoneUrl(id), true); + const { data, loading } = useShippingZone({ + displayLoader: true, + variables: { id } + }); - const onShippingRateCreate = (data: CreateShippingRate) => { - if (data.shippingPriceCreate.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - closeModal(); + const [openModal, closeModal] = createDialogActionHandlers< + ShippingZoneUrlDialog, + ShippingZoneUrlQueryParams + >(navigate, params => shippingZoneUrl(id, params), params); + const rate = data?.shippingZone?.shippingMethods.find( + rate => rate.id === params.id + ); + + const [createShippingRate, createShippingRateOpts] = useShippingRateCreate({ + onCompleted: data => { + if (data.shippingPriceCreate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + } } + }); + + const [updateShippingRate, updateShippingRateOpts] = useShippingRateUpdate({ + onCompleted: data => { + if (data.shippingPriceUpdate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + } + } + }); + + const [deleteShippingRate, deleteShippingRateOpts] = useShippingRateDelete({ + onCompleted: data => { + if (data.shippingPriceDelete.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + } + } + }); + + const [deleteShippingZone, deleteShippingZoneOpts] = useShippingZoneDelete({ + onCompleted: data => { + if (data.shippingZoneDelete.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + navigate(shippingZonesListUrl(), true); + } + } + }); + + const [updateShippingZone, updateShippingZoneOpts] = useShippingZoneUpdate({ + onCompleted: data => { + if (data.shippingZoneUpdate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + } + } + }); + + const handleSubmit = (data: FormData) => { + updateShippingZone({ + variables: { + id, + input: { + name: data.name + } + } + }); }; - const onShippingRateUpdate = (data: UpdateShippingRate) => { - if (data.shippingPriceUpdate.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - closeModal(); - } - }; - - const onShippingRateDelete = (data: DeleteShippingRate) => { - if (data.shippingPriceDelete.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - closeModal(); - } - }; - - const onShippingZoneDelete = (data: DeleteShippingZone) => { - if (data.shippingZoneDelete.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - navigate(shippingZonesListUrl(), true); - } - }; - - const onShippingZoneUpdate = (data: UpdateShippingZone) => { - if (data.shippingZoneUpdate.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - closeModal(); - } - }; + if (data?.shippingZone === null) { + return navigate(shippingZonesListUrl())} />; + } return ( - - {ops => ( - - {({ data, loading }) => ( - <> - navigate(shippingZonesListUrl())} - onCountryAdd={() => - navigate( - shippingZoneUrl(id, { - action: "assign-country" - }) - ) - } - onCountryRemove={code => - navigate( - shippingZoneUrl(id, { - action: "unassign-country", - id: code - }) - ) - } - onDelete={() => - navigate( - shippingZoneUrl(id, { - action: "remove" - }) - ) - } - onPriceRateAdd={() => - navigate( - shippingZoneUrl(id, { - action: "add-rate", - type: ShippingMethodTypeEnum.PRICE - }) - ) - } - onPriceRateEdit={rateId => - navigate( - shippingZoneUrl(id, { - action: "edit-rate", - id: rateId - }) - ) - } - onRateRemove={rateId => - navigate( - shippingZoneUrl(id, { - action: "remove-rate", - id: rateId - }) - ) - } - onSubmit={formData => { - ops.shippingZoneUpdate.mutate({ - id, - input: { - name: formData.name - } - }); - updateWarehouse({ - variables: { - id: formData.warehouse - } - }); - }} - onWeightRateAdd={() => - navigate( - shippingZoneUrl(id, { - action: "add-rate", - type: ShippingMethodTypeEnum.WEIGHT - }) - ) - } - onWeightRateEdit={rateId => - navigate( - shippingZoneUrl(id, { - action: "edit-rate", - id: rateId - }) - ) - } - saveButtonBarState={ops.shippingZoneUpdate.opts.status} - shippingZone={maybe(() => data.shippingZone)} - warehouses={maybe( - () => - searchWarehousesOpts.data.search.edges.map( - edge => edge.node - ), - [] - )} - /> - - - )} - - )} - + <> + navigate(shippingZonesListUrl())} + onCountryAdd={() => openModal("assign-country")} + onCountryRemove={code => + openModal("unassign-country", { + id: code + }) + } + onDelete={() => openModal("remove")} + onPriceRateAdd={() => + openModal("add-rate", { + type: ShippingMethodTypeEnum.PRICE + }) + } + onPriceRateEdit={rateId => + openModal("edit-rate", { + id: rateId + }) + } + onRateRemove={rateId => + openModal("remove-rate", { + id: rateId + }) + } + onSubmit={handleSubmit} + onWeightRateAdd={() => + openModal("add-rate", { + type: ShippingMethodTypeEnum.WEIGHT + }) + } + onWeightRateEdit={rateId => + openModal("edit-rate", { + id: rateId + }) + } + saveButtonBarState={updateShippingZoneOpts.status} + shippingZone={data?.shippingZone} + warehouses={ + searchWarehousesOpts.data?.search.edges.map(edge => edge.node) || [] + } + /> + + updateShippingRate({ + variables: getUpdateShippingRateVariables(data, params, id) + }) + } + open={params.action === "edit-rate"} + rate={rate} + variant={rate?.type} + /> + + deleteShippingRate({ + variables: { + id: params.id + } + }) + } + open={params.action === "remove-rate"} + title={intl.formatMessage({ + defaultMessage: "Delete Shipping Method", + description: "dialog header" + })} + variant="delete" + > + + + + + + createShippingRate({ + variables: getCreateShippingRateVariables(data, params, id) + }) + } + open={params.action === "add-rate"} + rate={undefined} + variant={params.type} + /> + + deleteShippingZone({ + variables: { + id + } + }) + } + open={params.action === "remove"} + title={intl.formatMessage({ + defaultMessage: "Delete Shipping Zone", + description: "dialog header" + })} + variant="delete" + > + + + {getStringOrPlaceholder(data?.shippingZone.name)} + + ) + }} + /> + + + country.code) || [] + } + isDefault={data?.shippingZone?.default} + onClose={closeModal} + onConfirm={formData => + updateShippingZone({ + variables: { + id, + input: { + countries: formData.countries, + default: formData.restOfTheWorld + } + } + }) + } + open={params.action === "assign-country"} + /> + + updateShippingZone({ + variables: { + id, + input: { + countries: data.shippingZone.countries + .filter(country => country.code !== params.id) + .map(country => country.code) + } + } + }) + } + open={params.action === "unassign-country"} + title={intl.formatMessage({ + defaultMessage: "Delete from Shipping Zone", + description: "unassign country, dialog header" + })} + variant="delete" + > + + + {getStringOrPlaceholder( + data?.shippingZone?.countries.find( + country => country.code === params.id + )?.country + )} + + ) + }} + /> + + + ); }; export default ShippingZoneDetails; diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index e6066af22..4f0b0a325 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -746,6 +746,15 @@ export enum VoucherTypeEnum { SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT", } +export enum WarehouseErrorCode { + ALREADY_EXISTS = "ALREADY_EXISTS", + GRAPHQL_ERROR = "GRAPHQL_ERROR", + INVALID = "INVALID", + NOT_FOUND = "NOT_FOUND", + REQUIRED = "REQUIRED", + UNIQUE = "UNIQUE", +} + export enum WarehouseSortField { NAME = "NAME", } @@ -1431,11 +1440,12 @@ export interface WarehouseAddressInput { } export interface WarehouseCreateInput { - name: string; + slug?: string | null; companyName?: string | null; - shippingZones?: (string | null)[] | null; email?: string | null; + name: string; address: WarehouseAddressInput; + shippingZones?: (string | null)[] | null; } export interface WarehouseFilterInput { @@ -1448,10 +1458,10 @@ export interface WarehouseSortingInput { } export interface WarehouseUpdateInput { - name: string; + slug?: string | null; companyName?: string | null; - shippingZones?: (string | null)[] | null; email?: string | null; + name?: string | null; address?: WarehouseAddressInput | null; } From 8f021178654d766c5da07f8174ea655755a50947 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 6 Feb 2020 16:19:08 +0100 Subject: [PATCH 12/88] Add warehouse select --- .../ShippingZoneDetailsPage.tsx | 3 ++- .../ShippingZoneWarehouses/ShippingZoneWarehouses.tsx | 9 ++++++++- src/shipping/views/ShippingZoneDetails/index.tsx | 11 ++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index afaa9a798..0fab0ae87 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -13,6 +13,7 @@ import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; +import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { maybe } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import { @@ -78,7 +79,7 @@ const ShippingZoneDetailsPage: React.FC = ({ name: shippingZone?.name || "", warehouses: shippingZone?.warehouses.map(warehouse => warehouse.id) || [] }; - const [warehouseDisplayValues, setWarehouseDisplayValues] = React.useState( + const [warehouseDisplayValues, setWarehouseDisplayValues] = useStateFromProps( shippingZone?.warehouses.map(warehouseToChoice) ); diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx index 6e1eeffcb..0b0390667 100644 --- a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -36,7 +36,7 @@ export const ShippingZoneWarehouses: React.FC = pr @@ -46,10 +46,17 @@ export const ShippingZoneWarehouses: React.FC = pr displayValues={displayValue} fetchChoices={() => undefined} hasMore={hasMore} + label={intl.formatMessage({ + defaultMessage: "Warehouse" + })} loading={loading} name="warehouse" onChange={onChange} onFetchMore={onFetchMore} + placeholder={intl.formatMessage({ + defaultMessage: "Select Warehouse", + description: "input placeholder" + })} value={data.warehouses} /> diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index b5cb55b7d..451760a84 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -13,7 +13,8 @@ import { useShippingRateUpdate, useShippingRateDelete, useShippingZoneDelete, - useShippingZoneUpdate + useShippingZoneUpdate, + useAassignShippingZoneToWarehouse } from "@saleor/shipping/mutations"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import ShippingZoneRateDialog from "@saleor/shipping/components/ShippingZoneRateDialog"; @@ -55,6 +56,8 @@ const ShippingZoneDetails: React.FC = ({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const [assignToWarehouse] = useAassignShippingZoneToWarehouse({}); + const { data, loading } = useShippingZone({ displayLoader: true, variables: { id } @@ -132,6 +135,12 @@ const ShippingZoneDetails: React.FC = ({ } } }); + assignToWarehouse({ + variables: { + shippingZoneId: id, + warehouseId: data.warehouse + } + }); }; if (data?.shippingZone === null) { From 92d16effb309fc58688a52372b2951e5615791d5 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 6 Feb 2020 17:51:01 +0100 Subject: [PATCH 13/88] Add inventory status to variant list --- .../ProductVariants/ProductVariants.tsx | 76 ++++++++++--------- src/products/queries.ts | 8 ++ src/products/types/Product.ts | 7 ++ src/products/types/ProductCreate.ts | 7 ++ src/products/types/ProductDetails.ts | 7 ++ src/products/types/ProductImageCreate.ts | 7 ++ src/products/types/ProductImageUpdate.ts | 7 ++ src/products/types/ProductUpdate.ts | 7 ++ src/products/types/ProductVariant.ts | 7 ++ src/products/types/ProductVariantDetails.ts | 7 ++ src/products/types/SimpleProductUpdate.ts | 14 ++++ src/products/types/VariantCreate.ts | 7 ++ src/products/types/VariantImageAssign.ts | 7 ++ src/products/types/VariantImageUnassign.ts | 7 ++ src/products/types/VariantUpdate.ts | 7 ++ 15 files changed, 145 insertions(+), 37 deletions(-) diff --git a/src/products/components/ProductVariants/ProductVariants.tsx b/src/products/components/ProductVariants/ProductVariants.tsx index 6e46489a9..1146b9045 100644 --- a/src/products/components/ProductVariants/ProductVariants.tsx +++ b/src/products/components/ProductVariants/ProductVariants.tsx @@ -15,7 +15,6 @@ import Checkbox from "@saleor/components/Checkbox"; import Money from "@saleor/components/Money"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import Skeleton from "@saleor/components/Skeleton"; -import StatusLabel from "@saleor/components/StatusLabel"; import TableHead from "@saleor/components/TableHead"; import { maybe, renderCollection } from "../../../misc"; import { ListActions } from "../../../types"; @@ -25,17 +24,20 @@ import { ProductVariant_costPrice } from "../../types/ProductVariant"; const useStyles = makeStyles( theme => ({ [theme.breakpoints.up("lg")]: { + colInventory: { + width: 300 + }, colName: {}, colPrice: { - width: 200 + width: 150 }, colSku: { - width: 250 - }, - colStatus: { width: 200 } }, + colInventory: { + textAlign: "right" + }, colName: {}, colPrice: { textAlign: "right" @@ -148,12 +150,6 @@ export const ProductVariants: React.FC = props => { description="product variant name" /> - - - @@ -165,10 +161,20 @@ export const ProductVariants: React.FC = props => { /> + + + {renderCollection(variants, variant => { const isSelected = variant ? isChecked(variant.id) : false; + const numAvailable = + variant && variant.stock + ? variant.stock.reduce((acc, s) => acc + s.quantity, 0) + : null; return ( = props => { {variant ? variant.name || variant.sku : } - variant.stockQuantity > 0 - )} - > - {variant ? ( - 0 ? "success" : "error"} - label={ - variant.stockQuantity > 0 - ? intl.formatMessage({ - defaultMessage: "Available", - description: "product variant status" - }) - : intl.formatMessage({ - defaultMessage: "Unavailable", - description: "product variant status" - }) - } - /> - ) : ( - - )} - {variant ? variant.sku : } @@ -233,6 +213,28 @@ export const ProductVariants: React.FC = props => { )} + + {numAvailable === null ? ( + + ) : numAvailable === 0 ? ( + + ) : ( + + )} + ); })} diff --git a/src/products/queries.ts b/src/products/queries.ts index dbed486ce..5e5f58977 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -146,6 +146,10 @@ export const productFragmentDetails = gql` quantity quantityAllocated stockQuantity + stock { + id + quantity + } } productType { id @@ -212,6 +216,10 @@ export const fragmentVariant = gql` sku quantity quantityAllocated + stock { + id + quantity + } } `; diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index 1b7426fc4..e0cafa652 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -127,6 +127,12 @@ export interface Product_variants_priceOverride { currency: string; } +export interface Product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface Product_variants { __typename: "ProductVariant"; id: string; @@ -137,6 +143,7 @@ export interface Product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (Product_variants_stock | null)[] | null; } export interface Product_productType { diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index c265fd69f..b1409b4d8 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -133,6 +133,12 @@ export interface ProductCreate_productCreate_product_variants_priceOverride { currency: string; } +export interface ProductCreate_productCreate_product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductCreate_productCreate_product_variants { __typename: "ProductVariant"; id: string; @@ -143,6 +149,7 @@ export interface ProductCreate_productCreate_product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (ProductCreate_productCreate_product_variants_stock | null)[] | null; } export interface ProductCreate_productCreate_product_productType { diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index 2ebf1cfcc..78013430e 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -127,6 +127,12 @@ export interface ProductDetails_product_variants_priceOverride { currency: string; } +export interface ProductDetails_product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductDetails_product_variants { __typename: "ProductVariant"; id: string; @@ -137,6 +143,7 @@ export interface ProductDetails_product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (ProductDetails_product_variants_stock | null)[] | null; } export interface ProductDetails_product_productType_variantAttributes_values { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index c481ea341..45f62c860 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -133,6 +133,12 @@ export interface ProductImageCreate_productImageCreate_product_variants_priceOve currency: string; } +export interface ProductImageCreate_productImageCreate_product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductImageCreate_productImageCreate_product_variants { __typename: "ProductVariant"; id: string; @@ -143,6 +149,7 @@ export interface ProductImageCreate_productImageCreate_product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (ProductImageCreate_productImageCreate_product_variants_stock | null)[] | null; } export interface ProductImageCreate_productImageCreate_product_productType { diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 23687fe07..0be498717 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -133,6 +133,12 @@ export interface ProductImageUpdate_productImageUpdate_product_variants_priceOve currency: string; } +export interface ProductImageUpdate_productImageUpdate_product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductImageUpdate_productImageUpdate_product_variants { __typename: "ProductVariant"; id: string; @@ -143,6 +149,7 @@ export interface ProductImageUpdate_productImageUpdate_product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (ProductImageUpdate_productImageUpdate_product_variants_stock | null)[] | null; } export interface ProductImageUpdate_productImageUpdate_product_productType { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 20c745df8..7fce89379 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -133,6 +133,12 @@ export interface ProductUpdate_productUpdate_product_variants_priceOverride { currency: string; } +export interface ProductUpdate_productUpdate_product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductUpdate_productUpdate_product_variants { __typename: "ProductVariant"; id: string; @@ -143,6 +149,7 @@ export interface ProductUpdate_productUpdate_product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (ProductUpdate_productUpdate_product_variants_stock | null)[] | null; } export interface ProductUpdate_productUpdate_product_productType { diff --git a/src/products/types/ProductVariant.ts b/src/products/types/ProductVariant.ts index 2d8091000..14f5aa54f 100644 --- a/src/products/types/ProductVariant.ts +++ b/src/products/types/ProductVariant.ts @@ -89,6 +89,12 @@ export interface ProductVariant_product { variants: (ProductVariant_product_variants | null)[] | null; } +export interface ProductVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductVariant { __typename: "ProductVariant"; id: string; @@ -101,4 +107,5 @@ export interface ProductVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (ProductVariant_stock | null)[] | null; } diff --git a/src/products/types/ProductVariantDetails.ts b/src/products/types/ProductVariantDetails.ts index 0f948a9cc..e4c98a234 100644 --- a/src/products/types/ProductVariantDetails.ts +++ b/src/products/types/ProductVariantDetails.ts @@ -89,6 +89,12 @@ export interface ProductVariantDetails_productVariant_product { variants: (ProductVariantDetails_productVariant_product_variants | null)[] | null; } +export interface ProductVariantDetails_productVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface ProductVariantDetails_productVariant { __typename: "ProductVariant"; id: string; @@ -101,6 +107,7 @@ export interface ProductVariantDetails_productVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (ProductVariantDetails_productVariant_stock | null)[] | null; } export interface ProductVariantDetails { diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index 51c33a7e3..c49bd09a6 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -133,6 +133,12 @@ export interface SimpleProductUpdate_productUpdate_product_variants_priceOverrid currency: string; } +export interface SimpleProductUpdate_productUpdate_product_variants_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface SimpleProductUpdate_productUpdate_product_variants { __typename: "ProductVariant"; id: string; @@ -143,6 +149,7 @@ export interface SimpleProductUpdate_productUpdate_product_variants { quantity: number; quantityAllocated: number | null; stockQuantity: number; + stock: (SimpleProductUpdate_productUpdate_product_variants_stock | null)[] | null; } export interface SimpleProductUpdate_productUpdate_product_productType { @@ -271,6 +278,12 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant_product variants: (SimpleProductUpdate_productVariantUpdate_productVariant_product_variants | null)[] | null; } +export interface SimpleProductUpdate_productVariantUpdate_productVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface SimpleProductUpdate_productVariantUpdate_productVariant { __typename: "ProductVariant"; id: string; @@ -283,6 +296,7 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (SimpleProductUpdate_productVariantUpdate_productVariant_stock | null)[] | null; } export interface SimpleProductUpdate_productVariantUpdate { diff --git a/src/products/types/VariantCreate.ts b/src/products/types/VariantCreate.ts index da6dd3939..ae04aee61 100644 --- a/src/products/types/VariantCreate.ts +++ b/src/products/types/VariantCreate.ts @@ -97,6 +97,12 @@ export interface VariantCreate_productVariantCreate_productVariant_product { variants: (VariantCreate_productVariantCreate_productVariant_product_variants | null)[] | null; } +export interface VariantCreate_productVariantCreate_productVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface VariantCreate_productVariantCreate_productVariant { __typename: "ProductVariant"; id: string; @@ -109,6 +115,7 @@ export interface VariantCreate_productVariantCreate_productVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (VariantCreate_productVariantCreate_productVariant_stock | null)[] | null; } export interface VariantCreate_productVariantCreate { diff --git a/src/products/types/VariantImageAssign.ts b/src/products/types/VariantImageAssign.ts index 5a5c8ad0a..da34c19e2 100644 --- a/src/products/types/VariantImageAssign.ts +++ b/src/products/types/VariantImageAssign.ts @@ -97,6 +97,12 @@ export interface VariantImageAssign_variantImageAssign_productVariant_product { variants: (VariantImageAssign_variantImageAssign_productVariant_product_variants | null)[] | null; } +export interface VariantImageAssign_variantImageAssign_productVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface VariantImageAssign_variantImageAssign_productVariant { __typename: "ProductVariant"; id: string; @@ -109,6 +115,7 @@ export interface VariantImageAssign_variantImageAssign_productVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (VariantImageAssign_variantImageAssign_productVariant_stock | null)[] | null; } export interface VariantImageAssign_variantImageAssign { diff --git a/src/products/types/VariantImageUnassign.ts b/src/products/types/VariantImageUnassign.ts index 4978ee18b..46a910dd3 100644 --- a/src/products/types/VariantImageUnassign.ts +++ b/src/products/types/VariantImageUnassign.ts @@ -97,6 +97,12 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant_produc variants: (VariantImageUnassign_variantImageUnassign_productVariant_product_variants | null)[] | null; } +export interface VariantImageUnassign_variantImageUnassign_productVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface VariantImageUnassign_variantImageUnassign_productVariant { __typename: "ProductVariant"; id: string; @@ -109,6 +115,7 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (VariantImageUnassign_variantImageUnassign_productVariant_stock | null)[] | null; } export interface VariantImageUnassign_variantImageUnassign { diff --git a/src/products/types/VariantUpdate.ts b/src/products/types/VariantUpdate.ts index 0028a0887..e2e98e600 100644 --- a/src/products/types/VariantUpdate.ts +++ b/src/products/types/VariantUpdate.ts @@ -97,6 +97,12 @@ export interface VariantUpdate_productVariantUpdate_productVariant_product { variants: (VariantUpdate_productVariantUpdate_productVariant_product_variants | null)[] | null; } +export interface VariantUpdate_productVariantUpdate_productVariant_stock { + __typename: "Stock"; + id: string; + quantity: number; +} + export interface VariantUpdate_productVariantUpdate_productVariant { __typename: "ProductVariant"; id: string; @@ -109,6 +115,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant { sku: string; quantity: number; quantityAllocated: number | null; + stock: (VariantUpdate_productVariantUpdate_productVariant_stock | null)[] | null; } export interface VariantUpdate_productVariantUpdate { From ccc51b1243fc5eada169ec2e0c1a27ef52ac9df2 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 7 Feb 2020 17:12:01 +0100 Subject: [PATCH 14/88] Add link with choices component --- .../LinkChoice/LinkChoice.stories.tsx | 26 +++ src/components/LinkChoice/LinkChoice.tsx | 157 ++++++++++++++++++ src/components/LinkChoice/index.ts | 2 + 3 files changed, 185 insertions(+) create mode 100644 src/components/LinkChoice/LinkChoice.stories.tsx create mode 100644 src/components/LinkChoice/LinkChoice.tsx create mode 100644 src/components/LinkChoice/index.ts diff --git a/src/components/LinkChoice/LinkChoice.stories.tsx b/src/components/LinkChoice/LinkChoice.stories.tsx new file mode 100644 index 000000000..0b7f17610 --- /dev/null +++ b/src/components/LinkChoice/LinkChoice.stories.tsx @@ -0,0 +1,26 @@ +import { storiesOf } from "@storybook/react"; +import React from "react"; + +import { countries } from "@saleor/fixtures"; +import CardDecorator from "@saleor/storybook/CardDecorator"; +import Decorator from "@saleor/storybook/Decorator"; +import Form from "../Form"; +import LinkChoice, { LinkChoiceProps } from "./LinkChoice"; + +const suggestions = countries.map(c => ({ label: c.name, value: c.code })); + +const props: Omit = { + choices: suggestions.slice(0, 10), + name: "country" +}; + +storiesOf("Generics / Link with choices", module) + .addDecorator(CardDecorator) + .addDecorator(Decorator) + .add("default", () => ( +
+ {({ change, data }) => ( + + )} + + )); diff --git a/src/components/LinkChoice/LinkChoice.tsx b/src/components/LinkChoice/LinkChoice.tsx new file mode 100644 index 000000000..9cfe19663 --- /dev/null +++ b/src/components/LinkChoice/LinkChoice.tsx @@ -0,0 +1,157 @@ +import React from "react"; +import ClickAwayListener from "@material-ui/core/ClickAwayListener"; +import Paper from "@material-ui/core/Paper"; +import MenuItem from "@material-ui/core/MenuItem"; +import makeStyles from "@material-ui/core/styles/makeStyles"; +import Popper from "@material-ui/core/Popper"; +import { fade } from "@material-ui/core/styles/colorManipulator"; +import classNames from "classnames"; +import { codes } from "keycode"; + +import ArrowDropdown from "@saleor/icons/ArrowDropdown"; +import { FormChange } from "@saleor/hooks/useForm"; +import { SingleAutocompleteChoiceType } from "../SingleAutocompleteSelectField"; +import Link from "../Link"; + +const useStyles = makeStyles( + theme => ({ + arrow: { + position: "relative", + top: 6, + transition: theme.transitions.duration.short + "ms" + }, + highlighted: { + background: theme.palette.background.default + }, + menuItem: { + "&:not(:last-of-type)": { + marginBottom: theme.spacing() + } + }, + paper: { + padding: theme.spacing() + }, + popper: { + boxShadow: `0px 5px 10px 0 ${fade(theme.palette.common.black, 0.05)}`, + marginTop: theme.spacing(1), + zIndex: 2 + }, + root: { + "&:focus": { + textDecoration: "underline" + }, + outline: 0, + position: "relative" + }, + rotate: { + transform: "rotate(180deg)" + } + }), + { + name: "LinkChoice" + } +); + +export interface LinkChoiceProps { + choices: SingleAutocompleteChoiceType[]; + name: "country"; + value: string; + onChange: FormChange; +} + +const LinkChoice: React.FC = ({ + choices, + name, + value, + onChange +}) => { + const classes = useStyles({}); + const [open, setOpen] = React.useState(false); + const anchor = React.useRef(null); + const current = choices.find(c => c.value === value); + const [highlightedIndex, setHighlightedIndex] = React.useState(0); + + const handleChange = (value: string) => { + setOpen(false); + onChange({ + target: { + name, + value + } + }); + }; + + const handleKeyPress = (event: React.KeyboardEvent) => { + switch (event.keyCode) { + case codes.down: + setHighlightedIndex( + highlightedIndex => (highlightedIndex + 1) % choices.length + ); + break; + case codes.up: + setHighlightedIndex(highlightedIndex => + highlightedIndex === 0 + ? choices.length - 1 + : (highlightedIndex - 1) % choices.length + ); + break; + case codes.enter: + if (open) { + handleChange(choices[highlightedIndex].value); + } else { + setOpen(true); + } + break; + } + }; + + return ( + + setOpen(open => !open)}>{current.label} + + + + setOpen(false)} + mouseEvent="onClick" + > + + {choices.map((choice, choiceIndex) => ( + handleChange(choice.value)} + data-tc="select-option" + > + {choice.label} + + ))} + + + + + ); +}; + +LinkChoice.displayName = "LinkChoice"; +export default LinkChoice; diff --git a/src/components/LinkChoice/index.ts b/src/components/LinkChoice/index.ts new file mode 100644 index 000000000..9c927a90f --- /dev/null +++ b/src/components/LinkChoice/index.ts @@ -0,0 +1,2 @@ +export { default } from "./LinkChoice"; +export * from "./LinkChoice"; From ee36d6046c7c88b32980f31593f20b87a51dd72e Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 7 Feb 2020 17:44:42 +0100 Subject: [PATCH 15/88] Add variant stock filtering by warehouse --- src/components/LinkChoice/LinkChoice.tsx | 6 +- .../ProductVariants/ProductVariants.tsx | 117 +++++++++++++++--- src/products/queries.ts | 4 + src/products/types/Product.ts | 7 ++ src/products/types/ProductCreate.ts | 7 ++ src/products/types/ProductDetails.ts | 7 ++ src/products/types/ProductImageCreate.ts | 7 ++ src/products/types/ProductImageUpdate.ts | 7 ++ src/products/types/ProductUpdate.ts | 7 ++ src/products/types/SimpleProductUpdate.ts | 7 ++ 10 files changed, 160 insertions(+), 16 deletions(-) diff --git a/src/components/LinkChoice/LinkChoice.tsx b/src/components/LinkChoice/LinkChoice.tsx index 9cfe19663..8916ea2fa 100644 --- a/src/components/LinkChoice/LinkChoice.tsx +++ b/src/components/LinkChoice/LinkChoice.tsx @@ -53,13 +53,15 @@ const useStyles = makeStyles( ); export interface LinkChoiceProps { + className?: string; choices: SingleAutocompleteChoiceType[]; - name: "country"; + name?: string; value: string; onChange: FormChange; } const LinkChoice: React.FC = ({ + className, choices, name, value, @@ -107,7 +109,7 @@ const LinkChoice: React.FC = ({ return ( ( + (warehouses, variant) => [ + ...warehouses, + ...variant.stock.reduce< + ProductDetails_product_variants_stock_warehouse[] + >((variantStocks, stock) => { + if (!!warehouses.find(w => w.id === stock.warehouse.id)) { + return variantStocks; + } + + return [...variantStocks, stock.warehouse]; + }, []) + ], + [] + ) + .map(w => ({ + label: w.name, + value: w.id + })) + ]; +} + const useStyles = makeStyles( theme => ({ [theme.breakpoints.up("lg")]: { @@ -57,6 +97,13 @@ const useStyles = makeStyles( }, textRight: { textAlign: "right" as "right" + }, + warehouseLabel: { + display: "inline-block", + marginRight: theme.spacing() + }, + warehouseSelectContainer: { + paddingTop: theme.spacing(2) } }), { name: "ProductVariants" } @@ -90,6 +137,7 @@ export const ProductVariants: React.FC = props => { const classes = useStyles(props); const intl = useIntl(); + const [warehouse, setWarehouse] = React.useState(null); const hasVariants = maybe(() => variants.length > 0, true); return ( @@ -127,7 +175,23 @@ export const ProductVariants: React.FC = props => { ) } /> - {!variants.length && ( + + {variants.length > 0 ? ( + + + + + setWarehouse(event.target.value)} + /> + + ) : ( @@ -146,7 +210,7 @@ export const ProductVariants: React.FC = props => { > @@ -175,6 +239,9 @@ export const ProductVariants: React.FC = props => { variant && variant.stock ? variant.stock.reduce((acc, s) => acc + s.quantity, 0) : null; + const variantStock = variant.stock.find( + s => s.warehouse.id === warehouse + ); return ( = props => { > {numAvailable === null ? ( - ) : numAvailable === 0 ? ( - + ) : warehouse === null ? ( + numAvailable === 0 ? ( + + ) : ( + + ) + ) : !!variantStock ? ( + variantStock.quantity > 0 ? ( + + ) : ( + + ) ) : ( )} diff --git a/src/products/queries.ts b/src/products/queries.ts index 5e5f58977..1e292428b 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -149,6 +149,10 @@ export const productFragmentDetails = gql` stock { id quantity + warehouse { + id + name + } } } productType { diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index e0cafa652..0dfd6a748 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -127,10 +127,17 @@ export interface Product_variants_priceOverride { currency: string; } +export interface Product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface Product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: Product_variants_stock_warehouse; } export interface Product_variants { diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index b1409b4d8..e22239d5a 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -133,10 +133,17 @@ export interface ProductCreate_productCreate_product_variants_priceOverride { currency: string; } +export interface ProductCreate_productCreate_product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ProductCreate_productCreate_product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductCreate_productCreate_product_variants_stock_warehouse; } export interface ProductCreate_productCreate_product_variants { diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index 78013430e..a880cdccc 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -127,10 +127,17 @@ export interface ProductDetails_product_variants_priceOverride { currency: string; } +export interface ProductDetails_product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ProductDetails_product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductDetails_product_variants_stock_warehouse; } export interface ProductDetails_product_variants { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index 45f62c860..8efec0618 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -133,10 +133,17 @@ export interface ProductImageCreate_productImageCreate_product_variants_priceOve currency: string; } +export interface ProductImageCreate_productImageCreate_product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ProductImageCreate_productImageCreate_product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductImageCreate_productImageCreate_product_variants_stock_warehouse; } export interface ProductImageCreate_productImageCreate_product_variants { diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 0be498717..c98fe2909 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -133,10 +133,17 @@ export interface ProductImageUpdate_productImageUpdate_product_variants_priceOve currency: string; } +export interface ProductImageUpdate_productImageUpdate_product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ProductImageUpdate_productImageUpdate_product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductImageUpdate_productImageUpdate_product_variants_stock_warehouse; } export interface ProductImageUpdate_productImageUpdate_product_variants { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 7fce89379..3fab87f99 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -133,10 +133,17 @@ export interface ProductUpdate_productUpdate_product_variants_priceOverride { currency: string; } +export interface ProductUpdate_productUpdate_product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface ProductUpdate_productUpdate_product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductUpdate_productUpdate_product_variants_stock_warehouse; } export interface ProductUpdate_productUpdate_product_variants { diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index c49bd09a6..c7ffb7b9f 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -133,10 +133,17 @@ export interface SimpleProductUpdate_productUpdate_product_variants_priceOverrid currency: string; } +export interface SimpleProductUpdate_productUpdate_product_variants_stock_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface SimpleProductUpdate_productUpdate_product_variants_stock { __typename: "Stock"; id: string; quantity: number; + warehouse: SimpleProductUpdate_productUpdate_product_variants_stock_warehouse; } export interface SimpleProductUpdate_productUpdate_product_variants { From 12c5e406465699db8662e3ca21aec127727cf265 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 7 Feb 2020 17:50:32 +0100 Subject: [PATCH 16/88] Fix dropdown position --- src/products/components/ProductVariants/ProductVariants.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/products/components/ProductVariants/ProductVariants.tsx b/src/products/components/ProductVariants/ProductVariants.tsx index a266ec46a..fe6b79765 100644 --- a/src/products/components/ProductVariants/ProductVariants.tsx +++ b/src/products/components/ProductVariants/ProductVariants.tsx @@ -92,6 +92,9 @@ const useStyles = makeStyles( link: { cursor: "pointer" }, + select: { + display: "inline-block" + }, textLeft: { textAlign: "left" as "left" }, @@ -185,6 +188,7 @@ export const ProductVariants: React.FC = props => { /> Date: Mon, 10 Feb 2020 13:50:08 +0100 Subject: [PATCH 17/88] Simplify code --- src/shipping/queries.ts | 4 +- src/shipping/views/ShippingZonesList.tsx | 383 +++++++++++------------ 2 files changed, 178 insertions(+), 209 deletions(-) diff --git a/src/shipping/queries.ts b/src/shipping/queries.ts index 9779655e2..771a32b3f 100644 --- a/src/shipping/queries.ts +++ b/src/shipping/queries.ts @@ -1,7 +1,7 @@ import gql from "graphql-tag"; import makeQuery from "@saleor/hooks/makeQuery"; -import { pageInfoFragment, TypedQuery } from "../queries"; +import { pageInfoFragment } from "../queries"; import { ShippingZone, ShippingZoneVariables } from "./types/ShippingZone"; import { ShippingZones, ShippingZonesVariables } from "./types/ShippingZones"; @@ -79,7 +79,7 @@ const shippingZones = gql` } } `; -export const TypedShippingZones = TypedQuery< +export const useShippingZoneList = makeQuery< ShippingZones, ShippingZonesVariables >(shippingZones); diff --git a/src/shipping/views/ShippingZonesList.tsx b/src/shipping/views/ShippingZonesList.tsx index 488e629ae..dd2ab2241 100644 --- a/src/shipping/views/ShippingZonesList.tsx +++ b/src/shipping/views/ShippingZonesList.tsx @@ -16,23 +16,22 @@ import usePaginator, { import useShop from "@saleor/hooks/useShop"; import useUser from "@saleor/hooks/useUser"; import { commonMessages } from "@saleor/intl"; -import { maybe } from "@saleor/misc"; +import { maybe, getStringOrPlaceholder } from "@saleor/misc"; import { ListViews } from "@saleor/types"; +import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import ShippingZonesListPage from "../components/ShippingZonesListPage"; import { - TypedBulkDeleteShippingZone, - TypedDeleteShippingZone, - TypedUpdateDefaultWeightUnit + useShippingZoneBulkDelete, + useShippingZoneDelete, + useDefaultWeightUnitUpdate } from "../mutations"; -import { TypedShippingZones } from "../queries"; -import { BulkDeleteShippingZone } from "../types/BulkDeleteShippingZone"; -import { DeleteShippingZone } from "../types/DeleteShippingZone"; -import { UpdateDefaultWeightUnit } from "../types/UpdateDefaultWeightUnit"; +import { useShippingZoneList } from "../queries"; import { shippingZoneAddUrl, shippingZonesListUrl, ShippingZonesListUrlQueryParams, - shippingZoneUrl + shippingZoneUrl, + ShippingZonesListUrlDialog } from "../urls"; interface ShippingZonesListProps { @@ -57,206 +56,176 @@ export const ShippingZonesList: React.FC = ({ const paginationState = createPaginationState(settings.rowNumber, params); + const [openModal, closeModal] = createDialogActionHandlers< + ShippingZonesListUrlDialog, + ShippingZonesListUrlQueryParams + >(navigate, shippingZonesListUrl, params); + + const { data, loading, refetch } = useShippingZoneList({ + displayLoader: true, + variables: paginationState + }); + + const [deleteShippingZone, deleteShippingZoneOpts] = useShippingZoneDelete({ + onCompleted: data => { + if (data.shippingZoneDelete.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + refetch(); + } + } + }); + + const [ + updateDefaultWeightUnit, + updateDefaultWeightUnitOpts + ] = useDefaultWeightUnitUpdate({ + onCompleted: data => { + if (data.shopSettingsUpdate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + } + } + }); + + const [ + bulkDeleteShippingZone, + bulkDeleteShippingZoneOpts + ] = useShippingZoneBulkDelete({ + onCompleted: data => { + if (data.shippingZoneBulkDelete.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + reset(); + refetch(); + } + } + }); + + const { loadNextPage, loadPreviousPage, pageInfo } = paginate( + maybe(() => data.shippingZones.pageInfo), + paginationState, + params + ); return ( - - {({ data, loading, refetch }) => { - const handleUpdateDefaultWeightUnit = ( - data: UpdateDefaultWeightUnit - ) => { - if (data.shopSettingsUpdate.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - } - }; + <> + shop.defaultWeightUnit)} + settings={settings} + disabled={ + loading || + deleteShippingZoneOpts.loading || + updateDefaultWeightUnitOpts.loading + } + shippingZones={maybe(() => + data.shippingZones.edges.map(edge => edge.node) + )} + pageInfo={pageInfo} + onAdd={() => navigate(shippingZoneAddUrl)} + onBack={() => navigate(configurationMenuUrl)} + onUpdateListSettings={updateListSettings} + onNextPage={loadNextPage} + onPreviousPage={loadPreviousPage} + onRemove={id => + openModal("remove", { + id + }) + } + onRowClick={id => () => navigate(shippingZoneUrl(id))} + onSubmit={unit => + updateDefaultWeightUnit({ + variables: { unit } + }) + } + isChecked={isSelected} + selected={listElements.length} + toggle={toggle} + toggleAll={toggleAll} + toolbar={ + + openModal("remove-many", { + ids: listElements + }) + } + > + + + } + userPermissions={user?.userPermissions || []} + /> - const closeModal = () => - navigate( - shippingZonesListUrl({ - ...params, - action: undefined, - ids: undefined - }), - true - ); - - const handleShippingZoneDelete = (data: DeleteShippingZone) => { - if (data.shippingZoneDelete.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - closeModal(); - refetch(); - } - }; - - const handleBulkDeleteShippingZone = (data: BulkDeleteShippingZone) => { - if (data.shippingZoneBulkDelete.errors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - closeModal(); - reset(); - refetch(); - } - }; - return ( - - {(deleteShippingZone, deleteShippingZoneOpts) => ( - - {(updateDefaultWeightUnit, updateDefaultWeightUnitOpts) => ( - - {(bulkDeleteShippingZone, bulkDeleteShippingZoneOpts) => { - const { - loadNextPage, - loadPreviousPage, - pageInfo - } = paginate( - maybe(() => data.shippingZones.pageInfo), - paginationState, - params - ); - - return ( - <> - shop.defaultWeightUnit - )} - settings={settings} - disabled={ - loading || - deleteShippingZoneOpts.loading || - updateDefaultWeightUnitOpts.loading - } - shippingZones={maybe(() => - data.shippingZones.edges.map(edge => edge.node) - )} - pageInfo={pageInfo} - onAdd={() => navigate(shippingZoneAddUrl)} - onBack={() => navigate(configurationMenuUrl)} - onUpdateListSettings={updateListSettings} - onNextPage={loadNextPage} - onPreviousPage={loadPreviousPage} - onRemove={id => - navigate( - shippingZonesListUrl({ - ...params, - action: "remove", - id - }) - ) - } - onRowClick={id => () => - navigate(shippingZoneUrl(id))} - onSubmit={unit => - updateDefaultWeightUnit({ - variables: { unit } - }) - } - isChecked={isSelected} - selected={listElements.length} - toggle={toggle} - toggleAll={toggleAll} - toolbar={ - - navigate( - shippingZonesListUrl({ - action: "remove-many", - ids: listElements - }) - ) - } - > - - - } - userPermissions={user?.userPermissions || []} - /> - - - deleteShippingZone({ - variables: { id: params.id } - }) - } - > - - - {maybe( - () => - data.shippingZones.edges.find( - edge => edge.node.id === params.id - ).node.name, - "..." - )} - - ) - }} - /> - - - - bulkDeleteShippingZone({ - variables: { ids: params.ids } - }) - } - > - - params.ids.length), - displayQuantity: ( - - {maybe(() => params.ids.length)} - - ) - }} - /> - - - - ); - }} - - )} - - )} - - ); - }} - + + deleteShippingZone({ + variables: { id: params.id } + }) + } + > + + + {maybe( + () => + data.shippingZones.edges.find( + edge => edge.node.id === params.id + ).node.name, + "..." + )} + + ) + }} + /> + + + + bulkDeleteShippingZone({ + variables: { ids: params.ids } + }) + } + > + + + {getStringOrPlaceholder(params.ids?.length.toString())} + + ) + }} + /> + + + ); }; ShippingZonesList.displayName = "ShippingZonesList"; From 60ec16961cae70e17fe75d5e9817ec0005a9b218 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 10 Feb 2020 17:07:17 +0100 Subject: [PATCH 18/88] Add warehouse create action button --- .../MultiAutocompleteSelectField.tsx | 11 ++++- .../MultiAutocompleteSelectFieldContent.tsx | 25 +++++++++++ .../SingleAutocompleteSelectField.stories.tsx | 10 +++++ .../SingleAutocompleteSelectField.tsx | 12 +++++- .../SingleAutocompleteSelectFieldContent.tsx | 41 ++++++++++++++++--- .../ShippingZoneDetailsPage.tsx | 5 ++- .../ShippingZoneWarehouses.tsx | 11 ++++- src/shipping/urls.ts | 1 + .../views/ShippingZoneDetails/index.tsx | 1 + 9 files changed, 108 insertions(+), 9 deletions(-) diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx index 31f07ccd6..27cb334c1 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx @@ -12,7 +12,8 @@ import Debounce, { DebounceProps } from "@saleor/components/Debounce"; import ArrowDropdownIcon from "@saleor/icons/ArrowDropdown"; import { FetchMoreProps } from "@saleor/types"; import MultiAutocompleteSelectFieldContent, { - MultiAutocompleteChoiceType + MultiAutocompleteChoiceType, + MultiAutocompleteActionType } from "./MultiAutocompleteSelectFieldContent"; const useStyles = makeStyles( @@ -71,6 +72,7 @@ const useStyles = makeStyles( export interface MultiAutocompleteSelectFieldProps extends Partial { + add: MultiAutocompleteActionType; allowCustomValues?: boolean; displayValues: MultiAutocompleteChoiceType[]; error?: boolean; @@ -166,6 +168,13 @@ const MultiAutocompleteSelectFieldComponent: React.FC {isOpen && (!!inputValue || !!choices.length) && ( { + add.onClick(); + closeMenu(); + } + }} choices={choices.filter( choice => !value.includes(choice.value) )} diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx index f58e680dd..d414b8f3f 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx @@ -7,6 +7,7 @@ import { FormattedMessage } from "react-intl"; import chevronDown from "@assets/images/ChevronDown.svg"; import CircularProgress from "@material-ui/core/CircularProgress"; import MenuItem from "@material-ui/core/MenuItem"; +import Typography from "@material-ui/core/Typography"; import Paper from "@material-ui/core/Paper"; import { makeStyles } from "@material-ui/core/styles"; import AddIcon from "@material-ui/icons/Add"; @@ -22,6 +23,10 @@ const menuItemHeight = 46; const maxMenuItems = 5; const offset = 24; +export interface MultiAutocompleteActionType { + label: string; + onClick: () => void; +} export interface MultiAutocompleteChoiceType { label: string; value: any; @@ -29,6 +34,7 @@ export interface MultiAutocompleteChoiceType { } export interface MultiAutocompleteSelectFieldContentProps extends Partial { + add: MultiAutocompleteActionType; choices: MultiAutocompleteChoiceType[]; displayCustomValue: boolean; displayValues: MultiAutocompleteChoiceType[]; @@ -145,6 +151,7 @@ function getChoiceIndex( const MultiAutocompleteSelectFieldContent: React.FC = props => { const { + add, choices, displayCustomValue, displayValues, @@ -156,6 +163,10 @@ const MultiAutocompleteSelectFieldContent: React.FC(); const scrollPosition = useElementScroll(anchor); @@ -183,6 +194,20 @@ const MultiAutocompleteSelectFieldContent: React.FC 0 || displayCustomValue ? ( <> + {add && ( + + + {add.label} + + )} {displayCustomValue && ( ( )) + .add("with add", () => ( + undefined + }} + /> + )) .add("can load more", () => ( )) diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx index 48b6e0692..4df5b02e6 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx @@ -10,7 +10,8 @@ import { FetchMoreProps } from "@saleor/types"; import ArrowDropdownIcon from "../../icons/ArrowDropdown"; import Debounce, { DebounceProps } from "../Debounce"; import SingleAutocompleteSelectFieldContent, { - SingleAutocompleteChoiceType + SingleAutocompleteChoiceType, + SingleAutocompleteActionType } from "./SingleAutocompleteSelectFieldContent"; const useStyles = makeStyles( @@ -25,6 +26,7 @@ const useStyles = makeStyles( export interface SingleAutocompleteSelectFieldProps extends Partial { + add: SingleAutocompleteActionType; error?: boolean; name: string; displayValue: string; @@ -47,6 +49,7 @@ const DebounceAutocomplete: React.ComponentType = props => { const { + add, allowCustomValues, choices, disabled, @@ -144,6 +147,13 @@ const SingleAutocompleteSelectFieldComponent: React.FC {isOpen && (!!inputValue || !!choices.length) && ( { + add.onClick(); + closeMenu(); + } + }} choices={choices} displayCustomValue={displayCustomValue} emptyOption={emptyOption} diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx index 602a24b47..4e19e204d 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx @@ -1,5 +1,6 @@ import CircularProgress from "@material-ui/core/CircularProgress"; import MenuItem from "@material-ui/core/MenuItem"; +import Add from "@material-ui/icons/Add"; import Paper from "@material-ui/core/Paper"; import { makeStyles } from "@material-ui/core/styles"; import Typography from "@material-ui/core/Typography"; @@ -24,8 +25,13 @@ export interface SingleAutocompleteChoiceType { label: string; value: any; } +export interface SingleAutocompleteActionType { + label: string; + onClick: () => void; +} export interface SingleAutocompleteSelectFieldContentProps extends Partial { + add: SingleAutocompleteActionType; choices: SingleAutocompleteChoiceType[]; displayCustomValue: boolean; emptyOption: boolean; @@ -38,6 +44,14 @@ export interface SingleAutocompleteSelectFieldContentProps const useStyles = makeStyles( theme => ({ + add: { + background: theme.palette.background.default, + border: `1px solid ${theme.palette.divider}`, + borderRadius: "100%", + height: 24, + marginRight: theme.spacing(), + width: 24 + }, arrowContainer: { position: "relative" }, @@ -109,10 +123,9 @@ function getChoiceIndex( return choiceIndex; } -const SingleAutocompleteSelectFieldContent: React.FC< - SingleAutocompleteSelectFieldContentProps -> = props => { +const SingleAutocompleteSelectFieldContent: React.FC = props => { const { + add, choices, displayCustomValue, emptyOption, @@ -125,6 +138,10 @@ const SingleAutocompleteSelectFieldContent: React.FC< onFetchMore } = props; + if (!!add && !!displayCustomValue) { + throw new Error("Add and custom value cannot be displayed simultaneously"); + } + const classes = useStyles(props); const anchor = React.useRef(); const scrollPosition = useElementScroll(anchor); @@ -164,6 +181,20 @@ const SingleAutocompleteSelectFieldContent: React.FC< )} + {add && ( + + + {add.label} + + )} {displayCustomValue && ( )} - {choices.length > 0 && displayCustomValue && ( + {choices.length > 0 && (!!add || displayCustomValue) && (
)} {choices.map((suggestion, index) => { const choiceIndex = getChoiceIndex( index, emptyOption, - displayCustomValue + !!add || displayCustomValue ); return ( diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index 0fab0ae87..19805372b 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -43,6 +43,7 @@ export interface ShippingZoneDetailsPageProps { onPriceRateEdit: (id: string) => void; onRateRemove: (rateId: string) => void; onSubmit: (data: FormData) => void; + onWarehouseAdd: () => void; onWeightRateAdd: () => void; onWeightRateEdit: (id: string) => void; } @@ -67,6 +68,7 @@ const ShippingZoneDetailsPage: React.FC = ({ onPriceRateEdit, onRateRemove, onSubmit, + onWarehouseAdd, onWeightRateAdd, onWeightRateEdit, saveButtonBarState, @@ -165,9 +167,10 @@ const ShippingZoneDetailsPage: React.FC = ({ displayValue={warehouseDisplayValues} hasMore={false} loading={false} + warehouses={warehouseChoices} onChange={handleWarehouseChange} onFetchMore={() => undefined} - warehouses={warehouseChoices} + onWarehouseAdd={onWarehouseAdd} />
diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx index 0b0390667..f0580afde 100644 --- a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -18,6 +18,7 @@ interface ShippingZonewWarehousesProps extends FetchMoreProps { displayValue: MultiAutocompleteChoiceType[]; warehouses: MultiAutocompleteChoiceType[]; onChange: FormChange; + onWarehouseAdd: () => void; } export const ShippingZoneWarehouses: React.FC = props => { @@ -26,9 +27,10 @@ export const ShippingZoneWarehouses: React.FC = pr displayValue, hasMore, loading, + warehouses, onChange, onFetchMore, - warehouses + onWarehouseAdd } = props; const intl = useIntl(); @@ -42,6 +44,13 @@ export const ShippingZoneWarehouses: React.FC = pr /> undefined} diff --git a/src/shipping/urls.ts b/src/shipping/urls.ts index be4d3d316..c9dc4d062 100644 --- a/src/shipping/urls.ts +++ b/src/shipping/urls.ts @@ -20,6 +20,7 @@ export const shippingZonePath = (id: string) => urlJoin(shippingZonesListPath, id); export type ShippingZoneUrlDialog = | "add-rate" + | "add-warehouse" | "assign-country" | "edit-rate" | "remove" diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 451760a84..9350e8165 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -176,6 +176,7 @@ const ShippingZoneDetails: React.FC = ({ }) } onSubmit={handleSubmit} + onWarehouseAdd={() => openModal("add-warehouse")} onWeightRateAdd={() => openModal("add-rate", { type: ShippingMethodTypeEnum.WEIGHT From 93d1d74230c9f5b774750c451035b77d7ddd753d Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 11 Feb 2020 15:41:56 +0100 Subject: [PATCH 19/88] Allow creating warehouse from shipping zone view --- .../CompanyAddressForm.tsx | 190 ++++++++++++++++++ .../CompanyAddressInput.tsx | 180 +---------------- .../SingleAutocompleteSelectField.tsx | 16 +- .../ShippingZoneAddWarehouseDialog.tsx | 162 +++++++++++++++ .../ShippingZoneAddWarehouseDialog/index.ts | 2 + .../views/ShippingZoneDetails/index.tsx | 50 ++++- 6 files changed, 420 insertions(+), 180 deletions(-) create mode 100644 src/components/CompanyAddressInput/CompanyAddressForm.tsx create mode 100644 src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx create mode 100644 src/shipping/components/ShippingZoneAddWarehouseDialog/index.ts diff --git a/src/components/CompanyAddressInput/CompanyAddressForm.tsx b/src/components/CompanyAddressInput/CompanyAddressForm.tsx new file mode 100644 index 000000000..b94b87aac --- /dev/null +++ b/src/components/CompanyAddressInput/CompanyAddressForm.tsx @@ -0,0 +1,190 @@ +import { makeStyles } from "@material-ui/core/styles"; +import TextField from "@material-ui/core/TextField"; +import React from "react"; +import { useIntl, IntlShape } from "react-intl"; + +import FormSpacer from "@saleor/components/FormSpacer"; +import Grid from "@saleor/components/Grid"; +import SingleAutocompleteSelectField, { + SingleAutocompleteChoiceType +} from "@saleor/components/SingleAutocompleteSelectField"; +import { AddressTypeInput } from "@saleor/customers/types"; +import { ChangeEvent } from "@saleor/hooks/useForm"; +import getShopErrorMessage from "@saleor/utils/errors/shop"; +import { getFormErrors } from "@saleor/utils/errors"; +import { ShopErrorFragment } from "@saleor/siteSettings/types/ShopErrorFragment"; +import { AccountErrorFragment } from "@saleor/customers/types/AccountErrorFragment"; +import getAccountErrorMessage from "@saleor/utils/errors/account"; + +export interface CompanyAddressFormProps { + countries: SingleAutocompleteChoiceType[]; + data: AddressTypeInput; + displayCountry: string; + errors: Array; + disabled: boolean; + onChange: (event: ChangeEvent) => void; + onCountryChange: (event: ChangeEvent) => void; +} + +const useStyles = makeStyles( + { + root: {} + }, + { name: "CompanyAddressForm" } +); + +function getErrorMessage( + err: AccountErrorFragment | ShopErrorFragment, + intl: IntlShape +): string { + if (err?.__typename === "AccountError") { + return getAccountErrorMessage(err, intl); + } + + return getShopErrorMessage(err, intl); +} + +const CompanyAddressForm: React.FC = props => { + const { + countries, + data, + disabled, + displayCountry, + errors, + onChange, + onCountryChange + } = props; + + const classes = useStyles(props); + const intl = useIntl(); + + const formFields = [ + "companyName", + "streetAddress1", + "streetAddress2", + "city", + "postalCode", + "country", + "companyArea", + "phone" + ]; + const formErrors = getFormErrors(formFields, errors); + + return ( +
+ + + + + + + + + + + + + + + + + +
+ ); +}; +CompanyAddressForm.displayName = "CompanyAddressForm"; +export default CompanyAddressForm; diff --git a/src/components/CompanyAddressInput/CompanyAddressInput.tsx b/src/components/CompanyAddressInput/CompanyAddressInput.tsx index bdd2374a4..a064b4c25 100644 --- a/src/components/CompanyAddressInput/CompanyAddressInput.tsx +++ b/src/components/CompanyAddressInput/CompanyAddressInput.tsx @@ -1,33 +1,17 @@ import Card from "@material-ui/core/Card"; import CardContent from "@material-ui/core/CardContent"; import { makeStyles } from "@material-ui/core/styles"; -import TextField from "@material-ui/core/TextField"; import React from "react"; -import { useIntl, IntlShape } from "react-intl"; +import classNames from "classnames"; -import CardTitle from "@saleor/components/CardTitle"; -import FormSpacer from "@saleor/components/FormSpacer"; -import Grid from "@saleor/components/Grid"; -import SingleAutocompleteSelectField, { - SingleAutocompleteChoiceType -} from "@saleor/components/SingleAutocompleteSelectField"; -import { ChangeEvent } from "@saleor/hooks/useForm"; -import { getFormErrors } from "@saleor/utils/errors"; -import { ShopErrorFragment } from "@saleor/siteSettings/types/ShopErrorFragment"; -import getShopErrorMessage from "@saleor/utils/errors/shop"; -import { AccountErrorFragment } from "@saleor/customers/types/AccountErrorFragment"; -import getAccountErrorMessage from "@saleor/utils/errors/account"; -import { AddressTypeInput } from "@saleor/customers/types"; +import CardTitle from "../CardTitle"; +import CompanyAddressForm, { + CompanyAddressFormProps +} from "./CompanyAddressForm"; -interface CompanyAddressInputProps { - countries: SingleAutocompleteChoiceType[]; - data: AddressTypeInput; - displayCountry: string; - errors: Array; - disabled: boolean; +interface CompanyAddressInputProps extends CompanyAddressFormProps { + className: string; header: string; - onChange: (event: ChangeEvent) => void; - onCountryChange: (event: ChangeEvent) => void; } const useStyles = makeStyles( @@ -39,159 +23,15 @@ const useStyles = makeStyles( { name: "CompanyAddressInput" } ); -function getErrorMessage( - err: AccountErrorFragment | ShopErrorFragment, - intl: IntlShape -): string { - if (err?.__typename === "AccountError") { - return getAccountErrorMessage(err, intl); - } - - return getShopErrorMessage(err, intl); -} - const CompanyAddressInput: React.FC = props => { - const { - countries, - data, - disabled, - displayCountry, - errors, - header, - onChange, - onCountryChange - } = props; - + const { className, header, ...formProps } = props; const classes = useStyles(props); - const intl = useIntl(); - - const formFields = [ - "companyName", - "streetAddress1", - "streetAddress2", - "city", - "postalCode", - "country", - "companyArea", - "phone" - ]; - const formErrors = getFormErrors(formFields, errors); return ( - + - - - - - - - - - - - - - - - - - + ); diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx index 4df5b02e6..f140d4c05 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx @@ -26,7 +26,7 @@ const useStyles = makeStyles( export interface SingleAutocompleteSelectFieldProps extends Partial { - add: SingleAutocompleteActionType; + add?: SingleAutocompleteActionType; error?: boolean; name: string; displayValue: string; @@ -147,13 +147,15 @@ const SingleAutocompleteSelectFieldComponent: React.FC {isOpen && (!!inputValue || !!choices.length) && ( { - add.onClick(); - closeMenu(); + add={ + !!add && { + ...add, + onClick: () => { + add.onClick(); + closeMenu(); + } } - }} + } choices={choices} displayCustomValue={displayCustomValue} emptyOption={emptyOption} diff --git a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx new file mode 100644 index 000000000..4e2f3e806 --- /dev/null +++ b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx @@ -0,0 +1,162 @@ +import Button from "@material-ui/core/Button"; +import Dialog from "@material-ui/core/Dialog"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import TextField from "@material-ui/core/TextField"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; +import makeStyles from "@material-ui/core/styles/makeStyles"; + +import ConfirmButton, { + ConfirmButtonTransitionState +} from "@saleor/components/ConfirmButton"; +import { DialogProps, UserError } from "@saleor/types"; +import { AddressTypeInput } from "@saleor/customers/types"; +import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; +import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; +import CompanyAddressForm from "@saleor/components/CompanyAddressInput/CompanyAddressForm"; +import { buttonMessages } from "@saleor/intl"; +import Hr from "@saleor/components/Hr"; +import Form from "@saleor/components/Form"; +import useAddressValidation from "@saleor/hooks/useAddressValidation"; +import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo"; +import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; +import FormSpacer from "@saleor/components/FormSpacer"; + +export interface ShippingZoneAddWarehouseDialogSubmitData + extends AddressTypeInput { + name: string; +} +export interface ShippingZoneAddWarehouseDialogProps extends DialogProps { + confirmButtonState: ConfirmButtonTransitionState; + countries: ShopInfo_shop_countries[]; + disabled: boolean; + errors: UserError[]; + onSubmit: (data: ShippingZoneAddWarehouseDialogSubmitData) => void; +} + +const initialForm: ShippingZoneAddWarehouseDialogSubmitData = { + city: "", + cityArea: "", + companyName: "", + country: "", + countryArea: "", + firstName: "", + lastName: "", + name: "", + phone: "", + postalCode: "", + streetAddress1: "", + streetAddress2: "" +}; + +const useStyles = makeStyles( + { + overflow: { + overflowY: "visible" + } + }, + { + name: "ShippingZoneAddWarehouseDialog" + } +); + +const ShippingZoneAddWarehouseDialog: React.FC = ({ + confirmButtonState, + countries, + disabled, + errors: apiErrors, + open, + onClose, + onSubmit +}) => { + const classes = useStyles({}); + const [countryDisplayName, setCountryDisplayName] = useStateFromProps(""); + const { + errors: validationErrors, + submit: handleSubmit + } = useAddressValidation(onSubmit); + const errors = useModalDialogErrors( + [...apiErrors, ...validationErrors], + open + ); + useModalDialogOpen(open, {}); + const intl = useIntl(); + + const countryChoices = countries.map(country => ({ + label: country.country, + value: country.code + })); + + return ( + + + + +
+ {({ change, data, errors: formErrors, submit }) => { + const handleCountrySelect = createSingleAutocompleteSelectHandler( + change, + setCountryDisplayName, + countryChoices + ); + + return ( + <> + + + +
+ + +
+ + + + + + + + ); + }} +
+
+ ); +}; + +ShippingZoneAddWarehouseDialog.displayName = "ShippingZoneAddWarehouseDialog"; +export default ShippingZoneAddWarehouseDialog; diff --git a/src/shipping/components/ShippingZoneAddWarehouseDialog/index.ts b/src/shipping/components/ShippingZoneAddWarehouseDialog/index.ts new file mode 100644 index 000000000..3d5129332 --- /dev/null +++ b/src/shipping/components/ShippingZoneAddWarehouseDialog/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ShippingZoneAddWarehouseDialog"; +export * from "./ShippingZoneAddWarehouseDialog"; diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 9350e8165..ea22654e4 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -21,8 +21,13 @@ import ShippingZoneRateDialog from "@saleor/shipping/components/ShippingZoneRate import useShop from "@saleor/hooks/useShop"; import ShippingZoneCountriesAssignDialog from "@saleor/shipping/components/ShippingZoneCountriesAssignDialog"; import NotFoundPage from "@saleor/components/NotFoundPage"; -import { getStringOrPlaceholder } from "../../../misc"; -import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; +import ShippingZoneAddWarehouseDialog from "@saleor/shipping/components/ShippingZoneAddWarehouseDialog"; +import { useWarehouseCreate } from "@saleor/warehouses/mutations"; +import { getStringOrPlaceholder, findValueInEnum } from "../../../misc"; +import { + ShippingMethodTypeEnum, + CountryCode +} from "../../../types/globalTypes"; import ShippingZoneDetailsPage, { FormData } from "../../components/ShippingZoneDetailsPage"; @@ -126,6 +131,17 @@ const ShippingZoneDetails: React.FC = ({ } }); + const [createWarehouse, createWarehouseOpts] = useWarehouseCreate({ + onCompleted: data => { + if (data.createWarehouse.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + closeModal(); + } + } + }); + const handleSubmit = (data: FormData) => { updateShippingZone({ variables: { @@ -138,7 +154,7 @@ const ShippingZoneDetails: React.FC = ({ assignToWarehouse({ variables: { shippingZoneId: id, - warehouseId: data.warehouse + warehouseId: data.warehouses[0] } }); }; @@ -346,6 +362,34 @@ const ShippingZoneDetails: React.FC = ({ /> + + createWarehouse({ + variables: { + input: { + address: { + city: data.city, + cityArea: data.cityArea, + country: findValueInEnum(data.country, CountryCode), + countryArea: data.countryArea, + phone: data.phone, + postalCode: data.postalCode, + streetAddress1: data.streetAddress1, + streetAddress2: data.streetAddress2 + }, + companyName: data.companyName, + name: data.name + } + } + }) + } + /> ); }; From fbc809879f29839c48bbfe62ed881be0943eecc4 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 11 Feb 2020 16:05:09 +0100 Subject: [PATCH 20/88] Add warehouse search --- .../ShippingZoneAddWarehouseDialog.tsx | 2 +- .../ShippingZoneDetailsPage.tsx | 30 +++++++++++-------- .../ShippingZoneWarehouses.tsx | 11 +++++-- .../views/ShippingZoneDetails/index.tsx | 12 ++++++-- src/types.ts | 6 ++-- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx index 4e2f3e806..632fe73fc 100644 --- a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx +++ b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx @@ -105,7 +105,7 @@ const ShippingZoneAddWarehouseDialog: React.FC
- {({ change, data, errors: formErrors, submit }) => { + {({ change, data, errors: formErrors }) => { const handleCountrySelect = createSingleAutocompleteSelectHandler( change, setCountryDisplayName, diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index 19805372b..1dc6ed09e 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -15,6 +15,7 @@ import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAu import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { maybe } from "../../../misc"; +import { FetchMoreProps, SearchProps } from "../../../types"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import { ShippingZoneDetailsFragment, @@ -29,7 +30,9 @@ export interface FormData { warehouses: string[]; } -export interface ShippingZoneDetailsPageProps { +export interface ShippingZoneDetailsPageProps + extends FetchMoreProps, + SearchProps { disabled: boolean; errors: ShippingErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; @@ -60,13 +63,17 @@ function warehouseToChoice( const ShippingZoneDetailsPage: React.FC = ({ disabled, errors, + hasMore, + loading, onBack, onCountryAdd, onCountryRemove, onDelete, + onFetchMore, onPriceRateAdd, onPriceRateEdit, onRateRemove, + onSearchChange, onSubmit, onWarehouseAdd, onWeightRateAdd, @@ -140,10 +147,8 @@ const ShippingZoneDetailsPage: React.FC = ({ onRateAdd={onPriceRateAdd} onRateEdit={onPriceRateEdit} onRateRemove={onRateRemove} - rates={maybe(() => - shippingZone.shippingMethods.filter( - method => method.type === ShippingMethodTypeEnum.PRICE - ) + rates={shippingZone?.shippingMethods?.filter( + method => method.type === ShippingMethodTypeEnum.PRICE )} variant="price" /> @@ -153,10 +158,8 @@ const ShippingZoneDetailsPage: React.FC = ({ onRateAdd={onWeightRateAdd} onRateEdit={onWeightRateEdit} onRateRemove={onRateRemove} - rates={maybe(() => - shippingZone.shippingMethods.filter( - method => method.type === ShippingMethodTypeEnum.WEIGHT - ) + rates={shippingZone?.shippingMethods?.filter( + method => method.type === ShippingMethodTypeEnum.WEIGHT )} variant="weight" /> @@ -165,12 +168,13 @@ const ShippingZoneDetailsPage: React.FC = ({ undefined} + onFetchMore={onFetchMore} + onSearchChange={onSearchChange} onWarehouseAdd={onWarehouseAdd} + warehouses={warehouseChoices} /> diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx index f0580afde..79f57a64f 100644 --- a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -4,7 +4,7 @@ import React from "react"; import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; -import { FetchMoreProps } from "@saleor/types"; +import { FetchMoreProps, SearchProps } from "@saleor/types"; import { FormChange } from "@saleor/hooks/useForm"; import MultiAutocompleteSelectField, { MultiAutocompleteChoiceType @@ -13,7 +13,7 @@ import MultiAutocompleteSelectField, { interface ShippingZoneWarehousesFormData { warehouses: string[]; } -interface ShippingZonewWarehousesProps extends FetchMoreProps { +interface ShippingZonewWarehousesProps extends FetchMoreProps, SearchProps { data: ShippingZoneWarehousesFormData; displayValue: MultiAutocompleteChoiceType[]; warehouses: MultiAutocompleteChoiceType[]; @@ -30,6 +30,7 @@ export const ShippingZoneWarehouses: React.FC = pr warehouses, onChange, onFetchMore, + onSearchChange, onWarehouseAdd } = props; const intl = useIntl(); @@ -53,8 +54,12 @@ export const ShippingZoneWarehouses: React.FC = pr }} choices={warehouses} displayValues={displayValue} - fetchChoices={() => undefined} + fetchChoices={onSearchChange} hasMore={hasMore} + helperText={intl.formatMessage({ + defaultMessage: + "Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes." + })} label={intl.formatMessage({ defaultMessage: "Warehouse" })} diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index ea22654e4..90fc9378e 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -57,9 +57,11 @@ const ShippingZoneDetails: React.FC = ({ const intl = useIntl(); const shop = useShop(); - const { result: searchWarehousesOpts } = useWarehouseSearch({ - variables: DEFAULT_INITIAL_SEARCH_DATA - }); + const { result: searchWarehousesOpts, loadMore, search } = useWarehouseSearch( + { + variables: DEFAULT_INITIAL_SEARCH_DATA + } + ); const [assignToWarehouse] = useAassignShippingZoneToWarehouse({}); @@ -208,6 +210,10 @@ const ShippingZoneDetails: React.FC = ({ warehouses={ searchWarehousesOpts.data?.search.edges.map(edge => edge.node) || [] } + hasMore={searchWarehousesOpts.data?.search.pageInfo.hasNextPage} + loading={searchWarehousesOpts.loading} + onFetchMore={loadMore} + onSearchChange={search} /> onAdd: () => void; } -export interface SearchPageProps { - initialSearch: string; +export interface SearchProps { onSearchChange: (value: string) => void; } +export interface SearchPageProps extends SearchProps { + initialSearch: string; +} export interface FilterPageProps extends FilterProps, SearchPageProps, From 369be9685003ac3c6f4d45b248b12a738f82b2bb Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 11 Feb 2020 16:32:47 +0100 Subject: [PATCH 21/88] Fix types --- .../CompanyAddressInput.tsx | 2 +- src/products/fixtures.ts | 37 +++++- .../ShippingZoneInfo/ShippingZoneInfo.tsx | 5 +- src/shipping/fixtures.ts | 4 +- src/shipping/views/ShippingZoneCreate.tsx | 52 ++++---- .../ShippingZoneOperations.tsx | 111 ------------------ .../shipping/ShippingZoneDetailsPage.tsx | 8 +- 7 files changed, 73 insertions(+), 146 deletions(-) delete mode 100644 src/shipping/views/ShippingZoneDetails/ShippingZoneOperations.tsx diff --git a/src/components/CompanyAddressInput/CompanyAddressInput.tsx b/src/components/CompanyAddressInput/CompanyAddressInput.tsx index a064b4c25..87ecaf788 100644 --- a/src/components/CompanyAddressInput/CompanyAddressInput.tsx +++ b/src/components/CompanyAddressInput/CompanyAddressInput.tsx @@ -10,7 +10,7 @@ import CompanyAddressForm, { } from "./CompanyAddressForm"; interface CompanyAddressInputProps extends CompanyAddressFormProps { - className: string; + className?: string; header: string; } diff --git a/src/products/fixtures.ts b/src/products/fixtures.ts index 5f019f4dc..34355ff65 100644 --- a/src/products/fixtures.ts +++ b/src/products/fixtures.ts @@ -1,4 +1,5 @@ import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; +import { warehouseList } from "@saleor/warehouses/fixtures"; import { content } from "../storybook/stories/components/RichTextEditor"; import { ProductDetails_product } from "./types/ProductDetails"; import { ProductList_products_edges_node } from "./types/ProductList"; @@ -262,6 +263,20 @@ export const product: ( quantity: 12, quantityAllocated: 1, sku: "87192-94370", + stock: [ + { + __typename: "Stock", + id: "1", + quantity: 1, + warehouse: warehouseList[0] + }, + { + __typename: "Stock", + id: "2", + quantity: 4, + warehouse: warehouseList[1] + } + ], stockQuantity: 48 }, { @@ -285,6 +300,14 @@ export const product: ( quantity: 12, quantityAllocated: 1, sku: "69055-15190", + stock: [ + { + __typename: "Stock", + id: "1", + quantity: 13, + warehouse: warehouseList[0] + } + ], stockQuantity: 14 } ] @@ -1230,7 +1253,19 @@ export const variant = (placeholderImage: string): ProductVariant => ({ }, quantity: 19, quantityAllocated: 12, - sku: "1230959124123" + sku: "1230959124123", + stock: [ + { + __typename: "Stock", + id: "1", + quantity: 1 + }, + { + __typename: "Stock", + id: "2", + quantity: 4 + } + ] }); export const variantImages = (placeholderImage: string) => variant(placeholderImage).images; diff --git a/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx b/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx index 0ad8e0d08..6aeacf402 100644 --- a/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx +++ b/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx @@ -9,10 +9,9 @@ import { commonMessages } from "@saleor/intl"; import { getFormErrors } from "@saleor/utils/errors"; import getShippingErrorMessage from "@saleor/utils/errors/shipping"; import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; -import { FormData } from "../ShippingZoneDetailsPage"; export interface ShippingZoneInfoProps { - data: FormData; + data: Record<"name", string>; disabled: boolean; errors: ShippingErrorFragment[]; onChange: (event: React.ChangeEvent) => void; @@ -42,7 +41,7 @@ const ShippingZoneInfo: React.FC = ({ label={intl.formatMessage({ defaultMessage: "Shipping Zone Name" })} - name={"name" as keyof FormData} + name="name" value={data.name} onChange={onChange} /> diff --git a/src/shipping/fixtures.ts b/src/shipping/fixtures.ts index cefe56d87..c05e6d2da 100644 --- a/src/shipping/fixtures.ts +++ b/src/shipping/fixtures.ts @@ -1,3 +1,4 @@ +import { warehouseList } from "@saleor/warehouses/fixtures"; import { ShippingMethodTypeEnum } from "../types/globalTypes"; import { ShippingZoneDetailsFragment } from "./types/ShippingZoneDetailsFragment"; import { ShippingZoneFragment } from "./types/ShippingZoneFragment"; @@ -1644,5 +1645,6 @@ export const shippingZone: ShippingZoneDetailsFragment = { }, type: ShippingMethodTypeEnum.PRICE } - ] + ], + warehouses: warehouseList }; diff --git a/src/shipping/views/ShippingZoneCreate.tsx b/src/shipping/views/ShippingZoneCreate.tsx index bf063090d..95928cc08 100644 --- a/src/shipping/views/ShippingZoneCreate.tsx +++ b/src/shipping/views/ShippingZoneCreate.tsx @@ -5,45 +5,41 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; import { commonMessages } from "@saleor/intl"; -import { maybe } from "../../misc"; import ShippingZoneCreatePage from "../components/ShippingZoneCreatePage"; -import { TypedCreateShippingZone } from "../mutations"; -import { CreateShippingZone } from "../types/CreateShippingZone"; +import { useShippingZoneCreate } from "../mutations"; import { shippingZonesListUrl, shippingZoneUrl } from "../urls"; const ShippingZoneCreate: React.FC<{}> = () => { const navigate = useNavigator(); - const pushMessage = useNotifier(); + const notify = useNotifier(); const shop = useShop(); const intl = useIntl(); - const onShippingZoneCreate = (data: CreateShippingZone) => { - if (data.shippingZoneCreate.errors.length === 0) { - pushMessage({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - navigate(shippingZoneUrl(data.shippingZoneCreate.shippingZone.id)); + const [createShippingZone, createShippingZoneOpts] = useShippingZoneCreate({ + onCompleted: data => { + if (data.shippingZoneCreate.errors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + navigate(shippingZoneUrl(data.shippingZoneCreate.shippingZone.id)); + } } - }; + }); return ( - - {(createShippingZone, createShippingZoneOpts) => ( - shop.countries, [])} - disabled={createShippingZoneOpts.loading} - errors={createShippingZoneOpts.data?.shippingZoneCreate.errors || []} - onBack={() => navigate(shippingZonesListUrl())} - onSubmit={formData => - createShippingZone({ - variables: { - input: formData - } - }) + navigate(shippingZonesListUrl())} + onSubmit={formData => + createShippingZone({ + variables: { + input: formData } - saveButtonBarState={createShippingZoneOpts.status} - /> - )} - + }) + } + saveButtonBarState={createShippingZoneOpts.status} + /> ); }; export default ShippingZoneCreate; diff --git a/src/shipping/views/ShippingZoneDetails/ShippingZoneOperations.tsx b/src/shipping/views/ShippingZoneDetails/ShippingZoneOperations.tsx deleted file mode 100644 index cbf7db83b..000000000 --- a/src/shipping/views/ShippingZoneDetails/ShippingZoneOperations.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import React from "react"; - -import { getMutationProviderData } from "../../../misc"; -import { PartialMutationProviderOutput } from "../../../types"; -import { - TypedCreateShippingRate, - TypedDeleteShippingRate, - TypedDeleteShippingZone, - TypedUpdateShippingRate, - TypedUpdateShippingZone -} from "../../mutations"; -import { - CreateShippingRate, - CreateShippingRateVariables -} from "../../types/CreateShippingRate"; -import { - DeleteShippingRate, - DeleteShippingRateVariables -} from "../../types/DeleteShippingRate"; -import { - DeleteShippingZone, - DeleteShippingZoneVariables -} from "../../types/DeleteShippingZone"; -import { - UpdateShippingRate, - UpdateShippingRateVariables -} from "../../types/UpdateShippingRate"; -import { - UpdateShippingZone, - UpdateShippingZoneVariables -} from "../../types/UpdateShippingZone"; - -export interface ShippingZoneOperationsOutput { - shippingRateCreate: PartialMutationProviderOutput< - CreateShippingRate, - CreateShippingRateVariables - >; - shippingRateDelete: PartialMutationProviderOutput< - DeleteShippingRate, - DeleteShippingRateVariables - >; - shippingRateUpdate: PartialMutationProviderOutput< - UpdateShippingRate, - UpdateShippingRateVariables - >; - shippingZoneDelete: PartialMutationProviderOutput< - DeleteShippingZone, - DeleteShippingZoneVariables - >; - shippingZoneUpdate: PartialMutationProviderOutput< - UpdateShippingZone, - UpdateShippingZoneVariables - >; -} -interface ShippingZoneOperationsProps { - children: (props: ShippingZoneOperationsOutput) => React.ReactNode; - onShippingRateCreate: (data: CreateShippingRate) => void; - onShippingRateDelete: (data: DeleteShippingRate) => void; - onShippingRateUpdate: (data: UpdateShippingRate) => void; - onShippingZoneDelete: (data: DeleteShippingZone) => void; - onShippingZoneUpdate: (data: UpdateShippingZone) => void; -} - -const ShippingZoneOperations: React.FC = ({ - children, - onShippingRateCreate, - onShippingRateDelete, - onShippingRateUpdate, - onShippingZoneDelete, - onShippingZoneUpdate -}) => ( - - {(...shippingRateCreate) => ( - - {(...shippingRateDelete) => ( - - {(...shippingRateUpdate) => ( - - {(...shippingZoneDelete) => ( - - {(...shippingZoneUpdate) => - children({ - shippingRateCreate: getMutationProviderData( - ...shippingRateCreate - ), - shippingRateDelete: getMutationProviderData( - ...shippingRateDelete - ), - shippingRateUpdate: getMutationProviderData( - ...shippingRateUpdate - ), - shippingZoneDelete: getMutationProviderData( - ...shippingZoneDelete - ), - shippingZoneUpdate: getMutationProviderData( - ...shippingZoneUpdate - ) - }) - } - - )} - - )} - - )} - - )} - -); -ShippingZoneOperations.displayName = "ShippingZoneOperations"; -export default ShippingZoneOperations; diff --git a/src/storybook/stories/shipping/ShippingZoneDetailsPage.tsx b/src/storybook/stories/shipping/ShippingZoneDetailsPage.tsx index 0bfc95c76..d510de60f 100644 --- a/src/storybook/stories/shipping/ShippingZoneDetailsPage.tsx +++ b/src/storybook/stories/shipping/ShippingZoneDetailsPage.tsx @@ -2,6 +2,8 @@ import { storiesOf } from "@storybook/react"; import React from "react"; import { ShippingErrorCode } from "@saleor/types/globalTypes"; +import { warehouseList } from "@saleor/warehouses/fixtures"; +import { fetchMoreProps, searchPageProps } from "@saleor/fixtures"; import ShippingZoneDetailsPage, { ShippingZoneDetailsPageProps } from "../../../shipping/components/ShippingZoneDetailsPage"; @@ -9,6 +11,8 @@ import { shippingZone } from "../../../shipping/fixtures"; import Decorator from "../../Decorator"; const props: ShippingZoneDetailsPageProps = { + ...fetchMoreProps, + ...searchPageProps, disabled: false, errors: [], onBack: () => undefined, @@ -19,10 +23,12 @@ const props: ShippingZoneDetailsPageProps = { onPriceRateEdit: () => undefined, onRateRemove: () => undefined, onSubmit: () => undefined, + onWarehouseAdd: () => undefined, onWeightRateAdd: () => undefined, onWeightRateEdit: () => undefined, saveButtonBarState: "default", - shippingZone + shippingZone, + warehouses: warehouseList }; storiesOf("Views / Shipping / Shipping zone details", module) From be1750530c6ad7d4f8de785d6395d2de66182ca9 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 11 Feb 2020 16:33:28 +0100 Subject: [PATCH 22/88] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fb784847..f8caf1fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ All notable, unreleased changes to this project will be documented in this file. - Filter column ids before send it to GridAttributes operation - #476 by @gabmartinez - Display Is Published column correctly in main Product Listing - #475 by @gabmartinez - Add Permission Groups section - #406 by @krzysztofwolski +- Add warehouse management - #390 by @dominik-zeglen ## 2.0.0 From 1e37867e3ebeadecb8971ad76aa58875c1684cb9 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 11 Feb 2020 16:44:08 +0100 Subject: [PATCH 23/88] Update stories and messages --- .../ShippingZoneWarehouses.tsx | 5 + .../__snapshots__/Stories.test.ts.snap | 6440 +++++++++++++++-- 2 files changed, 5702 insertions(+), 743 deletions(-) diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx index 79f57a64f..d3b09808d 100644 --- a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -71,6 +71,11 @@ export const ShippingZoneWarehouses: React.FC = pr defaultMessage: "Select Warehouse", description: "input placeholder" })} + label={intl.formatMessage({ + defaultMessage: "Warehouse", + description:"autocomplete select label" + id: "shippingZoneWarehouses.autocomplete.label" + })} value={data.warehouses} /> diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 256772bbf..f6535eb25 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -2640,6 +2640,49 @@ exports[`Storyshots Generics / Global messages with undo action 1`] = ` `; +exports[`Storyshots Generics / Link with choices default 1`] = ` +
+
+
+ + + + Åland Islands + + + + +
+
+
+`; + exports[`Storyshots Generics / Money formatting default 1`] = `
`; +exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` +
+
+
+
+
+ +
+ + + + + + + + + + +
+
+
+ +
+
+
+
+
+
+`; + exports[`Storyshots Generics / SingleSelectField with error hint 1`] = `
+
+
+
+ +
+
+
+ Warehouses +
+
+ Manage and update your warehouse information +
+
+
+
+ + +
+
+
+ Product Settings +
+
+
+
+
+
+ +
+
+
+ Warehouses +
+
+ Manage and update your warehouse information +
+
+
+
+
+
+
+ +
+
+
+ Permission Groups +
+
+ Manage your permission groups and their permissions +
+
+
+
+
+
+
+
+
+ Product Settings +
+
+
@@ -34546,44 +34889,6 @@ exports[`Storyshots Views / Configuration default 1`] = `
-
-
-
- -
-
-
- Permission Groups -
-
- Manage your permission groups and their permissions -
-
-
-
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -102715,6 +103054,40 @@ exports[`Storyshots Views / Products / Create product variant add first variant
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -103172,6 +103545,40 @@ exports[`Storyshots Views / Products / Create product variant default 1`] = `
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -104124,6 +104531,40 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] =
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -105850,13 +106291,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id ProductVariants-colName-id" scope="col" > - Name - - - Status + Variant SKU + + Inventory + Cordoba Oro - -
- Available -
- 87192-94370 + + 5 available at 2 locations + silver - -
- Available -
- 69055-15190 + + 13 available at 1 location + @@ -107387,13 +107818,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id ProductVariants-colName-id" scope="col" > - Name - - - Status + Variant SKU + + Inventory + Cordoba Oro - -
- Available -
- 87192-94370 + + 5 available at 2 locations + silver - -
- Available -
- 69055-15190 + + 13 available at 1 location + @@ -109172,13 +109593,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id ProductVariants-colName-id" scope="col" > - Name - - - Status + Variant SKU + + Inventory + Cordoba Oro - -
- Available -
- 87192-94370 + + 5 available at 2 locations + silver - -
- Available -
- 69055-15190 + + 13 available at 1 location + @@ -110957,13 +111368,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id ProductVariants-colName-id" scope="col" > - Name - - - Status + Variant SKU + + Inventory + Cordoba Oro - -
- Available -
- 87192-94370 + + 5 available at 2 locations + silver - -
- Available -
- 69055-15190 + + 13 available at 1 location + @@ -116006,6 +116407,99 @@ Ctrl + K"
+
+
+
+ + Warehouse + +
+
+
+
+
+
+
+ + +

+ Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. +

+
+
+
+
+
@@ -116192,7 +116686,7 @@ exports[`Storyshots Views / Products / Product image details when loaded data 1` > ​ @@ -116245,6 +116739,99 @@ exports[`Storyshots Views / Products / Product image details when loaded data 1`
+
+
+
+ + Warehouse + +
+
+
+
+
+
+
+ + +

+ Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. +

+
+
+
+
+
@@ -116417,6 +117004,99 @@ exports[`Storyshots Views / Products / Product image details when loading data 1 +
+
+
+ + Warehouse + +
+
+
+
+
+
+
+ + +

+ Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. +

+
+
+
+
+
@@ -123015,7 +123695,7 @@ exports[`Storyshots Views / Services / Create service default 1`] = ` > ​ @@ -123826,7 +124506,7 @@ exports[`Storyshots Views / Services / Create service form errors 1`] = ` > ​ @@ -125464,7 +126144,7 @@ exports[`Storyshots Views / Services / Service details default 1`] = ` > ​ @@ -134935,7 +135615,7 @@ exports[`Storyshots Views / Site settings / Page default 1`] = `
- -
- - -
-
-
-
- -
- - -
-
-
-
- -
- - -
-
-
-
- City + Company
+
@@ -135116,7 +135686,7 @@ exports[`Storyshots Views / Site settings / Page default 1`] = ` class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id MuiFormLabel-filled-id" data-shrink="true" > - ZIP / Postal code + Address line 1
-
-
-
+
+ +
+ + +
+
+
+
- Country + City +
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
-
-
- -
- - -
-

- -
- - -
-
-
-
- -
- - -
-
-
-
- -
- - -
-
-
-
- City + Company
+
@@ -135987,7 +136561,7 @@ exports[`Storyshots Views / Site settings / Page form errors 1`] = ` class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id MuiFormLabel-filled-id" data-shrink="true" > - ZIP / Postal code + Address line 1
-
-
-
+
+ +
+ + +
+
+
+
- Country + City +
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
-
-
- -
- - -
-

- -
- - -
-
-
-
- -
- - -
-
-
-
- -
- - -
-
-
-
- City + Company
@@ -136852,6 +137423,9 @@ exports[`Storyshots Views / Site settings / Page loading 1`] = `
+
@@ -136859,7 +137433,7 @@ exports[`Storyshots Views / Site settings / Page loading 1`] = ` class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-disabled-id MuiInputLabel-disabled-id" data-shrink="false" > - ZIP / Postal code + Address line 1
@@ -136888,15 +137462,50 @@ exports[`Storyshots Views / Site settings / Page loading 1`] = `
-
-
-
+
+ +
+ + +
+
+
+
- Country + City +
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
@@ -136962,7 +137693,7 @@ exports[`Storyshots Views / Site settings / Page loading 1`] = ` class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-disabled-id MuiInputLabel-disabled-id" data-shrink="false" > - Country area + Phone
@@ -136992,45 +137723,6 @@ exports[`Storyshots Views / Site settings / Page loading 1`] = `
-
-
- -
- - -
-

`; +exports[`Storyshots Views / Warehouses / Create warehouse default 1`] = ` +
+
+
+
+
+ Create Warehouse +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ + Address Information + +
+
+
+
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+
+ +
+`; + +exports[`Storyshots Views / Warehouses / Create warehouse form errors 1`] = ` +
+
+
+
+
+ Create Warehouse +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+
+
+ + Address Information + +
+
+
+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+
+
+ + +

+ Generic form error +

+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+
+
+
+ +
+`; + +exports[`Storyshots Views / Warehouses / Create warehouse loading 1`] = ` +
+
+
+
+
+ Create Warehouse +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ + Address Information + +
+
+
+
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+
+ +
+`; + +exports[`Storyshots Views / Warehouses / Warehouse details default 1`] = ` +
+
+
+
+
+ C our wares +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ + Address Information + +
+
+
+
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+
+
+ + Shipping Zones + +
+
+ +
+
+
+ +
+`; + +exports[`Storyshots Views / Warehouses / Warehouse details form errors 1`] = ` +
+
+
+
+
+ C our wares +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+
+
+ + Address Information + +
+
+
+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+
+
+ + +

+ Generic form error +

+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+ +
+ + +
+

+ Generic form error +

+
+
+
+
+
+
+
+
+ + Shipping Zones + +
+
+ +
+
+
+ +
+`; + +exports[`Storyshots Views / Warehouses / Warehouse details loading 1`] = ` +
+
+
+
+
+ + ‌ + +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ + Address Information + +
+
+
+
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+
+
+ + Shipping Zones + +
+
+
+
+
+ + ‌ + +
+
+
+
+
+ +
+`; + +exports[`Storyshots Views / Warehouses / Warehouse list default 1`] = ` +
+
+
+
+ Warehouses +
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ Name +
+ +
+
+ Shipping Zones + + Actions +
+ C our wares + + Europe, Oceania, Asia, Americas, Africa + +
+ + +
+
+ Be stocked + + Europe, Oceania, Asia, Americas, Africa + +
+ + +
+
+ A Warehouse + + Europe, Oceania, Asia, Americas, Africa + +
+ + +
+
+ Darkwares + + Europe, Oceania, Asia, Americas, Africa + +
+ + +
+
+
+
+
+
+`; + +exports[`Storyshots Views / Warehouses / Warehouse list loading 1`] = ` +
+
+
+
+ Warehouses +
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + +
+
+
+ Name +
+ +
+
+ Shipping Zones + + Actions +
+ + ‌ + + + + ‌ + + +
+ + +
+
+
+
+
+
+`; + +exports[`Storyshots Views / Warehouses / Warehouse list no data 1`] = ` +
+
+
+
+ Warehouses +
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + +
+
+
+ Name +
+ +
+
+ Shipping Zones + + Actions +
+ No warehouses found +
+
+
+
+
+`; + exports[`Storyshots Views / Webhooks / Create webhook default 1`] = `
Date: Fri, 14 Feb 2020 12:19:17 +0100 Subject: [PATCH 24/88] Move label creation logic to util function --- .../ProductVariants/ProductVariants.tsx | 101 +++++++++++------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/products/components/ProductVariants/ProductVariants.tsx b/src/products/components/ProductVariants/ProductVariants.tsx index fe6b79765..f92aff08f 100644 --- a/src/products/components/ProductVariants/ProductVariants.tsx +++ b/src/products/components/ProductVariants/ProductVariants.tsx @@ -112,6 +112,61 @@ const useStyles = makeStyles( { name: "ProductVariants" } ); +function getAvailabilityLabel( + intl: IntlShape, + warehouse: string, + variant: ProductDetails_product_variants, + numAvailable: number +): string { + const variantStock = variant.stock.find(s => s.warehouse.id === warehouse); + + if (!!warehouse) { + if (!!variantStock) { + if (variantStock.quantity > 0) { + return intl.formatMessage( + { + defaultMessage: + "{stockQuantity,plural,other{{stockQuantity} available}}", + description: "product variant inventory" + }, + { + stockQuantity: variantStock.quantity + } + ); + } else { + return intl.formatMessage({ + defaultMessage: "Unavailable", + description: "product variant inventory" + }); + } + } else { + return intl.formatMessage({ + defaultMessage: "Not stocked", + description: "product variant inventory" + }); + } + } else { + if (numAvailable > 0) { + return intl.formatMessage( + { + defaultMessage: + "{numLocations,plural,one{{numAvailable} available at {numLocations} location} other{{numAvailable} available at {numLocations} locations}}", + description: "product variant inventory" + }, + { + numAvailable, + numLocations: variant.stock.length + } + ); + } else { + return intl.formatMessage({ + defaultMessage: "Unavailable in all locations", + description: "product variant inventory" + }); + } + } +} + interface ProductVariantsProps extends ListActions { disabled: boolean; variants: ProductDetails_product_variants[]; @@ -140,7 +195,7 @@ export const ProductVariants: React.FC = props => { const classes = useStyles(props); const intl = useIntl(); - const [warehouse, setWarehouse] = React.useState(null); + const [warehouse, setWarehouse] = React.useState(null); const hasVariants = maybe(() => variants.length > 0, true); return ( @@ -243,9 +298,6 @@ export const ProductVariants: React.FC = props => { variant && variant.stock ? variant.stock.reduce((acc, s) => acc + s.quantity, 0) : null; - const variantStock = variant.stock.find( - s => s.warehouse.id === warehouse - ); return ( = props => { > {numAvailable === null ? ( - ) : warehouse === null ? ( - numAvailable === 0 ? ( - - ) : ( - - ) - ) : !!variantStock ? ( - variantStock.quantity > 0 ? ( - - ) : ( - - ) ) : ( - + getAvailabilityLabel( + intl, + warehouse, + variant, + numAvailable + ) )} From 61db9d147634ec74f434d1090e8324910b8651bc Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 18 Mar 2020 17:57:59 +0100 Subject: [PATCH 25/88] Fix label --- .../ShippingZoneWarehouses/ShippingZoneWarehouses.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx index d3b09808d..10d454f4a 100644 --- a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -61,7 +61,9 @@ export const ShippingZoneWarehouses: React.FC = pr "Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes." })} label={intl.formatMessage({ - defaultMessage: "Warehouse" + defaultMessage: "Warehouse", + description: "autocomplete select label", + id: "shippingZoneWarehouses.autocomplete.label" })} loading={loading} name="warehouse" @@ -71,11 +73,6 @@ export const ShippingZoneWarehouses: React.FC = pr defaultMessage: "Select Warehouse", description: "input placeholder" })} - label={intl.formatMessage({ - defaultMessage: "Warehouse", - description:"autocomplete select label" - id: "shippingZoneWarehouses.autocomplete.label" - })} value={data.warehouses} /> From 97ffc077385d46e61111c936d0f34e3b45d3cdfe Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 18 Mar 2020 18:24:55 +0100 Subject: [PATCH 26/88] Make warehouse and shipping work --- .../MultiAutocompleteSelectField.tsx | 4 ++- .../MultiAutocompleteSelectFieldContent.tsx | 19 +++++++++++--- .../SingleAutocompleteSelectFieldContent.tsx | 2 +- .../ShippingZoneAddWarehouseDialog.tsx | 6 ++--- .../ShippingZoneDetailsPage.tsx | 2 +- .../WarehouseCreatePage.tsx | 12 +++------ .../WarehouseDetailsPage.tsx | 16 ++++-------- .../WarehouseInfo/WarehouseInfo.tsx | 9 ++++--- .../WarehouseDetails/WarehouseDetails.tsx | 25 +++++++++++-------- 9 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx index 27cb334c1..d7aab9a97 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectField.tsx @@ -72,7 +72,7 @@ const useStyles = makeStyles( export interface MultiAutocompleteSelectFieldProps extends Partial { - add: MultiAutocompleteActionType; + add?: MultiAutocompleteActionType; allowCustomValues?: boolean; displayValues: MultiAutocompleteChoiceType[]; error?: boolean; @@ -93,6 +93,7 @@ const DebounceAutocomplete: React.ComponentType = props => { const { + add, allowCustomValues, choices, displayValues, @@ -131,6 +132,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC ""} > {({ + closeMenu, getInputProps, getItemProps, isOpen, diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx index d414b8f3f..31d3f7a30 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx @@ -34,7 +34,7 @@ export interface MultiAutocompleteChoiceType { } export interface MultiAutocompleteSelectFieldContentProps extends Partial { - add: MultiAutocompleteActionType; + add?: MultiAutocompleteActionType; choices: MultiAutocompleteChoiceType[]; displayCustomValue: boolean; displayValues: MultiAutocompleteChoiceType[]; @@ -45,6 +45,14 @@ export interface MultiAutocompleteSelectFieldContentProps const useStyles = makeStyles( theme => ({ + add: { + background: theme.palette.background.default, + border: `1px solid ${theme.palette.divider}`, + borderRadius: "100%", + height: 24, + marginRight: theme.spacing(), + width: 24 + }, addIcon: { height: 24, margin: 9, @@ -106,6 +114,7 @@ const useStyles = makeStyles( gridColumnGap: theme.spacing(1), gridTemplateColumns: "30px 1fr", height: "auto", + marginBottom: theme.spacing(0.5), padding: 0, whiteSpace: "normal" }, @@ -136,10 +145,11 @@ const useStyles = makeStyles( function getChoiceIndex( index: number, displayValues: MultiAutocompleteChoiceType[], - displayCustomValue: boolean + displayCustomValue: boolean, + add: boolean ) { let choiceIndex = index; - if (displayCustomValue) { + if (add || displayCustomValue) { choiceIndex += 2; } if (displayValues.length > 0) { @@ -258,7 +268,8 @@ const MultiAutocompleteSelectFieldContent: React.FC { - add: SingleAutocompleteActionType; + add?: SingleAutocompleteActionType; choices: SingleAutocompleteChoiceType[]; displayCustomValue: boolean; emptyOption: boolean; diff --git a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx index 632fe73fc..fcf7d038c 100644 --- a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx +++ b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx @@ -104,8 +104,8 @@ const ShippingZoneAddWarehouseDialog: React.FC -
- {({ change, data, errors: formErrors }) => { + + {({ change, data }) => { const handleCountrySelect = createSingleAutocompleteSelectHandler( change, setCountryDisplayName, @@ -132,7 +132,7 @@ const ShippingZoneAddWarehouseDialog: React.FC diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index 1dc6ed09e..e10f3cba2 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -89,7 +89,7 @@ const ShippingZoneDetailsPage: React.FC = ({ warehouses: shippingZone?.warehouses.map(warehouse => warehouse.id) || [] }; const [warehouseDisplayValues, setWarehouseDisplayValues] = useStateFromProps( - shippingZone?.warehouses.map(warehouseToChoice) + shippingZone?.warehouses.map(warehouseToChoice) || [] ); const warehouseChoices = warehouses.map(warehouseToChoice); diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx index ec50f6a61..61a25f254 100644 --- a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx @@ -47,7 +47,7 @@ const initialForm: WarehouseCreatePageFormData = { const WarehouseCreatePage: React.FC = ({ countries, disabled, - errors: apiErrors, + errors, saveButtonBarState, onBack, onSubmit @@ -61,12 +61,8 @@ const WarehouseCreatePage: React.FC = ({ } = useAddressValidation(onSubmit); return ( - - {({ change, data, errors, submit }) => { + + {({ change, data, submit }) => { const countryChoices = mapCountriesToChoices(countries); const handleCountryChange = createSingleAutocompleteSelectHandler( change, @@ -99,7 +95,7 @@ const WarehouseCreatePage: React.FC = ({ data={data} disabled={disabled} displayCountry={displayCountry} - errors={errors} + errors={[...errors, ...validationErrors]} header={intl.formatMessage({ defaultMessage: "Address Information", description: "warehouse" diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx index 148dda244..d15bf3836 100644 --- a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx @@ -42,7 +42,7 @@ export interface WarehouseDetailsPageProps { const WarehouseDetailsPage: React.FC = ({ countries, disabled, - errors: apiErrors, + errors, saveButtonBarState, warehouse, onBack, @@ -73,12 +73,8 @@ const WarehouseDetailsPage: React.FC = ({ }; return ( - - {({ change, data, errors, submit }) => { + + {({ change, data, submit }) => { const countryChoices = mapCountriesToChoices(countries); const handleCountryChange = createSingleAutocompleteSelectHandler( change, @@ -106,7 +102,7 @@ const WarehouseDetailsPage: React.FC = ({ data={data} disabled={disabled} displayCountry={displayCountry} - errors={errors} + errors={[...errors, ...validationErrors]} header={intl.formatMessage({ defaultMessage: "Address Information", description: "warehouse" @@ -117,9 +113,7 @@ const WarehouseDetailsPage: React.FC = ({
- warehouse.shippingZones.edges.map(edge => edge.node) - )} + zones={warehouse?.shippingZones?.edges.map(edge => edge.node)} onShippingZoneClick={onShippingZoneClick} />
diff --git a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx index 7b31cc2ea..fdc51a261 100644 --- a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx +++ b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx @@ -7,12 +7,13 @@ import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { commonMessages } from "@saleor/intl"; import { FormChange } from "@saleor/hooks/useForm"; -import { FormErrors } from "@saleor/types"; +import { UserError } from "@saleor/types"; +import { getFieldError } from "@saleor/utils/errors"; export interface WarehouseInfoProps { data: Record<"name", string>; disabled: boolean; - errors: FormErrors<"name">; + errors: UserError[]; onChange: FormChange; } @@ -32,9 +33,9 @@ const WarehouseInfo: React.FC = ({ = ({ id, params }) => { const shop = useShop(); const { data, loading } = useWarehouseDetails({ displayLoader: true, - require: ["warehouse"], variables: { id } }); const [updateWarehouse, updateWarehouseOpts] = useWarehouseUpdate({ @@ -65,18 +69,19 @@ const WarehouseDetails: React.FC = ({ id, params }) => { params ); + if (data?.warehouse === null) { + return navigate(warehouseListUrl())} />; + } + return ( <> - data.warehouse.name)} /> + shop.countries, [])} + countries={shop?.countries || []} disabled={loading || updateWarehouseOpts.loading} - errors={maybe( - () => updateWarehouseOpts.data.updateWarehouse.errors, - [] - )} + errors={updateWarehouseOpts.data?.updateWarehouse.errors || []} saveButtonBarState={updateWarehouseTransitionState} - warehouse={maybe(() => data.warehouse)} + warehouse={data?.warehouse} onBack={() => navigate(warehouseListUrl())} onDelete={() => openModal("delete")} onShippingZoneClick={id => navigate(shippingZoneUrl(id))} @@ -103,7 +108,7 @@ const WarehouseDetails: React.FC = ({ id, params }) => { /> data.warehouse.name)} + name={getStringOrPlaceholder(data?.warehouse?.name)} onClose={closeModal} onConfirm={() => deleteWarehouse({ From 1afafa6732c0ad088d78415d002de4f375eee9be Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 18 Mar 2020 18:29:20 +0100 Subject: [PATCH 27/88] Fix minor bug causing form not to reload --- .../MultiAutocompleteSelectFieldContent.tsx | 2 +- .../ShippingZoneWarehouses/ShippingZoneWarehouses.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx index 31d3f7a30..9bc21a39a 100644 --- a/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx +++ b/src/components/MultiAutocompleteSelectField/MultiAutocompleteSelectFieldContent.tsx @@ -50,7 +50,7 @@ const useStyles = makeStyles( border: `1px solid ${theme.palette.divider}`, borderRadius: "100%", height: 24, - marginRight: theme.spacing(), + margin: theme.spacing(), width: 24 }, addIcon: { diff --git a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx index 10d454f4a..a6351feed 100644 --- a/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx +++ b/src/shipping/components/ShippingZoneWarehouses/ShippingZoneWarehouses.tsx @@ -66,7 +66,7 @@ export const ShippingZoneWarehouses: React.FC = pr id: "shippingZoneWarehouses.autocomplete.label" })} loading={loading} - name="warehouse" + name="warehouses" onChange={onChange} onFetchMore={onFetchMore} placeholder={intl.formatMessage({ From 490e2a2baa5cdf368a22aede10d627ed7f073858 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 19 Mar 2020 10:53:00 +0100 Subject: [PATCH 28/88] Fix typo --- src/shipping/mutations.ts | 2 +- src/shipping/views/ShippingZoneDetails/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shipping/mutations.ts b/src/shipping/mutations.ts index 6408f1a3d..c9e32169a 100644 --- a/src/shipping/mutations.ts +++ b/src/shipping/mutations.ts @@ -239,7 +239,7 @@ const assignShippingZoneToWarehouse = gql` } } `; -export const useAassignShippingZoneToWarehouse = makeMutation< +export const useAssignShippingZoneToWarehouse = makeMutation< AssignShippingZoneToWarehouse, AssignShippingZoneToWarehouseVariables >(assignShippingZoneToWarehouse); diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 90fc9378e..b91810aee 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -14,7 +14,7 @@ import { useShippingRateDelete, useShippingZoneDelete, useShippingZoneUpdate, - useAassignShippingZoneToWarehouse + useAssignShippingZoneToWarehouse } from "@saleor/shipping/mutations"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import ShippingZoneRateDialog from "@saleor/shipping/components/ShippingZoneRateDialog"; @@ -63,7 +63,7 @@ const ShippingZoneDetails: React.FC = ({ } ); - const [assignToWarehouse] = useAassignShippingZoneToWarehouse({}); + const [assignToWarehouse] = useAssignShippingZoneToWarehouse({}); const { data, loading } = useShippingZone({ displayLoader: true, From 220f77c20a74ff064211adeac370469bef68d0d7 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 19 Mar 2020 13:15:47 +0100 Subject: [PATCH 29/88] Update types --- src/products/queries.ts | 33 ++++++++++--------- src/products/types/Product.ts | 12 +++---- src/products/types/ProductCreate.ts | 12 +++---- src/products/types/ProductDetails.ts | 12 +++---- src/products/types/ProductImageCreate.ts | 12 +++---- src/products/types/ProductImageUpdate.ts | 12 +++---- src/products/types/ProductUpdate.ts | 12 +++---- src/products/types/ProductVariant.ts | 13 +++++--- src/products/types/ProductVariantDetails.ts | 13 +++++--- src/products/types/SimpleProductUpdate.ts | 25 +++++++------- src/products/types/StockFragment.ts | 2 -- src/products/types/VariantCreate.ts | 13 +++++--- src/products/types/VariantImageAssign.ts | 13 +++++--- src/products/types/VariantImageUnassign.ts | 13 +++++--- src/products/types/VariantUpdate.ts | 13 +++++--- .../types/AssignShippingZoneToWarehouse.ts | 4 +-- .../types/UnassignShippingZoneToWarehouse.ts | 4 +-- src/warehouses/types/WarehouseCreate.ts | 2 +- src/warehouses/types/WarehouseDelete.ts | 2 +- src/warehouses/types/WarehouseUpdate.ts | 2 +- 20 files changed, 115 insertions(+), 109 deletions(-) diff --git a/src/products/queries.ts b/src/products/queries.ts index 1e292428b..a4b792488 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -28,6 +28,17 @@ import { InitialProductFilterDataVariables } from "./types/InitialProductFilterData"; +export const stockFragment = gql` + fragment StockFragment on Stock { + id + quantity + warehouse { + id + name + } + } +`; + export const fragmentMoney = gql` fragment Money on Money { amount @@ -66,6 +77,7 @@ export const productFragment = gql` export const productFragmentDetails = gql` ${fragmentProductImage} ${fragmentMoney} + ${stockFragment} fragment Product on Product { id name @@ -143,16 +155,8 @@ export const productFragmentDetails = gql` ...Money } margin - quantity - quantityAllocated - stockQuantity - stock { - id - quantity - warehouse { - id - name - } + stocks { + ...StockFragment } } productType { @@ -160,13 +164,13 @@ export const productFragmentDetails = gql` name hasVariants } - url } `; export const fragmentVariant = gql` ${fragmentMoney} ${fragmentProductImage} + ${stockFragment} fragment ProductVariant on ProductVariant { id attributes { @@ -218,11 +222,8 @@ export const fragmentVariant = gql` } } sku - quantity - quantityAllocated - stock { - id - quantity + stocks { + ...StockFragment } } `; diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index 0dfd6a748..66711a57d 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -127,17 +127,17 @@ export interface Product_variants_priceOverride { currency: string; } -export interface Product_variants_stock_warehouse { +export interface Product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface Product_variants_stock { +export interface Product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: Product_variants_stock_warehouse; + warehouse: Product_variants_stocks_warehouse; } export interface Product_variants { @@ -147,10 +147,7 @@ export interface Product_variants { name: string; priceOverride: Product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (Product_variants_stock | null)[] | null; + stocks: (Product_variants_stocks | null)[] | null; } export interface Product_productType { @@ -181,5 +178,4 @@ export interface Product { images: (Product_images | null)[] | null; variants: (Product_variants | null)[] | null; productType: Product_productType; - url: string; } diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index e22239d5a..3782b4045 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -133,17 +133,17 @@ export interface ProductCreate_productCreate_product_variants_priceOverride { currency: string; } -export interface ProductCreate_productCreate_product_variants_stock_warehouse { +export interface ProductCreate_productCreate_product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface ProductCreate_productCreate_product_variants_stock { +export interface ProductCreate_productCreate_product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: ProductCreate_productCreate_product_variants_stock_warehouse; + warehouse: ProductCreate_productCreate_product_variants_stocks_warehouse; } export interface ProductCreate_productCreate_product_variants { @@ -153,10 +153,7 @@ export interface ProductCreate_productCreate_product_variants { name: string; priceOverride: ProductCreate_productCreate_product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (ProductCreate_productCreate_product_variants_stock | null)[] | null; + stocks: (ProductCreate_productCreate_product_variants_stocks | null)[] | null; } export interface ProductCreate_productCreate_product_productType { @@ -187,7 +184,6 @@ export interface ProductCreate_productCreate_product { images: (ProductCreate_productCreate_product_images | null)[] | null; variants: (ProductCreate_productCreate_product_variants | null)[] | null; productType: ProductCreate_productCreate_product_productType; - url: string; } export interface ProductCreate_productCreate { diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index a880cdccc..89ea83b2f 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -127,17 +127,17 @@ export interface ProductDetails_product_variants_priceOverride { currency: string; } -export interface ProductDetails_product_variants_stock_warehouse { +export interface ProductDetails_product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface ProductDetails_product_variants_stock { +export interface ProductDetails_product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: ProductDetails_product_variants_stock_warehouse; + warehouse: ProductDetails_product_variants_stocks_warehouse; } export interface ProductDetails_product_variants { @@ -147,10 +147,7 @@ export interface ProductDetails_product_variants { name: string; priceOverride: ProductDetails_product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (ProductDetails_product_variants_stock | null)[] | null; + stocks: (ProductDetails_product_variants_stocks | null)[] | null; } export interface ProductDetails_product_productType_variantAttributes_values { @@ -196,7 +193,6 @@ export interface ProductDetails_product { images: (ProductDetails_product_images | null)[] | null; variants: (ProductDetails_product_variants | null)[] | null; productType: ProductDetails_product_productType; - url: string; } export interface ProductDetails { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index 8efec0618..f56195a1a 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -133,17 +133,17 @@ export interface ProductImageCreate_productImageCreate_product_variants_priceOve currency: string; } -export interface ProductImageCreate_productImageCreate_product_variants_stock_warehouse { +export interface ProductImageCreate_productImageCreate_product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface ProductImageCreate_productImageCreate_product_variants_stock { +export interface ProductImageCreate_productImageCreate_product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: ProductImageCreate_productImageCreate_product_variants_stock_warehouse; + warehouse: ProductImageCreate_productImageCreate_product_variants_stocks_warehouse; } export interface ProductImageCreate_productImageCreate_product_variants { @@ -153,10 +153,7 @@ export interface ProductImageCreate_productImageCreate_product_variants { name: string; priceOverride: ProductImageCreate_productImageCreate_product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (ProductImageCreate_productImageCreate_product_variants_stock | null)[] | null; + stocks: (ProductImageCreate_productImageCreate_product_variants_stocks | null)[] | null; } export interface ProductImageCreate_productImageCreate_product_productType { @@ -187,7 +184,6 @@ export interface ProductImageCreate_productImageCreate_product { images: (ProductImageCreate_productImageCreate_product_images | null)[] | null; variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null; productType: ProductImageCreate_productImageCreate_product_productType; - url: string; } export interface ProductImageCreate_productImageCreate { diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index c98fe2909..2f4d3a773 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -133,17 +133,17 @@ export interface ProductImageUpdate_productImageUpdate_product_variants_priceOve currency: string; } -export interface ProductImageUpdate_productImageUpdate_product_variants_stock_warehouse { +export interface ProductImageUpdate_productImageUpdate_product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface ProductImageUpdate_productImageUpdate_product_variants_stock { +export interface ProductImageUpdate_productImageUpdate_product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: ProductImageUpdate_productImageUpdate_product_variants_stock_warehouse; + warehouse: ProductImageUpdate_productImageUpdate_product_variants_stocks_warehouse; } export interface ProductImageUpdate_productImageUpdate_product_variants { @@ -153,10 +153,7 @@ export interface ProductImageUpdate_productImageUpdate_product_variants { name: string; priceOverride: ProductImageUpdate_productImageUpdate_product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (ProductImageUpdate_productImageUpdate_product_variants_stock | null)[] | null; + stocks: (ProductImageUpdate_productImageUpdate_product_variants_stocks | null)[] | null; } export interface ProductImageUpdate_productImageUpdate_product_productType { @@ -187,7 +184,6 @@ export interface ProductImageUpdate_productImageUpdate_product { images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null; variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null; productType: ProductImageUpdate_productImageUpdate_product_productType; - url: string; } export interface ProductImageUpdate_productImageUpdate { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 3fab87f99..e62b1e88d 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -133,17 +133,17 @@ export interface ProductUpdate_productUpdate_product_variants_priceOverride { currency: string; } -export interface ProductUpdate_productUpdate_product_variants_stock_warehouse { +export interface ProductUpdate_productUpdate_product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface ProductUpdate_productUpdate_product_variants_stock { +export interface ProductUpdate_productUpdate_product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: ProductUpdate_productUpdate_product_variants_stock_warehouse; + warehouse: ProductUpdate_productUpdate_product_variants_stocks_warehouse; } export interface ProductUpdate_productUpdate_product_variants { @@ -153,10 +153,7 @@ export interface ProductUpdate_productUpdate_product_variants { name: string; priceOverride: ProductUpdate_productUpdate_product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (ProductUpdate_productUpdate_product_variants_stock | null)[] | null; + stocks: (ProductUpdate_productUpdate_product_variants_stocks | null)[] | null; } export interface ProductUpdate_productUpdate_product_productType { @@ -187,7 +184,6 @@ export interface ProductUpdate_productUpdate_product { images: (ProductUpdate_productUpdate_product_images | null)[] | null; variants: (ProductUpdate_productUpdate_product_variants | null)[] | null; productType: ProductUpdate_productUpdate_product_productType; - url: string; } export interface ProductUpdate_productUpdate { diff --git a/src/products/types/ProductVariant.ts b/src/products/types/ProductVariant.ts index 14f5aa54f..a2dee190f 100644 --- a/src/products/types/ProductVariant.ts +++ b/src/products/types/ProductVariant.ts @@ -89,10 +89,17 @@ export interface ProductVariant_product { variants: (ProductVariant_product_variants | null)[] | null; } -export interface ProductVariant_stock { +export interface ProductVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface ProductVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductVariant_stocks_warehouse; } export interface ProductVariant { @@ -105,7 +112,5 @@ export interface ProductVariant { priceOverride: ProductVariant_priceOverride | null; product: ProductVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (ProductVariant_stock | null)[] | null; + stocks: (ProductVariant_stocks | null)[] | null; } diff --git a/src/products/types/ProductVariantDetails.ts b/src/products/types/ProductVariantDetails.ts index e4c98a234..441436ec9 100644 --- a/src/products/types/ProductVariantDetails.ts +++ b/src/products/types/ProductVariantDetails.ts @@ -89,10 +89,17 @@ export interface ProductVariantDetails_productVariant_product { variants: (ProductVariantDetails_productVariant_product_variants | null)[] | null; } -export interface ProductVariantDetails_productVariant_stock { +export interface ProductVariantDetails_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface ProductVariantDetails_productVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: ProductVariantDetails_productVariant_stocks_warehouse; } export interface ProductVariantDetails_productVariant { @@ -105,9 +112,7 @@ export interface ProductVariantDetails_productVariant { priceOverride: ProductVariantDetails_productVariant_priceOverride | null; product: ProductVariantDetails_productVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (ProductVariantDetails_productVariant_stock | null)[] | null; + stocks: (ProductVariantDetails_productVariant_stocks | null)[] | null; } export interface ProductVariantDetails { diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index c7ffb7b9f..90aaf877f 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -133,17 +133,17 @@ export interface SimpleProductUpdate_productUpdate_product_variants_priceOverrid currency: string; } -export interface SimpleProductUpdate_productUpdate_product_variants_stock_warehouse { +export interface SimpleProductUpdate_productUpdate_product_variants_stocks_warehouse { __typename: "Warehouse"; id: string; name: string; } -export interface SimpleProductUpdate_productUpdate_product_variants_stock { +export interface SimpleProductUpdate_productUpdate_product_variants_stocks { __typename: "Stock"; id: string; quantity: number; - warehouse: SimpleProductUpdate_productUpdate_product_variants_stock_warehouse; + warehouse: SimpleProductUpdate_productUpdate_product_variants_stocks_warehouse; } export interface SimpleProductUpdate_productUpdate_product_variants { @@ -153,10 +153,7 @@ export interface SimpleProductUpdate_productUpdate_product_variants { name: string; priceOverride: SimpleProductUpdate_productUpdate_product_variants_priceOverride | null; margin: number | null; - quantity: number; - quantityAllocated: number | null; - stockQuantity: number; - stock: (SimpleProductUpdate_productUpdate_product_variants_stock | null)[] | null; + stocks: (SimpleProductUpdate_productUpdate_product_variants_stocks | null)[] | null; } export interface SimpleProductUpdate_productUpdate_product_productType { @@ -187,7 +184,6 @@ export interface SimpleProductUpdate_productUpdate_product { images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null; variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null; productType: SimpleProductUpdate_productUpdate_product_productType; - url: string; } export interface SimpleProductUpdate_productUpdate { @@ -285,10 +281,17 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant_product variants: (SimpleProductUpdate_productVariantUpdate_productVariant_product_variants | null)[] | null; } -export interface SimpleProductUpdate_productVariantUpdate_productVariant_stock { +export interface SimpleProductUpdate_productVariantUpdate_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface SimpleProductUpdate_productVariantUpdate_productVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: SimpleProductUpdate_productVariantUpdate_productVariant_stocks_warehouse; } export interface SimpleProductUpdate_productVariantUpdate_productVariant { @@ -301,9 +304,7 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant { priceOverride: SimpleProductUpdate_productVariantUpdate_productVariant_priceOverride | null; product: SimpleProductUpdate_productVariantUpdate_productVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (SimpleProductUpdate_productVariantUpdate_productVariant_stock | null)[] | null; + stocks: (SimpleProductUpdate_productVariantUpdate_productVariant_stocks | null)[] | null; } export interface SimpleProductUpdate_productVariantUpdate { diff --git a/src/products/types/StockFragment.ts b/src/products/types/StockFragment.ts index 7aba2f87d..bdd9674a3 100644 --- a/src/products/types/StockFragment.ts +++ b/src/products/types/StockFragment.ts @@ -16,7 +16,5 @@ export interface StockFragment { __typename: "Stock"; id: string; quantity: number; - quantityAllocated: number; - stockQuantity: number; warehouse: StockFragment_warehouse; } diff --git a/src/products/types/VariantCreate.ts b/src/products/types/VariantCreate.ts index ae04aee61..dc2ddc181 100644 --- a/src/products/types/VariantCreate.ts +++ b/src/products/types/VariantCreate.ts @@ -97,10 +97,17 @@ export interface VariantCreate_productVariantCreate_productVariant_product { variants: (VariantCreate_productVariantCreate_productVariant_product_variants | null)[] | null; } -export interface VariantCreate_productVariantCreate_productVariant_stock { +export interface VariantCreate_productVariantCreate_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface VariantCreate_productVariantCreate_productVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: VariantCreate_productVariantCreate_productVariant_stocks_warehouse; } export interface VariantCreate_productVariantCreate_productVariant { @@ -113,9 +120,7 @@ export interface VariantCreate_productVariantCreate_productVariant { priceOverride: VariantCreate_productVariantCreate_productVariant_priceOverride | null; product: VariantCreate_productVariantCreate_productVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (VariantCreate_productVariantCreate_productVariant_stock | null)[] | null; + stocks: (VariantCreate_productVariantCreate_productVariant_stocks | null)[] | null; } export interface VariantCreate_productVariantCreate { diff --git a/src/products/types/VariantImageAssign.ts b/src/products/types/VariantImageAssign.ts index da34c19e2..a0edcd624 100644 --- a/src/products/types/VariantImageAssign.ts +++ b/src/products/types/VariantImageAssign.ts @@ -97,10 +97,17 @@ export interface VariantImageAssign_variantImageAssign_productVariant_product { variants: (VariantImageAssign_variantImageAssign_productVariant_product_variants | null)[] | null; } -export interface VariantImageAssign_variantImageAssign_productVariant_stock { +export interface VariantImageAssign_variantImageAssign_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface VariantImageAssign_variantImageAssign_productVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: VariantImageAssign_variantImageAssign_productVariant_stocks_warehouse; } export interface VariantImageAssign_variantImageAssign_productVariant { @@ -113,9 +120,7 @@ export interface VariantImageAssign_variantImageAssign_productVariant { priceOverride: VariantImageAssign_variantImageAssign_productVariant_priceOverride | null; product: VariantImageAssign_variantImageAssign_productVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (VariantImageAssign_variantImageAssign_productVariant_stock | null)[] | null; + stocks: (VariantImageAssign_variantImageAssign_productVariant_stocks | null)[] | null; } export interface VariantImageAssign_variantImageAssign { diff --git a/src/products/types/VariantImageUnassign.ts b/src/products/types/VariantImageUnassign.ts index 46a910dd3..0d532d910 100644 --- a/src/products/types/VariantImageUnassign.ts +++ b/src/products/types/VariantImageUnassign.ts @@ -97,10 +97,17 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant_produc variants: (VariantImageUnassign_variantImageUnassign_productVariant_product_variants | null)[] | null; } -export interface VariantImageUnassign_variantImageUnassign_productVariant_stock { +export interface VariantImageUnassign_variantImageUnassign_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface VariantImageUnassign_variantImageUnassign_productVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: VariantImageUnassign_variantImageUnassign_productVariant_stocks_warehouse; } export interface VariantImageUnassign_variantImageUnassign_productVariant { @@ -113,9 +120,7 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant { priceOverride: VariantImageUnassign_variantImageUnassign_productVariant_priceOverride | null; product: VariantImageUnassign_variantImageUnassign_productVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (VariantImageUnassign_variantImageUnassign_productVariant_stock | null)[] | null; + stocks: (VariantImageUnassign_variantImageUnassign_productVariant_stocks | null)[] | null; } export interface VariantImageUnassign_variantImageUnassign { diff --git a/src/products/types/VariantUpdate.ts b/src/products/types/VariantUpdate.ts index e2e98e600..cd7b5644e 100644 --- a/src/products/types/VariantUpdate.ts +++ b/src/products/types/VariantUpdate.ts @@ -97,10 +97,17 @@ export interface VariantUpdate_productVariantUpdate_productVariant_product { variants: (VariantUpdate_productVariantUpdate_productVariant_product_variants | null)[] | null; } -export interface VariantUpdate_productVariantUpdate_productVariant_stock { +export interface VariantUpdate_productVariantUpdate_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface VariantUpdate_productVariantUpdate_productVariant_stocks { __typename: "Stock"; id: string; quantity: number; + warehouse: VariantUpdate_productVariantUpdate_productVariant_stocks_warehouse; } export interface VariantUpdate_productVariantUpdate_productVariant { @@ -113,9 +120,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant { priceOverride: VariantUpdate_productVariantUpdate_productVariant_priceOverride | null; product: VariantUpdate_productVariantUpdate_productVariant_product; sku: string; - quantity: number; - quantityAllocated: number | null; - stock: (VariantUpdate_productVariantUpdate_productVariant_stock | null)[] | null; + stocks: (VariantUpdate_productVariantUpdate_productVariant_stocks | null)[] | null; } export interface VariantUpdate_productVariantUpdate { diff --git a/src/shipping/types/AssignShippingZoneToWarehouse.ts b/src/shipping/types/AssignShippingZoneToWarehouse.ts index 378d365c7..2f8b1789a 100644 --- a/src/shipping/types/AssignShippingZoneToWarehouse.ts +++ b/src/shipping/types/AssignShippingZoneToWarehouse.ts @@ -10,13 +10,13 @@ import { WarehouseErrorCode } from "./../../types/globalTypes"; export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors { __typename: "WarehouseError"; - code: WarehouseErrorCode | null; + code: WarehouseErrorCode; field: string | null; } export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone { __typename: "WarehouseShippingZoneAssign"; - warehouseErrors: AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors[] | null; + warehouseErrors: AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors[]; } export interface AssignShippingZoneToWarehouse { diff --git a/src/shipping/types/UnassignShippingZoneToWarehouse.ts b/src/shipping/types/UnassignShippingZoneToWarehouse.ts index a8f8e1721..3004a8356 100644 --- a/src/shipping/types/UnassignShippingZoneToWarehouse.ts +++ b/src/shipping/types/UnassignShippingZoneToWarehouse.ts @@ -10,13 +10,13 @@ import { WarehouseErrorCode } from "./../../types/globalTypes"; export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors { __typename: "WarehouseError"; - code: WarehouseErrorCode | null; + code: WarehouseErrorCode; field: string | null; } export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone { __typename: "WarehouseShippingZoneUnassign"; - warehouseErrors: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors[] | null; + warehouseErrors: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors[]; } export interface UnassignShippingZoneToWarehouse { diff --git a/src/warehouses/types/WarehouseCreate.ts b/src/warehouses/types/WarehouseCreate.ts index 5caeb87b9..9973edd90 100644 --- a/src/warehouses/types/WarehouseCreate.ts +++ b/src/warehouses/types/WarehouseCreate.ts @@ -62,7 +62,7 @@ export interface WarehouseCreate_createWarehouse_warehouse { export interface WarehouseCreate_createWarehouse { __typename: "WarehouseCreate"; - errors: WarehouseCreate_createWarehouse_errors[] | null; + errors: WarehouseCreate_createWarehouse_errors[]; warehouse: WarehouseCreate_createWarehouse_warehouse | null; } diff --git a/src/warehouses/types/WarehouseDelete.ts b/src/warehouses/types/WarehouseDelete.ts index 0e2aa5efa..82bfc25da 100644 --- a/src/warehouses/types/WarehouseDelete.ts +++ b/src/warehouses/types/WarehouseDelete.ts @@ -14,7 +14,7 @@ export interface WarehouseDelete_deleteWarehouse_errors { export interface WarehouseDelete_deleteWarehouse { __typename: "WarehouseDelete"; - errors: WarehouseDelete_deleteWarehouse_errors[] | null; + errors: WarehouseDelete_deleteWarehouse_errors[]; } export interface WarehouseDelete { diff --git a/src/warehouses/types/WarehouseUpdate.ts b/src/warehouses/types/WarehouseUpdate.ts index 345f6f9fb..6706227b2 100644 --- a/src/warehouses/types/WarehouseUpdate.ts +++ b/src/warehouses/types/WarehouseUpdate.ts @@ -62,7 +62,7 @@ export interface WarehouseUpdate_updateWarehouse_warehouse { export interface WarehouseUpdate_updateWarehouse { __typename: "WarehouseUpdate"; - errors: WarehouseUpdate_updateWarehouse_errors[] | null; + errors: WarehouseUpdate_updateWarehouse_errors[]; warehouse: WarehouseUpdate_updateWarehouse_warehouse | null; } From 0805ff052da0f6e96456d38df9a1beaf20410d26 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 19 Mar 2020 13:44:54 +0100 Subject: [PATCH 30/88] Fix assigning shipping zone to warehouse --- .../SingleAutocompleteSelectFieldContent.tsx | 8 +-- .../ShippingZoneDetailsPage.tsx | 47 +++++++++-------- .../ShippingZoneWarehouses.tsx | 20 ++++---- src/shipping/mutations.ts | 32 ++---------- .../types/AssignShippingZoneToWarehouse.ts | 4 +- .../views/ShippingZoneDetails/index.tsx | 50 ++++++++++++++----- src/warehouses/mutations.ts | 7 +++ .../types/WarehouseErrorFragment.ts | 15 ++++++ 8 files changed, 103 insertions(+), 80 deletions(-) create mode 100644 src/warehouses/types/WarehouseErrorFragment.ts diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx index 0029b0f1a..1375deebf 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx @@ -110,13 +110,14 @@ const useStyles = makeStyles( function getChoiceIndex( index: number, emptyValue: boolean, - customValue: boolean + customValue: boolean, + add: boolean ) { let choiceIndex = index; if (emptyValue) { choiceIndex += 1; } - if (customValue) { + if (customValue || add) { choiceIndex += 2; } @@ -222,7 +223,8 @@ const SingleAutocompleteSelectFieldContent: React.FC -): MultiAutocompleteChoiceType { +): SingleAutocompleteChoiceType { return { label: warehouse.name, value: warehouse.id @@ -86,10 +86,10 @@ const ShippingZoneDetailsPage: React.FC = ({ const initialForm: FormData = { name: shippingZone?.name || "", - warehouses: shippingZone?.warehouses.map(warehouse => warehouse.id) || [] + warehouse: shippingZone?.warehouses[0]?.id || null }; - const [warehouseDisplayValues, setWarehouseDisplayValues] = useStateFromProps( - shippingZone?.warehouses.map(warehouseToChoice) || [] + const [warehouseDisplayValue, setWarehouseDisplayValue] = useStateFromProps( + shippingZone?.warehouses[0]?.name || "" ); const warehouseChoices = warehouses.map(warehouseToChoice); @@ -97,10 +97,9 @@ const ShippingZoneDetailsPage: React.FC = ({ return ( {({ change, data, hasChanged, submit }) => { - const handleWarehouseChange = createMultiAutocompleteSelectHandler( + const handleWarehouseChange = createSingleAutocompleteSelectHandler( change, - setWarehouseDisplayValues, - warehouseDisplayValues, + setWarehouseDisplayValue, warehouseChoices ); @@ -122,18 +121,18 @@ const ShippingZoneDetailsPage: React.FC = ({ - shippingZone.default - ? intl.formatMessage({ - defaultMessage: - "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" - }) - : intl.formatMessage({ - defaultMessage: - "Currently, there are no countries assigned to this shipping zone" - }), - "..." + emptyText={getStringOrPlaceholder( + shippingZone?.default === undefined + ? undefined + : shippingZone.default + ? intl.formatMessage({ + defaultMessage: + "This is default shipping zone, which means that it covers all of the countries which are not assigned to other shipping zones" + }) + : intl.formatMessage({ + defaultMessage: + "Currently, there are no countries assigned to this shipping zone" + }) )} onCountryAssign={onCountryAdd} onCountryUnassign={onCountryRemove} @@ -167,7 +166,7 @@ const ShippingZoneDetailsPage: React.FC = ({
void; } @@ -44,7 +44,7 @@ export const ShippingZoneWarehouses: React.FC = pr })} /> - = pr onClick: onWarehouseAdd }} choices={warehouses} - displayValues={displayValue} + displayValue={displayValue} fetchChoices={onSearchChange} hasMore={hasMore} helperText={intl.formatMessage({ @@ -66,14 +66,14 @@ export const ShippingZoneWarehouses: React.FC = pr id: "shippingZoneWarehouses.autocomplete.label" })} loading={loading} - name="warehouses" + name="warehouse" onChange={onChange} onFetchMore={onFetchMore} placeholder={intl.formatMessage({ defaultMessage: "Select Warehouse", description: "input placeholder" })} - value={data.warehouses} + value={data.warehouse} /> diff --git a/src/shipping/mutations.ts b/src/shipping/mutations.ts index c9e32169a..b5430e640 100644 --- a/src/shipping/mutations.ts +++ b/src/shipping/mutations.ts @@ -1,6 +1,7 @@ import gql from "graphql-tag"; import makeMutation from "@saleor/hooks/makeMutation"; +import { warehouseErrorFragment } from "@saleor/warehouses/mutations"; import { countryFragment } from "../taxes/queries"; import { shippingMethodFragment, shippingZoneDetailsFragment } from "./queries"; import { @@ -43,10 +44,6 @@ import { AssignShippingZoneToWarehouse, AssignShippingZoneToWarehouseVariables } from "./types/AssignShippingZoneToWarehouse"; -import { - UnassignShippingZoneToWarehouse, - UnassignShippingZoneToWarehouseVariables -} from "./types/UnassignShippingZoneToWarehouse"; export const shippingErrorFragment = gql` fragment ShippingErrorFragment on ShippingError { @@ -224,6 +221,7 @@ export const useShippingRateBulkDelete = makeMutation< >(bulkDeleteShippingRate); const assignShippingZoneToWarehouse = gql` + ${warehouseErrorFragment} mutation AssignShippingZoneToWarehouse( $warehouseId: ID! $shippingZoneId: ID! @@ -232,9 +230,8 @@ const assignShippingZoneToWarehouse = gql` id: $warehouseId shippingZoneIds: [$shippingZoneId] ) { - warehouseErrors { - code - field + errors: warehouseErrors { + ...WarehouseErrorFragment } } } @@ -243,24 +240,3 @@ export const useAssignShippingZoneToWarehouse = makeMutation< AssignShippingZoneToWarehouse, AssignShippingZoneToWarehouseVariables >(assignShippingZoneToWarehouse); - -const unassignShippingZoneToWarehouse = gql` - mutation UnassignShippingZoneToWarehouse( - $warehouseId: ID! - $shippingZoneId: ID! - ) { - unassignWarehouseShippingZone( - id: $warehouseId - shippingZoneIds: [$shippingZoneId] - ) { - warehouseErrors { - code - field - } - } - } -`; -export const useUnassignShippingZoneToWarehouse = makeMutation< - UnassignShippingZoneToWarehouse, - UnassignShippingZoneToWarehouseVariables ->(unassignShippingZoneToWarehouse); diff --git a/src/shipping/types/AssignShippingZoneToWarehouse.ts b/src/shipping/types/AssignShippingZoneToWarehouse.ts index 2f8b1789a..ae104a3a4 100644 --- a/src/shipping/types/AssignShippingZoneToWarehouse.ts +++ b/src/shipping/types/AssignShippingZoneToWarehouse.ts @@ -8,7 +8,7 @@ import { WarehouseErrorCode } from "./../../types/globalTypes"; // GraphQL mutation operation: AssignShippingZoneToWarehouse // ==================================================== -export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors { +export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone_errors { __typename: "WarehouseError"; code: WarehouseErrorCode; field: string | null; @@ -16,7 +16,7 @@ export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone_wareh export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone { __typename: "WarehouseShippingZoneAssign"; - warehouseErrors: AssignShippingZoneToWarehouse_assignWarehouseShippingZone_warehouseErrors[]; + errors: AssignShippingZoneToWarehouse_assignWarehouseShippingZone_errors[]; } export interface AssignShippingZoneToWarehouse { diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index b91810aee..dc66c7d59 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -144,21 +144,45 @@ const ShippingZoneDetails: React.FC = ({ } }); - const handleSubmit = (data: FormData) => { - updateShippingZone({ - variables: { - id, - input: { - name: data.name + const handleSubmit = async (data: FormData) => { + try { + const updateResult = await updateShippingZone({ + variables: { + id, + input: { + name: data.name + } } + }); + const updateErrors = updateResult.data.shippingZoneUpdate.errors; + + if (updateErrors.length === 0) { + const assignResult = await assignToWarehouse({ + variables: { + shippingZoneId: id, + warehouseId: data.warehouse + } + }); + const assignErrors = + assignResult.data.assignWarehouseShippingZone.errors; + + if (assignErrors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + } else { + throw new Error( + `Assigning to warehouse failed: ${assignErrors[0].code}` + ); + } + } else { + throw new Error(`Updating failed: ${updateErrors[0].message}`); } - }); - assignToWarehouse({ - variables: { - shippingZoneId: id, - warehouseId: data.warehouses[0] - } - }); + } catch (err) { + notify({ + text: intl.formatMessage(commonMessages.somethingWentWrong) + }); + } }; if (data?.shippingZone === null) { diff --git a/src/warehouses/mutations.ts b/src/warehouses/mutations.ts index 26a9b2805..fbc86e437 100644 --- a/src/warehouses/mutations.ts +++ b/src/warehouses/mutations.ts @@ -15,6 +15,13 @@ import { } from "./types/WarehouseDelete"; import { warehouseDetailsFragment } from "./queries"; +export const warehouseErrorFragment = gql` + fragment WarehouseErrorFragment on WarehouseError { + code + field + } +`; + const deleteWarehouse = gql` mutation WarehouseDelete($id: ID!) { deleteWarehouse(id: $id) { diff --git a/src/warehouses/types/WarehouseErrorFragment.ts b/src/warehouses/types/WarehouseErrorFragment.ts new file mode 100644 index 000000000..efb04bb45 --- /dev/null +++ b/src/warehouses/types/WarehouseErrorFragment.ts @@ -0,0 +1,15 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { WarehouseErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: WarehouseErrorFragment +// ==================================================== + +export interface WarehouseErrorFragment { + __typename: "WarehouseError"; + code: WarehouseErrorCode; + field: string | null; +} From 11a10686ce8c3ffb3ca9abc718d20c96186306f1 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 19 Mar 2020 18:15:22 +0100 Subject: [PATCH 31/88] Add stock management components to simple product --- .../components/ProductStock/ProductStock.tsx | 96 --------- src/products/components/ProductStock/index.ts | 2 - .../ProductStocks/ProductStocks.tsx | 199 ++++++++++++++++++ .../components/ProductStocks/index.ts | 2 + .../ProductUpdatePage/ProductUpdatePage.tsx | 19 +- .../ProductVariants/ProductVariants.tsx | 16 +- src/products/fixtures.ts | 12 +- src/products/queries.ts | 2 + src/products/types/Product.ts | 1 + src/products/types/ProductCreate.ts | 1 + src/products/types/ProductDetails.ts | 1 + src/products/types/ProductImageCreate.ts | 1 + src/products/types/ProductImageUpdate.ts | 1 + src/products/types/ProductUpdate.ts | 1 + src/products/types/ProductVariant.ts | 1 + src/products/types/ProductVariantDetails.ts | 1 + src/products/types/SimpleProductUpdate.ts | 2 + src/products/types/VariantCreate.ts | 1 + src/products/types/VariantImageAssign.ts | 1 + src/products/types/VariantImageUnassign.ts | 1 + src/products/types/VariantUpdate.ts | 1 + src/products/utils/data.ts | 24 ++- .../views/ProductUpdate/ProductUpdate.tsx | 5 - 23 files changed, 256 insertions(+), 135 deletions(-) delete mode 100644 src/products/components/ProductStock/ProductStock.tsx delete mode 100644 src/products/components/ProductStock/index.ts create mode 100644 src/products/components/ProductStocks/ProductStocks.tsx create mode 100644 src/products/components/ProductStocks/index.ts diff --git a/src/products/components/ProductStock/ProductStock.tsx b/src/products/components/ProductStock/ProductStock.tsx deleted file mode 100644 index 6fce4b609..000000000 --- a/src/products/components/ProductStock/ProductStock.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import Card from "@material-ui/core/Card"; -import CardContent from "@material-ui/core/CardContent"; -import { makeStyles } from "@material-ui/core/styles"; -import TextField from "@material-ui/core/TextField"; -import React from "react"; -import { useIntl } from "react-intl"; - -import CardTitle from "@saleor/components/CardTitle"; -import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment"; -import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors"; -import { ProductDetails_product } from "../../types/ProductDetails"; - -const useStyles = makeStyles( - theme => ({ - root: { - display: "grid", - gridColumnGap: theme.spacing(2), - gridTemplateColumns: "1fr 1fr" - } - }), - { name: "ProductStock" } -); - -interface ProductStockProps { - data: { - sku: string; - stockQuantity: number; - }; - disabled: boolean; - errors: ProductErrorFragment[]; - product: ProductDetails_product; - onChange: (event: React.ChangeEvent) => void; -} - -const ProductStock: React.FC = props => { - const { data, disabled, product, onChange, errors } = props; - - const classes = useStyles(props); - const intl = useIntl(); - - const formErrors = getFormErrors(["sku", "stockQuantity"], errors); - - return ( - - - -
- - -
-
-
- ); -}; -ProductStock.displayName = "ProductStock"; -export default ProductStock; diff --git a/src/products/components/ProductStock/index.ts b/src/products/components/ProductStock/index.ts deleted file mode 100644 index f98d67440..000000000 --- a/src/products/components/ProductStock/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./ProductStock"; -export * from "./ProductStock"; diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx new file mode 100644 index 000000000..02f14b64a --- /dev/null +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -0,0 +1,199 @@ +import Button from "@material-ui/core/Button"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import Table from "@material-ui/core/Table"; +import TableHead from "@material-ui/core/TableHead"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableRow from "@material-ui/core/TableRow"; +import TextField from "@material-ui/core/TextField"; +import Typography from "@material-ui/core/Typography"; +import React from "react"; +import { useIntl, FormattedMessage } from "react-intl"; +import makeStyles from "@material-ui/core/styles/makeStyles"; + +import { FormChange } from "@saleor/hooks/useForm"; +import { FormsetChange, FormsetAtomicData } from "@saleor/hooks/useFormset"; +import CardTitle from "@saleor/components/CardTitle"; +import { getFieldError } from "@saleor/utils/errors"; +import { UserError } from "@saleor/types"; +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import FormSpacer from "@saleor/components/FormSpacer"; +import Hr from "@saleor/components/Hr"; +import { renderCollection } from "@saleor/misc"; + +export type ProductStockInput = FormsetAtomicData; +export interface ProductStockFormData { + sku: string; + trackInventory: boolean; +} + +export interface ProductStocksProps { + data: ProductStockFormData; + disabled: boolean; + errors: UserError[]; + stocks: ProductStockInput[]; + onChange: FormsetChange; + onFormDataChange: FormChange; + onWarehousesEdit: () => undefined; +} + +const useStyles = makeStyles( + theme => ({ + colName: {}, + colQuantity: { + textAlign: "right", + width: 200 + }, + editWarehouses: { + marginRight: -theme.spacing() + }, + input: { + padding: theme.spacing(1.5), + textAlign: "right" + }, + inputComponent: { + width: 100 + }, + quantityContainer: { + paddingTop: theme.spacing() + }, + quantityHeader: { + alignItems: "center", + display: "flex", + justifyContent: "space-between" + }, + skuInputContainer: { + display: "grid", + gridColumnGap: theme.spacing(3) + "px", + gridTemplateColumns: "repeat(2, 1fr)" + } + }), + { + name: "ProductStocks" + } +); + +const ProductStocks: React.FC = ({ + data, + disabled, + errors, + stocks, + onChange, + onFormDataChange, + onWarehousesEdit +}) => { + const classes = useStyles({}); + const intl = useIntl(); + + return ( + + + +
+ +
+ + + + + + + + } + /> +
+
+ + +
+ + + + +
+
+
+ + + + + + + + + + + + + {renderCollection(stocks, stock => ( + + {stock.label} + + onChange(stock.id, event.target.value)} + value={stock.value} + /> + + + ))} + +
+
+ ); +}; + +ProductStocks.displayName = "ProductStocks"; +export default ProductStocks; diff --git a/src/products/components/ProductStocks/index.ts b/src/products/components/ProductStocks/index.ts new file mode 100644 index 000000000..ef1830648 --- /dev/null +++ b/src/products/components/ProductStocks/index.ts @@ -0,0 +1,2 @@ +export * from "./ProductStocks"; +export { default } from "./ProductStocks"; diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 0e7362403..53113317f 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -34,7 +34,8 @@ import { getProductUpdatePageFormData, getSelectedAttributesFromProduct, ProductAttributeValueChoices, - ProductUpdatePageFormData + ProductUpdatePageFormData, + getStockInputFromProduct } from "../../utils/data"; import { createAttributeChangeHandler, @@ -45,8 +46,8 @@ import ProductDetailsForm from "../ProductDetailsForm"; import ProductImages from "../ProductImages"; import ProductOrganization from "../ProductOrganization"; import ProductPricing from "../ProductPricing"; -import ProductStock from "../ProductStock"; import ProductVariants from "../ProductVariants"; +import ProductStocks, { ProductStockInput } from "../ProductStocks"; export interface ProductUpdatePageProps extends ListActions { errors: ProductErrorFragment[]; @@ -71,7 +72,6 @@ export interface ProductUpdatePageProps extends ListActions { onImageEdit?(id: string); onImageReorder?(event: { oldIndex: number; newIndex: number }); onImageUpload(file: File); - onProductShow?(); onSeoClick?(); onSubmit?(data: ProductUpdatePageSubmitData); onVariantAdd?(); @@ -80,6 +80,7 @@ export interface ProductUpdatePageProps extends ListActions { export interface ProductUpdatePageSubmitData extends ProductUpdatePageFormData { attributes: ProductAttributeInput[]; collections: string[]; + stocks: ProductStockInput[]; } export const ProductUpdatePage: React.FC = ({ @@ -120,9 +121,13 @@ export const ProductUpdatePage: React.FC = ({ () => getAttributeInputFromProduct(product), [product] ); + const stockInput = React.useMemo(() => getStockInputFromProduct(product), [ + product + ]); const { change: changeAttributeData, data: attributes } = useFormset( attributeInput ); + const { change: changeStockData, data: stocks } = useFormset(stockInput); const [selectedAttributes, setSelectedAttributes] = useStateFromProps< ProductAttributeValueChoices[] @@ -149,6 +154,7 @@ export const ProductUpdatePage: React.FC = ({ const handleSubmit = (data: ProductUpdatePageFormData) => onSubmit({ attributes, + stocks, ...data }); @@ -239,12 +245,13 @@ export const ProductUpdatePage: React.FC = ({ toggleAll={toggleAll} /> ) : ( - )} diff --git a/src/products/components/ProductVariants/ProductVariants.tsx b/src/products/components/ProductVariants/ProductVariants.tsx index f92aff08f..da53ce059 100644 --- a/src/products/components/ProductVariants/ProductVariants.tsx +++ b/src/products/components/ProductVariants/ProductVariants.tsx @@ -22,7 +22,7 @@ import { maybe, renderCollection } from "../../../misc"; import { ListActions } from "../../../types"; import { ProductDetails_product_variants, - ProductDetails_product_variants_stock_warehouse + ProductDetails_product_variants_stocks_warehouse } from "../../types/ProductDetails"; import { ProductVariant_costPrice } from "../../types/ProductVariant"; @@ -39,11 +39,11 @@ function getWarehouseChoices( value: null }, ...variants - .reduce( + .reduce( (warehouses, variant) => [ ...warehouses, - ...variant.stock.reduce< - ProductDetails_product_variants_stock_warehouse[] + ...variant.stocks.reduce< + ProductDetails_product_variants_stocks_warehouse[] >((variantStocks, stock) => { if (!!warehouses.find(w => w.id === stock.warehouse.id)) { return variantStocks; @@ -118,7 +118,7 @@ function getAvailabilityLabel( variant: ProductDetails_product_variants, numAvailable: number ): string { - const variantStock = variant.stock.find(s => s.warehouse.id === warehouse); + const variantStock = variant.stocks.find(s => s.warehouse.id === warehouse); if (!!warehouse) { if (!!variantStock) { @@ -155,7 +155,7 @@ function getAvailabilityLabel( }, { numAvailable, - numLocations: variant.stock.length + numLocations: variant.stocks.length } ); } else { @@ -295,8 +295,8 @@ export const ProductVariants: React.FC = props => { {renderCollection(variants, variant => { const isSelected = variant ? isChecked(variant.id) : false; const numAvailable = - variant && variant.stock - ? variant.stock.reduce((acc, s) => acc + s.quantity, 0) + variant && variant.stocks + ? variant.stocks.reduce((acc, s) => acc + s.quantity, 0) : null; return ( diff --git a/src/products/fixtures.ts b/src/products/fixtures.ts index 34355ff65..b45ac7bd4 100644 --- a/src/products/fixtures.ts +++ b/src/products/fixtures.ts @@ -260,10 +260,8 @@ export const product: ( amount: 678.78, currency: "USD" }, - quantity: 12, - quantityAllocated: 1, sku: "87192-94370", - stock: [ + stocks: [ { __typename: "Stock", id: "1", @@ -277,7 +275,7 @@ export const product: ( warehouse: warehouseList[1] } ], - stockQuantity: 48 + trackInventory: true }, { __typename: "ProductVariant", @@ -297,10 +295,8 @@ export const product: ( margin: 7, name: "silver", priceOverride: null, - quantity: 12, - quantityAllocated: 1, sku: "69055-15190", - stock: [ + stocks: [ { __typename: "Stock", id: "1", @@ -308,7 +304,7 @@ export const product: ( warehouse: warehouseList[0] } ], - stockQuantity: 14 + trackInventory: false } ] }); diff --git a/src/products/queries.ts b/src/products/queries.ts index a4b792488..a14d917ca 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -158,6 +158,7 @@ export const productFragmentDetails = gql` stocks { ...StockFragment } + trackInventory } productType { id @@ -225,6 +226,7 @@ export const fragmentVariant = gql` stocks { ...StockFragment } + trackInventory } `; diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index 66711a57d..7b1ce054e 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -148,6 +148,7 @@ export interface Product_variants { priceOverride: Product_variants_priceOverride | null; margin: number | null; stocks: (Product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface Product_productType { diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index 3782b4045..32cdd2304 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -154,6 +154,7 @@ export interface ProductCreate_productCreate_product_variants { priceOverride: ProductCreate_productCreate_product_variants_priceOverride | null; margin: number | null; stocks: (ProductCreate_productCreate_product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface ProductCreate_productCreate_product_productType { diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index 89ea83b2f..c426f408a 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -148,6 +148,7 @@ export interface ProductDetails_product_variants { priceOverride: ProductDetails_product_variants_priceOverride | null; margin: number | null; stocks: (ProductDetails_product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface ProductDetails_product_productType_variantAttributes_values { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index f56195a1a..fcbb37415 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -154,6 +154,7 @@ export interface ProductImageCreate_productImageCreate_product_variants { priceOverride: ProductImageCreate_productImageCreate_product_variants_priceOverride | null; margin: number | null; stocks: (ProductImageCreate_productImageCreate_product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface ProductImageCreate_productImageCreate_product_productType { diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 2f4d3a773..0bca7c7c9 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -154,6 +154,7 @@ export interface ProductImageUpdate_productImageUpdate_product_variants { priceOverride: ProductImageUpdate_productImageUpdate_product_variants_priceOverride | null; margin: number | null; stocks: (ProductImageUpdate_productImageUpdate_product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface ProductImageUpdate_productImageUpdate_product_productType { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index e62b1e88d..90b5615c1 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -154,6 +154,7 @@ export interface ProductUpdate_productUpdate_product_variants { priceOverride: ProductUpdate_productUpdate_product_variants_priceOverride | null; margin: number | null; stocks: (ProductUpdate_productUpdate_product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface ProductUpdate_productUpdate_product_productType { diff --git a/src/products/types/ProductVariant.ts b/src/products/types/ProductVariant.ts index a2dee190f..9a9d2e743 100644 --- a/src/products/types/ProductVariant.ts +++ b/src/products/types/ProductVariant.ts @@ -113,4 +113,5 @@ export interface ProductVariant { product: ProductVariant_product; sku: string; stocks: (ProductVariant_stocks | null)[] | null; + trackInventory: boolean; } diff --git a/src/products/types/ProductVariantDetails.ts b/src/products/types/ProductVariantDetails.ts index 441436ec9..1bd3a8d52 100644 --- a/src/products/types/ProductVariantDetails.ts +++ b/src/products/types/ProductVariantDetails.ts @@ -113,6 +113,7 @@ export interface ProductVariantDetails_productVariant { product: ProductVariantDetails_productVariant_product; sku: string; stocks: (ProductVariantDetails_productVariant_stocks | null)[] | null; + trackInventory: boolean; } export interface ProductVariantDetails { diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index 90aaf877f..d9d137e59 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -154,6 +154,7 @@ export interface SimpleProductUpdate_productUpdate_product_variants { priceOverride: SimpleProductUpdate_productUpdate_product_variants_priceOverride | null; margin: number | null; stocks: (SimpleProductUpdate_productUpdate_product_variants_stocks | null)[] | null; + trackInventory: boolean; } export interface SimpleProductUpdate_productUpdate_product_productType { @@ -305,6 +306,7 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant { product: SimpleProductUpdate_productVariantUpdate_productVariant_product; sku: string; stocks: (SimpleProductUpdate_productVariantUpdate_productVariant_stocks | null)[] | null; + trackInventory: boolean; } export interface SimpleProductUpdate_productVariantUpdate { diff --git a/src/products/types/VariantCreate.ts b/src/products/types/VariantCreate.ts index dc2ddc181..67d363617 100644 --- a/src/products/types/VariantCreate.ts +++ b/src/products/types/VariantCreate.ts @@ -121,6 +121,7 @@ export interface VariantCreate_productVariantCreate_productVariant { product: VariantCreate_productVariantCreate_productVariant_product; sku: string; stocks: (VariantCreate_productVariantCreate_productVariant_stocks | null)[] | null; + trackInventory: boolean; } export interface VariantCreate_productVariantCreate { diff --git a/src/products/types/VariantImageAssign.ts b/src/products/types/VariantImageAssign.ts index a0edcd624..f85d92ee4 100644 --- a/src/products/types/VariantImageAssign.ts +++ b/src/products/types/VariantImageAssign.ts @@ -121,6 +121,7 @@ export interface VariantImageAssign_variantImageAssign_productVariant { product: VariantImageAssign_variantImageAssign_productVariant_product; sku: string; stocks: (VariantImageAssign_variantImageAssign_productVariant_stocks | null)[] | null; + trackInventory: boolean; } export interface VariantImageAssign_variantImageAssign { diff --git a/src/products/types/VariantImageUnassign.ts b/src/products/types/VariantImageUnassign.ts index 0d532d910..294514c50 100644 --- a/src/products/types/VariantImageUnassign.ts +++ b/src/products/types/VariantImageUnassign.ts @@ -121,6 +121,7 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant { product: VariantImageUnassign_variantImageUnassign_productVariant_product; sku: string; stocks: (VariantImageUnassign_variantImageUnassign_productVariant_stocks | null)[] | null; + trackInventory: boolean; } export interface VariantImageUnassign_variantImageUnassign { diff --git a/src/products/types/VariantUpdate.ts b/src/products/types/VariantUpdate.ts index cd7b5644e..c0deeabd3 100644 --- a/src/products/types/VariantUpdate.ts +++ b/src/products/types/VariantUpdate.ts @@ -121,6 +121,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant { product: VariantUpdate_productVariantUpdate_productVariant_product; sku: string; stocks: (VariantUpdate_productVariantUpdate_productVariant_stocks | null)[] | null; + trackInventory: boolean; } export interface VariantUpdate_productVariantUpdate { diff --git a/src/products/utils/data.ts b/src/products/utils/data.ts index 37036d1a6..23c19429c 100644 --- a/src/products/utils/data.ts +++ b/src/products/utils/data.ts @@ -13,6 +13,7 @@ import { ProductAttributeInput } from "../components/ProductAttributes"; import { VariantAttributeInput } from "../components/ProductVariantAttributes"; import { ProductVariant } from "../types/ProductVariant"; import { ProductVariantCreateData_product } from "../types/ProductVariantCreateData"; +import { ProductStockInput } from "../components/ProductStocks"; export interface Collection { id: string; @@ -117,6 +118,17 @@ export function getVariantAttributeInputFromProduct( ); } +export function getStockInputFromProduct( + product: ProductDetails_product +): ProductStockInput[] { + return product?.variants[0].stocks.map(stock => ({ + data: null, + id: stock.warehouse.id, + label: stock.warehouse.name, + value: stock.quantity.toString() + })); +} + export function getCollectionInput( productCollections: ProductDetails_product_collections[] ): Collection[] { @@ -153,7 +165,7 @@ export interface ProductUpdatePageFormData { seoDescription: string; seoTitle: string; sku: string; - stockQuantity: number; + trackInventory: boolean; } export function getProductUpdatePageFormData( @@ -183,14 +195,6 @@ export function getProductUpdatePageFormData( : undefined, "" ), - stockQuantity: maybe( - () => - product.productType.hasVariants - ? undefined - : variants && variants[0] - ? variants[0].quantity - : undefined, - 0 - ) + trackInventory: !!product?.variants[0]?.trackInventory }; } diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 4de424226..6a509ebd4 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -232,11 +232,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { variants={maybe(() => product.variants)} onBack={handleBack} onDelete={() => openModal("remove")} - onProductShow={() => { - if (product) { - window.open(product.url); - } - }} onImageReorder={handleImageReorder} onSubmit={handleSubmit} onVariantAdd={handleVariantAdd} From 4d81c89f5850678cbb60bab87b9b20d9f3ca2ab8 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 19 Mar 2020 18:21:41 +0100 Subject: [PATCH 32/88] Add tracking to update --- src/products/views/ProductUpdate/handlers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/products/views/ProductUpdate/handlers.ts b/src/products/views/ProductUpdate/handlers.ts index fd356f33a..78ccd60f2 100644 --- a/src/products/views/ProductUpdate/handlers.ts +++ b/src/products/views/ProductUpdate/handlers.ts @@ -42,8 +42,8 @@ export function createUpdateHandler( ...productVariables, productVariantId: product.variants[0].id, productVariantInput: { - quantity: data.stockQuantity, - sku: data.sku + sku: data.sku, + trackInventory: data.trackInventory } }); } From 65dedb4263396a514c4bab673f8cc2cf64b1be4e Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 23 Mar 2020 11:49:25 +0100 Subject: [PATCH 33/88] Add warehouse select dialog --- src/components/ControlledCheckbox.tsx | 1 + .../ProductCreatePage/ProductCreatePage.tsx | 17 ++- .../ProductWarehousesDialog.stories.tsx | 50 +++++++ .../ProductWarehousesDialog.tsx | 133 ++++++++++++++++++ .../ProductWarehousesDialog/index.ts | 2 + 5 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.stories.tsx create mode 100644 src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx create mode 100644 src/products/components/ProductWarehousesDialog/index.ts diff --git a/src/components/ControlledCheckbox.tsx b/src/components/ControlledCheckbox.tsx index 4a79d9085..ebace41f9 100644 --- a/src/components/ControlledCheckbox.tsx +++ b/src/components/ControlledCheckbox.tsx @@ -25,6 +25,7 @@ export const ControlledCheckbox: React.FC = ({ control={ onChange({ target: { name, value: !checked } })} diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 8386cfb8c..81f725818 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -41,7 +41,7 @@ import ProductAttributes, { import ProductDetailsForm from "../ProductDetailsForm"; import ProductOrganization from "../ProductOrganization"; import ProductPricing from "../ProductPricing"; -import ProductStock from "../ProductStock"; +import ProductStocks, { ProductStockInput } from "../ProductStocks"; interface FormData { basePrice: number; @@ -57,9 +57,11 @@ interface FormData { seoTitle: string; sku: string; stockQuantity: number; + trackInventory: boolean; } export interface ProductCreatePageSubmitData extends FormData { attributes: ProductAttributeInput[]; + stocks: ProductStockInput[]; } interface ProductCreatePageProps { @@ -112,6 +114,7 @@ export const ProductCreatePage: React.FC = ({ data: attributes, set: setAttributeData } = useFormset([]); + const { change: changeStockData, data: stocks } = useFormset([]); // Ensures that it will not change after component rerenders, because it // generates different block keys and it causes editor to lose its content. @@ -131,7 +134,8 @@ export const ProductCreatePage: React.FC = ({ seoDescription: "", seoTitle: "", sku: null, - stockQuantity: null + stockQuantity: null, + trackInventory: false }; // Display values @@ -159,6 +163,7 @@ export const ProductCreatePage: React.FC = ({ const handleSubmit = (data: FormData) => onSubmit({ attributes, + stocks, ...data }); @@ -234,12 +239,14 @@ export const ProductCreatePage: React.FC = ({ {!productType.hasVariants && ( <> - diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.stories.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.stories.tsx new file mode 100644 index 000000000..546c187d8 --- /dev/null +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.stories.tsx @@ -0,0 +1,50 @@ +import { storiesOf } from "@storybook/react"; +import React from "react"; + +import Decorator from "@saleor/storybook//Decorator"; +import { warehouseList } from "@saleor/warehouses/fixtures"; +import { formError } from "@saleor/storybook/misc"; +import ProductWarehousesDialog, { + ProductWarehousesDialogProps +} from "./ProductWarehousesDialog"; + +const props: ProductWarehousesDialogProps = { + confirmButtonState: "default", + disabled: false, + errors: [], + onClose: () => undefined, + onConfirm: () => undefined, + open: true, + stocks: [ + { + __typename: "Stock", + id: "5123", + quantity: 2, + warehouse: warehouseList[0] + }, + { + __typename: "Stock", + id: "5223", + quantity: 4, + warehouse: warehouseList[2] + } + ], + warehouses: warehouseList +}; + +storiesOf("Views / Products / Edit warehouses", module) + .addDecorator(Decorator) + .add("default", () => ) + .add("loading warehouses", () => ( + + )) + .add("loading confirmation", () => ( + + )) + .add("with error", () => ( + + )); diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx new file mode 100644 index 000000000..3482c28e7 --- /dev/null +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx @@ -0,0 +1,133 @@ +import Button from "@material-ui/core/Button"; +import Dialog from "@material-ui/core/Dialog"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import DialogTitle from "@material-ui/core/DialogTitle"; +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 ConfirmButton, { + ConfirmButtonTransitionState +} from "@saleor/components/ConfirmButton"; +import { buttonMessages } from "@saleor/intl"; +import { UserError } from "@saleor/types"; +import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; +import Skeleton from "@saleor/components/Skeleton"; +import { Product_variants_stocks } from "@saleor/products/types/Product"; +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import { isSelected, toggle } from "@saleor/utils/lists"; +import useStateFromProps from "@saleor/hooks/useStateFromProps"; + +const useStyles = makeStyles( + theme => ({ + dropShadow: { + boxShadow: `0px -5px 10px 0px ${theme.palette.divider}` + }, + errorParagraph: { + paddingTop: 0 + }, + helperText: { + marginBottom: theme.spacing(1) + } + }), + { + name: "ProductWarehousesDialog" + } +); + +export interface ProductWarehousesDialogProps { + confirmButtonState: ConfirmButtonTransitionState; + disabled: boolean; + errors: UserError[]; + open: boolean; + stocks: Product_variants_stocks[]; + warehouses: SearchWarehouses_search_edges_node[]; + onClose: () => void; + onConfirm: (data: string[]) => void; +} + +const ProductWarehousesDialog: React.FC = ({ + confirmButtonState, + disabled, + errors, + onClose, + onConfirm, + open, + stocks, + warehouses +}) => { + const classes = useStyles({}); + const intl = useIntl(); + + const [selectedWarehouses, setSelectedWarehouses] = useStateFromProps( + stocks?.map(stock => stock.warehouse.id) || [] + ); + + const handleConfirm = () => onConfirm(selectedWarehouses); + + return ( + + + + + + + + + + {warehouses === undefined ? ( + + ) : ( + warehouses.map(warehouse => ( +
+ a === b + )} + name={`warehouse:${warehouse.id}`} + onChange={() => + setSelectedWarehouses( + toggle( + warehouse.id, + selectedWarehouses, + (a, b) => a === b + ) + ) + } + disabled={disabled} + label={warehouse.name} + /> +
+ )) + )} +
+ {errors.length > 0 && ( + + {errors[0]?.message} + + )} + + + + + + + +
+ ); +}; + +ProductWarehousesDialog.displayName = "ProductWarehousesDialog"; +export default ProductWarehousesDialog; diff --git a/src/products/components/ProductWarehousesDialog/index.ts b/src/products/components/ProductWarehousesDialog/index.ts new file mode 100644 index 000000000..233e2f720 --- /dev/null +++ b/src/products/components/ProductWarehousesDialog/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ProductWarehousesDialog"; +export * from "./ProductWarehousesDialog"; From f94fdba7b957b35853d2d3ea9ce074f99047c131 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 23 Mar 2020 13:23:29 +0100 Subject: [PATCH 34/88] Add warehouse stock edit prototype --- .../ProductUpdatePage/ProductUpdatePage.tsx | 3 + .../ProductWarehousesDialog.tsx | 8 +- src/products/mutations.ts | 50 ++++++++++- src/products/types/AddOrRemoveStocks.ts | 83 +++++++++++++++++++ src/products/urls.ts | 6 +- .../views/ProductUpdate/ProductUpdate.tsx | 57 +++++++++++++ src/types/globalTypes.ts | 9 ++ 7 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 src/products/types/AddOrRemoveStocks.ts diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 53113317f..b3740c60e 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -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 = ({ onVariantAdd, onVariantsAdd, onVariantShow, + onWarehousesEdit, isChecked, selected, toggle, @@ -252,6 +254,7 @@ export const ProductUpdatePage: React.FC = ({ stocks={stocks} onChange={changeStockData} onFormDataChange={change} + onWarehousesEdit={onWarehousesEdit} /> )} diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx index 3482c28e7..ec602ea12 100644 --- a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx @@ -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) => void; } const ProductWarehousesDialog: React.FC = ({ @@ -61,11 +62,12 @@ const ProductWarehousesDialog: React.FC = ({ 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 ( diff --git a/src/products/mutations.ts b/src/products/mutations.ts index e469e4adf..42605ba11 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -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); diff --git a/src/products/types/AddOrRemoveStocks.ts b/src/products/types/AddOrRemoveStocks.ts new file mode 100644 index 000000000..4bf5efc6d --- /dev/null +++ b/src/products/types/AddOrRemoveStocks.ts @@ -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[]; +} diff --git a/src/products/urls.ts b/src/products/urls.ts index 9441c04a5..5cf5e5d95 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -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; export const productUrl = (id: string, params?: ProductUrlQueryParams) => productPath(encodeURIComponent(id)) + "?" + stringifyQs(params); diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 6a509ebd4..b6a1f6f03 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -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 = ({ 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 = ({ id, params }) => { loading: searchCollectionsOpts.loading, onFetchMore: loadMoreCollections }} + onWarehousesEdit={() => openModal("edit-stocks")} /> = ({ id, params }) => { }) } /> + {!product?.productType?.hasVariants && ( + edge.node + )} + onConfirm={data => + addOrRemoveStocks({ + variables: { + add: data.added.map(id => ({ + quantity: 0, + warehouse: id + })), + remove: data.removed, + variantId: product.variants[0].id + } + }) + } + /> + )} ); }} diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 4f0b0a325..229e4662b 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -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", From c161de1270a905388dc967f2f8c527300a5d1bf4 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 24 Mar 2020 20:37:14 +0100 Subject: [PATCH 35/88] Fix product create view --- .../components/ProductCreatePage/ProductCreatePage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 81f725818..e3f6d61a5 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -84,6 +84,7 @@ interface ProductCreatePageProps { fetchCategories: (data: string) => void; fetchCollections: (data: string) => void; fetchProductTypes: (data: string) => void; + onWarehouseEdit: () => void; onBack?(); onSubmit?(data: ProductCreatePageSubmitData); } @@ -104,7 +105,8 @@ export const ProductCreatePage: React.FC = ({ saveButtonBarState, onBack, fetchProductTypes, - onSubmit + onSubmit, + onWarehouseEdit }: ProductCreatePageProps) => { const intl = useIntl(); const localizeDate = useDateLocalize(); From db3b51f9310eafadcc073cb12dc7d49b9ab5f2d9 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 24 Mar 2020 22:38:26 +0100 Subject: [PATCH 36/88] Add simple product stock management --- .../ProductUpdatePage/ProductUpdatePage.tsx | 5 +- .../ProductWarehousesDialog.tsx | 5 +- src/products/mutations.ts | 60 ++- src/products/types/AddOrRemoveStocks.ts | 8 +- src/products/types/BulkStockErrorFragment.ts | 16 + src/products/types/SimpleProductUpdate.ts | 376 +++++++++++++++++- src/products/types/StockErrorFragment.ts | 15 + .../views/ProductUpdate/ProductUpdate.tsx | 11 +- src/products/views/ProductUpdate/handlers.ts | 8 +- 9 files changed, 485 insertions(+), 19 deletions(-) create mode 100644 src/products/types/BulkStockErrorFragment.ts create mode 100644 src/products/types/StockErrorFragment.ts diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index b3740c60e..d8c23ed2e 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -252,7 +252,10 @@ export const ProductUpdatePage: React.FC = ({ disabled={disabled} errors={errors} stocks={stocks} - onChange={changeStockData} + onChange={(id, value) => { + triggerChange(); + changeStockData(id, value); + }} onFormDataChange={change} onWarehousesEdit={onWarehousesEdit} /> diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx index ec602ea12..9faaa1be9 100644 --- a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx @@ -13,13 +13,14 @@ import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { buttonMessages } from "@saleor/intl"; -import { UserError } from "@saleor/types"; import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import Skeleton from "@saleor/components/Skeleton"; import { Product_variants_stocks } from "@saleor/products/types/Product"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import { isSelected, toggle } from "@saleor/utils/lists"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { BulkStockErrorFragment } from "@saleor/products/types/BulkStockErrorFragment"; +import { StockErrorFragment } from "@saleor/products/types/StockErrorFragment"; const useStyles = makeStyles( theme => ({ @@ -41,7 +42,7 @@ const useStyles = makeStyles( export interface ProductWarehousesDialogProps { confirmButtonState: ConfirmButtonTransitionState; disabled: boolean; - errors: UserError[]; + errors: Array; open: boolean; stocks: Product_variants_stocks[]; warehouses: SearchWarehouses_search_edges_node[]; diff --git a/src/products/mutations.ts b/src/products/mutations.ts index 42605ba11..98247c432 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -71,6 +71,19 @@ export const bulkProductErrorFragment = gql` index } `; +const bulkStockErrorFragment = gql` + fragment BulkStockErrorFragment on BulkStockError { + code + field + index + } +`; +const stockErrorFragment = gql` + fragment StockErrorFragment on StockError { + code + field + } +`; export const productImageCreateMutation = gql` ${productErrorFragment} @@ -179,8 +192,10 @@ export const TypedProductUpdateMutation = TypedMutation< >(productUpdateMutation); export const simpleProductUpdateMutation = gql` + ${bulkStockErrorFragment} ${productErrorFragment} ${productFragmentDetails} + ${stockErrorFragment} ${fragmentVariant} mutation SimpleProductUpdate( $id: ID! @@ -196,6 +211,9 @@ export const simpleProductUpdateMutation = gql` $productVariantId: ID! $productVariantInput: ProductVariantInput! $seo: SeoInput + $addStocks: [StockInput!]! + $deleteStocks: [ID!]! + $updateStocks: [StockInput!]! ) { productUpdate( id: $id @@ -227,6 +245,39 @@ export const simpleProductUpdateMutation = gql` ...ProductVariant } } + productVariantStocksCreate( + stocks: $addStocks + variantId: $productVariantId + ) { + errors: bulkStockErrors { + ...BulkStockErrorFragment + } + productVariant { + ...ProductVariant + } + } + productVariantStocksDelete( + warehouseIds: $deleteStocks + variantId: $productVariantId + ) { + errors: stockErrors { + ...StockErrorFragment + } + productVariant { + ...ProductVariant + } + } + productVariantStocksUpdate( + stocks: $updateStocks + variantId: $productVariantId + ) { + errors: bulkStockErrors { + ...BulkStockErrorFragment + } + productVariant { + ...ProductVariant + } + } } `; export const TypedSimpleProductUpdateMutation = TypedMutation< @@ -499,6 +550,7 @@ export const TypedProductVariantBulkDeleteMutation = TypedMutation< >(ProductVariantBulkDeleteMutation); const addOrRemoveStocks = gql` + ${bulkStockErrorFragment} ${stockFragment} mutation AddOrRemoveStocks( $variantId: ID! @@ -506,10 +558,8 @@ const addOrRemoveStocks = gql` $remove: [ID!]! ) { productVariantStocksCreate(stocks: $add, variantId: $variantId) { - bulkStockErrors { - code - field - index + errors: bulkStockErrors { + ...BulkStockErrorFragment } productVariant { id @@ -519,7 +569,7 @@ const addOrRemoveStocks = gql` } } productVariantStocksDelete(warehouseIds: $remove, variantId: $variantId) { - stockErrors { + errors: stockErrors { code field } diff --git a/src/products/types/AddOrRemoveStocks.ts b/src/products/types/AddOrRemoveStocks.ts index 4bf5efc6d..723501871 100644 --- a/src/products/types/AddOrRemoveStocks.ts +++ b/src/products/types/AddOrRemoveStocks.ts @@ -8,7 +8,7 @@ import { StockInput, ProductErrorCode, StockErrorCode } from "./../../types/glob // GraphQL mutation operation: AddOrRemoveStocks // ==================================================== -export interface AddOrRemoveStocks_productVariantStocksCreate_bulkStockErrors { +export interface AddOrRemoveStocks_productVariantStocksCreate_errors { __typename: "BulkStockError"; code: ProductErrorCode; field: string | null; @@ -36,11 +36,11 @@ export interface AddOrRemoveStocks_productVariantStocksCreate_productVariant { export interface AddOrRemoveStocks_productVariantStocksCreate { __typename: "ProductVariantStocksCreate"; - bulkStockErrors: AddOrRemoveStocks_productVariantStocksCreate_bulkStockErrors[]; + errors: AddOrRemoveStocks_productVariantStocksCreate_errors[]; productVariant: AddOrRemoveStocks_productVariantStocksCreate_productVariant | null; } -export interface AddOrRemoveStocks_productVariantStocksDelete_stockErrors { +export interface AddOrRemoveStocks_productVariantStocksDelete_errors { __typename: "StockError"; code: StockErrorCode; field: string | null; @@ -67,7 +67,7 @@ export interface AddOrRemoveStocks_productVariantStocksDelete_productVariant { export interface AddOrRemoveStocks_productVariantStocksDelete { __typename: "ProductVariantStocksDelete"; - stockErrors: AddOrRemoveStocks_productVariantStocksDelete_stockErrors[]; + errors: AddOrRemoveStocks_productVariantStocksDelete_errors[]; productVariant: AddOrRemoveStocks_productVariantStocksDelete_productVariant | null; } diff --git a/src/products/types/BulkStockErrorFragment.ts b/src/products/types/BulkStockErrorFragment.ts new file mode 100644 index 000000000..9333796c8 --- /dev/null +++ b/src/products/types/BulkStockErrorFragment.ts @@ -0,0 +1,16 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { ProductErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: BulkStockErrorFragment +// ==================================================== + +export interface BulkStockErrorFragment { + __typename: "BulkStockError"; + code: ProductErrorCode; + field: string | null; + index: number | null; +} diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index d9d137e59..c54d9ea19 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { AttributeValueInput, ProductVariantInput, SeoInput, ProductErrorCode, AttributeInputTypeEnum } from "./../../types/globalTypes"; +import { AttributeValueInput, ProductVariantInput, SeoInput, StockInput, ProductErrorCode, AttributeInputTypeEnum, StockErrorCode } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: SimpleProductUpdate @@ -315,9 +315,380 @@ export interface SimpleProductUpdate_productVariantUpdate { productVariant: SimpleProductUpdate_productVariantUpdate_productVariant | null; } +export interface SimpleProductUpdate_productVariantStocksCreate_errors { + __typename: "BulkStockError"; + code: ProductErrorCode; + field: string | null; + index: number | null; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute { + __typename: "Attribute"; + id: string; + name: string | null; + slug: string | null; + valueRequired: boolean; + values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute_values | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes { + __typename: "SelectedAttribute"; + attribute: SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute; + values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_values | null)[]; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_costPrice { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_images { + __typename: "ProductImage"; + id: string; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_priceOverride { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_product_images { + __typename: "ProductImage"; + id: string; + alt: string; + sortOrder: number | null; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_product_thumbnail { + __typename: "Image"; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_product_variants_images { + __typename: "ProductImage"; + id: string; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_product_variants { + __typename: "ProductVariant"; + id: string; + name: string; + sku: string; + images: (SimpleProductUpdate_productVariantStocksCreate_productVariant_product_variants_images | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_product { + __typename: "Product"; + id: string; + images: (SimpleProductUpdate_productVariantStocksCreate_productVariant_product_images | null)[] | null; + name: string; + thumbnail: SimpleProductUpdate_productVariantStocksCreate_productVariant_product_thumbnail | null; + variants: (SimpleProductUpdate_productVariantStocksCreate_productVariant_product_variants | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks { + __typename: "Stock"; + id: string; + quantity: number; + warehouse: SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks_warehouse; +} + +export interface SimpleProductUpdate_productVariantStocksCreate_productVariant { + __typename: "ProductVariant"; + id: string; + attributes: SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes[]; + costPrice: SimpleProductUpdate_productVariantStocksCreate_productVariant_costPrice | null; + images: (SimpleProductUpdate_productVariantStocksCreate_productVariant_images | null)[] | null; + name: string; + priceOverride: SimpleProductUpdate_productVariantStocksCreate_productVariant_priceOverride | null; + product: SimpleProductUpdate_productVariantStocksCreate_productVariant_product; + sku: string; + stocks: (SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks | null)[] | null; + trackInventory: boolean; +} + +export interface SimpleProductUpdate_productVariantStocksCreate { + __typename: "ProductVariantStocksCreate"; + errors: SimpleProductUpdate_productVariantStocksCreate_errors[]; + productVariant: SimpleProductUpdate_productVariantStocksCreate_productVariant | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_errors { + __typename: "StockError"; + code: StockErrorCode; + field: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute { + __typename: "Attribute"; + id: string; + name: string | null; + slug: string | null; + valueRequired: boolean; + values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute_values | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes { + __typename: "SelectedAttribute"; + attribute: SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute; + values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_values | null)[]; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_costPrice { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_images { + __typename: "ProductImage"; + id: string; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_priceOverride { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_product_images { + __typename: "ProductImage"; + id: string; + alt: string; + sortOrder: number | null; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_product_thumbnail { + __typename: "Image"; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_product_variants_images { + __typename: "ProductImage"; + id: string; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_product_variants { + __typename: "ProductVariant"; + id: string; + name: string; + sku: string; + images: (SimpleProductUpdate_productVariantStocksDelete_productVariant_product_variants_images | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_product { + __typename: "Product"; + id: string; + images: (SimpleProductUpdate_productVariantStocksDelete_productVariant_product_images | null)[] | null; + name: string; + thumbnail: SimpleProductUpdate_productVariantStocksDelete_productVariant_product_thumbnail | null; + variants: (SimpleProductUpdate_productVariantStocksDelete_productVariant_product_variants | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks { + __typename: "Stock"; + id: string; + quantity: number; + warehouse: SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks_warehouse; +} + +export interface SimpleProductUpdate_productVariantStocksDelete_productVariant { + __typename: "ProductVariant"; + id: string; + attributes: SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes[]; + costPrice: SimpleProductUpdate_productVariantStocksDelete_productVariant_costPrice | null; + images: (SimpleProductUpdate_productVariantStocksDelete_productVariant_images | null)[] | null; + name: string; + priceOverride: SimpleProductUpdate_productVariantStocksDelete_productVariant_priceOverride | null; + product: SimpleProductUpdate_productVariantStocksDelete_productVariant_product; + sku: string; + stocks: (SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks | null)[] | null; + trackInventory: boolean; +} + +export interface SimpleProductUpdate_productVariantStocksDelete { + __typename: "ProductVariantStocksDelete"; + errors: SimpleProductUpdate_productVariantStocksDelete_errors[]; + productVariant: SimpleProductUpdate_productVariantStocksDelete_productVariant | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_errors { + __typename: "BulkStockError"; + code: ProductErrorCode; + field: string | null; + index: number | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute { + __typename: "Attribute"; + id: string; + name: string | null; + slug: string | null; + valueRequired: boolean; + values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes { + __typename: "SelectedAttribute"; + attribute: SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute; + values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_values | null)[]; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_costPrice { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_images { + __typename: "ProductImage"; + id: string; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_priceOverride { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_images { + __typename: "ProductImage"; + id: string; + alt: string; + sortOrder: number | null; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_thumbnail { + __typename: "Image"; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_variants_images { + __typename: "ProductImage"; + id: string; + url: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_variants { + __typename: "ProductVariant"; + id: string; + name: string; + sku: string; + images: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_variants_images | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_product { + __typename: "Product"; + id: string; + images: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_images | null)[] | null; + name: string; + thumbnail: SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_thumbnail | null; + variants: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_product_variants | null)[] | null; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks { + __typename: "Stock"; + id: string; + quantity: number; + warehouse: SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant { + __typename: "ProductVariant"; + id: string; + attributes: SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes[]; + costPrice: SimpleProductUpdate_productVariantStocksUpdate_productVariant_costPrice | null; + images: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_images | null)[] | null; + name: string; + priceOverride: SimpleProductUpdate_productVariantStocksUpdate_productVariant_priceOverride | null; + product: SimpleProductUpdate_productVariantStocksUpdate_productVariant_product; + sku: string; + stocks: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks | null)[] | null; + trackInventory: boolean; +} + +export interface SimpleProductUpdate_productVariantStocksUpdate { + __typename: "ProductVariantStocksUpdate"; + errors: SimpleProductUpdate_productVariantStocksUpdate_errors[]; + productVariant: SimpleProductUpdate_productVariantStocksUpdate_productVariant | null; +} + export interface SimpleProductUpdate { productUpdate: SimpleProductUpdate_productUpdate | null; productVariantUpdate: SimpleProductUpdate_productVariantUpdate | null; + productVariantStocksCreate: SimpleProductUpdate_productVariantStocksCreate | null; + productVariantStocksDelete: SimpleProductUpdate_productVariantStocksDelete | null; + productVariantStocksUpdate: SimpleProductUpdate_productVariantStocksUpdate | null; } export interface SimpleProductUpdateVariables { @@ -334,4 +705,7 @@ export interface SimpleProductUpdateVariables { productVariantId: string; productVariantInput: ProductVariantInput; seo?: SeoInput | null; + addStocks: StockInput[]; + deleteStocks: string[]; + updateStocks: StockInput[]; } diff --git a/src/products/types/StockErrorFragment.ts b/src/products/types/StockErrorFragment.ts new file mode 100644 index 000000000..18a48980f --- /dev/null +++ b/src/products/types/StockErrorFragment.ts @@ -0,0 +1,15 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { StockErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: StockErrorFragment +// ==================================================== + +export interface StockErrorFragment { + __typename: "StockError"; + code: StockErrorCode; + field: string | null; +} diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index b6a1f6f03..9c0433895 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -88,8 +88,8 @@ export const ProductUpdate: React.FC = ({ id, params }) => { const [addOrRemoveStocks, addOrRemoveStocksOpts] = useAddOrRemoveStocks({ onCompleted: data => { if ( - data.productVariantStocksCreate.bulkStockErrors.length === 0 && - data.productVariantStocksDelete.stockErrors.length === 0 + data.productVariantStocksCreate.errors.length === 0 && + data.productVariantStocksDelete.errors.length === 0 ) { notify({ text: intl.formatMessage(commonMessages.savedChanges) @@ -376,11 +376,12 @@ export const ProductUpdate: React.FC = ({ id, params }) => { {!product?.productType?.hasVariants && ( ({ + quantity: parseInt(stock.value, 0), + warehouse: stock.id + })) }); } }; From 4b661c9bffa59d5a782f485650d7ef7940dccaeb Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 25 Mar 2020 14:06:14 +0100 Subject: [PATCH 37/88] Add simple product stock management --- src/categories/views/CategoryDetails.tsx | 2 +- .../Navigator/modes/commands/actions.ts | 2 +- .../ProductCreatePage/ProductCreatePage.tsx | 18 ++++- .../ProductStocks/ProductStocks.tsx | 56 +++++++++----- .../ProductWarehousesDialog.tsx | 11 ++- src/products/index.tsx | 12 ++- src/products/mutations.ts | 2 + src/products/types/ProductCreate.ts | 3 +- src/products/urls.ts | 5 +- src/products/views/ProductCreate.tsx | 73 +++++++++++++++++-- .../views/ProductList/ProductList.tsx | 2 +- .../views/ProductUpdate/ProductUpdate.tsx | 6 +- 12 files changed, 150 insertions(+), 42 deletions(-) diff --git a/src/categories/views/CategoryDetails.tsx b/src/categories/views/CategoryDetails.tsx index e33d91b96..5e8f5ab12 100644 --- a/src/categories/views/CategoryDetails.tsx +++ b/src/categories/views/CategoryDetails.tsx @@ -172,7 +172,7 @@ export const CategoryDetails: React.FC = ({ disabled={loading} errors={updateResult.data?.categoryUpdate.errors || []} onAddCategory={() => navigate(categoryAddUrl(id))} - onAddProduct={() => navigate(productAddUrl)} + onAddProduct={() => navigate(productAddUrl())} onBack={() => navigate( maybe( diff --git a/src/components/Navigator/modes/commands/actions.ts b/src/components/Navigator/modes/commands/actions.ts index 6a85d568a..9956ba8b1 100644 --- a/src/components/Navigator/modes/commands/actions.ts +++ b/src/components/Navigator/modes/commands/actions.ts @@ -46,7 +46,7 @@ export function searchInCommands( { label: intl.formatMessage(messages.createProduct), onClick: () => { - navigate(productAddUrl); + navigate(productAddUrl()); return false; } }, diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index e3f6d61a5..b7538c25d 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -28,6 +28,7 @@ import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/ import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment"; +import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import { FetchMoreProps } from "../../../types"; import { createAttributeChangeHandler, @@ -81,6 +82,7 @@ interface ProductCreatePageProps { }>; header: string; saveButtonBarState: ConfirmButtonTransitionState; + warehouses: SearchWarehouses_search_edges_node[]; fetchCategories: (data: string) => void; fetchCollections: (data: string) => void; fetchProductTypes: (data: string) => void; @@ -103,6 +105,7 @@ export const ProductCreatePage: React.FC = ({ header, productTypes: productTypeChoiceList, saveButtonBarState, + warehouses, onBack, fetchProductTypes, onSubmit, @@ -116,7 +119,18 @@ export const ProductCreatePage: React.FC = ({ data: attributes, set: setAttributeData } = useFormset([]); - const { change: changeStockData, data: stocks } = useFormset([]); + const { change: changeStockData, data: stocks, set: setStocks } = useFormset< + null + >([]); + React.useEffect(() => { + const newStocks = warehouses.map(warehouse => ({ + data: null, + id: warehouse.id, + label: warehouse.name, + value: stocks.find(stock => stock.id === warehouse.id)?.value || 0 + })); + setStocks(newStocks); + }, [JSON.stringify(warehouses)]); // Ensures that it will not change after component rerenders, because it // generates different block keys and it causes editor to lose its content. @@ -248,7 +262,7 @@ export const ProductCreatePage: React.FC = ({ onFormDataChange={change} errors={errors} stocks={stocks} - onWarehouseEdit={onWarehouseEdit} + onWarehousesEdit={onWarehouseEdit} /> diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx index 02f14b64a..54c770223 100644 --- a/src/products/components/ProductStocks/ProductStocks.tsx +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -21,6 +21,7 @@ import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import FormSpacer from "@saleor/components/FormSpacer"; import Hr from "@saleor/components/Hr"; import { renderCollection } from "@saleor/misc"; +import Link from "@saleor/components/Link"; export type ProductStockInput = FormsetAtomicData; export interface ProductStockFormData { @@ -35,7 +36,7 @@ export interface ProductStocksProps { stocks: ProductStockInput[]; onChange: FormsetChange; onFormDataChange: FormChange; - onWarehousesEdit: () => undefined; + onWarehousesEdit: () => void; } const useStyles = makeStyles( @@ -171,24 +172,41 @@ const ProductStocks: React.FC = ({ - {renderCollection(stocks, stock => ( - - {stock.label} - - onChange(stock.id, event.target.value)} - value={stock.value} - /> - - - ))} + {renderCollection( + stocks, + stock => ( + + {stock.label} + + onChange(stock.id, event.target.value)} + value={stock.value} + /> + + + ), + () => ( + + + here." + } + values={{ + l: str => {str} + }} + /> + + + ) + )} diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx index 9faaa1be9..a975f31bb 100644 --- a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx @@ -15,7 +15,6 @@ import ConfirmButton, { import { buttonMessages } from "@saleor/intl"; import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import Skeleton from "@saleor/components/Skeleton"; -import { Product_variants_stocks } from "@saleor/products/types/Product"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import { isSelected, toggle } from "@saleor/utils/lists"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; @@ -44,8 +43,8 @@ export interface ProductWarehousesDialogProps { disabled: boolean; errors: Array; open: boolean; - stocks: Product_variants_stocks[]; warehouses: SearchWarehouses_search_edges_node[]; + warehousesWithStocks: string[]; onClose: () => void; onConfirm: (data: DiffData) => void; } @@ -57,18 +56,18 @@ const ProductWarehousesDialog: React.FC = ({ onClose, onConfirm, open, - stocks, + warehousesWithStocks, warehouses }) => { const classes = useStyles({}); const intl = useIntl(); - const initial = stocks?.map(stock => stock.warehouse.id) || []; const [selectedWarehouses, setSelectedWarehouses] = useStateFromProps( - initial + warehousesWithStocks || [] ); - const handleConfirm = () => onConfirm(diff(initial, selectedWarehouses)); + const handleConfirm = () => + onConfirm(diff(warehousesWithStocks, selectedWarehouses)); return ( diff --git a/src/products/index.tsx b/src/products/index.tsx index 9db230308..c17a75799 100644 --- a/src/products/index.tsx +++ b/src/products/index.tsx @@ -18,9 +18,10 @@ import { ProductUrlQueryParams, productVariantAddPath, productVariantEditPath, - ProductVariantEditUrlQueryParams + ProductVariantEditUrlQueryParams, + ProductAddUrlQueryParams } from "./urls"; -import ProductCreate from "./views/ProductCreate"; +import ProductCreateComponent from "./views/ProductCreate"; import ProductImageComponent from "./views/ProductImage"; import ProductListComponent from "./views/ProductList"; import ProductUpdateComponent from "./views/ProductUpdate"; @@ -92,6 +93,13 @@ const ProductVariantCreate: React.FC> = ({ /> ); +const ProductCreate: React.FC = ({ location }) => { + const qs = parseQs(location.search.substr(1)); + const params: ProductAddUrlQueryParams = qs; + + return ; +}; + const Component = () => { const intl = useIntl(); diff --git a/src/products/mutations.ts b/src/products/mutations.ts index 98247c432..48c625ec2 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -302,6 +302,7 @@ export const productCreateMutation = gql` $sku: String $stockQuantity: Int $seo: SeoInput + $stocks: [StockInput!]! ) { productCreate( input: { @@ -318,6 +319,7 @@ export const productCreateMutation = gql` sku: $sku quantity: $stockQuantity seo: $seo + stocks: $stocks } ) { errors: productErrors { diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index 32cdd2304..a38b7cf40 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { AttributeValueInput, SeoInput, ProductErrorCode, AttributeInputTypeEnum } from "./../../types/globalTypes"; +import { AttributeValueInput, SeoInput, StockInput, ProductErrorCode, AttributeInputTypeEnum } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: ProductCreate @@ -211,4 +211,5 @@ export interface ProductCreateVariables { sku?: string | null; stockQuantity?: number | null; seo?: SeoInput | null; + stocks: StockInput[]; } diff --git a/src/products/urls.ts b/src/products/urls.ts index 5cf5e5d95..17ecded15 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -17,7 +17,10 @@ import { const productSection = "/products/"; export const productAddPath = urlJoin(productSection, "add"); -export const productAddUrl = productAddPath; +export type ProductAddUrlDialog = "edit-stocks"; +export type ProductAddUrlQueryParams = Dialog; +export const productAddUrl = (params?: ProductAddUrlQueryParams): string => + productAddPath + "?" + stringifyQs(params); export const productListPath = productSection; export type ProductListUrlDialog = diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index ae7b565e6..94d77c116 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -9,19 +9,31 @@ import useShop from "@saleor/hooks/useShop"; import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import useProductTypeSearch from "@saleor/searches/useProductTypeSearch"; +import useWarehouseSearch from "@saleor/searches/useWarehouseSearch"; +import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import { decimal, maybe } from "../../misc"; import ProductCreatePage, { ProductCreatePageSubmitData } from "../components/ProductCreatePage"; import { TypedProductCreateMutation } from "../mutations"; import { ProductCreate } from "../types/ProductCreate"; -import { productListUrl, productUrl } from "../urls"; +import { + productListUrl, + productUrl, + ProductAddUrlDialog, + ProductAddUrlQueryParams, + productAddUrl +} from "../urls"; +import ProductWarehousesDialog from "../components/ProductWarehousesDialog"; -interface ProductUpdateProps { - id: string; +interface ProductCreateViewProps { + params: ProductAddUrlQueryParams; } -export const ProductUpdate: React.FC = () => { +export const ProductCreateView: React.FC = ({ + params +}) => { const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); @@ -47,6 +59,24 @@ export const ProductUpdate: React.FC = () => { } = useProductTypeSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const { + loadMore: loadMoreWarehouses, + search: searchWarehouses, + result: searchWarehousesOpts + } = useWarehouseSearch({ + variables: { + ...DEFAULT_INITIAL_SEARCH_DATA, + first: 20 + } + }); + const [warehouses, setWarehouses] = React.useState< + SearchWarehouses_search_edges_node[] + >([]); + + const [openModal, closeModal] = createDialogActionHandlers< + ProductAddUrlDialog, + ProductAddUrlQueryParams + >(navigate, productAddUrl, params); const handleBack = () => navigate(productListUrl()); @@ -88,8 +118,10 @@ export const ProductUpdate: React.FC = () => { title: formData.seoTitle }, sku: formData.sku, - stockQuantity: - formData.stockQuantity !== null ? formData.stockQuantity : 0 + stocks: formData.stocks.map(stock => ({ + quantity: parseInt(stock.value, 0), + warehouse: stock.id + })) } }); }; @@ -124,6 +156,7 @@ export const ProductUpdate: React.FC = () => { productTypes={maybe(() => searchProductTypesOpts.data.search.edges.map(edge => edge.node) )} + warehouses={warehouses} onBack={handleBack} onSubmit={handleSubmit} saveButtonBarState={productCreateOpts.status} @@ -148,6 +181,32 @@ export const ProductUpdate: React.FC = () => { loading: searchProductTypesOpts.loading, onFetchMore: loadMoreProductTypes }} + onWarehouseEdit={() => openModal("edit-stocks")} + /> + edge.node + )} + warehousesWithStocks={warehouses.map(warehouse => warehouse.id)} + onConfirm={data => { + setWarehouses( + [ + ...warehouses, + ...data.added.map( + addedId => + searchWarehousesOpts.data.search.edges.find( + edge => edge.node.id === addedId + ).node + ) + ].filter(warehouse => !data.removed.includes(warehouse.id)) + ); + closeModal(); + }} /> ); @@ -155,4 +214,4 @@ export const ProductUpdate: React.FC = () => { ); }; -export default ProductUpdate; +export default ProductCreateView; diff --git a/src/products/views/ProductList/ProductList.tsx b/src/products/views/ProductList/ProductList.tsx index de9ebe432..302006ca0 100644 --- a/src/products/views/ProductList/ProductList.tsx +++ b/src/products/views/ProductList/ProductList.tsx @@ -306,7 +306,7 @@ export const ProductList: React.FC = ({ params }) => { .hasNextPage, false )} - onAdd={() => navigate(productAddUrl)} + onAdd={() => navigate(productAddUrl())} disabled={loading} products={maybe(() => data.products.edges.map(edge => edge.node) diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 9c0433895..477e41c69 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -384,11 +384,15 @@ export const ProductUpdate: React.FC = ({ id, params }) => { ?.productVariantStocksDelete.errors || []) ]} onClose={closeModal} - stocks={product?.variants[0].stocks || []} open={params.action === "edit-stocks"} warehouses={searchWarehousesOpts.data?.search.edges.map( edge => edge.node )} + warehousesWithStocks={ + product?.variants[0].stocks.map( + stock => stock.warehouse.id + ) || [] + } onConfirm={data => addOrRemoveStocks({ variables: { From 0eb7750321af9807858d0452ea7c6d512902a230 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 27 Mar 2020 11:40:34 +0100 Subject: [PATCH 38/88] Add variant stock management --- .../ProductStocks/ProductStocks.tsx | 1 + .../ProductVariantPage/ProductVariantPage.tsx | 41 ++++-- src/products/mutations.ts | 10 ++ src/products/types/VariantUpdate.ts | 127 +++++++++++++++++- src/products/urls.ts | 6 +- src/products/utils/data.ts | 13 ++ src/products/views/ProductVariant.tsx | 114 +++++++++++++--- 7 files changed, 274 insertions(+), 38 deletions(-) diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx index 54c770223..1a2063b8b 100644 --- a/src/products/components/ProductStocks/ProductStocks.tsx +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -180,6 +180,7 @@ const ProductStocks: React.FC = ({ ; + stocks: ProductStockInput[]; } interface ProductVariantPageProps { @@ -44,6 +48,7 @@ interface ProductVariantPageProps { loading?: boolean; placeholderImage?: string; header: string; + onWarehousesEdit: () => void; onAdd(); onBack(); onDelete(); @@ -64,15 +69,20 @@ const ProductVariantPage: React.FC = ({ onDelete, onImageSelect, onSubmit, + onWarehousesEdit, onVariantClick }) => { const attributeInput = React.useMemo( () => getAttributeInputFromVariant(variant), [variant] ); + const stockInput = React.useMemo(() => getStockInputFromVariant(variant), [ + variant + ]); const { change: changeAttributeData, data: attributes } = useFormset( attributeInput ); + const { change: changeStockData, data: stocks } = useFormset(stockInput); const [isModalOpened, setModalStatus] = React.useState(false); const toggleModal = () => setModalStatus(!isModalOpened); @@ -92,14 +102,15 @@ const ProductVariantPage: React.FC = ({ const initialForm: ProductVariantPageFormData = { costPrice: maybe(() => variant.costPrice.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) => onSubmit({ ...data, - attributes + attributes, + stocks }); return ( @@ -164,15 +175,17 @@ const ProductVariantPage: React.FC = ({ onChange={change} /> - { + triggerChange(); + changeStockData(id, value); + }} + onFormDataChange={change} + onWarehousesEdit={onWarehousesEdit} />
diff --git a/src/products/mutations.ts b/src/products/mutations.ts index 48c625ec2..a8252094d 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -355,6 +355,7 @@ export const TypedVariantDeleteMutation = TypedMutation< >(variantDeleteMutation); export const variantUpdateMutation = gql` + ${bulkStockErrorFragment} ${fragmentVariant} ${productErrorFragment} mutation VariantUpdate( @@ -365,6 +366,7 @@ export const variantUpdateMutation = gql` $sku: String $quantity: Int $trackInventory: Boolean! + $stocks: [StockInput!]! ) { productVariantUpdate( id: $id @@ -384,6 +386,14 @@ export const variantUpdateMutation = gql` ...ProductVariant } } + productVariantStocksUpdate(stocks: $stocks, variantId: $id) { + errors: bulkStockErrors { + ...BulkStockErrorFragment + } + productVariant { + ...ProductVariant + } + } } `; export const TypedVariantUpdateMutation = TypedMutation< diff --git a/src/products/types/VariantUpdate.ts b/src/products/types/VariantUpdate.ts index c0deeabd3..27546842c 100644 --- a/src/products/types/VariantUpdate.ts +++ b/src/products/types/VariantUpdate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // 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 @@ -130,8 +130,132 @@ export interface VariantUpdate_productVariantUpdate { 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 { productVariantUpdate: VariantUpdate_productVariantUpdate | null; + productVariantStocksUpdate: VariantUpdate_productVariantStocksUpdate | null; } export interface VariantUpdateVariables { @@ -142,4 +266,5 @@ export interface VariantUpdateVariables { sku?: string | null; quantity?: number | null; trackInventory: boolean; + stocks: StockInput[]; } diff --git a/src/products/urls.ts b/src/products/urls.ts index 17ecded15..4229e7871 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -80,8 +80,10 @@ export const productUrl = (id: string, params?: ProductUrlQueryParams) => export const productVariantEditPath = (productId: string, variantId: string) => urlJoin(productSection, productId, "variant", variantId); -export type ProductVariantEditUrlDialog = "remove"; -export type ProductVariantEditUrlQueryParams = Dialog<"remove">; +export type ProductVariantEditUrlDialog = "edit-stocks" | "remove"; +export type ProductVariantEditUrlQueryParams = Dialog< + ProductVariantEditUrlDialog +>; export const productVariantEditUrl = ( productId: string, variantId: string, diff --git a/src/products/utils/data.ts b/src/products/utils/data.ts index 23c19429c..45be5ee4b 100644 --- a/src/products/utils/data.ts +++ b/src/products/utils/data.ts @@ -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( product: ProductVariantCreateData_product ): VariantAttributeInput[] { diff --git a/src/products/views/ProductVariant.tsx b/src/products/views/ProductVariant.tsx index 6a68c2d49..fb3c4a28f 100644 --- a/src/products/views/ProductVariant.tsx +++ b/src/products/views/ProductVariant.tsx @@ -7,7 +7,10 @@ import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; 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 ProductVariantPage, { ProductVariantPageSubmitData @@ -22,8 +25,11 @@ import { productUrl, productVariantAddUrl, productVariantEditUrl, - ProductVariantEditUrlQueryParams + ProductVariantEditUrlQueryParams, + ProductVariantEditUrlDialog } from "../urls"; +import ProductWarehousesDialog from "../components/ProductWarehousesDialog"; +import { useAddOrRemoveStocks } from "../mutations"; interface ProductUpdateProps { variantId: string; @@ -46,6 +52,40 @@ export const ProductVariant: React.FC = ({ setErrors([]); }, [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)); return ( @@ -107,14 +147,14 @@ export const ProductVariant: React.FC = ({ return ( <> - data.productVariant.name)} /> + navigate(productVariantAddUrl(productId))} onBack={handleBack} onDelete={() => @@ -125,25 +165,27 @@ export const ProductVariant: React.FC = ({ ) } onImageSelect={handleImageSelect} - onSubmit={(data: ProductVariantPageSubmitData) => { - if (variant) { - updateVariant.mutate({ - attributes: data.attributes.map(attribute => ({ - id: attribute.id, - values: [attribute.value] - })), - costPrice: decimal(data.costPrice), - id: variantId, - priceOverride: decimal(data.priceOverride), - quantity: parseInt(data.quantity, 0), - sku: data.sku, - trackInventory: true // FIXME: missing in UI - }); - } - }} + onSubmit={(data: ProductVariantPageSubmitData) => + updateVariant.mutate({ + attributes: data.attributes.map(attribute => ({ + id: attribute.id, + values: [attribute.value] + })), + costPrice: decimal(data.costPrice), + id: variantId, + priceOverride: decimal(data.priceOverride), + sku: data.sku, + stocks: data.stocks.map(stock => ({ + quantity: parseInt(stock.value, 10), + warehouse: stock.id + })), + trackInventory: data.trackInventory + }) + } onVariantClick={variantId => { navigate(productVariantEditUrl(productId, variantId)); }} + onWarehousesEdit={() => openModal("edit-stocks")} /> = ({ }) } open={params.action === "remove"} - name={maybe(() => data.productVariant.name)} + name={data?.productVariant?.name} + /> + 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 + } + }) + } /> ); From d38fa424625cb91413c83a5b6cd706ab7c592dd2 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 27 Mar 2020 12:06:11 +0100 Subject: [PATCH 39/88] Add stock in product variant create view --- .../ProductVariantCreatePage.tsx | 54 +++++++---- .../ProductVariantStock.tsx | 97 ------------------- .../components/ProductVariantStock/index.ts | 2 - src/products/index.tsx | 19 ++-- src/products/mutations.ts | 2 + src/products/types/ProductCreate.ts | 1 + src/products/urls.ts | 13 ++- src/products/views/ProductCreate.tsx | 3 +- src/products/views/ProductVariantCreate.tsx | 80 ++++++++++++++- 9 files changed, 139 insertions(+), 132 deletions(-) delete mode 100644 src/products/components/ProductVariantStock/ProductVariantStock.tsx delete mode 100644 src/products/components/ProductVariantStock/index.ts diff --git a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx index 47b3c4d13..27f8cb595 100644 --- a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx +++ b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx @@ -15,6 +15,7 @@ import useFormset, { } from "@saleor/hooks/useFormset"; import { getVariantAttributeInputFromProduct } from "@saleor/products/utils/data"; import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment"; +import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import { maybe } from "../../../misc"; import { ProductVariantCreateData_product } from "../../types/ProductVariantCreateData"; import ProductVariantAttributes, { @@ -22,7 +23,7 @@ import ProductVariantAttributes, { } from "../ProductVariantAttributes"; import ProductVariantNavigation from "../ProductVariantNavigation"; import ProductVariantPrice from "../ProductVariantPrice"; -import ProductVariantStock from "../ProductVariantStock"; +import ProductStocks, { ProductStockInput } from "../ProductStocks"; interface ProductVariantCreatePageFormData { costPrice: string; @@ -30,35 +31,43 @@ interface ProductVariantCreatePageFormData { priceOverride: string; quantity: string; sku: string; + trackInventory: boolean; } export interface ProductVariantCreatePageSubmitData extends ProductVariantCreatePageFormData { attributes: FormsetData; + stocks: ProductStockInput[]; } interface ProductVariantCreatePageProps { currencySymbol: string; + disabled: boolean; errors: ProductErrorFragment[]; header: string; loading: boolean; product: ProductVariantCreateData_product; saveButtonBarState: ConfirmButtonTransitionState; + warehouses: SearchWarehouses_search_edges_node[]; onBack: () => void; onSubmit: (data: ProductVariantCreatePageSubmitData) => void; onVariantClick: (variantId: string) => void; + onWarehouseEdit: () => void; } const ProductVariantCreatePage: React.FC = ({ currencySymbol, + disabled, errors, loading, header, product, saveButtonBarState, + warehouses, onBack, onSubmit, - onVariantClick + onVariantClick, + onWarehouseEdit }) => { const intl = useIntl(); const attributeInput = React.useMemo( @@ -68,28 +77,33 @@ const ProductVariantCreatePage: React.FC = ({ const { change: changeAttributeData, data: attributes } = useFormset( attributeInput ); + const { change: changeStockData, data: stocks, set: setStocks } = useFormset< + null + >([]); + React.useEffect(() => { + const newStocks = warehouses.map(warehouse => ({ + data: null, + id: warehouse.id, + label: warehouse.name, + value: stocks.find(stock => stock.id === warehouse.id)?.value || 0 + })); + setStocks(newStocks); + }, [JSON.stringify(warehouses)]); - const initialForm = { - attributes: maybe( - () => - product.productType.variantAttributes.map(attribute => ({ - name: attribute.name, - slug: attribute.slug, - values: [""] - })), - [] - ), + const initialForm: ProductVariantCreatePageFormData = { costPrice: "", images: maybe(() => product.images.map(image => image.id)), priceOverride: "", quantity: "0", - sku: "" + sku: "", + trackInventory: true }; const handleSubmit = (data: ProductVariantCreatePageFormData) => onSubmit({ ...data, - attributes + attributes, + stocks }); return ( @@ -133,12 +147,14 @@ const ProductVariantCreatePage: React.FC = ({ onChange={change} /> -
diff --git a/src/products/components/ProductVariantStock/ProductVariantStock.tsx b/src/products/components/ProductVariantStock/ProductVariantStock.tsx deleted file mode 100644 index fe8b52776..000000000 --- a/src/products/components/ProductVariantStock/ProductVariantStock.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import Card from "@material-ui/core/Card"; -import CardContent from "@material-ui/core/CardContent"; -import { makeStyles } from "@material-ui/core/styles"; -import TextField from "@material-ui/core/TextField"; -import React from "react"; -import { useIntl } from "react-intl"; - -import CardTitle from "@saleor/components/CardTitle"; -import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors"; -import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment"; - -const useStyles = makeStyles( - theme => ({ - grid: { - display: "grid", - gridColumnGap: theme.spacing(2), - gridTemplateColumns: "1fr 1fr" - } - }), - { name: "ProductVariantStock" } -); - -interface ProductVariantStockProps { - errors: ProductErrorFragment[]; - sku: string; - quantity: string; - stockAllocated?: number; - loading?: boolean; - onChange(event: any); -} - -const ProductVariantStock: React.FC = props => { - const { errors, sku, quantity, stockAllocated, loading, onChange } = props; - - const classes = useStyles(props); - const intl = useIntl(); - - const formErrors = getFormErrors(["quantity", "sku"], errors); - - return ( - - - -
-
- -
-
- -
-
-
-
- ); -}; -ProductVariantStock.displayName = "ProductVariantStock"; -export default ProductVariantStock; diff --git a/src/products/components/ProductVariantStock/index.ts b/src/products/components/ProductVariantStock/index.ts deleted file mode 100644 index 0cb07fabd..000000000 --- a/src/products/components/ProductVariantStock/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./ProductVariantStock"; -export * from "./ProductVariantStock"; diff --git a/src/products/index.tsx b/src/products/index.tsx index c17a75799..dfd75cd77 100644 --- a/src/products/index.tsx +++ b/src/products/index.tsx @@ -19,7 +19,8 @@ import { productVariantAddPath, productVariantEditPath, ProductVariantEditUrlQueryParams, - ProductAddUrlQueryParams + ProductAddUrlQueryParams, + ProductVariantAddUrlQueryParams } from "./urls"; import ProductCreateComponent from "./views/ProductCreate"; import ProductImageComponent from "./views/ProductImage"; @@ -87,11 +88,17 @@ const ProductImage: React.FC> = ({ const ProductVariantCreate: React.FC> = ({ match -}) => ( - -); +}) => { + const qs = parseQs(location.search.substr(1)); + const params: ProductVariantAddUrlQueryParams = qs; + + return ( + + ); +}; const ProductCreate: React.FC = ({ location }) => { const qs = parseQs(location.search.substr(1)); diff --git a/src/products/mutations.ts b/src/products/mutations.ts index a8252094d..72cb86adc 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -303,6 +303,7 @@ export const productCreateMutation = gql` $stockQuantity: Int $seo: SeoInput $stocks: [StockInput!]! + $trackInventory: Boolean! ) { productCreate( input: { @@ -320,6 +321,7 @@ export const productCreateMutation = gql` quantity: $stockQuantity seo: $seo stocks: $stocks + trackInventory: $trackInventory } ) { errors: productErrors { diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index a38b7cf40..710f81e8f 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -212,4 +212,5 @@ export interface ProductCreateVariables { stockQuantity?: number | null; seo?: SeoInput | null; stocks: StockInput[]; + trackInventory: boolean; } diff --git a/src/products/urls.ts b/src/products/urls.ts index 4229e7871..08b8aeb7a 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -98,8 +98,17 @@ export const productVariantEditUrl = ( export const productVariantAddPath = (productId: string) => urlJoin(productSection, productId, "variant/add"); -export const productVariantAddUrl = (productId: string) => - productVariantAddPath(encodeURIComponent(productId)); +export type ProductVariantAddUrlDialog = "edit-stocks"; +export type ProductVariantAddUrlQueryParams = Dialog< + ProductVariantAddUrlDialog +>; +export const productVariantAddUrl = ( + productId: string, + params?: ProductVariantAddUrlQueryParams +): string => + productVariantAddPath(encodeURIComponent(productId)) + + "?" + + stringifyQs(params); export const productImagePath = (productId: string, imageId: string) => urlJoin(productSection, productId, "image", imageId); diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 94d77c116..18cd8b1a8 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -121,7 +121,8 @@ export const ProductCreateView: React.FC = ({ stocks: formData.stocks.map(stock => ({ quantity: parseInt(stock.value, 0), warehouse: stock.id - })) + })), + trackInventory: formData.trackInventory } }); }; diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index c2e446ab1..103086e5e 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -7,24 +7,58 @@ import useNotifier from "@saleor/hooks/useNotifier"; import useShop from "@saleor/hooks/useShop"; import NotFoundPage from "@saleor/components/NotFoundPage"; import { commonMessages } from "@saleor/intl"; -import { decimal, maybe } from "../../misc"; +import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; +import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; +import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; +import useWarehouseSearch from "@saleor/searches/useWarehouseSearch"; +import { decimal } from "../../misc"; import ProductVariantCreatePage, { ProductVariantCreatePageSubmitData } from "../components/ProductVariantCreatePage"; import { TypedVariantCreateMutation } from "../mutations"; import { TypedProductVariantCreateQuery } from "../queries"; import { VariantCreate } from "../types/VariantCreate"; -import { productUrl, productVariantEditUrl, productListUrl } from "../urls"; +import { + productUrl, + productVariantEditUrl, + productListUrl, + productVariantAddUrl, + ProductVariantAddUrlDialog, + ProductVariantAddUrlQueryParams +} from "../urls"; +import ProductWarehousesDialog from "../components/ProductWarehousesDialog"; -interface ProductUpdateProps { +interface ProductVariantCreateProps { + params: ProductVariantAddUrlQueryParams; productId: string; } -export const ProductVariant: React.FC = ({ productId }) => { +export const ProductVariant: React.FC = ({ + params, + productId +}) => { const navigate = useNavigator(); const notify = useNotifier(); const shop = useShop(); const intl = useIntl(); + const { + loadMore: loadMoreWarehouses, + search: searchWarehouses, + result: searchWarehousesOpts + } = useWarehouseSearch({ + variables: { + ...DEFAULT_INITIAL_SEARCH_DATA, + first: 20 + } + }); + const [warehouses, setWarehouses] = React.useState< + SearchWarehouses_search_edges_node[] + >([]); + + const [openModal, closeModal] = createDialogActionHandlers< + ProductVariantAddUrlDialog, + ProductVariantAddUrlQueryParams + >(navigate, params => productVariantAddUrl(productId, params), params); return ( @@ -70,6 +104,10 @@ export const ProductVariant: React.FC = ({ productId }) => { product: productId, quantity: parseInt(formData.quantity, 0), sku: formData.sku, + stocks: formData.stocks.map(stock => ({ + quantity: parseInt(stock.value, 0), + warehouse: stock.id + })), trackInventory: true } } @@ -88,7 +126,8 @@ export const ProductVariant: React.FC = ({ productId }) => { })} /> shop.defaultCurrency)} + currencySymbol={shop?.defaultCurrency} + disabled={productLoading} errors={ variantCreateResult.data?.productVariantCreate.errors || [] @@ -103,6 +142,37 @@ export const ProductVariant: React.FC = ({ productId }) => { onSubmit={handleSubmit} onVariantClick={handleVariantClick} saveButtonBarState={variantCreateResult.status} + warehouses={warehouses} + onWarehouseEdit={() => openModal("edit-stocks")} + /> + edge.node + )} + warehousesWithStocks={warehouses.map( + warehouse => warehouse.id + )} + onConfirm={data => { + setWarehouses( + [ + ...warehouses, + ...data.added.map( + addedId => + searchWarehousesOpts.data.search.edges.find( + edge => edge.node.id === addedId + ).node + ) + ].filter( + warehouse => !data.removed.includes(warehouse.id) + ) + ); + closeModal(); + }} /> ); From d0e082dc21453c7ea738023c84f4ac4088250015 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 27 Mar 2020 13:21:34 +0100 Subject: [PATCH 40/88] Add error translations --- .../CompanyAddressForm.tsx | 19 ++++--- .../ProductWarehousesDialog.tsx | 21 +++++++- src/utils/errors/stock.ts | 47 +++++++++++++++++ src/utils/errors/warehouse.ts | 51 +++++++++++++++++++ .../WarehouseCreatePage.tsx | 4 +- .../WarehouseDetailsPage.tsx | 4 +- .../WarehouseInfo/WarehouseInfo.tsx | 13 +++-- src/warehouses/mutations.ts | 18 +++---- src/warehouses/types/WarehouseCreate.ts | 6 +-- src/warehouses/types/WarehouseDelete.ts | 6 ++- src/warehouses/types/WarehouseUpdate.ts | 6 +-- 11 files changed, 161 insertions(+), 34 deletions(-) create mode 100644 src/utils/errors/stock.ts create mode 100644 src/utils/errors/warehouse.ts diff --git a/src/components/CompanyAddressInput/CompanyAddressForm.tsx b/src/components/CompanyAddressInput/CompanyAddressForm.tsx index b94b87aac..a3b58f8a0 100644 --- a/src/components/CompanyAddressInput/CompanyAddressForm.tsx +++ b/src/components/CompanyAddressInput/CompanyAddressForm.tsx @@ -15,12 +15,16 @@ import { getFormErrors } from "@saleor/utils/errors"; import { ShopErrorFragment } from "@saleor/siteSettings/types/ShopErrorFragment"; import { AccountErrorFragment } from "@saleor/customers/types/AccountErrorFragment"; import getAccountErrorMessage from "@saleor/utils/errors/account"; +import getWarehouseErrorMessage from "@saleor/utils/errors/warehouse"; +import { WarehouseErrorFragment } from "@saleor/warehouses/types/WarehouseErrorFragment"; export interface CompanyAddressFormProps { countries: SingleAutocompleteChoiceType[]; data: AddressTypeInput; displayCountry: string; - errors: Array; + errors: Array< + AccountErrorFragment | ShopErrorFragment | WarehouseErrorFragment + >; disabled: boolean; onChange: (event: ChangeEvent) => void; onCountryChange: (event: ChangeEvent) => void; @@ -34,14 +38,17 @@ const useStyles = makeStyles( ); function getErrorMessage( - err: AccountErrorFragment | ShopErrorFragment, + err: AccountErrorFragment | ShopErrorFragment | WarehouseErrorFragment, intl: IntlShape ): string { - if (err?.__typename === "AccountError") { - return getAccountErrorMessage(err, intl); + switch (err?.__typename) { + case "AccountError": + return getAccountErrorMessage(err, intl); + case "WarehouseError": + return getWarehouseErrorMessage(err, intl); + default: + return getShopErrorMessage(err, intl); } - - return getShopErrorMessage(err, intl); } const CompanyAddressForm: React.FC = props => { diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx index a975f31bb..f027fcad9 100644 --- a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx @@ -5,7 +5,7 @@ import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; import Typography from "@material-ui/core/Typography"; import React from "react"; -import { FormattedMessage, useIntl } from "react-intl"; +import { FormattedMessage, useIntl, IntlShape } from "react-intl"; import makeStyles from "@material-ui/core/styles/makeStyles"; import { diff, DiffData } from "fast-array-diff"; @@ -20,6 +20,9 @@ import { isSelected, toggle } from "@saleor/utils/lists"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { BulkStockErrorFragment } from "@saleor/products/types/BulkStockErrorFragment"; import { StockErrorFragment } from "@saleor/products/types/StockErrorFragment"; +import getStockErrorMessage, { + getBulkStockErrorMessage +} from "@saleor/utils/errors/stock"; const useStyles = makeStyles( theme => ({ @@ -49,6 +52,18 @@ export interface ProductWarehousesDialogProps { onConfirm: (data: DiffData) => void; } +function getErrorMessage( + err: BulkStockErrorFragment | StockErrorFragment, + intl: IntlShape +): string { + switch (err?.__typename) { + case "BulkStockError": + return getBulkStockErrorMessage(err, intl); + default: + getStockErrorMessage(err, intl); + } +} + const ProductWarehousesDialog: React.FC = ({ confirmButtonState, disabled, @@ -112,7 +127,9 @@ const ProductWarehousesDialog: React.FC = ({ {errors.length > 0 && ( - {errors[0]?.message} + + {getErrorMessage(errors[0], intl)} + )} diff --git a/src/utils/errors/stock.ts b/src/utils/errors/stock.ts new file mode 100644 index 000000000..6bf4d1da9 --- /dev/null +++ b/src/utils/errors/stock.ts @@ -0,0 +1,47 @@ +import { IntlShape, defineMessages } from "react-intl"; + +import { StockErrorFragment } from "@saleor/products/types/StockErrorFragment"; +import { StockErrorCode } from "@saleor/types/globalTypes"; +import { commonMessages } from "@saleor/intl"; +import { BulkStockErrorFragment } from "@saleor/products/types/BulkStockErrorFragment"; +import commonErrorMessages from "./common"; +import getProductErrorMessage from "./product"; + +const messages = defineMessages({ + slugUnique: { + defaultMessage: + "Stock for this warehouse already exists for this product variant", + description: "error message" + } +}); + +function getStockErrorMessage( + err: Omit | undefined, + intl: IntlShape +): string { + if (err) { + switch (err.code) { + case StockErrorCode.UNIQUE: + return intl.formatMessage(messages.slugUnique); + case StockErrorCode.GRAPHQL_ERROR: + return intl.formatMessage(commonErrorMessages.graphqlError); + case StockErrorCode.REQUIRED: + return intl.formatMessage(commonMessages.requiredField); + case StockErrorCode.INVALID: + return intl.formatMessage(commonErrorMessages.invalid); + default: + return intl.formatMessage(commonErrorMessages.unknownError); + } + } + + return undefined; +} + +export function getBulkStockErrorMessage( + err: Omit | undefined, + intl: IntlShape +): string { + return getProductErrorMessage(err, intl); +} + +export default getStockErrorMessage; diff --git a/src/utils/errors/warehouse.ts b/src/utils/errors/warehouse.ts new file mode 100644 index 000000000..ee45e04a3 --- /dev/null +++ b/src/utils/errors/warehouse.ts @@ -0,0 +1,51 @@ +import { IntlShape, defineMessages } from "react-intl"; + +import { WarehouseErrorFragment } from "@saleor/warehouses/types/WarehouseErrorFragment"; +import { WarehouseErrorCode } from "@saleor/types/globalTypes"; +import { commonMessages } from "@saleor/intl"; +import commonErrorMessages from "./common"; + +const messages = defineMessages({ + slugUnique: { + defaultMessage: "Slug must be unique for each warehouse", + description: "error message" + } +}); + +function getWarehouseErrorMessage( + err: Omit | undefined, + intl: IntlShape +): string { + if (err) { + switch (err.code) { + case WarehouseErrorCode.GRAPHQL_ERROR: + return intl.formatMessage(commonErrorMessages.graphqlError); + case WarehouseErrorCode.REQUIRED: + return intl.formatMessage(commonMessages.requiredField); + case WarehouseErrorCode.INVALID: + return intl.formatMessage(commonErrorMessages.invalid); + default: + return intl.formatMessage(commonErrorMessages.unknownError); + } + } + + return undefined; +} + +export function getWarehouseSlugErrorMessage( + err: Omit | undefined, + intl: IntlShape +): string { + if (err) { + switch (err.code) { + case WarehouseErrorCode.UNIQUE: + return intl.formatMessage(messages.slugUnique); + default: + return getWarehouseErrorMessage(err, intl); + } + } + + return undefined; +} + +export default getWarehouseErrorMessage; diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx index 61a25f254..b49e010f2 100644 --- a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.tsx @@ -5,7 +5,6 @@ import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import { UserError } from "@saleor/types"; import Grid from "@saleor/components/Grid"; import CardSpacer from "@saleor/components/CardSpacer"; import CompanyAddressInput from "@saleor/components/CompanyAddressInput"; @@ -18,6 +17,7 @@ import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo" import AppHeader from "@saleor/components/AppHeader"; import PageHeader from "@saleor/components/PageHeader"; import { sectionNames } from "@saleor/intl"; +import { WarehouseErrorFragment } from "@saleor/warehouses/types/WarehouseErrorFragment"; import WarehouseInfo from "../WarehouseInfo"; export interface WarehouseCreatePageFormData extends AddressTypeInput { @@ -26,7 +26,7 @@ export interface WarehouseCreatePageFormData extends AddressTypeInput { export interface WarehouseCreatePageProps { countries: ShopInfo_shop_countries[]; disabled: boolean; - errors: UserError[]; + errors: WarehouseErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; onBack: () => void; onSubmit: (data: WarehouseCreatePageFormData) => void; diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx index d15bf3836..c4c53c811 100644 --- a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.tsx @@ -5,7 +5,6 @@ import Container from "@saleor/components/Container"; import Form from "@saleor/components/Form"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import { UserError } from "@saleor/types"; import Grid from "@saleor/components/Grid"; import CardSpacer from "@saleor/components/CardSpacer"; import CompanyAddressInput from "@saleor/components/CompanyAddressInput"; @@ -20,6 +19,7 @@ import AppHeader from "@saleor/components/AppHeader"; import PageHeader from "@saleor/components/PageHeader"; import { sectionNames } from "@saleor/intl"; import { CountryCode } from "@saleor/types/globalTypes"; +import { WarehouseErrorFragment } from "@saleor/warehouses/types/WarehouseErrorFragment"; import WarehouseInfo from "../WarehouseInfo"; import WarehouseZones from "../WarehouseZones"; import { WarehouseDetails_warehouse } from "../../types/WarehouseDetails"; @@ -30,7 +30,7 @@ export interface WarehouseDetailsPageFormData extends AddressTypeInput { export interface WarehouseDetailsPageProps { countries: ShopInfo_shop_countries[]; disabled: boolean; - errors: UserError[]; + errors: WarehouseErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; warehouse: WarehouseDetails_warehouse; onBack: () => void; diff --git a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx index fdc51a261..1dde8858a 100644 --- a/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx +++ b/src/warehouses/components/WarehouseInfo/WarehouseInfo.tsx @@ -7,13 +7,14 @@ import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { commonMessages } from "@saleor/intl"; import { FormChange } from "@saleor/hooks/useForm"; -import { UserError } from "@saleor/types"; -import { getFieldError } from "@saleor/utils/errors"; +import { getFormErrors } from "@saleor/utils/errors"; +import { WarehouseErrorFragment } from "@saleor/warehouses/types/WarehouseErrorFragment"; +import getWarehouseErrorMessage from "@saleor/utils/errors/warehouse"; export interface WarehouseInfoProps { data: Record<"name", string>; disabled: boolean; - errors: UserError[]; + errors: WarehouseErrorFragment[]; onChange: FormChange; } @@ -25,6 +26,8 @@ const WarehouseInfo: React.FC = ({ }) => { const intl = useIntl(); + const formErrors = getFormErrors(["name"], errors); + return ( = ({ Date: Fri, 27 Mar 2020 15:51:21 +0100 Subject: [PATCH 41/88] Fix type errors --- .../ProductCreatePage/ProductCreatePage.tsx | 11 ++----- .../ProductStocks/ProductStocks.tsx | 2 +- .../ProductVariantCreatePage.tsx | 8 ++--- .../ProductWarehousesDialog.stories.tsx | 30 ++++++++----------- .../ProductWarehousesDialog.tsx | 2 +- src/products/fixtures.ts | 21 +++++++++---- src/products/views/ProductCreate.tsx | 6 +--- .../views/ProductUpdate/ProductUpdate.tsx | 6 +--- src/products/views/ProductVariant.tsx | 6 +--- src/products/views/ProductVariantCreate.tsx | 9 ++---- .../ShippingZoneAddWarehouseDialog.tsx | 5 ++-- .../views/ShippingZoneDetails/index.tsx | 2 +- .../stories/products/ProductCreatePage.tsx | 7 +++++ .../stories/products/ProductUpdatePage.tsx | 25 ++++++++++++++-- .../products/ProductVariantCreatePage.tsx | 17 ++++++++--- .../stories/products/ProductVariantPage.tsx | 3 ++ .../WarehouseCreatePage.stories.tsx | 10 ++++--- .../WarehouseDetailsPage.stories.tsx | 10 ++++--- 18 files changed, 103 insertions(+), 77 deletions(-) diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index b7538c25d..ba8174f4f 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -165,12 +165,7 @@ export const ProductCreatePage: React.FC = ({ MultiAutocompleteChoiceType[] >([]); - const [productType, setProductType] = React.useState({ - hasVariants: false, - id: "", - name: "", - productAttributes: [] - }); + const [productType, setProductType] = React.useState(null); const categories = getChoices(categoryChoiceList); const collections = getChoices(collectionChoiceList); @@ -253,7 +248,7 @@ export const ProductCreatePage: React.FC = ({ onChange={change} /> - {!productType.hasVariants && ( + {!!productType && !productType.hasVariants && ( <> = ({ fetchMoreProductTypes={fetchMoreProductTypes} fetchProductTypes={fetchProductTypes} productType={productType} - productTypeInputDisplayValue={productType.name} + productTypeInputDisplayValue={productType?.name || ""} productTypes={productTypes} onCategoryChange={handleCategorySelect} onCollectionChange={handleCollectionSelect} diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx index 1a2063b8b..e66532cd3 100644 --- a/src/products/components/ProductStocks/ProductStocks.tsx +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -175,7 +175,7 @@ const ProductStocks: React.FC = ({ {renderCollection( stocks, stock => ( - + {stock.label} = ({ currencySymbol, disabled, errors, - loading, header, product, saveButtonBarState, @@ -133,7 +131,7 @@ const ProductVariantCreatePage: React.FC = ({
@@ -143,7 +141,7 @@ const ProductVariantCreatePage: React.FC = ({ priceOverride={data.priceOverride} currencySymbol={currencySymbol} costPrice={data.costPrice} - loading={loading} + loading={disabled} onChange={change} /> @@ -159,7 +157,7 @@ const ProductVariantCreatePage: React.FC = ({
undefined, onConfirm: () => undefined, open: true, - stocks: [ - { - __typename: "Stock", - id: "5123", - quantity: 2, - warehouse: warehouseList[0] - }, - { - __typename: "Stock", - id: "5223", - quantity: 4, - warehouse: warehouseList[2] - } - ], - warehouses: warehouseList + warehouses: warehouseList, + warehousesWithStocks: [warehouseList[0].id, warehouseList[2].id] }; storiesOf("Views / Products / Edit warehouses", module) @@ -46,5 +33,14 @@ storiesOf("Views / Products / Edit warehouses", module) /> )) .add("with error", () => ( - + )); diff --git a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx index f027fcad9..0b9192c1d 100644 --- a/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx +++ b/src/products/components/ProductWarehousesDialog/ProductWarehousesDialog.tsx @@ -60,7 +60,7 @@ function getErrorMessage( case "BulkStockError": return getBulkStockErrorMessage(err, intl); default: - getStockErrorMessage(err, intl); + return getStockErrorMessage(err, intl); } } diff --git a/src/products/fixtures.ts b/src/products/fixtures.ts index b45ac7bd4..04eca4b56 100644 --- a/src/products/fixtures.ts +++ b/src/products/fixtures.ts @@ -1247,21 +1247,30 @@ export const variant = (placeholderImage: string): ProductVariant => ({ } ] }, - quantity: 19, - quantityAllocated: 12, sku: "1230959124123", - stock: [ + stocks: [ { __typename: "Stock", id: "1", - quantity: 1 + quantity: 1, + warehouse: { + __typename: "Warehouse", + id: "123", + name: "Warehouse 1" + } }, { __typename: "Stock", id: "2", - quantity: 4 + quantity: 4, + warehouse: { + __typename: "Warehouse", + id: "1234", + name: "Warehouse 2" + } } - ] + ], + trackInventory: true }); export const variantImages = (placeholderImage: string) => variant(placeholderImage).images; diff --git a/src/products/views/ProductCreate.tsx b/src/products/views/ProductCreate.tsx index 18cd8b1a8..84928e85a 100644 --- a/src/products/views/ProductCreate.tsx +++ b/src/products/views/ProductCreate.tsx @@ -59,11 +59,7 @@ export const ProductCreateView: React.FC = ({ } = useProductTypeSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); - const { - loadMore: loadMoreWarehouses, - search: searchWarehouses, - result: searchWarehousesOpts - } = useWarehouseSearch({ + const { result: searchWarehousesOpts } = useWarehouseSearch({ variables: { ...DEFAULT_INITIAL_SEARCH_DATA, first: 20 diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 477e41c69..899d14dd1 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -74,11 +74,7 @@ export const ProductUpdate: React.FC = ({ id, params }) => { } = useCollectionSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); - const { - loadMore: loadMoreWarehouses, - search: searchWarehouses, - result: searchWarehousesOpts - } = useWarehouseSearch({ + const { result: searchWarehousesOpts } = useWarehouseSearch({ variables: { ...DEFAULT_INITIAL_SEARCH_DATA, first: 20 diff --git a/src/products/views/ProductVariant.tsx b/src/products/views/ProductVariant.tsx index fb3c4a28f..b03f3a33e 100644 --- a/src/products/views/ProductVariant.tsx +++ b/src/products/views/ProductVariant.tsx @@ -52,11 +52,7 @@ export const ProductVariant: React.FC = ({ setErrors([]); }, [variantId]); - const { - loadMore: loadMoreWarehouses, - search: searchWarehouses, - result: searchWarehousesOpts - } = useWarehouseSearch({ + const { result: searchWarehousesOpts } = useWarehouseSearch({ variables: { ...DEFAULT_INITIAL_SEARCH_DATA, first: 20 diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index 103086e5e..5c69cc919 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -41,11 +41,7 @@ export const ProductVariant: React.FC = ({ const notify = useNotifier(); const shop = useShop(); const intl = useIntl(); - const { - loadMore: loadMoreWarehouses, - search: searchWarehouses, - result: searchWarehousesOpts - } = useWarehouseSearch({ + const { result: searchWarehousesOpts } = useWarehouseSearch({ variables: { ...DEFAULT_INITIAL_SEARCH_DATA, first: 20 @@ -127,7 +123,7 @@ export const ProductVariant: React.FC = ({ /> = ({ defaultMessage: "Create Variant", description: "header" })} - loading={disableForm} product={data?.product} onBack={handleBack} onSubmit={handleSubmit} diff --git a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx index fcf7d038c..4315c31c1 100644 --- a/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx +++ b/src/shipping/components/ShippingZoneAddWarehouseDialog/ShippingZoneAddWarehouseDialog.tsx @@ -11,7 +11,7 @@ import makeStyles from "@material-ui/core/styles/makeStyles"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import { DialogProps, UserError } from "@saleor/types"; +import { DialogProps } from "@saleor/types"; import { AddressTypeInput } from "@saleor/customers/types"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; @@ -24,6 +24,7 @@ import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import FormSpacer from "@saleor/components/FormSpacer"; +import { WarehouseErrorFragment } from "@saleor/warehouses/types/WarehouseErrorFragment"; export interface ShippingZoneAddWarehouseDialogSubmitData extends AddressTypeInput { @@ -33,7 +34,7 @@ export interface ShippingZoneAddWarehouseDialogProps extends DialogProps { confirmButtonState: ConfirmButtonTransitionState; countries: ShopInfo_shop_countries[]; disabled: boolean; - errors: UserError[]; + errors: WarehouseErrorFragment[]; onSubmit: (data: ShippingZoneAddWarehouseDialogSubmitData) => void; } diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index dc66c7d59..0dd6a6777 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -176,7 +176,7 @@ const ShippingZoneDetails: React.FC = ({ ); } } else { - throw new Error(`Updating failed: ${updateErrors[0].message}`); + throw new Error(`Updating failed: ${updateErrors[0].code}`); } } catch (err) { notify({ diff --git a/src/storybook/stories/products/ProductCreatePage.tsx b/src/storybook/stories/products/ProductCreatePage.tsx index 306c5eca9..4d37c89ed 100644 --- a/src/storybook/stories/products/ProductCreatePage.tsx +++ b/src/storybook/stories/products/ProductCreatePage.tsx @@ -3,6 +3,7 @@ import React from "react"; import { fetchMoreProps } from "@saleor/fixtures"; import { ProductErrorCode } from "@saleor/types/globalTypes"; +import { warehouseList } from "@saleor/warehouses/fixtures"; import ProductCreatePage, { ProductCreatePageSubmitData } from "../../../products/components/ProductCreatePage"; @@ -32,6 +33,8 @@ storiesOf("Views / Products / Create product", module) onBack={() => undefined} onSubmit={() => undefined} saveButtonBarState="default" + onWarehouseEdit={() => undefined} + warehouses={warehouseList} /> )) .add("When loading", () => ( @@ -52,6 +55,8 @@ storiesOf("Views / Products / Create product", module) onBack={() => undefined} onSubmit={() => undefined} saveButtonBarState="default" + onWarehouseEdit={() => undefined} + warehouses={undefined} /> )) .add("form errors", () => ( @@ -78,5 +83,7 @@ storiesOf("Views / Products / Create product", module) onBack={() => undefined} onSubmit={() => undefined} saveButtonBarState="default" + onWarehouseEdit={() => undefined} + warehouses={warehouseList} /> )); diff --git a/src/storybook/stories/products/ProductUpdatePage.tsx b/src/storybook/stories/products/ProductUpdatePage.tsx index 4deb5d08e..acff0e2d3 100644 --- a/src/storybook/stories/products/ProductUpdatePage.tsx +++ b/src/storybook/stories/products/ProductUpdatePage.tsx @@ -30,11 +30,11 @@ const props: ProductUpdatePageProps = { onDelete: () => undefined, onImageDelete: () => undefined, onImageUpload: () => undefined, - onProductShow: () => undefined, onSubmit: () => undefined, onVariantAdd: () => undefined, onVariantShow: () => undefined, onVariantsAdd: () => undefined, + onWarehousesEdit: () => undefined, placeholderImage, product, saveButtonBarState: "default", @@ -73,7 +73,28 @@ storiesOf("Views / Products / Product edit", module) {...props} product={{ ...props.product, - variants: [] + productType: { + ...product.productType, + hasVariants: false + } + }} + /> + )) + .add("no stock and no variants", () => ( + )) diff --git a/src/storybook/stories/products/ProductVariantCreatePage.tsx b/src/storybook/stories/products/ProductVariantCreatePage.tsx index 9269ae5e2..2d83d76c5 100644 --- a/src/storybook/stories/products/ProductVariantCreatePage.tsx +++ b/src/storybook/stories/products/ProductVariantCreatePage.tsx @@ -3,6 +3,7 @@ import React from "react"; import placeholderImage from "@assets/images/placeholder255x255.png"; import { ProductErrorCode } from "@saleor/types/globalTypes"; +import { warehouseList } from "@saleor/warehouses/fixtures"; import ProductVariantCreatePage from "../../../products/components/ProductVariantCreatePage"; import { product as productFixture } from "../../../products/fixtures"; import Decorator from "../../Decorator"; @@ -14,19 +15,22 @@ storiesOf("Views / Products / Create product variant", module) .add("default", () => ( undefined} onSubmit={() => undefined} onVariantClick={undefined} saveButtonBarState="default" + warehouses={warehouseList} + onWarehouseEdit={() => undefined} /> )) .add("with errors", () => ( undefined} onSubmit={() => undefined} onVariantClick={undefined} saveButtonBarState="default" + warehouses={warehouseList} + onWarehouseEdit={() => undefined} /> )) .add("when loading data", () => ( undefined} onSubmit={() => undefined} onVariantClick={undefined} saveButtonBarState="default" + warehouses={warehouseList} + onWarehouseEdit={() => undefined} /> )) .add("add first variant", () => ( undefined} onVariantClick={undefined} saveButtonBarState="default" + warehouses={warehouseList} + onWarehouseEdit={() => undefined} /> )); diff --git a/src/storybook/stories/products/ProductVariantPage.tsx b/src/storybook/stories/products/ProductVariantPage.tsx index e8413b3e4..4cd3853ce 100644 --- a/src/storybook/stories/products/ProductVariantPage.tsx +++ b/src/storybook/stories/products/ProductVariantPage.tsx @@ -23,6 +23,7 @@ storiesOf("Views / Products / Product variant details", module) onSubmit={() => undefined} onVariantClick={() => undefined} saveButtonBarState="default" + onWarehousesEdit={() => undefined} /> )) .add("when loading data", () => ( @@ -38,6 +39,7 @@ storiesOf("Views / Products / Product variant details", module) onSubmit={() => undefined} onVariantClick={() => undefined} saveButtonBarState="default" + onWarehousesEdit={() => undefined} /> )) .add("attribute errors", () => ( @@ -69,5 +71,6 @@ storiesOf("Views / Products / Product variant details", module) message: "Generic form error", ...error }))} + onWarehousesEdit={() => undefined} /> )); diff --git a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx index ff58e35b2..2dcb9ca69 100644 --- a/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx +++ b/src/warehouses/components/WarehouseCreatePage/WarehouseCreatePage.stories.tsx @@ -2,8 +2,8 @@ import { storiesOf } from "@storybook/react"; import React from "react"; import Decorator from "@saleor/storybook/Decorator"; -import { formError } from "@saleor/storybook/misc"; import { countries } from "@saleor/fixtures"; +import { WarehouseErrorCode } from "@saleor/types/globalTypes"; import WarehouseCreatePage, { WarehouseCreatePageProps, WarehouseCreatePageFormData @@ -39,8 +39,10 @@ storiesOf("Views / Warehouses / Create warehouse", module) "postalCode", "streetAddress1", "streetAddress2" - ] as Array).map(field => - formError(field) - )} + ] as Array).map(field => ({ + __typename: "WarehouseError", + code: WarehouseErrorCode.INVALID, + field + }))} /> )); diff --git a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx index 5a3dd646b..bf7e9ab4f 100644 --- a/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx +++ b/src/warehouses/components/WarehouseDetailsPage/WarehouseDetailsPage.stories.tsx @@ -3,7 +3,7 @@ import React from "react"; import { address, countries } from "@saleor/fixtures"; import Decorator from "@saleor/storybook/Decorator"; -import { formError } from "@saleor/storybook/misc"; +import { WarehouseErrorCode } from "@saleor/types/globalTypes"; import { warehouseList } from "../../fixtures"; import WarehouseDetailsPage, { WarehouseDetailsPageProps, @@ -48,8 +48,10 @@ storiesOf("Views / Warehouses / Warehouse details", module) "postalCode", "streetAddress1", "streetAddress2" - ] as Array).map(field => - formError(field) - )} + ] as Array).map(field => ({ + __typename: "WarehouseError", + code: WarehouseErrorCode.INVALID, + field + }))} /> )); From 5967c71d1399e86e5ee6dbfbd2a3208b43b072c8 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 31 Mar 2020 19:46:07 +0200 Subject: [PATCH 42/88] Fix error causing error if product has no variants --- src/products/utils/data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/products/utils/data.ts b/src/products/utils/data.ts index 45be5ee4b..f5b6098a5 100644 --- a/src/products/utils/data.ts +++ b/src/products/utils/data.ts @@ -134,7 +134,7 @@ export function getVariantAttributeInputFromProduct( export function getStockInputFromProduct( product: ProductDetails_product ): ProductStockInput[] { - return product?.variants[0].stocks.map(stock => ({ + return product?.variants[0]?.stocks.map(stock => ({ data: null, id: stock.warehouse.id, label: stock.warehouse.name, From 50ff0501552f0b9793076194b40239c3563546bd Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 31 Mar 2020 19:56:53 +0200 Subject: [PATCH 43/88] Use dedicated wizard hook --- src/hooks/useWizard.ts | 47 ++++++++++++++++ .../ProductVariantCreateContent.tsx | 6 +- .../ProductVariantCreateDialog.tsx | 55 ++++++------------- .../ProductVariantCreateTabs.tsx | 10 ++-- .../ProductVariantCreateDialog/types.ts | 6 +- .../ProductMultipleVariantCreate.tsx | 0 .../ProductMultipleVariantCreate/index.ts | 0 .../ProductMultipleVariantCreate/paginate.ts | 0 8 files changed, 76 insertions(+), 48 deletions(-) create mode 100644 src/hooks/useWizard.ts create mode 100644 src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx create mode 100644 src/products/views/ProductMultipleVariantCreate/index.ts create mode 100644 src/products/views/ProductMultipleVariantCreate/paginate.ts diff --git a/src/hooks/useWizard.ts b/src/hooks/useWizard.ts new file mode 100644 index 000000000..963f4de96 --- /dev/null +++ b/src/hooks/useWizard.ts @@ -0,0 +1,47 @@ +import { useState } from "react"; + +export interface UseWizardOpts { + next: () => void; + prev: () => void; + set: (step: T) => void; +} +export type UseWizard = [T, UseWizardOpts]; +function useWizard(initial: T, steps: T[]): UseWizard { + const [stepIndex, setStepIndex] = useState(steps.indexOf(initial)); + + function next() { + if (stepIndex === steps.length - 1) { + console.error("This is the last step"); + } else { + setStepIndex(stepIndex + 1); + } + } + + function prev() { + if (stepIndex === 0) { + console.error("This is the first step"); + } else { + setStepIndex(stepIndex - 1); + } + } + + function set(step: T) { + const newStepIndex = steps.findIndex(s => s === step); + if (newStepIndex === -1) { + console.error("Step does not exist"); + } else { + setStepIndex(newStepIndex); + } + } + + return [ + steps[stepIndex], + { + next, + prev, + set + } + ]; +} + +export default useWizard; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx index 02bc0ae66..2b0fae0b1 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx +++ b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx @@ -62,7 +62,7 @@ const ProductVariantCreateContent: React.FC =
- {step === "values" && ( + {step === ProductVariantCreateStep.values && ( = } /> )} - {step === "prices" && ( + {step === ProductVariantCreateStep.prices && ( = } /> )} - {step === "summary" && ( + {step === ProductVariantCreateStep.summary && ( attribute.values.length > 0); - case "prices": + case ProductVariantCreateStep.prices: if (data.price.all) { if (data.price.value === "") { return false; @@ -69,7 +70,7 @@ function canHitNext( } return true; - case "summary": + case ProductVariantCreateStep.summary: return data.variants.every(variant => variant.sku !== ""); default: @@ -88,9 +89,7 @@ export interface ProductVariantCreateDialogProps onSubmit: (data: ProductVariantBulkCreateInput[]) => void; } -const ProductVariantCreateDialog: React.FC< - ProductVariantCreateDialogProps -> = props => { +const ProductVariantCreateDialog: React.FC = props => { const { attributes, defaultPrice, @@ -101,29 +100,13 @@ const ProductVariantCreateDialog: React.FC< ...contentProps } = props; const classes = useStyles(props); - const [step, setStep] = React.useState("values"); - - function handleNextStep() { - switch (step) { - case "values": - setStep("prices"); - break; - case "prices": - setStep("summary"); - break; - } - } - - function handlePrevStep() { - switch (step) { - case "prices": - setStep("values"); - break; - case "summary": - setStep("prices"); - break; - } - } + const [step, { next, prev, set: setStep }] = useWizard< + ProductVariantCreateStep + >(ProductVariantCreateStep.values, [ + ProductVariantCreateStep.values, + ProductVariantCreateStep.prices, + ProductVariantCreateStep.summary + ]); const [data, dispatchFormDataAction] = React.useReducer( reduceProductVariantCreateFormData, @@ -141,7 +124,7 @@ const ProductVariantCreateDialog: React.FC< useModalDialogOpen(open, { onClose: () => { reloadForm(); - setStep("values"); + setStep(ProductVariantCreateStep.values); } }); @@ -171,25 +154,21 @@ const ProductVariantCreateDialog: React.FC<
- {step !== "values" && ( - )} - {step !== "summary" ? ( + {step !== ProductVariantCreateStep.summary ? ( diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx index 40f03e03f..039c5b8e0 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx +++ b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx @@ -17,21 +17,21 @@ function getSteps(intl: IntlShape): Step[] { defaultMessage: "Select Values", description: "attribute values, variant creation step" }), - value: "values" + value: ProductVariantCreateStep.values }, { label: intl.formatMessage({ defaultMessage: "Prices and SKU", description: "variant creation step" }), - value: "prices" + value: ProductVariantCreateStep.prices }, { label: intl.formatMessage({ defaultMessage: "Summary", description: "variant creation step" }), - value: "summary" + value: ProductVariantCreateStep.summary } ]; } @@ -71,9 +71,7 @@ export interface ProductVariantCreateTabsProps { onStepClick: (step: ProductVariantCreateStep) => void; } -const ProductVariantCreateTabs: React.FC< - ProductVariantCreateTabsProps -> = props => { +const ProductVariantCreateTabs: React.FC = props => { const { step: currentStep, onStepClick } = props; const classes = useStyles(props); const intl = useIntl(); diff --git a/src/products/components/ProductVariantCreateDialog/types.ts b/src/products/components/ProductVariantCreateDialog/types.ts index 576a569aa..f8b088f0a 100644 --- a/src/products/components/ProductVariantCreateDialog/types.ts +++ b/src/products/components/ProductVariantCreateDialog/types.ts @@ -1 +1,5 @@ -export type ProductVariantCreateStep = "values" | "prices" | "summary"; +export enum ProductVariantCreateStep { + values, + prices, + summary +} diff --git a/src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx b/src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/products/views/ProductMultipleVariantCreate/index.ts b/src/products/views/ProductMultipleVariantCreate/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/products/views/ProductMultipleVariantCreate/paginate.ts b/src/products/views/ProductMultipleVariantCreate/paginate.ts new file mode 100644 index 000000000..e69de29bb From e41a79fe78956de6a66c1b3124b3ba6d0c8914f7 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 1 Apr 2020 18:28:47 +0200 Subject: [PATCH 44/88] Make variant creator view instead of dialog --- .../ProductVariantCreateContent.tsx | 147 -------- .../ProductVariantCreatePrices.tsx | 315 ----------------- .../ProductVariantCreateValues.tsx | 81 ----- .../ProductVariantCreateDialog/index.ts | 0 .../ProductVariantCreateDialog/types.ts | 5 - .../ProductVariantCreator.stories.tsx} | 63 ++-- .../ProductVariantCreatorContent.tsx | 122 +++++++ .../ProductVariantCreatorPage.tsx} | 136 ++++--- .../ProductVariantCreatorPrices.tsx | 331 ++++++++++++++++++ .../ProductVariantCreatorSummary.tsx} | 29 +- .../ProductVariantCreatorTabs.tsx} | 24 +- .../ProductVariantCreatorValues.tsx | 75 ++++ .../__snapshots__/reducer.test.ts.snap | 0 .../createVariants.test.ts | 0 .../createVariants.ts | 7 +- .../fixtures.ts | 0 .../form.ts | 0 .../ProductVariantCreatorPage/index.ts | 2 + .../reducer.test.ts | 0 .../reducer.ts | 0 .../ProductVariantCreatorPage/types.ts | 5 + .../containers/ProductUpdateOperations.tsx | 70 ++-- src/products/index.tsx | 14 +- src/products/mutations.ts | 2 +- src/products/queries.ts | 91 +++-- .../types/CreateMultipleVariantsData.ts | 80 +++++ src/products/types/Product.ts | 93 ++--- src/products/types/ProductCreate.ts | 93 ++--- src/products/types/ProductDetails.ts | 108 +++--- src/products/types/ProductImageCreate.ts | 93 ++--- src/products/types/ProductImageUpdate.ts | 93 ++--- src/products/types/ProductUpdate.ts | 93 ++--- .../types/ProductVariantAttributesFragment.ts | 65 ++++ src/products/types/SimpleProductUpdate.ts | 93 ++--- src/products/urls.ts | 11 +- .../ProductMultipleVariantCreate.tsx | 0 .../ProductMultipleVariantCreate/index.ts | 0 .../ProductMultipleVariantCreate/paginate.ts | 0 .../views/ProductUpdate/ProductUpdate.tsx | 42 +-- .../ProductVariantCreator.tsx | 71 ++++ .../views/ProductVariantCreator/index.ts | 2 + 41 files changed, 1352 insertions(+), 1104 deletions(-) delete mode 100644 src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx delete mode 100644 src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx delete mode 100644 src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx delete mode 100644 src/products/components/ProductVariantCreateDialog/index.ts delete mode 100644 src/products/components/ProductVariantCreateDialog/types.ts rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreate.stories.tsx => ProductVariantCreatorPage/ProductVariantCreator.stories.tsx} (66%) create mode 100644 src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreateDialog.tsx => ProductVariantCreatorPage/ProductVariantCreatorPage.tsx} (54%) create mode 100644 src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreateSummary.tsx => ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx} (92%) rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreateTabs.tsx => ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx} (78%) create mode 100644 src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/__snapshots__/reducer.test.ts.snap (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/createVariants.test.ts (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/createVariants.ts (94%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/fixtures.ts (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/form.ts (100%) create mode 100644 src/products/components/ProductVariantCreatorPage/index.ts rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/reducer.test.ts (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/reducer.ts (100%) create mode 100644 src/products/components/ProductVariantCreatorPage/types.ts create mode 100644 src/products/types/CreateMultipleVariantsData.ts create mode 100644 src/products/types/ProductVariantAttributesFragment.ts delete mode 100644 src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx delete mode 100644 src/products/views/ProductMultipleVariantCreate/index.ts delete mode 100644 src/products/views/ProductMultipleVariantCreate/paginate.ts create mode 100644 src/products/views/ProductVariantCreator/ProductVariantCreator.tsx create mode 100644 src/products/views/ProductVariantCreator/index.ts diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx deleted file mode 100644 index 2b0fae0b1..000000000 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { makeStyles } from "@material-ui/core/styles"; -import React from "react"; - -import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; -import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; -import { isSelected } from "@saleor/utils/lists"; -import { ProductVariantCreateFormData } from "./form"; -import ProductVariantCreatePrices from "./ProductVariantCreatePrices"; -import ProductVariantCreateSummary from "./ProductVariantCreateSummary"; -import ProductVariantCreateTabs from "./ProductVariantCreateTabs"; -import ProductVariantCreateValues from "./ProductVariantCreateValues"; -import { ProductVariantCreateReducerAction } from "./reducer"; -import { ProductVariantCreateStep } from "./types"; - -const useStyles = makeStyles( - theme => ({ - root: { - maxHeight: 400, - overflowX: "hidden", - overflowY: "scroll", - paddingLeft: theme.spacing(3), - paddingRight: theme.spacing(2), - position: "relative", - right: theme.spacing(3), - width: `calc(100% + ${theme.spacing(3)}px)` - } - }), - { name: "ProductVariantCreateContent" } -); - -export interface ProductVariantCreateContentProps { - attributes: ProductDetails_product_productType_variantAttributes[]; - currencySymbol: string; - data: ProductVariantCreateFormData; - dispatchFormDataAction: React.Dispatch; - errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[]; - step: ProductVariantCreateStep; - onStepClick: (step: ProductVariantCreateStep) => void; -} - -const ProductVariantCreateContent: React.FC = props => { - const { - attributes, - currencySymbol, - data, - dispatchFormDataAction, - errors, - step, - onStepClick - } = props; - const classes = useStyles(props); - - const selectedAttributes = attributes.filter(attribute => - isSelected( - attribute.id, - data.attributes.map(dataAttribute => dataAttribute.id), - (a, b) => a === b - ) - ); - - return ( -
- -
- {step === ProductVariantCreateStep.values && ( - - dispatchFormDataAction({ - attributeId, - type: "selectValue", - valueId - }) - } - /> - )} - {step === ProductVariantCreateStep.prices && ( - - dispatchFormDataAction({ - all, - type: type === "price" ? "applyPriceToAll" : "applyStockToAll" - }) - } - onApplyToAllChange={(value, type) => - dispatchFormDataAction({ - type: - type === "price" - ? "changeApplyPriceToAllValue" - : "changeApplyStockToAllValue", - value - }) - } - onAttributeSelect={(attributeId, type) => - dispatchFormDataAction({ - attributeId, - type: - type === "price" - ? "changeApplyPriceToAttributeId" - : "changeApplyStockToAttributeId" - }) - } - onAttributeValueChange={(valueId, value, type) => - dispatchFormDataAction({ - type: - type === "price" - ? "changeAttributeValuePrice" - : "changeAttributeValueStock", - value, - valueId - }) - } - /> - )} - {step === ProductVariantCreateStep.summary && ( - - dispatchFormDataAction({ - field, - type: "changeVariantData", - value, - variantIndex - }) - } - onVariantDelete={variantIndex => - dispatchFormDataAction({ - type: "deleteVariant", - variantIndex - }) - } - /> - )} -
-
- ); -}; - -ProductVariantCreateContent.displayName = "ProductVariantCreateContent"; -export default ProductVariantCreateContent; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx deleted file mode 100644 index d4ef692f9..000000000 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx +++ /dev/null @@ -1,315 +0,0 @@ -import FormControlLabel from "@material-ui/core/FormControlLabel"; -import Radio from "@material-ui/core/Radio"; -import RadioGroup from "@material-ui/core/RadioGroup"; -import { makeStyles } from "@material-ui/core/styles"; -import TextField from "@material-ui/core/TextField"; -import Typography from "@material-ui/core/Typography"; -import React from "react"; -import { FormattedMessage, useIntl } from "react-intl"; - -import FormSpacer from "@saleor/components/FormSpacer"; -import Grid from "@saleor/components/Grid"; -import Hr from "@saleor/components/Hr"; -import SingleSelectField from "@saleor/components/SingleSelectField"; -import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; -import { ProductVariantCreateFormData } from "./form"; - -const useStyles = makeStyles( - theme => ({ - hr: { - marginBottom: theme.spacing(), - marginTop: theme.spacing(0.5) - }, - hrAttribute: { - marginTop: theme.spacing(2) - }, - label: { - alignSelf: "center" - }, - shortInput: { - width: "50%" - } - }), - { name: "ProductVariantCreatePrices" } -); - -export type PriceOrStock = "price" | "stock"; -export interface ProductVariantCreatePricesProps { - attributes: ProductDetails_product_productType_variantAttributes[]; - currencySymbol: string; - data: ProductVariantCreateFormData; - onApplyPriceOrStockChange: (applyToAll: boolean, type: PriceOrStock) => void; - onApplyToAllChange: (value: string, type: PriceOrStock) => void; - onAttributeSelect: (id: string, type: PriceOrStock) => void; - onAttributeValueChange: ( - id: string, - value: string, - type: PriceOrStock - ) => void; -} - -const ProductVariantCreatePrices: React.FC< - ProductVariantCreatePricesProps -> = props => { - const { - attributes, - currencySymbol, - data, - onApplyPriceOrStockChange, - onApplyToAllChange, - onAttributeSelect, - onAttributeValueChange - } = props; - const classes = useStyles(props); - const intl = useIntl(); - - const attributeChoices = attributes.map(attribute => ({ - label: attribute.name, - value: attribute.id - })); - const priceAttributeValues = data.price.all - ? null - : data.price.attribute - ? attributes - .find(attribute => attribute.id === data.price.attribute) - .values.filter(value => - data.attributes - .find(attribute => attribute.id === data.price.attribute) - .values.includes(value.slug) - ) - : []; - const stockAttributeValues = data.stock.all - ? null - : data.stock.attribute - ? attributes - .find(attribute => attribute.id === data.stock.attribute) - .values.filter(value => - data.attributes - .find(attribute => attribute.id === data.stock.attribute) - .values.includes(value.slug) - ) - : []; - - return ( - <> - - - -
- - } - label={intl.formatMessage({ - defaultMessage: "Apply single price to all SKUs" - })} - onChange={() => onApplyPriceOrStockChange(true, "price")} - /> - - onApplyToAllChange(event.target.value, "price")} - /> - - } - label={intl.formatMessage({ - defaultMessage: "Apply unique prices by attribute to each SKU" - })} - onChange={() => onApplyPriceOrStockChange(false, "price")} - /> - - {!data.price.all && ( - <> - - -
- - - -
-
- - onAttributeSelect(event.target.value, "price") - } - /> -
-
-
- {priceAttributeValues && - priceAttributeValues.map(attributeValue => ( - - - -
- {attributeValue.name} -
-
- value.slug === attributeValue.slug - ).value - } - onChange={event => - onAttributeValueChange( - attributeValue.slug, - event.target.value, - "price" - ) - } - /> -
-
-
- ))} - - )} - - - - -
- - } - label={intl.formatMessage({ - defaultMessage: "Apply single stock to all SKUs" - })} - onChange={() => onApplyPriceOrStockChange(true, "stock")} - /> - - onApplyToAllChange(event.target.value, "stock")} - /> - - } - label={intl.formatMessage({ - defaultMessage: "Apply unique stock by attribute to each SKU" - })} - onChange={() => onApplyPriceOrStockChange(false, "stock")} - /> - - {!data.stock.all && ( - <> - - -
- - - -
-
- - onAttributeSelect(event.target.value, "stock") - } - /> -
-
-
- {stockAttributeValues && - stockAttributeValues.map(attributeValue => ( - - - -
- {attributeValue.name} -
-
- value.slug === attributeValue.slug - ).value - } - onChange={event => - onAttributeValueChange( - attributeValue.slug, - event.target.value, - "stock" - ) - } - /> -
-
-
- ))} - - )} - - ); -}; - -ProductVariantCreatePrices.displayName = "ProductVariantCreatePrices"; -export default ProductVariantCreatePrices; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx deleted file mode 100644 index 212f7dcbd..000000000 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import makeStyles from "@material-ui/core/styles/makeStyles"; -import Typography from "@material-ui/core/Typography"; -import React from "react"; - -import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; -import Debounce from "@saleor/components/Debounce"; -import Hr from "@saleor/components/Hr"; -import Skeleton from "@saleor/components/Skeleton"; -import { maybe } from "@saleor/misc"; -import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; -import { isSelected } from "@saleor/utils/lists"; -import { ProductVariantCreateFormData } from "./form"; - -export interface ProductVariantCreateValuesProps { - attributes: ProductDetails_product_productType_variantAttributes[]; - data: ProductVariantCreateFormData; - onValueClick: (attributeId: string, valueId: string) => void; -} - -const useStyles = makeStyles( - theme => ({ - hr: { - marginBottom: theme.spacing(), - marginTop: theme.spacing(0.5) - }, - valueContainer: { - display: "grid", - gridColumnGap: theme.spacing(3), - gridTemplateColumns: "repeat(3, 1fr)", - marginBottom: theme.spacing(3) - } - }), - { name: "ProductVariantCreateValues" } -); - -const ProductVariantCreateValues: React.FC< - ProductVariantCreateValuesProps -> = props => { - const { attributes, data, onValueClick } = props; - const classes = useStyles(props); - - return ( - <> - {attributes.map(attribute => ( - - - {maybe(() => attribute.name, )} - -
-
- {attribute.values.map(value => ( - onValueClick(attribute.id, value.slug)} - time={100} - key={value.slug} - > - {change => ( - attribute.id === dataAttribute.id - ).values, - (a, b) => a === b - )} - name={`value:${value.slug}`} - label={value.name} - onChange={change} - /> - )} - - ))} -
-
- ))} - - ); -}; - -ProductVariantCreateValues.displayName = "ProductVariantCreateValues"; -export default ProductVariantCreateValues; diff --git a/src/products/components/ProductVariantCreateDialog/index.ts b/src/products/components/ProductVariantCreateDialog/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/components/ProductVariantCreateDialog/types.ts b/src/products/components/ProductVariantCreateDialog/types.ts deleted file mode 100644 index f8b088f0a..000000000 --- a/src/products/components/ProductVariantCreateDialog/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum ProductVariantCreateStep { - values, - prices, - summary -} diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreate.stories.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx similarity index 66% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreate.stories.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx index b735d3f0f..3305d853f 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreate.stories.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx @@ -1,18 +1,18 @@ -import Card from "@material-ui/core/Card"; -import CardContent from "@material-ui/core/CardContent"; import { storiesOf } from "@storybook/react"; import React from "react"; import { attributes } from "@saleor/attributes/fixtures"; import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; import { ProductErrorCode } from "@saleor/types/globalTypes"; +import Container from "@saleor/components/Container"; import Decorator from "../../../storybook/Decorator"; import { createVariants } from "./createVariants"; import { AllOrAttribute } from "./form"; -import ProductVariantCreateContent, { - ProductVariantCreateContentProps -} from "./ProductVariantCreateContent"; -import ProductVariantCreateDialog from "./ProductVariantCreateDialog"; +import ProductVariantCreatorContent, { + ProductVariantCreatorContentProps +} from "./ProductVariantCreatorContent"; +import ProductVariantCreatorPage from "./ProductVariantCreatorPage"; +import { ProductVariantCreatorStep } from "./types"; const selectedAttributes = [1, 4, 5].map(index => attributes[index]); @@ -52,7 +52,7 @@ const errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[] = [ } ]; -const props: ProductVariantCreateContentProps = { +const props: ProductVariantCreatorContentProps = { attributes, currencySymbol: "USD", data: { @@ -68,56 +68,43 @@ const props: ProductVariantCreateContentProps = { }, dispatchFormDataAction: () => undefined, errors: [], - onStepClick: () => undefined, - step: "values" + step: ProductVariantCreatorStep.values }; storiesOf("Views / Products / Create multiple variants", module) - .addDecorator(storyFn => ( - - {storyFn()} - - )) + .addDecorator(storyFn => {storyFn()}) .addDecorator(Decorator) - .add("choose values", () => ) + .add("choose values", () => ) .add("prices and SKU", () => ( - + )); storiesOf("Views / Products / Create multiple variants / summary", module) - .addDecorator(storyFn => ( - - {storyFn()} - - )) + .addDecorator(storyFn => {storyFn()}) .addDecorator(Decorator) .add("default", () => ( - + )) .add("errors", () => ( - + )); storiesOf("Views / Products / Create multiple variants", module) .addDecorator(Decorator) .add("interactive", () => ( - undefined} onSubmit={() => undefined} /> )); diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx new file mode 100644 index 000000000..4316c2df5 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx @@ -0,0 +1,122 @@ +import React from "react"; + +import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; +import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; +import { isSelected } from "@saleor/utils/lists"; +import { ProductVariantCreateFormData } from "./form"; +import ProductVariantCreatePrices from "./ProductVariantCreatorPrices"; +import ProductVariantCreateSummary from "./ProductVariantCreatorSummary"; +import ProductVariantCreateValues from "./ProductVariantCreatorValues"; +import { ProductVariantCreateReducerAction } from "./reducer"; +import { ProductVariantCreatorStep } from "./types"; + +export interface ProductVariantCreatorContentProps { + attributes: ProductDetails_product_productType_variantAttributes[]; + currencySymbol: string; + data: ProductVariantCreateFormData; + dispatchFormDataAction: React.Dispatch; + errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[]; + step: ProductVariantCreatorStep; +} + +const ProductVariantCreatorContent: React.FC = props => { + const { + attributes, + currencySymbol, + data, + dispatchFormDataAction, + errors, + step + } = props; + const selectedAttributes = attributes.filter(attribute => + isSelected( + attribute.id, + data.attributes.map(dataAttribute => dataAttribute.id), + (a, b) => a === b + ) + ); + + return ( + <> + {step === ProductVariantCreatorStep.values && ( + + dispatchFormDataAction({ + attributeId, + type: "selectValue", + valueId + }) + } + /> + )} + {step === ProductVariantCreatorStep.prices && ( + + dispatchFormDataAction({ + all, + type: type === "price" ? "applyPriceToAll" : "applyStockToAll" + }) + } + onApplyToAllChange={(value, type) => + dispatchFormDataAction({ + type: + type === "price" + ? "changeApplyPriceToAllValue" + : "changeApplyStockToAllValue", + value + }) + } + onAttributeSelect={(attributeId, type) => + dispatchFormDataAction({ + attributeId, + type: + type === "price" + ? "changeApplyPriceToAttributeId" + : "changeApplyStockToAttributeId" + }) + } + onAttributeValueChange={(valueId, value, type) => + dispatchFormDataAction({ + type: + type === "price" + ? "changeAttributeValuePrice" + : "changeAttributeValueStock", + value, + valueId + }) + } + /> + )} + {step === ProductVariantCreatorStep.summary && ( + + dispatchFormDataAction({ + field, + type: "changeVariantData", + value, + variantIndex + }) + } + onVariantDelete={variantIndex => + dispatchFormDataAction({ + type: "deleteVariant", + variantIndex + }) + } + /> + )} + + ); +}; + +ProductVariantCreatorContent.displayName = "ProductVariantCreatorContent"; +export default ProductVariantCreatorContent; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx similarity index 54% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx index b2fcfed6c..aaf03a9b2 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx @@ -1,22 +1,19 @@ import Button from "@material-ui/core/Button"; -import Dialog from "@material-ui/core/Dialog"; -import DialogActions from "@material-ui/core/DialogActions"; -import DialogContent from "@material-ui/core/DialogContent"; -import DialogTitle from "@material-ui/core/DialogTitle"; import { makeStyles } from "@material-ui/core/styles"; import React from "react"; -import { FormattedMessage } from "react-intl"; +import { FormattedMessage, useIntl, IntlShape } from "react-intl"; -import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; -import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useWizard from "@saleor/hooks/useWizard"; +import PageHeader from "@saleor/components/PageHeader"; +import Container from "@saleor/components/Container"; import { ProductVariantBulkCreateInput } from "../../../types/globalTypes"; import { createInitialForm, ProductVariantCreateFormData } from "./form"; -import ProductVariantCreateContent, { - ProductVariantCreateContentProps -} from "./ProductVariantCreateContent"; +import ProductVariantCreatorContent, { + ProductVariantCreatorContentProps +} from "./ProductVariantCreatorContent"; import reduceProductVariantCreateFormData from "./reducer"; -import { ProductVariantCreateStep } from "./types"; +import { ProductVariantCreatorStep } from "./types"; +import ProductVariantCreateTabs from "./ProductVariantCreatorTabs"; const useStyles = makeStyles( theme => ({ @@ -27,22 +24,19 @@ const useStyles = makeStyles( overflowX: "visible", overflowY: "hidden", width: 800 - }, - spacer: { - flex: 1 } }), - { name: "ProductVariantCreateDialog" } + { name: "ProductVariantCreatePage" } ); function canHitNext( - step: ProductVariantCreateStep, + step: ProductVariantCreatorStep, data: ProductVariantCreateFormData ): boolean { switch (step) { - case ProductVariantCreateStep.values: + case ProductVariantCreatorStep.values: return data.attributes.every(attribute => attribute.values.length > 0); - case ProductVariantCreateStep.prices: + case ProductVariantCreatorStep.prices: if (data.price.all) { if (data.price.value === "") { return false; @@ -70,7 +64,7 @@ function canHitNext( } return true; - case ProductVariantCreateStep.summary: + case ProductVariantCreatorStep.summary: return data.variants.every(variant => variant.sku !== ""); default: @@ -78,34 +72,45 @@ function canHitNext( } } -export interface ProductVariantCreateDialogProps +export interface ProductVariantCreatePageProps extends Omit< - ProductVariantCreateContentProps, + ProductVariantCreatorContentProps, "data" | "dispatchFormDataAction" | "step" | "onStepClick" > { defaultPrice: string; - open: boolean; - onClose: () => void; onSubmit: (data: ProductVariantBulkCreateInput[]) => void; } -const ProductVariantCreateDialog: React.FC = props => { - const { - attributes, - defaultPrice, - errors: apiErrors, - open, - onClose, - onSubmit, - ...contentProps - } = props; +function getTitle(step: ProductVariantCreatorStep, intl: IntlShape): string { + switch (step) { + case ProductVariantCreatorStep.values: + return intl.formatMessage({ + defaultMessage: "Choose Values", + description: "product attribute values, page title" + }); + case ProductVariantCreatorStep.prices: + return intl.formatMessage({ + defaultMessage: "Price and SKUs", + description: "page title" + }); + case ProductVariantCreatorStep.summary: + return intl.formatMessage({ + defaultMessage: "Summary", + description: "page title" + }); + } +} + +const ProductVariantCreatePage: React.FC = props => { + const { attributes, defaultPrice, errors, onSubmit, ...contentProps } = props; const classes = useStyles(props); + const intl = useIntl(); const [step, { next, prev, set: setStep }] = useWizard< - ProductVariantCreateStep - >(ProductVariantCreateStep.values, [ - ProductVariantCreateStep.values, - ProductVariantCreateStep.prices, - ProductVariantCreateStep.summary + ProductVariantCreatorStep + >(ProductVariantCreatorStep.values, [ + ProductVariantCreatorStep.values, + ProductVariantCreatorStep.prices, + ProductVariantCreatorStep.summary ]); const [data, dispatchFormDataAction] = React.useReducer( @@ -121,40 +126,11 @@ const ProductVariantCreateDialog: React.FC = pr React.useEffect(reloadForm, [attributes.length]); - useModalDialogOpen(open, { - onClose: () => { - reloadForm(); - setStep(ProductVariantCreateStep.values); - } - }); - - const errors = useModalDialogErrors(apiErrors, open); - return ( - - - - - - setStep(step)} - /> - - - -
- {step !== ProductVariantCreateStep.values && ( + + + + {step !== ProductVariantCreatorStep.values && ( )} - {step !== ProductVariantCreateStep.summary ? ( + {step !== ProductVariantCreatorStep.summary ? ( )} - -
+ + + ); }; -ProductVariantCreateDialog.displayName = "ProductVariantCreateDialog"; -export default ProductVariantCreateDialog; +ProductVariantCreatePage.displayName = "ProductVariantCreatePage"; +export default ProductVariantCreatePage; diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx new file mode 100644 index 000000000..e63ac92dc --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx @@ -0,0 +1,331 @@ +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import Radio from "@material-ui/core/Radio"; +import RadioGroup from "@material-ui/core/RadioGroup"; +import { makeStyles } from "@material-ui/core/styles"; +import TextField from "@material-ui/core/TextField"; +import Typography from "@material-ui/core/Typography"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import FormSpacer from "@saleor/components/FormSpacer"; +import Grid from "@saleor/components/Grid"; +import Hr from "@saleor/components/Hr"; +import SingleSelectField from "@saleor/components/SingleSelectField"; +import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; +import CardTitle from "@saleor/components/CardTitle"; +import CardSpacer from "@saleor/components/CardSpacer"; +import { ProductVariantCreateFormData } from "./form"; + +const useStyles = makeStyles( + theme => ({ + hr: { + marginBottom: theme.spacing(), + marginTop: theme.spacing(0.5) + }, + hrAttribute: { + marginTop: theme.spacing(2) + }, + label: { + alignSelf: "center" + }, + shortInput: { + width: "33%" + } + }), + { name: "ProductVariantCreatorPrices" } +); + +export type PriceOrStock = "price" | "stock"; +export interface ProductVariantCreatorPricesProps { + attributes: ProductDetails_product_productType_variantAttributes[]; + currencySymbol: string; + data: ProductVariantCreateFormData; + onApplyPriceOrStockChange: (applyToAll: boolean, type: PriceOrStock) => void; + onApplyToAllChange: (value: string, type: PriceOrStock) => void; + onAttributeSelect: (id: string, type: PriceOrStock) => void; + onAttributeValueChange: ( + id: string, + value: string, + type: PriceOrStock + ) => void; +} + +const ProductVariantCreatorPrices: React.FC = props => { + const { + attributes, + currencySymbol, + data, + onApplyPriceOrStockChange, + onApplyToAllChange, + onAttributeSelect, + onAttributeValueChange + } = props; + const classes = useStyles(props); + const intl = useIntl(); + + const attributeChoices = attributes.map(attribute => ({ + label: attribute.name, + value: attribute.id + })); + const priceAttributeValues = data.price.all + ? null + : data.price.attribute + ? attributes + .find(attribute => attribute.id === data.price.attribute) + .values.filter(value => + data.attributes + .find(attribute => attribute.id === data.price.attribute) + .values.includes(value.slug) + ) + : []; + const stockAttributeValues = data.stock.all + ? null + : data.stock.attribute + ? attributes + .find(attribute => attribute.id === data.stock.attribute) + .values.filter(value => + data.attributes + .find(attribute => attribute.id === data.stock.attribute) + .values.includes(value.slug) + ) + : []; + + return ( + <> + + + + + } + label={intl.formatMessage({ + defaultMessage: "Apply single price to all SKUs" + })} + onChange={() => onApplyPriceOrStockChange(true, "price")} + /> + + + onApplyToAllChange(event.target.value, "price") + } + /> + + } + label={intl.formatMessage({ + defaultMessage: "Apply unique prices by attribute to each SKU" + })} + onChange={() => onApplyPriceOrStockChange(false, "price")} + /> + + {!data.price.all && ( + <> + + +
+ + + +
+
+ + onAttributeSelect(event.target.value, "price") + } + /> +
+
+ {priceAttributeValues && + priceAttributeValues.map(attributeValue => ( + +
+ + +
+ {attributeValue.name} +
+
+ value.slug === attributeValue.slug + ).value + } + onChange={event => + onAttributeValueChange( + attributeValue.slug, + event.target.value, + "price" + ) + } + /> +
+
+
+ ))} + + )} +
+
+ + + + + + } + label={intl.formatMessage({ + defaultMessage: "Apply single stock to all SKUs" + })} + onChange={() => onApplyPriceOrStockChange(true, "stock")} + /> + + + onApplyToAllChange(event.target.value, "stock") + } + /> + + } + label={intl.formatMessage({ + defaultMessage: "Apply unique stock by attribute to each SKU" + })} + onChange={() => onApplyPriceOrStockChange(false, "stock")} + /> + + {!data.stock.all && ( + <> + + +
+ + + +
+
+ + onAttributeSelect(event.target.value, "stock") + } + /> +
+
+ {stockAttributeValues && + stockAttributeValues.map(attributeValue => ( + +
+ + +
+ {attributeValue.name} +
+
+ value.slug === attributeValue.slug + ).value + } + onChange={event => + onAttributeValueChange( + attributeValue.slug, + event.target.value, + "stock" + ) + } + /> +
+
+
+ ))} + + )} +
+
+ + ); +}; + +ProductVariantCreatorPrices.displayName = "ProductVariantCreatorPrices"; +export default ProductVariantCreatorPrices; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateSummary.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx similarity index 92% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreateSummary.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx index 01e370e9e..aab3db002 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateSummary.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx @@ -3,25 +3,26 @@ import cyan from "@material-ui/core/colors/cyan"; import green from "@material-ui/core/colors/green"; import purple from "@material-ui/core/colors/purple"; import yellow from "@material-ui/core/colors/yellow"; +import Card from "@material-ui/core/Card"; import IconButton from "@material-ui/core/IconButton"; import { makeStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; -import Typography from "@material-ui/core/Typography"; import DeleteIcon from "@material-ui/icons/Delete"; import classNames from "classnames"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import Hr from "@saleor/components/Hr"; import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; import { ProductVariantBulkCreateInput } from "@saleor/types/globalTypes"; import { getFormErrors } from "@saleor/utils/errors"; import { getBulkProductErrorMessage } from "@saleor/utils/errors/product"; +import CardTitle from "@saleor/components/CardTitle"; +import { commonMessages } from "@saleor/intl"; import { ProductDetails_product_productType_variantAttributes } from "../../types/ProductDetails"; import { ProductVariantCreateFormData } from "./form"; import { VariantField } from "./reducer"; -export interface ProductVariantCreateSummaryProps { +export interface ProductVariantCreatorSummaryProps { attributes: ProductDetails_product_productType_variantAttributes[]; currencySymbol: string; data: ProductVariantCreateFormData; @@ -81,11 +82,11 @@ const useStyles = makeStyles( borderBottom: `1px solid ${theme.palette.divider}`, display: "grid", gridTemplateColumns: "1fr 180px 120px 180px 64px", - padding: theme.spacing(1, 0) + padding: theme.spacing(1, 1, 1, 3) } }), { - name: "ProductVariantCreateSummary" + name: "ProductVariantCreatorSummary" } ); @@ -108,7 +109,7 @@ function getVariantName( ); } -const ProductVariantCreateSummary: React.FC = props => { +const ProductVariantCreatorSummary: React.FC = props => { const { attributes, currencySymbol, @@ -121,14 +122,8 @@ const ProductVariantCreateSummary: React.FC = const intl = useIntl(); return ( - <> - - - -
+ +
= ); })}
- + ); }; -ProductVariantCreateSummary.displayName = "ProductVariantCreateSummary"; -export default ProductVariantCreateSummary; +ProductVariantCreatorSummary.displayName = "ProductVariantCreatorSummary"; +export default ProductVariantCreatorSummary; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx similarity index 78% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx index 039c5b8e0..49c4ab52a 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx @@ -4,11 +4,11 @@ import classNames from "classnames"; import React from "react"; import { IntlShape, useIntl } from "react-intl"; -import { ProductVariantCreateStep } from "./types"; +import { ProductVariantCreatorStep } from "./types"; interface Step { label: string; - value: ProductVariantCreateStep; + value: ProductVariantCreatorStep; } function getSteps(intl: IntlShape): Step[] { return [ @@ -17,21 +17,21 @@ function getSteps(intl: IntlShape): Step[] { defaultMessage: "Select Values", description: "attribute values, variant creation step" }), - value: ProductVariantCreateStep.values + value: ProductVariantCreatorStep.values }, { label: intl.formatMessage({ defaultMessage: "Prices and SKU", description: "variant creation step" }), - value: ProductVariantCreateStep.prices + value: ProductVariantCreatorStep.prices }, { label: intl.formatMessage({ defaultMessage: "Summary", description: "variant creation step" }), - value: ProductVariantCreateStep.summary + value: ProductVariantCreatorStep.summary } ]; } @@ -62,16 +62,16 @@ const useStyles = makeStyles( } }), { - name: "ProductVariantCreateTabs" + name: "ProductVariantCreatorTabs" } ); -export interface ProductVariantCreateTabsProps { - step: ProductVariantCreateStep; - onStepClick: (step: ProductVariantCreateStep) => void; +export interface ProductVariantCreatorTabsProps { + step: ProductVariantCreatorStep; + onStepClick: (step: ProductVariantCreatorStep) => void; } -const ProductVariantCreateTabs: React.FC = props => { +const ProductVariantCreatorTabs: React.FC = props => { const { step: currentStep, onStepClick } = props; const classes = useStyles(props); const intl = useIntl(); @@ -102,5 +102,5 @@ const ProductVariantCreateTabs: React.FC = props ); }; -ProductVariantCreateTabs.displayName = "ProductVariantCreateTabs"; -export default ProductVariantCreateTabs; +ProductVariantCreatorTabs.displayName = "ProductVariantCreatorTabs"; +export default ProductVariantCreatorTabs; diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx new file mode 100644 index 000000000..19acb45d8 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx @@ -0,0 +1,75 @@ +import makeStyles from "@material-ui/core/styles/makeStyles"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import React from "react"; + +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import Debounce from "@saleor/components/Debounce"; +import Skeleton from "@saleor/components/Skeleton"; +import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; +import { isSelected } from "@saleor/utils/lists"; +import CardTitle from "@saleor/components/CardTitle"; +import CardSpacer from "@saleor/components/CardSpacer"; +import { ProductVariantCreateFormData } from "./form"; + +export interface ProductVariantCreatorValuesProps { + attributes: ProductDetails_product_productType_variantAttributes[]; + data: ProductVariantCreateFormData; + onValueClick: (attributeId: string, valueId: string) => void; +} + +const useStyles = makeStyles( + theme => ({ + valueContainer: { + display: "grid", + gridColumnGap: theme.spacing(3), + gridTemplateColumns: "repeat(5, 1fr)" + } + }), + { name: "ProductVariantCreatorValues" } +); + +const ProductVariantCreatorValues: React.FC = props => { + const { attributes, data, onValueClick } = props; + const classes = useStyles(props); + + return ( + <> + {attributes.map(attribute => ( + <> + + } /> + + {attribute.values.map(value => ( + onValueClick(attribute.id, value.slug)} + time={100} + key={value.slug} + > + {change => ( + attribute.id === dataAttribute.id + ).values, + (a, b) => a === b + )} + name={`value:${value.slug}`} + label={value.name} + onChange={change} + /> + )} + + ))} + + + + + ))} + + ); +}; + +ProductVariantCreatorValues.displayName = "ProductVariantCreatorValues"; +export default ProductVariantCreatorValues; diff --git a/src/products/components/ProductVariantCreateDialog/__snapshots__/reducer.test.ts.snap b/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap similarity index 100% rename from src/products/components/ProductVariantCreateDialog/__snapshots__/reducer.test.ts.snap rename to src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap diff --git a/src/products/components/ProductVariantCreateDialog/createVariants.test.ts b/src/products/components/ProductVariantCreatorPage/createVariants.test.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/createVariants.test.ts rename to src/products/components/ProductVariantCreatorPage/createVariants.test.ts diff --git a/src/products/components/ProductVariantCreateDialog/createVariants.ts b/src/products/components/ProductVariantCreatorPage/createVariants.ts similarity index 94% rename from src/products/components/ProductVariantCreateDialog/createVariants.ts rename to src/products/components/ProductVariantCreatorPage/createVariants.ts index 6239832e2..186972c60 100644 --- a/src/products/components/ProductVariantCreateDialog/createVariants.ts +++ b/src/products/components/ProductVariantCreatorPage/createVariants.ts @@ -97,9 +97,10 @@ export function createVariants( ) { return []; } - const variants = createVariantFlatMatrixDimension([[]], data.attributes).map( - variant => createVariant(data, variant) - ); + const variants = createVariantFlatMatrixDimension( + [[]], + data.attributes + ).map(variant => createVariant(data, variant)); return variants; } diff --git a/src/products/components/ProductVariantCreateDialog/fixtures.ts b/src/products/components/ProductVariantCreatorPage/fixtures.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/fixtures.ts rename to src/products/components/ProductVariantCreatorPage/fixtures.ts diff --git a/src/products/components/ProductVariantCreateDialog/form.ts b/src/products/components/ProductVariantCreatorPage/form.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/form.ts rename to src/products/components/ProductVariantCreatorPage/form.ts diff --git a/src/products/components/ProductVariantCreatorPage/index.ts b/src/products/components/ProductVariantCreatorPage/index.ts new file mode 100644 index 000000000..5e4e6b074 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/index.ts @@ -0,0 +1,2 @@ +export * from "./ProductVariantCreatorPage"; +export { default } from "./ProductVariantCreatorPage"; diff --git a/src/products/components/ProductVariantCreateDialog/reducer.test.ts b/src/products/components/ProductVariantCreatorPage/reducer.test.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/reducer.test.ts rename to src/products/components/ProductVariantCreatorPage/reducer.test.ts diff --git a/src/products/components/ProductVariantCreateDialog/reducer.ts b/src/products/components/ProductVariantCreatorPage/reducer.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/reducer.ts rename to src/products/components/ProductVariantCreatorPage/reducer.ts diff --git a/src/products/components/ProductVariantCreatorPage/types.ts b/src/products/components/ProductVariantCreatorPage/types.ts new file mode 100644 index 000000000..baab8f3e7 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/types.ts @@ -0,0 +1,5 @@ +export enum ProductVariantCreatorStep { + values, + prices, + summary +} diff --git a/src/products/containers/ProductUpdateOperations.tsx b/src/products/containers/ProductUpdateOperations.tsx index d07c6561b..a2e79a952 100644 --- a/src/products/containers/ProductUpdateOperations.tsx +++ b/src/products/containers/ProductUpdateOperations.tsx @@ -7,7 +7,6 @@ import { TypedProductImageCreateMutation, TypedProductImageDeleteMutation, TypedProductUpdateMutation, - TypedProductVariantBulkCreateMutation, TypedProductVariantBulkDeleteMutation, TypedSimpleProductUpdateMutation } from "../mutations"; @@ -26,10 +25,6 @@ import { ProductImageReorderVariables } from "../types/ProductImageReorder"; import { ProductUpdate, ProductUpdateVariables } from "../types/ProductUpdate"; -import { - ProductVariantBulkCreate, - ProductVariantBulkCreateVariables -} from "../types/ProductVariantBulkCreate"; import { ProductVariantBulkDelete, ProductVariantBulkDeleteVariables @@ -43,10 +38,6 @@ import ProductImagesReorderProvider from "./ProductImagesReorder"; interface ProductUpdateOperationsProps { product: ProductDetails_product; children: (props: { - bulkProductVariantCreate: PartialMutationProviderOutput< - ProductVariantBulkCreate, - ProductVariantBulkCreateVariables - >; bulkProductVariantDelete: PartialMutationProviderOutput< ProductVariantBulkDelete, ProductVariantBulkDeleteVariables @@ -76,7 +67,6 @@ interface ProductUpdateOperationsProps { SimpleProductUpdateVariables >; }) => React.ReactNode; - onBulkProductVariantCreate?: (data: ProductVariantBulkCreate) => void; onBulkProductVariantDelete?: (data: ProductVariantBulkDelete) => void; onDelete?: (data: ProductDelete) => void; onImageCreate?: (data: ProductImageCreate) => void; @@ -88,7 +78,6 @@ interface ProductUpdateOperationsProps { const ProductUpdateOperations: React.FC = ({ product, children, - onBulkProductVariantCreate, onBulkProductVariantDelete, onDelete, onImageDelete, @@ -121,40 +110,31 @@ const ProductUpdateOperations: React.FC = ({ - {(...bulkProductVariantDelete) => ( - - {(...bulkProductVariantCreate) => - children({ - bulkProductVariantCreate: getMutationProviderData( - ...bulkProductVariantCreate - ), - bulkProductVariantDelete: getMutationProviderData( - ...bulkProductVariantDelete - ), - createProductImage: getMutationProviderData( - ...createProductImage - ), - deleteProduct: getMutationProviderData( - ...deleteProduct - ), - deleteProductImage: getMutationProviderData( - ...deleteProductImage - ), - reorderProductImages: getMutationProviderData( - ...reorderProductImages - ), - updateProduct: getMutationProviderData( - ...updateProduct - ), - updateSimpleProduct: getMutationProviderData( - ...updateSimpleProduct - ) - }) - } - - )} + {(...bulkProductVariantDelete) => + children({ + bulkProductVariantDelete: getMutationProviderData( + ...bulkProductVariantDelete + ), + createProductImage: getMutationProviderData( + ...createProductImage + ), + deleteProduct: getMutationProviderData( + ...deleteProduct + ), + deleteProductImage: getMutationProviderData( + ...deleteProductImage + ), + reorderProductImages: getMutationProviderData( + ...reorderProductImages + ), + updateProduct: getMutationProviderData( + ...updateProduct + ), + updateSimpleProduct: getMutationProviderData( + ...updateSimpleProduct + ) + }) + } )} diff --git a/src/products/index.tsx b/src/products/index.tsx index dfd75cd77..624a50346 100644 --- a/src/products/index.tsx +++ b/src/products/index.tsx @@ -20,7 +20,8 @@ import { productVariantEditPath, ProductVariantEditUrlQueryParams, ProductAddUrlQueryParams, - ProductVariantAddUrlQueryParams + ProductVariantAddUrlQueryParams, + productVariantCreatorPath } from "./urls"; import ProductCreateComponent from "./views/ProductCreate"; import ProductImageComponent from "./views/ProductImage"; @@ -28,6 +29,7 @@ import ProductListComponent from "./views/ProductList"; import ProductUpdateComponent from "./views/ProductUpdate"; import ProductVariantComponent from "./views/ProductVariant"; import ProductVariantCreateComponent from "./views/ProductVariantCreate"; +import ProductVariantCreatorComponent from "./views/ProductVariantCreator"; const ProductList: React.FC> = ({ location }) => { const qs = parseQs(location.search.substr(1)); @@ -100,6 +102,12 @@ const ProductVariantCreate: React.FC> = ({ ); }; +const ProductVariantCreator: React.FC> = ({ match }) => ( + +); + const ProductCreate: React.FC = ({ location }) => { const qs = parseQs(location.search.substr(1)); const params: ProductAddUrlQueryParams = qs; @@ -116,6 +124,10 @@ const Component = () => { + (ProductVariantBulkCreateMutation); diff --git a/src/products/queries.ts b/src/products/queries.ts index a14d917ca..2749cf718 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -27,6 +27,10 @@ import { InitialProductFilterData, InitialProductFilterDataVariables } from "./types/InitialProductFilterData"; +import { + CreateMultipleVariantsData, + CreateMultipleVariantsDataVariables +} from "./types/CreateMultipleVariantsData"; export const stockFragment = gql` fragment StockFragment on Stock { @@ -74,12 +78,50 @@ export const productFragment = gql` } } `; + +const productVariantAttributesFragment = gql` + fragment ProductVariantAttributesFragment on Product { + id + attributes { + attribute { + id + slug + name + inputType + valueRequired + values { + id + name + slug + } + } + values { + id + name + slug + } + } + productType { + variantAttributes { + id + name + values { + id + name + slug + } + } + } + } +`; + export const productFragmentDetails = gql` ${fragmentProductImage} ${fragmentMoney} + ${productVariantAttributesFragment} ${stockFragment} fragment Product on Product { - id + ...ProductVariantAttributesFragment name descriptionJson seoTitle @@ -111,25 +153,6 @@ export const productFragmentDetails = gql` isPublished chargeTaxes publicationDate - attributes { - attribute { - id - slug - name - inputType - valueRequired - values { - id - name - slug - } - } - values { - id - name - slug - } - } pricing { priceRange { start { @@ -332,17 +355,6 @@ const productDetailsQuery = gql` query ProductDetails($id: ID!) { product(id: $id) { ...Product - productType { - variantAttributes { - id - name - values { - id - name - slug - } - } - } } } `; @@ -464,3 +476,20 @@ export const AvailableInGridAttributesQuery = TypedQuery< AvailableInGridAttributes, AvailableInGridAttributesVariables >(availableInGridAttributes); + +const createMultipleVariantsData = gql` + ${fragmentMoney} + ${productVariantAttributesFragment} + query CreateMultipleVariantsData($id: ID!) { + product(id: $id) { + ...ProductVariantAttributesFragment + basePrice { + ...Money + } + } + } +`; +export const useCreateMultipleVariantsData = makeQuery< + CreateMultipleVariantsData, + CreateMultipleVariantsDataVariables +>(createMultipleVariantsData); diff --git a/src/products/types/CreateMultipleVariantsData.ts b/src/products/types/CreateMultipleVariantsData.ts new file mode 100644 index 000000000..d73feae44 --- /dev/null +++ b/src/products/types/CreateMultipleVariantsData.ts @@ -0,0 +1,80 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { AttributeInputTypeEnum } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL query operation: CreateMultipleVariantsData +// ==================================================== + +export interface CreateMultipleVariantsData_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface CreateMultipleVariantsData_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (CreateMultipleVariantsData_product_attributes_attribute_values | null)[] | null; +} + +export interface CreateMultipleVariantsData_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface CreateMultipleVariantsData_product_attributes { + __typename: "SelectedAttribute"; + attribute: CreateMultipleVariantsData_product_attributes_attribute; + values: (CreateMultipleVariantsData_product_attributes_values | null)[]; +} + +export interface CreateMultipleVariantsData_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface CreateMultipleVariantsData_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (CreateMultipleVariantsData_product_productType_variantAttributes_values | null)[] | null; +} + +export interface CreateMultipleVariantsData_product_productType { + __typename: "ProductType"; + variantAttributes: (CreateMultipleVariantsData_product_productType_variantAttributes | null)[] | null; +} + +export interface CreateMultipleVariantsData_product_basePrice { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface CreateMultipleVariantsData_product { + __typename: "Product"; + id: string; + attributes: CreateMultipleVariantsData_product_attributes[]; + productType: CreateMultipleVariantsData_product_productType; + basePrice: CreateMultipleVariantsData_product_basePrice | null; +} + +export interface CreateMultipleVariantsData { + product: CreateMultipleVariantsData_product | null; +} + +export interface CreateMultipleVariantsDataVariables { + id: string; +} diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index 7b1ce054e..bf6d5b287 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -8,6 +8,58 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes"; // GraphQL fragment: Product // ==================================================== +export interface Product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface Product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (Product_attributes_attribute_values | null)[] | null; +} + +export interface Product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface Product_attributes { + __typename: "SelectedAttribute"; + attribute: Product_attributes_attribute; + values: (Product_attributes_values | null)[]; +} + +export interface Product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface Product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (Product_productType_variantAttributes_values | null)[] | null; +} + +export interface Product_productType { + __typename: "ProductType"; + variantAttributes: (Product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface Product_category { __typename: "Category"; id: string; @@ -50,36 +102,6 @@ export interface Product_purchaseCost { stop: Product_purchaseCost_stop | null; } -export interface Product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface Product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (Product_attributes_attribute_values | null)[] | null; -} - -export interface Product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface Product_attributes { - __typename: "SelectedAttribute"; - attribute: Product_attributes_attribute; - values: (Product_attributes_values | null)[]; -} - export interface Product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -151,16 +173,11 @@ export interface Product_variants { trackInventory: boolean; } -export interface Product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface Product { __typename: "Product"; id: string; + attributes: Product_attributes[]; + productType: Product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -174,9 +191,7 @@ export interface Product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: Product_attributes[]; pricing: Product_pricing | null; images: (Product_images | null)[] | null; variants: (Product_variants | null)[] | null; - productType: Product_productType; } diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index 710f81e8f..07e21aa5a 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -14,6 +14,58 @@ export interface ProductCreate_productCreate_errors { field: string | null; } +export interface ProductCreate_productCreate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductCreate_productCreate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductCreate_productCreate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductCreate_productCreate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductCreate_productCreate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductCreate_productCreate_product_attributes_attribute; + values: (ProductCreate_productCreate_product_attributes_values | null)[]; +} + +export interface ProductCreate_productCreate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductCreate_productCreate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductCreate_productCreate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductCreate_productCreate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductCreate_productCreate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductCreate_productCreate_product_purchaseCost { stop: ProductCreate_productCreate_product_purchaseCost_stop | null; } -export interface ProductCreate_productCreate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductCreate_productCreate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductCreate_productCreate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductCreate_productCreate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductCreate_productCreate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductCreate_productCreate_product_attributes_attribute; - values: (ProductCreate_productCreate_product_attributes_values | null)[]; -} - export interface ProductCreate_productCreate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductCreate_productCreate_product_variants { trackInventory: boolean; } -export interface ProductCreate_productCreate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductCreate_productCreate_product { __typename: "Product"; id: string; + attributes: ProductCreate_productCreate_product_attributes[]; + productType: ProductCreate_productCreate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductCreate_productCreate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductCreate_productCreate_product_attributes[]; pricing: ProductCreate_productCreate_product_pricing | null; images: (ProductCreate_productCreate_product_images | null)[] | null; variants: (ProductCreate_productCreate_product_variants | null)[] | null; - productType: ProductCreate_productCreate_product_productType; } export interface ProductCreate_productCreate { diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index c426f408a..19b2b3e40 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -8,6 +8,58 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes"; // GraphQL query operation: ProductDetails // ==================================================== +export interface ProductDetails_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductDetails_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductDetails_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductDetails_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductDetails_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductDetails_product_attributes_attribute; + values: (ProductDetails_product_attributes_values | null)[]; +} + +export interface ProductDetails_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductDetails_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductDetails_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductDetails_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductDetails_product_category { __typename: "Category"; id: string; @@ -50,36 +102,6 @@ export interface ProductDetails_product_purchaseCost { stop: ProductDetails_product_purchaseCost_stop | null; } -export interface ProductDetails_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductDetails_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductDetails_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductDetails_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductDetails_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductDetails_product_attributes_attribute; - values: (ProductDetails_product_attributes_values | null)[]; -} - export interface ProductDetails_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -151,31 +173,11 @@ export interface ProductDetails_product_variants { trackInventory: boolean; } -export interface ProductDetails_product_productType_variantAttributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductDetails_product_productType_variantAttributes { - __typename: "Attribute"; - id: string; - name: string | null; - values: (ProductDetails_product_productType_variantAttributes_values | null)[] | null; -} - -export interface ProductDetails_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; - variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; -} - export interface ProductDetails_product { __typename: "Product"; id: string; + attributes: ProductDetails_product_attributes[]; + productType: ProductDetails_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -189,11 +191,9 @@ export interface ProductDetails_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductDetails_product_attributes[]; pricing: ProductDetails_product_pricing | null; images: (ProductDetails_product_images | null)[] | null; variants: (ProductDetails_product_variants | null)[] | null; - productType: ProductDetails_product_productType; } export interface ProductDetails { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index fcbb37415..6c6d583a9 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -14,6 +14,58 @@ export interface ProductImageCreate_productImageCreate_errors { field: string | null; } +export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageCreate_productImageCreate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductImageCreate_productImageCreate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductImageCreate_productImageCreate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageCreate_productImageCreate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductImageCreate_productImageCreate_product_attributes_attribute; + values: (ProductImageCreate_productImageCreate_product_attributes_values | null)[]; +} + +export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductImageCreate_productImageCreate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductImageCreate_productImageCreate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductImageCreate_productImageCreate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductImageCreate_productImageCreate_product_purchaseCost { stop: ProductImageCreate_productImageCreate_product_purchaseCost_stop | null; } -export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageCreate_productImageCreate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductImageCreate_productImageCreate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductImageCreate_productImageCreate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageCreate_productImageCreate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductImageCreate_productImageCreate_product_attributes_attribute; - values: (ProductImageCreate_productImageCreate_product_attributes_values | null)[]; -} - export interface ProductImageCreate_productImageCreate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductImageCreate_productImageCreate_product_variants { trackInventory: boolean; } -export interface ProductImageCreate_productImageCreate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductImageCreate_productImageCreate_product { __typename: "Product"; id: string; + attributes: ProductImageCreate_productImageCreate_product_attributes[]; + productType: ProductImageCreate_productImageCreate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductImageCreate_productImageCreate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductImageCreate_productImageCreate_product_attributes[]; pricing: ProductImageCreate_productImageCreate_product_pricing | null; images: (ProductImageCreate_productImageCreate_product_images | null)[] | null; variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null; - productType: ProductImageCreate_productImageCreate_product_productType; } export interface ProductImageCreate_productImageCreate { diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 0bca7c7c9..5bb8acfea 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -14,6 +14,58 @@ export interface ProductImageUpdate_productImageUpdate_errors { field: string | null; } +export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductImageUpdate_productImageUpdate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductImageUpdate_productImageUpdate_product_attributes_attribute; + values: (ProductImageUpdate_productImageUpdate_product_attributes_values | null)[]; +} + +export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductImageUpdate_productImageUpdate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductImageUpdate_productImageUpdate_product_purchaseCost { stop: ProductImageUpdate_productImageUpdate_product_purchaseCost_stop | null; } -export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductImageUpdate_productImageUpdate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductImageUpdate_productImageUpdate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageUpdate_productImageUpdate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductImageUpdate_productImageUpdate_product_attributes_attribute; - values: (ProductImageUpdate_productImageUpdate_product_attributes_values | null)[]; -} - export interface ProductImageUpdate_productImageUpdate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductImageUpdate_productImageUpdate_product_variants { trackInventory: boolean; } -export interface ProductImageUpdate_productImageUpdate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductImageUpdate_productImageUpdate_product { __typename: "Product"; id: string; + attributes: ProductImageUpdate_productImageUpdate_product_attributes[]; + productType: ProductImageUpdate_productImageUpdate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductImageUpdate_productImageUpdate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductImageUpdate_productImageUpdate_product_attributes[]; pricing: ProductImageUpdate_productImageUpdate_product_pricing | null; images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null; variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null; - productType: ProductImageUpdate_productImageUpdate_product_productType; } export interface ProductImageUpdate_productImageUpdate { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 90b5615c1..f0b15d703 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -14,6 +14,58 @@ export interface ProductUpdate_productUpdate_errors { field: string | null; } +export interface ProductUpdate_productUpdate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductUpdate_productUpdate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductUpdate_productUpdate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductUpdate_productUpdate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductUpdate_productUpdate_product_attributes_attribute; + values: (ProductUpdate_productUpdate_product_attributes_values | null)[]; +} + +export interface ProductUpdate_productUpdate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductUpdate_productUpdate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductUpdate_productUpdate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductUpdate_productUpdate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductUpdate_productUpdate_product_purchaseCost { stop: ProductUpdate_productUpdate_product_purchaseCost_stop | null; } -export interface ProductUpdate_productUpdate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductUpdate_productUpdate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductUpdate_productUpdate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductUpdate_productUpdate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductUpdate_productUpdate_product_attributes_attribute; - values: (ProductUpdate_productUpdate_product_attributes_values | null)[]; -} - export interface ProductUpdate_productUpdate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductUpdate_productUpdate_product_variants { trackInventory: boolean; } -export interface ProductUpdate_productUpdate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductUpdate_productUpdate_product { __typename: "Product"; id: string; + attributes: ProductUpdate_productUpdate_product_attributes[]; + productType: ProductUpdate_productUpdate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductUpdate_productUpdate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductUpdate_productUpdate_product_attributes[]; pricing: ProductUpdate_productUpdate_product_pricing | null; images: (ProductUpdate_productUpdate_product_images | null)[] | null; variants: (ProductUpdate_productUpdate_product_variants | null)[] | null; - productType: ProductUpdate_productUpdate_product_productType; } export interface ProductUpdate_productUpdate { diff --git a/src/products/types/ProductVariantAttributesFragment.ts b/src/products/types/ProductVariantAttributesFragment.ts new file mode 100644 index 000000000..462cbd1e6 --- /dev/null +++ b/src/products/types/ProductVariantAttributesFragment.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { AttributeInputTypeEnum } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: ProductVariantAttributesFragment +// ==================================================== + +export interface ProductVariantAttributesFragment_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductVariantAttributesFragment_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductVariantAttributesFragment_attributes_attribute_values | null)[] | null; +} + +export interface ProductVariantAttributesFragment_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductVariantAttributesFragment_attributes { + __typename: "SelectedAttribute"; + attribute: ProductVariantAttributesFragment_attributes_attribute; + values: (ProductVariantAttributesFragment_attributes_values | null)[]; +} + +export interface ProductVariantAttributesFragment_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductVariantAttributesFragment_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductVariantAttributesFragment_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductVariantAttributesFragment_productType { + __typename: "ProductType"; + variantAttributes: (ProductVariantAttributesFragment_productType_variantAttributes | null)[] | null; +} + +export interface ProductVariantAttributesFragment { + __typename: "Product"; + id: string; + attributes: ProductVariantAttributesFragment_attributes[]; + productType: ProductVariantAttributesFragment_productType; +} diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index c54d9ea19..adfa2075b 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -14,6 +14,58 @@ export interface SimpleProductUpdate_productUpdate_errors { field: string | null; } +export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productUpdate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (SimpleProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; +} + +export interface SimpleProductUpdate_productUpdate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productUpdate_product_attributes { + __typename: "SelectedAttribute"; + attribute: SimpleProductUpdate_productUpdate_product_attributes_attribute; + values: (SimpleProductUpdate_productUpdate_product_attributes_values | null)[]; +} + +export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface SimpleProductUpdate_productUpdate_product_productType { + __typename: "ProductType"; + variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface SimpleProductUpdate_productUpdate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface SimpleProductUpdate_productUpdate_product_purchaseCost { stop: SimpleProductUpdate_productUpdate_product_purchaseCost_stop | null; } -export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface SimpleProductUpdate_productUpdate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (SimpleProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; -} - -export interface SimpleProductUpdate_productUpdate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface SimpleProductUpdate_productUpdate_product_attributes { - __typename: "SelectedAttribute"; - attribute: SimpleProductUpdate_productUpdate_product_attributes_attribute; - values: (SimpleProductUpdate_productUpdate_product_attributes_values | null)[]; -} - export interface SimpleProductUpdate_productUpdate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface SimpleProductUpdate_productUpdate_product_variants { trackInventory: boolean; } -export interface SimpleProductUpdate_productUpdate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface SimpleProductUpdate_productUpdate_product { __typename: "Product"; id: string; + attributes: SimpleProductUpdate_productUpdate_product_attributes[]; + productType: SimpleProductUpdate_productUpdate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface SimpleProductUpdate_productUpdate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: SimpleProductUpdate_productUpdate_product_attributes[]; pricing: SimpleProductUpdate_productUpdate_product_pricing | null; images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null; variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null; - productType: SimpleProductUpdate_productUpdate_product_productType; } export interface SimpleProductUpdate_productUpdate { diff --git a/src/products/urls.ts b/src/products/urls.ts index 08b8aeb7a..5160034a8 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -69,11 +69,7 @@ export const productListUrl = (params?: ProductListUrlQueryParams): string => productListPath + "?" + stringifyQs(params); export const productPath = (id: string) => urlJoin(productSection + id); -export type ProductUrlDialog = - | "create-variants" - | "edit-stocks" - | "remove" - | "remove-variants"; +export type ProductUrlDialog = "edit-stocks" | "remove" | "remove-variants"; export type ProductUrlQueryParams = BulkAction & Dialog; export const productUrl = (id: string, params?: ProductUrlQueryParams) => productPath(encodeURIComponent(id)) + "?" + stringifyQs(params); @@ -96,6 +92,11 @@ export const productVariantEditUrl = ( "?" + stringifyQs(params); +export const productVariantCreatorPath = (productId: string) => + urlJoin(productSection, productId, "variant-creator"); +export const productVariantCreatorUrl = (productId: string) => + productVariantCreatorPath(encodeURIComponent(productId)); + export const productVariantAddPath = (productId: string) => urlJoin(productSection, productId, "variant/add"); export type ProductVariantAddUrlDialog = "edit-stocks"; diff --git a/src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx b/src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/views/ProductMultipleVariantCreate/index.ts b/src/products/views/ProductMultipleVariantCreate/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/views/ProductMultipleVariantCreate/paginate.ts b/src/products/views/ProductMultipleVariantCreate/paginate.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 899d14dd1..c0c35acf8 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -11,10 +11,7 @@ import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import useShop from "@saleor/hooks/useShop"; import { commonMessages } from "@saleor/intl"; -import ProductVariantCreateDialog from "@saleor/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog"; -import { ProductVariantBulkCreate } from "@saleor/products/types/ProductVariantBulkCreate"; import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; @@ -39,7 +36,8 @@ import { ProductUrlQueryParams, productVariantAddUrl, productVariantEditUrl, - ProductUrlDialog + ProductUrlDialog, + productVariantCreatorUrl } from "../../urls"; import { createImageReorderHandler, @@ -59,7 +57,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { params.ids ); const intl = useIntl(); - const shop = useShop(); const { loadMore: loadMoreCategories, search: searchCategories, @@ -144,15 +141,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { }); const handleVariantAdd = () => navigate(productVariantAddUrl(id)); - const handleBulkProductVariantCreate = ( - data: ProductVariantBulkCreate - ) => { - if (data.productVariantBulkCreate.errors.length === 0) { - closeModal(); - refetch(); - } - }; - const handleBulkProductVariantDelete = ( data: ProductVariantBulkDelete ) => { @@ -166,7 +154,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { return ( = ({ id, params }) => { onUpdate={handleUpdate} > {({ - bulkProductVariantCreate, bulkProductVariantDelete, createProductImage, deleteProduct, @@ -258,7 +244,7 @@ export const ProductUpdate: React.FC = ({ id, params }) => { onImageReorder={handleImageReorder} onSubmit={handleSubmit} onVariantAdd={handleVariantAdd} - onVariantsAdd={() => openModal("create-variants")} + onVariantsAdd={() => navigate(productVariantCreatorUrl(id))} onVariantShow={variantId => () => navigate(productVariantEditUrl(product.id, variantId))} onImageUpload={handleImageUpload} @@ -347,28 +333,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { /> - - data.product.basePrice.amount.toFixed(2) - )} - errors={ - bulkProductVariantCreate.opts.data - ?.productVariantBulkCreate.errors || [] - } - open={params.action === "create-variants"} - attributes={maybe( - () => data.product.productType.variantAttributes, - [] - )} - currencySymbol={maybe(() => shop.defaultCurrency)} - onClose={closeModal} - onSubmit={inputs => - bulkProductVariantCreate.mutate({ - id, - inputs - }) - } - /> {!product?.productType?.hasVariants && ( = ({ + id +}) => { + const navigate = useNavigator(); + const notify = useNotifier(); + const intl = useIntl(); + const { data } = useCreateMultipleVariantsData({ + displayLoader: true, + variables: { id } + }); + const [ + bulkProductVariantCreate, + bulkProductVariantCreateOpts + ] = useProductVariantBulkCreateMutation({ + onCompleted: data => { + if (data.productVariantBulkCreate.errors.length === 0) { + notify({ + text: intl.formatMessage({ + defaultMessage: "Successfully created variants", + description: "success message" + }) + }); + navigate(productUrl(id)); + } + } + }); + const shop = useShop(); + + return ( + <> + + + bulkProductVariantCreate({ + variables: { id, inputs } + }) + } + /> + + ); +}; +ProductVariantCreator.displayName = "ProductVariantCreator"; +export default ProductVariantCreator; diff --git a/src/products/views/ProductVariantCreator/index.ts b/src/products/views/ProductVariantCreator/index.ts new file mode 100644 index 000000000..033e63894 --- /dev/null +++ b/src/products/views/ProductVariantCreator/index.ts @@ -0,0 +1,2 @@ +export * from "./ProductVariantCreator"; +export { default } from "./ProductVariantCreator"; From 85b730bce85d38ce8e88a90f213775ed60b29a82 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 1 Apr 2020 18:40:19 +0200 Subject: [PATCH 45/88] Update stories --- src/shipping/fixtures.ts | 14 +- .../__snapshots__/Stories.test.ts.snap | 10884 ++++++++++------ 2 files changed, 7163 insertions(+), 3735 deletions(-) diff --git a/src/shipping/fixtures.ts b/src/shipping/fixtures.ts index c05e6d2da..77eab37f9 100644 --- a/src/shipping/fixtures.ts +++ b/src/shipping/fixtures.ts @@ -1,4 +1,3 @@ -import { warehouseList } from "@saleor/warehouses/fixtures"; import { ShippingMethodTypeEnum } from "../types/globalTypes"; import { ShippingZoneDetailsFragment } from "./types/ShippingZoneDetailsFragment"; import { ShippingZoneFragment } from "./types/ShippingZoneFragment"; @@ -1646,5 +1645,16 @@ export const shippingZone: ShippingZoneDetailsFragment = { type: ShippingMethodTypeEnum.PRICE } ], - warehouses: warehouseList + warehouses: [ + { + __typename: "Warehouse", + id: "V2FyZWhvdXNlOmEzMThmMGZlLTcwMmYtNDNjYy1hYmFjLWZmZmMzN2Y3ZTliYw==", + name: "C our wares" + }, + { + __typename: "Warehouse", + id: "V2FyZWhvdXNlOjJmN2UyOTlmLWEwMzMtNDhjZS1iYmM5LTFkZDM4NjU2ZjMwYw==", + name: "Be stocked" + } + ] }; diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index f6535eb25..2dc1dd71d 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -34628,7 +34628,7 @@ exports[`Storyshots Views / Configuration default 1`] = ` > @@ -34638,50 +34638,12 @@ exports[`Storyshots Views / Configuration default 1`] = `
- Shipping Methods + Taxes
- Manage how you ship out orders -
-
-
-
-
-
-
- -
-
-
- Warehouses -
-
- Manage and update your warehouse information + Manage how your store charges tax
@@ -34697,7 +34659,7 @@ exports[`Storyshots Views / Configuration default 1`] = `
- Product Settings + Staff Settings
@@ -34731,12 +34693,12 @@ exports[`Storyshots Views / Configuration default 1`] = `
- Warehouses + Staff Members
- Manage and update your warehouse information + Manage your employees and their permissions
@@ -34814,7 +34776,7 @@ exports[`Storyshots Views / Configuration default 1`] = ` > @@ -34824,33 +34786,16 @@ exports[`Storyshots Views / Configuration default 1`] = `
- Taxes + Shipping Methods
- Manage how your store charges tax + Manage how you ship out orders
-
-
-
-
-
- Staff Settings -
-
-
@@ -34869,7 +34814,7 @@ exports[`Storyshots Views / Configuration default 1`] = ` > @@ -34879,12 +34824,12 @@ exports[`Storyshots Views / Configuration default 1`] = `
- Staff Members + Warehouses
- Manage your employees and their permissions + Manage and update your warehouse information
@@ -35314,6 +35259,61 @@ exports[`Storyshots Views / Configuration partial access 1`] = `
+
+
+
+ Product Settings +
+
+
+
+
+
+ +
+
+
+ Warehouses +
+
+ Manage and update your warehouse information +
+
+
+
+
+
@@ -96180,40 +96180,6 @@ exports[`Storyshots Views / Product types / Product type details no attributes 1
-
-
- Available inventoty at: -
- - - All Warehouses - - - -
@@ -97529,1792 +97495,94 @@ exports[`Storyshots Views / Products / Create multiple variants / summary defaul style="padding:24px" >
-
-
+ -
-
- Select Values -
-
-
-
- Prices and SKU -
-
-
-
- Summary -
-
-
+ Summary +
-
- You will create variants below -
-
-
-
-
- Variant -
-
- Price -
-
- Inventory -
-
- SKU -
-
-
-
- - 100g - - - Arabica - - - Round - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- - 100g - - - Arabica - - - Polo - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- - 500g - - - Arabica - - - Round - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- - 500g - - - Arabica - - - Polo - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
+ class="CardTitle-toolbar-id" + />
-
-
-
-`; - -exports[`Storyshots Views / Products / Create multiple variants / summary errors 1`] = ` -
-
-
+
+
-
- Select Values -
+ Variant
-
- Prices and SKU -
-
-
-
- Summary -
-
-
-
-
- You will create variants below -
-
-
-
-
- Variant -
-
- Price -
-
- Inventory -
-
- SKU -
-
-
-
- - 100g - - - Arabica - - - Round - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- - 100g - - - Arabica - - - Polo - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- - 500g - - - Arabica - - - Round - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
-
-
-
- - 500g - - - Arabica - - - Polo - -
-
-
-
- - USD - -
-
-
-
-
-
- - -
-
-
-
-
-
- - -
-

- SKUs must be unique -

-
-
-
- -
-
-
-
-
-
-
-
-`; - -exports[`Storyshots Views / Products / Create multiple variants choose values 1`] = ` -
-
-
-
-
-
-
- Select Values -
-
-
-
- Prices and SKU -
-
-
-
- Summary -
-
-
-
-
- Box Size -
-
-
- - - - -
-
- Coffee Genre -
-
-
- - -
-
- Collar -
-
-
- - - -
-
-
-
-
-
-`; - -exports[`Storyshots Views / Products / Create multiple variants interactive 1`] = ` -
-`; - -exports[`Storyshots Views / Products / Create multiple variants prices and SKU 1`] = ` -
-
-
-
-
-
-
- Select Values -
-
-
-
- Prices and SKU -
-
-
-
- Summary -
-
-
-
-
Price
-
-
+
+
+ - - - -
- - -
-
-
- - Apply single price to all SKUs - - -
-
+ + Arabica + + + Round + +
+
+
-
USD
-
-
-
- Choose attribute -
-
-
-
- -
-
- Coffee Genre -
- - - -
-
-
-
-
-
-
-
-
- Arabica -
-
-
-
- -
- - USD - -
-
-
-
-
-
- Stock -
-
-
- -
-
- -
-
-
-
- Choose attribute + +
-
-
+
+ +
+
+
+
+ + 100g + + + Arabica + + + Polo + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + 500g + + + Arabica + + + Round + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + 500g + + + Arabica + + + Polo + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants / summary errors 1`] = ` +
+
+
+
+ + Summary + +
+
+
+
+
+
+
+ Variant +
+
+ Price +
+
+ Inventory +
+
+ SKU +
+
+
+
+ + 100g + + + Arabica + + + Round + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + 100g + + + Arabica + + + Polo + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + 500g + + + Arabica + + + Round + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ + 500g + + + Arabica + + + Polo + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+

+ SKUs must be unique +

+
+
+
+ +
+
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants choose values 1`] = ` +
+
+
+
+ + Box Size + +
+
+
+
+
+ + + + +
+
+
+
+
+ + Coffee Genre + +
+
+
+
+
+ + +
+
+
+
+
+ + Collar + +
+
+
+
+
+ + + +
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants interactive 1`] = ` +
+
+
+
+
+ Select Values +
+
+
+
+ Prices and SKU +
+
+
+
+ Summary +
+
+
+
+
+ Choose Values +
+
+
+ +
+
+
+
+
+ + Author + +
+
+
+
+
+ + +
+
+
+
+
+ + Box Size + +
+
+
+
+
+ + + + +
+
+
+
+
+ + Brand + +
+
+
+
+
+ +
+
+
+
+
+ + Candy Box Size + +
+
+
+
+
+ + + +
+
+
+
+
+ + Coffee Genre + +
+
+
+
+
+ + +
+
+
+
+
+ + Collar + +
+
+
+
+
+ + + +
+
+
+
+
+ + Color + +
+
+
+
+
+ + +
+
+
+
+
+ + Cover + +
+
+
+
+
+ + + + + + +
+
+
+
+
+ + Flavor + +
+
+
+
+
+ + +
+
+
+
+
+ + Language + +
+
+
+
+
+ + +
+
+
+
+
+ + Publisher + +
+
+
+
+
+ + +
+
+
+
+
+ + Size + +
+
+
+
+
+ + + + + + +
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants prices and SKU 1`] = ` +
+
+
+
+ + Price + +
+
+
+
+
+
+
-
-
-
+ + + + Apply single price to all SKUs + +
+ +
+ + USD + +
+
+
+ +
+
+
+
-
+
+
+
+ +
+
+ Coffee Genre +
+ + +
-
-
+
+
+
+
+
+
+ Arabica +
+
+
+
+
+
+
+
+
+
+
+
+ + Stock + +
+
+
+
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+
+
+ Choose attribute +
+
+
+
+ +
+
+ Coffee Genre +
+ + + +
+
+
+
+
+
+
+
+
+ Arabica +
+
+
+
+ +
+ +
@@ -100316,109 +101377,6 @@ Ctrl + K"
-
-
- - Inventory - -
-
-
-
-
-
-
- -
- - -
-
-
- -
- - -
-
-
-
-
-
@@ -101381,107 +102339,6 @@ Ctrl + K"
-
-
- - Inventory - -
-
-
-
-
-
-
- -
- - -
-
-
- -
- - -
-
-
-
-
-
@@ -102443,112 +103300,6 @@ Ctrl + K"
-
-
- - Inventory - -
-
-
-
-
-
-
- -
- - -
-

- Invalid value -

-
-
- -
- - -
-
-
-
-
-
@@ -103054,40 +103805,6 @@ exports[`Storyshots Views / Products / Create product variant add first variant
-
-
- Available inventoty at: -
- - - All Warehouses - - - -
@@ -103394,7 +104111,7 @@ exports[`Storyshots Views / Products / Create product variant add first variant - Stock + Inventory
-
-
+
-
-
+ SKU (Stock Keeping Unit) +
-
+
+
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
@@ -103545,40 +104326,6 @@ exports[`Storyshots Views / Products / Create product variant default 1`] = `
-
-
- Available inventoty at: -
- - - All Warehouses - - - -
@@ -103941,7 +104688,7 @@ exports[`Storyshots Views / Products / Create product variant default 1`] = ` - Stock + Inventory
-
-
+
-
-
+ SKU (Stock Keeping Unit) +
-
+
+
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
@@ -104378,7 +105189,7 @@ exports[`Storyshots Views / Products / Create product variant when loading data - Stock + Inventory
-
-
+
-
-
+ SKU (Stock Keeping Unit) +
-
+
+
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
@@ -104531,40 +105407,6 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] =
-
-
- Available inventoty at: -
- - - All Warehouses - - - -
@@ -104940,7 +105782,7 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] = - Stock + Inventory
-
-
+
-
-
+ SKU (Stock Keeping Unit) +
-
+
+
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
@@ -105047,6 +105948,30 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] =
`; +exports[`Storyshots Views / Products / Edit warehouses default 1`] = ` +
+`; + +exports[`Storyshots Views / Products / Edit warehouses loading confirmation 1`] = ` +
+`; + +exports[`Storyshots Views / Products / Edit warehouses loading warehouses 1`] = ` +
+`; + +exports[`Storyshots Views / Products / Edit warehouses with error 1`] = ` +
+`; + exports[`Storyshots Views / Products / Product edit form errors 1`] = `
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -107786,6 +108745,40 @@ Ctrl + K"
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -108359,6 +109352,1786 @@ Ctrl + K"
`; +exports[`Storyshots Views / Products / Product edit no stock and no variants 1`] = ` +
+
+
+
+
+ Ergonomic Plastic Bacon +
+
+
+
+
+
+
+
+
+ + General Informations + +
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+ Description +
+
+ +
+
+
+
+
+
+ + + bold + + +
+
+
+
+ + + italic + + +
+
+
+
+ + + strikethrough + + +
+
+

+
+ + + h1 + + +
+

+

+
+ + + h2 + + +
+

+

+
+ + + h3 + + +
+

+
+
+ + + blockquote + + +
+
+
    +
  • +
    + + + ul + + +
    +
  • +
+
    +
  1. +
    + + + ol + + +
    +
  2. +
+
+
+ + + link + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + Images + +
+ + +
+
+
+
+
+
+
+ + +
+ Drop here to upload +
+
+
+
+
+
+
+
+
+ Id sit dolores adipisci +
+
+
+
+
+ Id sit dolores adipisci +
+
+
+
+
+ Id sit dolores adipisci +
+
+
+
+
+ Id sit dolores adipisci +
+
+
+
+
+ Id sit dolores adipisci +
+
+
+
+
+
+
+
+ + Attributes + +
+
+
+
+
+
+
+
+ 2 Attributes +
+
+ +
+
+
+
+
+ Borders +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ Legacy +
+
+
+
+
+ + +
+
+
+
+
+
+ Auto Loan Account +
+ +
+
+
+
+
+
+
+
+
+
+ + Pricing + +
+
+
+ +
+
+
+
+
+ +
+ +
+
+ NZD +
+
+ +
+
+
+
+
+
+
+
+ + Inventory + +
+
+
+
+
+
+
+ +
+ + +
+
+
+
+ +
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
+
+
+
+
+ + Search Engine Preview + +
+ +
+
+
+
+
+
+ Add search engine title and description to make this product easier to find +
+
+
+
+
+
+
+ + Organize Product + +
+
+
+
+
+
+ Product Type +
+
+ Versatile +
+
+
+ Product Type +
+
+ Simple +
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ + +

+ *Optional. Adding product to collection helps users find it. +

+
+
+
+
+
+
+ Winter sale +
+ +
+
+
+
+
+
+
+
+ + Visibility + +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ +
+`; + exports[`Storyshots Views / Products / Product edit no variants 1`] = `
- Variants + Inventory
- -
+ />
- - - - - - - - - - + ​ + + + + + + +
+
+ + + Track Inventory +
-
- - - - - - - - - - - -
+
+ +
- Variant - - SKU - - Inventory -
+ Active inventory tracking will automatically calculate changes of stock +
+ +
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ C our wares + +
+
+ + +
+
+
+ Be stocked + +
+
+ + +
+
+
- Configurable + Simple
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -112510,10 +115390,10 @@ Ctrl + K" class="MuiCardContent-root-id" >
-
+
+ +
+
+
+
+
+ + Quantity + +
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
+
+
+ Available inventoty at: +
+ + + All Warehouses + + + +
@@ -114145,13 +117128,7 @@ Ctrl + K" class="MuiTableCell-root-id MuiTableCell-head-id ProductVariants-colName-id" scope="col" > - Name - - - Status + Variant SKU + + Inventory + Cordoba Oro - -
- Available -
- 87192-94370 + + 5 available at 2 locations + silver - -
- Available -
- 69055-15190 + + 13 available at 1 location + @@ -115889,10 +118862,10 @@ Ctrl + K" class="MuiCardContent-root-id" >
-
+
+
+
+
+
+
+ + Quantity + +
+ + + + + + + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ C our wares + +
+
+ + +
+
+
+ Be stocked + +
+
+ + +
+
+
-
-
-
- - Warehouse - -
-
-
-
-
-
-
- - -

- Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. -

-
-
-
-
-
@@ -116686,7 +119697,7 @@ exports[`Storyshots Views / Products / Product image details when loaded data 1` > ​ @@ -116739,99 +119750,6 @@ exports[`Storyshots Views / Products / Product image details when loaded data 1`
-
-
-
- - Warehouse - -
-
-
-
-
-
-
- - -

- Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. -

-
-
-
-
-
@@ -117004,99 +119922,6 @@ exports[`Storyshots Views / Products / Product image details when loading data 1
-
-
-
- - Warehouse - -
-
-
-
-
-
-
- - -

- Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. -

-
-
-
-
-
@@ -122383,7 +125208,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors - Stock + Inventory
-
-
+
-
+
+
+ +
+
+
+
+
+ + Quantity + +
+ + + + + + + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ Warehouse 1 + +
+
+ + +
+
+
+ Warehouse 2 + +
+
+ + +
+
+
@@ -123065,7 +126017,7 @@ exports[`Storyshots Views / Products / Product variant details when loaded data - Stock + Inventory
-
-
+
-
-
+ SKU (Stock Keeping Unit) +
-
+
+
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ Warehouse 1 + +
+
+ + +
+
+
+ Warehouse 2 + +
+
+ + +
+
+
@@ -123513,7 +126592,7 @@ exports[`Storyshots Views / Products / Product variant details when loading data - Stock + Inventory
-
-
+
-
-
+ SKU (Stock Keeping Unit) +
-
+
+
+
+
+
+
+ + Quantity + + +
+
+
+ + + + + + + + + + + + +
+ Warehouse Name + + Quantity Available +
+ This product doesn't have any stock. You can add it + + here + + . +
@@ -123695,7 +126839,7 @@ exports[`Storyshots Views / Services / Create service default 1`] = ` > ​ @@ -124506,7 +127650,7 @@ exports[`Storyshots Views / Services / Create service form errors 1`] = ` > ​ @@ -126144,7 +129288,7 @@ exports[`Storyshots Views / Services / Service details default 1`] = ` > ​ @@ -132228,6 +135372,99 @@ exports[`Storyshots Views / Shipping / Shipping zone details default 1`] = `
+
+
+
+ + Warehouse + +
+
+
+
+
+
+
+ + +

+ Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. +

+
+
+
+
+
@@ -132858,6 +136095,99 @@ exports[`Storyshots Views / Shipping / Shipping zone details form errors 1`] = `
+
+
+
+ + Warehouse + +
+
+
+
+
+
+
+ + +

+ Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. +

+
+
+
+
+
@@ -132878,7 +136208,12 @@ exports[`Storyshots Views / Shipping / Shipping zone details loading 1`] = `
- ... + + ‌ +
+
+
+
+ + Warehouse + +
+
+
+
+
+
+
+ + +

+ Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes. +

+
+
+
+
+
@@ -135742,7 +139170,7 @@ exports[`Storyshots Views / Site settings / Page default 1`] = ` > ​ @@ -135854,7 +139282,7 @@ exports[`Storyshots Views / Site settings / Page default 1`] = ` > ​ @@ -136617,7 +140045,7 @@ exports[`Storyshots Views / Site settings / Page form errors 1`] = ` > ​ @@ -136729,7 +140157,7 @@ exports[`Storyshots Views / Site settings / Page form errors 1`] = ` > ​ @@ -137606,7 +141034,7 @@ exports[`Storyshots Views / Site settings / Page loading 1`] = ` > - Generic form error + Invalid value

@@ -142623,7 +146051,7 @@ exports[`Storyshots Views / Warehouses / Create warehouse form errors 1`] = `

- Generic form error + Invalid value

- Generic form error + Invalid value

- Generic form error + Invalid value

- Generic form error + Invalid value

- Generic form error + Invalid value

@@ -142825,7 +146253,7 @@ exports[`Storyshots Views / Warehouses / Create warehouse form errors 1`] = ` > - Generic form error + Invalid value

@@ -142873,16 +146301,16 @@ exports[`Storyshots Views / Warehouses / Create warehouse form errors 1`] = ` class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id" >
-

- Generic form error -

- Generic form error + Invalid value

@@ -143302,7 +146725,7 @@ exports[`Storyshots Views / Warehouses / Create warehouse loading 1`] = ` > - Generic form error + Invalid value

@@ -144118,7 +147541,7 @@ exports[`Storyshots Views / Warehouses / Warehouse details form errors 1`] = `

- Generic form error + Invalid value

- Generic form error + Invalid value

- Generic form error + Invalid value

- Generic form error + Invalid value

- Generic form error + Invalid value

@@ -144320,7 +147743,7 @@ exports[`Storyshots Views / Warehouses / Warehouse details form errors 1`] = ` > - Generic form error + Invalid value

@@ -144368,16 +147791,16 @@ exports[`Storyshots Views / Warehouses / Warehouse details form errors 1`] = ` class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id" >
-

- Generic form error -

- Generic form error + Invalid value

@@ -144875,7 +148293,7 @@ exports[`Storyshots Views / Warehouses / Warehouse details loading 1`] = ` > Date: Thu, 2 Apr 2020 11:52:15 +0200 Subject: [PATCH 46/88] Improve code readability --- .../ProductVariantCreatorPage.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx index aaf03a9b2..dca44165f 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx @@ -105,7 +105,7 @@ const ProductVariantCreatePage: React.FC = props const { attributes, defaultPrice, errors, onSubmit, ...contentProps } = props; const classes = useStyles(props); const intl = useIntl(); - const [step, { next, prev, set: setStep }] = useWizard< + const [step, { next: nextStep, prev: prevStep, set: setStep }] = useWizard< ProductVariantCreatorStep >(ProductVariantCreatorStep.values, [ ProductVariantCreatorStep.values, @@ -113,7 +113,7 @@ const ProductVariantCreatePage: React.FC = props ProductVariantCreatorStep.summary ]); - const [data, dispatchFormDataAction] = React.useReducer( + const [wizardData, dispatchFormDataAction] = React.useReducer( reduceProductVariantCreateFormData, createInitialForm(attributes, defaultPrice) ); @@ -131,7 +131,7 @@ const ProductVariantCreatePage: React.FC = props {step !== ProductVariantCreatorStep.values && ( - @@ -152,9 +152,9 @@ const ProductVariantCreatePage: React.FC = props -
- - 100g - - - Arabica - - - Polo - -
-
-
+
+ + ​ + + +
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
- - 500g - - - Arabica - - - Round - -
-
-
+
+ + ​ + + +
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
- - 500g - - - Arabica - - - Polo - -
-
-
+
+ + ​ + + +
+
+
+ +
+
+
+ + 100g + + + Arabica + + + Polo + +
+
-
+ USD +
+ + ​ + + +
+
+
-
+
+ + ​ + + +
+
+
- + + ​ + + + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+ + 500g + + + Arabica + + + Round + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+ + 500g + + + Arabica + + + Polo + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
@@ -98157,7 +98428,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary errors class="Container-root-id" >
- Summary + Created Variants
-
+
+ Variant +
+
+ Price +
+
+ C our wares +
+
+ Be stocked +
+
+ Darkwares +
+
+ SKU +
+
+
+
+ + 100g + + + Arabica + + + Round + +
+
- Variant -
-
- Price -
-
- Inventory -
-
- SKU +
+ + USD + +
- - 100g - - - Arabica - - - Round - -
-
-
+
+ + ​ + + +
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
- - 100g - - - Arabica - - - Polo - -
-
-
+
+ + ​ + + +
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
- - 500g - - - Arabica - - - Round - -
-
-
+
+ + ​ + + +
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- -
- - 500g - - - Arabica - - - Polo - -
-
-
+
+ + ​ + + +
+
+
+ +
+
+
+ + 100g + + + Arabica + + + Polo + +
+
-
+ USD +
+ + ​ + + +
+
+
-
+
-

- SKUs must be unique -

+ + ​ + + +
+
+
- + + ​ + + + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+ + 500g + + + Arabica + + + Round + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+ + 500g + + + Arabica + + + Polo + +
+
+
+
+ + USD + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+

+ SKUs must be unique +

+
+
+
+ +
@@ -100466,11 +101008,11 @@ exports[`Storyshots Views / Products / Create multiple variants prices and SKU 1 role="button" tabindex="0" > - Coffee Genre + Box Size
@@ -100558,6 +101100,63 @@ exports[`Storyshots Views / Products / Create multiple variants prices and SKU 1
+
+
+
+
+
+ 500g +
+
+
+
+ +
+ + USD + +
+
+
+
@@ -100837,7 +101436,62 @@ exports[`Storyshots Views / Products / Create multiple variants prices and SKU 1 aria-invalid="false" class="MuiInputBase-input-id MuiOutlinedInput-input-id" type="text" - value="30" + value="30,27,24" + /> + +
+
+
+
+
+
+
+
+
+ 500g +
+
+
+
+ +
+
From 715303e025879f91d935ba7e5353fd146240e29d Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 9 Apr 2020 12:13:42 +0200 Subject: [PATCH 60/88] Add ability to create stock in multiple warehouses --- .../ProductVariantCreatorContent.tsx | 50 +++--- .../ProductVariantCreatorPage.tsx | 4 +- .../ProductVariantCreatorPriceAndSku.tsx | 18 +-- .../ProductVariantCreatorStock.tsx | 144 +++++++++++------- .../ProductVariantCreatorSummary.tsx | 4 +- .../ProductVariantCreatorPage/reducer.ts | 12 +- 6 files changed, 133 insertions(+), 99 deletions(-) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx index a59e42cec..cc8fa7bb7 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx @@ -24,16 +24,15 @@ export interface ProductVariantCreatorContentProps { warehouses: WarehouseFragment[]; } -const ProductVariantCreatorContent: React.FC = props => { - const { - attributes, - currencySymbol, - data, - dispatchFormDataAction, - errors, - step, - warehouses - } = props; +const ProductVariantCreatorContent: React.FC = ({ + attributes, + currencySymbol, + data, + dispatchFormDataAction, + errors, + step, + warehouses +}) => { const selectedAttributes = attributes.filter(attribute => isSelected( attribute.id, @@ -104,17 +103,26 @@ const ProductVariantCreatorContent: React.FC : ProductVariantCreateReducerActionType.changeApplyStockToAttributeId }) } - onAttributeValueChange={(valueId, price, type) => - dispatchFormDataAction( - type === "price" && { - changeAttributeValuePrice: { - price, - valueId - }, - type: - ProductVariantCreateReducerActionType.changeAttributeValuePrice - } - ) + onAttributePriceChange={(valueId, price) => + dispatchFormDataAction({ + changeAttributeValuePrice: { + price, + valueId + }, + type: + ProductVariantCreateReducerActionType.changeAttributeValuePrice + }) + } + onAttributeStockChange={(valueId, quantity, warehouseIndex) => + dispatchFormDataAction({ + changeAttributeValueStock: { + quantity, + valueId, + warehouseIndex + }, + type: + ProductVariantCreateReducerActionType.changeAttributeValueStock + }) } onWarehouseToggle={warehouseId => dispatchFormDataAction({ diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx index 89135c1af..1e95564e1 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx @@ -50,11 +50,9 @@ function canHitNext( ) { return false; } - } else { - return true; } - if (data.stock.mode === "attribute" || data.stock.attribute) { + if (data.stock.mode === "attribute" && data.stock.attribute === "") { return false; } diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx index a70bf1332..0d6829942 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx @@ -23,10 +23,11 @@ export interface ProductVariantCreatorPriceAndSkuProps { onApplyToAllPriceChange: (value: string) => void; onApplyToAllStockChange: (warehouseIndex: number, value: string) => void; onAttributeSelect: (id: string, type: PriceOrStock) => void; - onAttributeValueChange: ( + onAttributePriceChange: (id: string, value: string) => void; + onAttributeStockChange: ( id: string, - value: string, - type: PriceOrStock + quantity: number, + warehouseIndex: number ) => void; onWarehouseToggle: (id: string) => void; } @@ -40,7 +41,8 @@ const ProductVariantCreatorPriceAndSku: React.FC ( <> @@ -51,9 +53,7 @@ const ProductVariantCreatorPriceAndSku: React.FC onApplyToAllChange(value, "price")} onApplyToAllPriceChange={onApplyToAllPriceChange} onAttributeSelect={id => onAttributeSelect(id, "price")} - onAttributeValueChange={(id, value) => - onAttributeValueChange(id, value, "price") - } + onAttributeValueChange={onAttributePriceChange} /> onApplyToAllChange(value, "stock")} onApplyToAllStockChange={onApplyToAllStockChange} onAttributeSelect={id => onAttributeSelect(id, "stock")} - onAttributeValueChange={(id, value) => - onAttributeValueChange(id, value, "stock") - } + onAttributeValueChange={onAttributeStockChange} onWarehouseToggle={onWarehouseToggle} /> diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx index 1c9768f39..6606c2e69 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx @@ -27,6 +27,17 @@ import { getStockAttributeValues } from "./utils"; const useStyles = makeStyles( 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: { marginBottom: theme.spacing(), marginTop: theme.spacing(0.5) @@ -75,7 +86,11 @@ export interface ProductVariantCreatorStockProps { onApplyToAllChange: (mode: VariantCreatorPricesAndSkuMode) => void; onApplyToAllStockChange: (warehouseIndex: number, value: string) => void; onAttributeSelect: (id: string) => void; - onAttributeValueChange: (id: string, value: string) => void; + onAttributeValueChange: ( + id: string, + quantity: number, + warehouseIndex: number + ) => void; onWarehouseToggle: (id: string) => void; } @@ -168,11 +183,8 @@ const ProductVariantCreatorStock: React.FC = pr {data.stock.mode === "all" && (
{data.warehouses.map((warehouseId, warehouseIndex) => ( -
- +
+ { warehouses.find(warehouse => warehouse.id === warehouseId) .name @@ -212,60 +224,74 @@ const ProductVariantCreatorStock: React.FC = pr {data.stock.mode === "attribute" && ( <> - -
- - - -
-
- -
-
- {stockAttributeValues && - stockAttributeValues.map(attributeValue => ( - -
- - -
- {attributeValue.name} -
-
- value.slug === attributeValue.slug - ).value - } - onChange={event => - onAttributeValueChange( - attributeValue.slug, - event.target.value + onAttributeSelect(event.target.value)} + /> + {stockAttributeValues && ( + <> +
+ +
+
+
+ {data.stock.attribute && + data.warehouses.map(warehouseId => ( + + { + warehouses.find( + warehouse => warehouse.id === warehouseId + ).name + } + + ))} + {stockAttributeValues.map(attributeValue => ( + + {attributeValue.name} + {data.warehouses.map( + (warehouseId, warehouseIndex) => ( + value.slug === attributeValue.slug + ).value[warehouseIndex] + } + onChange={event => + onAttributeValueChange( + attributeValue.slug, + parseInt(event.target.value, 10), + warehouseIndex + ) + } + key={warehouseId} + /> ) - } - /> -
- - - ))} + )} + + ))} +
+
+ + )} )} diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx index 46a5dd80f..620c7ea31 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx @@ -92,7 +92,7 @@ const useStyles = makeStyles< marginTop: theme.spacing(0.5) }, hr: { - gridColumn: props => `span ${4 + props.data.stock.value.length}` + gridColumn: props => `span ${4 + props.data.variants[0].stocks.length}` }, input: { "& input": { @@ -103,7 +103,7 @@ const useStyles = makeStyles< columnGap: theme.spacing(3), display: "grid", 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", rowGap: theme.spacing() + "px" } diff --git a/src/products/components/ProductVariantCreatorPage/reducer.ts b/src/products/components/ProductVariantCreatorPage/reducer.ts index 64e7b785a..93f2dbd16 100644 --- a/src/products/components/ProductVariantCreatorPage/reducer.ts +++ b/src/products/components/ProductVariantCreatorPage/reducer.ts @@ -186,8 +186,8 @@ function changeAttributeValuePrice( function changeAttributeValueStock( state: ProductVariantCreateFormData, attributeValueSlug: string, - warehouseIndex: number, - quantity: number + quantity: number, + warehouseIndex: number ): ProductVariantCreateFormData { const index = state.stock.values.findIndex( value => value.slug === attributeValueSlug @@ -199,8 +199,12 @@ function changeAttributeValueStock( const values = updateAtIndex( { - slug: attributeValueSlug, - value: updateAtIndex(quantity, state.stock.value, warehouseIndex) + ...state.stock.values[index], + value: updateAtIndex( + quantity, + state.stock.values[index].value, + warehouseIndex + ) }, state.stock.values, index From e52b2bb74a38d2cb6d331d60ced8c3ba0aabc968 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 14 Apr 2020 13:36:55 +0200 Subject: [PATCH 61/88] Fix attribute stock input --- src/products/components/ProductVariantCreatorPage/reducer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/products/components/ProductVariantCreatorPage/reducer.ts b/src/products/components/ProductVariantCreatorPage/reducer.ts index 93f2dbd16..81e410723 100644 --- a/src/products/components/ProductVariantCreatorPage/reducer.ts +++ b/src/products/components/ProductVariantCreatorPage/reducer.ts @@ -385,8 +385,8 @@ function reduceProductVariantCreateFormData( return changeAttributeValueStock( prevState, action.changeAttributeValueStock.valueId, - action.changeAttributeValueStock.warehouseIndex, - action.changeAttributeValueStock.quantity + action.changeAttributeValueStock.quantity, + action.changeAttributeValueStock.warehouseIndex ); case ProductVariantCreateReducerActionType.changeApplyPriceToAttributeId: return changeApplyPriceToAttributeId( From e167a6450eaec152858ae31f45dfee4293643408 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 14 Apr 2020 18:08:16 +0200 Subject: [PATCH 62/88] Improve test coverage --- .../ProductVariantCreatorContent.tsx | 10 +- .../ProductVariantCreatorPriceAndSku.tsx | 2 +- .../ProductVariantCreatorStock.tsx | 6 +- .../__snapshots__/reducer.test.ts.snap | 566 ++++++++++++++++-- .../createVariants.test.ts | 16 +- .../ProductVariantCreatorPage/fixtures.ts | 8 +- .../ProductVariantCreatorPage/reducer.test.ts | 36 +- .../ProductVariantCreatorPage/reducer.ts | 30 +- 8 files changed, 605 insertions(+), 69 deletions(-) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx index cc8fa7bb7..0653a0b0b 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx @@ -80,16 +80,18 @@ const ProductVariantCreatorContent: React.FC changeApplyPriceToAllValue: { price }, - type: ProductVariantCreateReducerActionType.applyPriceToAll + type: + ProductVariantCreateReducerActionType.changeApplyPriceToAllValue }) } - onApplyToAllStockChange={(warehouseIndex, quantity) => + onApplyToAllStockChange={(quantity, warehouseIndex) => dispatchFormDataAction({ changeApplyStockToAllValue: { - quantity: parseInt(quantity, 10), + quantity, warehouseIndex }, - type: ProductVariantCreateReducerActionType.applyStockToAll + type: + ProductVariantCreateReducerActionType.changeApplyStockToAllValue }) } onAttributeSelect={(attributeId, type) => diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx index 0d6829942..52ccf460c 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPriceAndSku.tsx @@ -21,7 +21,7 @@ export interface ProductVariantCreatorPriceAndSkuProps { type: PriceOrStock ) => void; onApplyToAllPriceChange: (value: string) => void; - onApplyToAllStockChange: (warehouseIndex: number, value: string) => void; + onApplyToAllStockChange: (quantity: number, warehouseIndex: number) => void; onAttributeSelect: (id: string, type: PriceOrStock) => void; onAttributePriceChange: (id: string, value: string) => void; onAttributeStockChange: ( diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx index 6606c2e69..0f3f45389 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx @@ -84,7 +84,7 @@ export interface ProductVariantCreatorStockProps { data: ProductVariantCreateFormData; warehouses: WarehouseFragment[]; onApplyToAllChange: (mode: VariantCreatorPricesAndSkuMode) => void; - onApplyToAllStockChange: (warehouseIndex: number, value: string) => void; + onApplyToAllStockChange: (quantity: number, warehouseIndex: number) => void; onAttributeSelect: (id: string) => void; onAttributeValueChange: ( id: string, @@ -203,8 +203,8 @@ const ProductVariantCreatorStock: React.FC = pr value={data.stock.value[warehouseIndex]} onChange={event => onApplyToAllStockChange( - warehouseIndex, - event.target.value + parseInt(event.target.value, 10), + warehouseIndex ) } /> diff --git a/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap b/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap index db7e66201..32a195361 100644 --- a/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap +++ b/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap @@ -26,8 +26,8 @@ Object { }, ], "price": Object { - "all": false, "attribute": "attr-2", + "mode": "attribute", "value": "", "values": Array [ Object { @@ -41,8 +41,8 @@ Object { ], }, "stock": Object { - "all": false, "attribute": "attr-4", + "mode": "attribute", "value": Array [], "values": Array [ Object { @@ -438,8 +438,8 @@ Object { }, ], "price": Object { - "all": false, "attribute": "attr-2", + "mode": "attribute", "value": "", "values": Array [ Object { @@ -453,8 +453,8 @@ Object { ], }, "stock": Object { - "all": false, "attribute": "attr-4", + "mode": "attribute", "value": Array [], "values": Array [ Object { @@ -850,14 +850,14 @@ Object { }, ], "price": Object { - "all": true, "attribute": undefined, + "mode": "all", "value": "10.99", "values": Array [], }, "stock": Object { - "all": true, "attribute": undefined, + "mode": "all", "value": Array [], "values": Array [], }, @@ -892,15 +892,20 @@ Object { }, ], "price": Object { - "all": true, "attribute": undefined, + "mode": "all", "value": "45.99", "values": Array [], }, "stock": Object { - "all": true, "attribute": undefined, - "value": Array [], + "mode": "all", + "value": Array [ + 0, + 0, + 0, + 0, + ], "values": Array [], }, "variants": Array [ @@ -927,7 +932,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -952,7 +974,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -977,7 +1016,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1002,7 +1058,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1027,7 +1100,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1052,7 +1142,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1077,7 +1184,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1102,7 +1226,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, ], "warehouses": Array [ @@ -1140,8 +1281,8 @@ Object { }, ], "price": Object { - "all": false, "attribute": "attr-1", + "mode": "attribute", "value": "10.99", "values": Array [ Object { @@ -1155,9 +1296,14 @@ Object { ], }, "stock": Object { - "all": true, "attribute": undefined, - "value": Array [], + "mode": "all", + "value": Array [ + 0, + 0, + 0, + 0, + ], "values": Array [], }, "variants": Array [ @@ -1184,7 +1330,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1209,7 +1372,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1234,7 +1414,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1259,7 +1456,24 @@ Object { ], "priceOverride": "45.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1284,7 +1498,24 @@ Object { ], "priceOverride": "51.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1309,7 +1540,24 @@ Object { ], "priceOverride": "51.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1334,7 +1582,24 @@ Object { ], "priceOverride": "51.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1359,7 +1624,24 @@ Object { ], "priceOverride": "51.99", "sku": "", - "stocks": Array [], + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 0, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, ], "warehouses": Array [ @@ -1397,15 +1679,20 @@ Object { }, ], "price": Object { - "all": true, "attribute": undefined, + "mode": "all", "value": "10.99", "values": Array [], }, "stock": Object { - "all": true, "attribute": undefined, - "value": "45.99", + "mode": "all", + "value": Array [ + 0, + 45, + 0, + 0, + ], "values": Array [], }, "variants": Array [ @@ -1431,8 +1718,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1456,8 +1760,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1481,8 +1802,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1506,8 +1844,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1531,8 +1886,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1556,8 +1928,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1581,8 +1970,25 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, Object { "attributes": Array [ @@ -1606,10 +2012,33 @@ Object { }, ], "priceOverride": "10.99", - "quantity": 45, "sku": "", + "stocks": Array [ + Object { + "quantity": 0, + "warehouse": "wh-1", + }, + Object { + "quantity": 45, + "warehouse": "wh-2", + }, + Object { + "quantity": 0, + "warehouse": "wh-3", + }, + Object { + "quantity": 0, + "warehouse": "wh-4", + }, + ], }, ], + "warehouses": Array [ + "wh-1", + "wh-2", + "wh-3", + "wh-4", + ], } `; @@ -1639,15 +2068,20 @@ Object { }, ], "price": Object { - "all": true, "attribute": undefined, + "mode": "all", "value": "10.99", "values": Array [], }, "stock": Object { - "all": false, "attribute": "attr-1", - "value": Array [], + "mode": "attribute", + "value": Array [ + 0, + 0, + 0, + 0, + ], "values": Array [ Object { "slug": "val-1-1", @@ -1913,3 +2347,51 @@ Object { ], } `; + +exports[`Reducer is able to select warehouses in which stock will be created 1`] = ` +Object { + "attributes": Array [ + Object { + "id": "attr-1", + "values": Array [ + "val-1-1", + "val-1-7", + ], + }, + Object { + "id": "attr-2", + "values": Array [ + "val-2-2", + "val-2-4", + ], + }, + Object { + "id": "attr-4", + "values": Array [ + "val-4-1", + "val-4-5", + ], + }, + ], + "price": Object { + "attribute": undefined, + "mode": "all", + "value": "10.99", + "values": Array [], + }, + "stock": Object { + "attribute": undefined, + "mode": "all", + "value": Array [ + 0, + 0, + ], + "values": Array [], + }, + "variants": Array [], + "warehouses": Array [ + "wh-2", + "wh-4", + ], +} +`; diff --git a/src/products/components/ProductVariantCreatorPage/createVariants.test.ts b/src/products/components/ProductVariantCreatorPage/createVariants.test.ts index 6957c2030..9fbcd609d 100644 --- a/src/products/components/ProductVariantCreatorPage/createVariants.test.ts +++ b/src/products/components/ProductVariantCreatorPage/createVariants.test.ts @@ -24,12 +24,12 @@ describe("Creates variant matrix", () => { ...thirdStep, price: { ...thirdStep.price, - all: true, + mode: "all", value: price }, stock: { ...thirdStep.stock, - all: true, + mode: "all", value: stock } }; @@ -61,8 +61,8 @@ describe("Creates variant matrix", () => { ...thirdStep, price: { ...thirdStep.price, - all: false, attribute: attribute.id, + mode: "attribute", values: attribute.values.map((attributeValue, attributeValueIndex) => ({ slug: attributeValue, value: (price * (attributeValueIndex + 1)).toString() @@ -70,7 +70,7 @@ describe("Creates variant matrix", () => { }, stock: { ...thirdStep.stock, - all: true, + mode: "all", value: stock } }; @@ -116,13 +116,13 @@ describe("Creates variant matrix", () => { ...thirdStep, price: { ...thirdStep.price, - all: true, + mode: "all", value: price }, stock: { ...thirdStep.stock, - all: false, attribute: attribute.id, + mode: "attribute", values: attribute.values.map((attributeValue, attributeValueIndex) => ({ slug: attributeValue, value: stock.map( @@ -173,8 +173,8 @@ describe("Creates variant matrix", () => { ...thirdStep, price: { ...thirdStep.price, - all: false, attribute: attribute.id, + mode: "attribute", values: attribute.values.map((attributeValue, attributeValueIndex) => ({ slug: attributeValue, value: (price * (attributeValueIndex + 1)).toString() @@ -182,8 +182,8 @@ describe("Creates variant matrix", () => { }, stock: { ...thirdStep.stock, - all: false, attribute: attribute.id, + mode: "attribute", values: attribute.values.map((attributeValue, attributeValueIndex) => ({ slug: attributeValue, value: stock.map( diff --git a/src/products/components/ProductVariantCreatorPage/fixtures.ts b/src/products/components/ProductVariantCreatorPage/fixtures.ts index 2972bc969..41aacbd6b 100644 --- a/src/products/components/ProductVariantCreatorPage/fixtures.ts +++ b/src/products/components/ProductVariantCreatorPage/fixtures.ts @@ -90,12 +90,16 @@ export const thirdStep: ProductVariantCreateFormData = { values: [0, 4].map(index => attributes[3].values[index]) } ], + stock: { + ...secondStep.stock, + value: warehouses.map(() => 0) + }, warehouses: warehouses.map(warehouse => warehouse.id) }; const price: AllOrAttribute = { - all: false, attribute: thirdStep.attributes[1].id, + mode: "attribute", value: "", values: [ { @@ -109,8 +113,8 @@ const price: AllOrAttribute = { ] }; const stock: AllOrAttribute = { - all: false, attribute: thirdStep.attributes[2].id, + mode: "attribute", value: [], values: [ { diff --git a/src/products/components/ProductVariantCreatorPage/reducer.test.ts b/src/products/components/ProductVariantCreatorPage/reducer.test.ts index 1d9059117..7cab43af8 100644 --- a/src/products/components/ProductVariantCreatorPage/reducer.test.ts +++ b/src/products/components/ProductVariantCreatorPage/reducer.test.ts @@ -77,7 +77,7 @@ describe("Reducer is able to", () => { const state = execActions(thirdStep, reducer, [ { applyPriceOrStockToAll: { - all: true + mode: "all" }, type: ProductVariantCreateReducerActionType.applyPriceToAll }, @@ -92,18 +92,38 @@ describe("Reducer is able to", () => { } ]); - expect(state.price.all).toBeTruthy(); + expect(state.price.mode).toBe("all"); expect(state.price.value).toBe(price); expect(state).toMatchSnapshot(); }); + it("select warehouses in which stock will be created", () => { + const state = execActions(thirdStep, reducer, [ + { + changeWarehouses: { + warehouseId: warehouses[0].id + }, + type: ProductVariantCreateReducerActionType.changeWarehouses + }, + { + changeWarehouses: { + warehouseId: warehouses[2].id + }, + type: ProductVariantCreateReducerActionType.changeWarehouses + } + ]); + + expect(state.warehouses).toHaveLength(2); + expect(state).toMatchSnapshot(); + }); + it("select stock for all variants", () => { const quantity = 45; const warehouseIndex = 1; const state = execActions(thirdStep, reducer, [ { applyPriceOrStockToAll: { - all: true + mode: "all" }, type: ProductVariantCreateReducerActionType.applyStockToAll }, @@ -119,7 +139,7 @@ describe("Reducer is able to", () => { } ]); - expect(state.stock.all).toBeTruthy(); + expect(state.stock.mode).toBe("all"); expect(state.stock.value[warehouseIndex]).toBe(quantity); expect(state).toMatchSnapshot(); }); @@ -130,7 +150,7 @@ describe("Reducer is able to", () => { const state = execActions(thirdStep, reducer, [ { applyPriceOrStockToAll: { - all: false + mode: "attribute" }, type: ProductVariantCreateReducerActionType.applyPriceToAll }, @@ -160,7 +180,7 @@ describe("Reducer is able to", () => { } ]); - expect(state.price.all).toBeFalsy(); + expect(state.price.mode).toBe("attribute"); expect(state.price.values).toHaveLength( state.attributes.find(attribute => state.price.attribute === attribute.id) .values.length @@ -174,7 +194,7 @@ describe("Reducer is able to", () => { const state = execActions(thirdStep, reducer, [ { applyPriceOrStockToAll: { - all: false + mode: "attribute" }, type: ProductVariantCreateReducerActionType.applyStockToAll }, @@ -206,7 +226,7 @@ describe("Reducer is able to", () => { } ]); - expect(state.stock.all).toBeFalsy(); + expect(state.stock.mode).toBe("attribute"); expect(state.stock.values).toHaveLength( state.attributes.find(attribute => state.stock.attribute === attribute.id) .values.length diff --git a/src/products/components/ProductVariantCreatorPage/reducer.ts b/src/products/components/ProductVariantCreatorPage/reducer.ts index 81e410723..23b387af7 100644 --- a/src/products/components/ProductVariantCreatorPage/reducer.ts +++ b/src/products/components/ProductVariantCreatorPage/reducer.ts @@ -335,9 +335,37 @@ function changeWarehouses( state: ProductVariantCreateFormData, warehouseId: string ): ProductVariantCreateFormData { + const warehouses = toggle(warehouseId, state.warehouses, (a, b) => a === b); + const added = warehouses.length > state.warehouses.length; + + if (added) { + return { + ...state, + stock: { + ...state.stock, + value: [...state.stock.value, 0], + values: state.stock.values.map(stockValue => ({ + ...stockValue, + value: [...stockValue.value, 0] + })) + }, + warehouses + }; + } + + const warehouseIndex = state.warehouses.indexOf(warehouseId); + return { ...state, - warehouses: toggle(warehouseId, state.warehouses, (a, b) => a === b) + stock: { + ...state.stock, + value: removeAtIndex(state.stock.value, warehouseIndex), + values: state.stock.values.map(stockValue => ({ + ...stockValue, + value: removeAtIndex(stockValue.value, warehouseIndex) + })) + }, + warehouses }; } From 60ed62ecd0cb1244c99e356782314a22eb8cbc99 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 14 Apr 2020 18:10:32 +0200 Subject: [PATCH 63/88] Fix types --- .../ProductVariantCreatorPage/ProductVariantCreatorStock.tsx | 1 - src/products/components/ProductVariantCreatorPage/utils.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx index 0f3f45389..b405d6524 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx @@ -10,7 +10,6 @@ import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; import FormSpacer from "@saleor/components/FormSpacer"; -import Grid from "@saleor/components/Grid"; import Hr from "@saleor/components/Hr"; import SingleSelectField from "@saleor/components/SingleSelectField"; import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; diff --git a/src/products/components/ProductVariantCreatorPage/utils.ts b/src/products/components/ProductVariantCreatorPage/utils.ts index 5ac5acdf0..eae1a5714 100644 --- a/src/products/components/ProductVariantCreatorPage/utils.ts +++ b/src/products/components/ProductVariantCreatorPage/utils.ts @@ -8,7 +8,7 @@ export function getPriceAttributeValues( data: ProductVariantCreateFormData, attributes: ProductDetails_product_productType_variantAttributes[] ): ProductDetails_product_productType_variantAttributes_values[] { - return data.price.all + return data.price.mode === "all" ? null : data.price.attribute ? attributes @@ -25,7 +25,7 @@ export function getStockAttributeValues( data: ProductVariantCreateFormData, attributes: ProductDetails_product_productType_variantAttributes[] ): ProductDetails_product_productType_variantAttributes_values[] { - return data.stock.all + return data.stock.mode === "all" ? null : data.stock.attribute ? attributes From 94dad3e4d7deaffa35e7e1b7aac6c2441c4ae407 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 15 Apr 2020 18:57:21 +0200 Subject: [PATCH 64/88] Improve single warehouse UX --- .../ProductVariantCreator.stories.tsx | 26 + .../ProductVariantCreatorPage.tsx | 45 +- .../ProductVariantCreatorStock.tsx | 7 + .../__snapshots__/Stories.test.ts.snap | 4728 +++++++++++------ 4 files changed, 3186 insertions(+), 1620 deletions(-) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx index 2c903f43d..08986ab6c 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx @@ -109,11 +109,37 @@ storiesOf( step={ProductVariantCreatorStep.prices} /> )) + .add("apply to all when one warehouse", () => ( + + )) .add("apply to attribute", () => ( + )) + .add("apply to attribute when one warehouse", () => ( + )); storiesOf("Views / Products / Create multiple variants / summary", module) diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx index 1e95564e1..ec1879404 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx @@ -1,4 +1,5 @@ import Button from "@material-ui/core/Button"; +import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/core/styles"; import React from "react"; import { FormattedMessage, useIntl, IntlShape } from "react-intl"; @@ -6,6 +7,7 @@ import { FormattedMessage, useIntl, IntlShape } from "react-intl"; import useWizard from "@saleor/hooks/useWizard"; import PageHeader from "@saleor/components/PageHeader"; import Container from "@saleor/components/Container"; +import Hr from "@saleor/components/Hr"; import { ProductVariantBulkCreateInput } from "../../../types/globalTypes"; import { createInitialForm, ProductVariantCreateFormData } from "./form"; import ProductVariantCreatorContent, { @@ -26,6 +28,12 @@ const useStyles = makeStyles( overflowX: "visible", overflowY: "hidden", width: 800 + }, + description: { + marginTop: theme.spacing() + }, + hr: { + margin: theme.spacing(3, 0) } }), { name: "ProductVariantCreatePage" } @@ -94,6 +102,29 @@ function getTitle(step: ProductVariantCreatorStep, intl: IntlShape): string { } } +function getDescription( + step: ProductVariantCreatorStep, + intl: IntlShape +): string { + switch (step) { + case ProductVariantCreatorStep.values: + return intl.formatMessage({ + defaultMessage: + "Selected values will be used to create variants for the configurable product." + }); + case ProductVariantCreatorStep.prices: + return intl.formatMessage({ + defaultMessage: + "Based on your selections we will create 8 products. Use this step to customize price and stocks for your new products." + }); + case ProductVariantCreatorStep.summary: + return intl.formatMessage({ + defaultMessage: + "Here is the summary of variants that will be created. You can change prices, stocks an SKU for each one created." + }); + } +} + const ProductVariantCreatePage: React.FC = props => { const { attributes, @@ -136,12 +167,21 @@ const ProductVariantCreatePage: React.FC = props type: ProductVariantCreateReducerActionType.reload }); - React.useEffect(reloadForm, [attributes.length]); + React.useEffect(reloadForm, [attributes.length, warehouses.length]); return ( - + + {getTitle(step, intl)} + + {getDescription(step, intl)} + + + } + > {step !== ProductVariantCreatorStep.values && ( )} +
= pr )} )} + {data.stock.mode === "attribute" && !!data.stock.attribute && ( + <> + +
+ + )} `; +exports[`Storyshots Views / Products / Create multiple variants / prices and SKUs apply to all 1`] = ` +
+
+
+
+ + Price + +
+
+
+
+
+
+ +
+
+ +
+ + USD + +
+
+
+ +
+
+
+
+
+ Choose attribute +
+
+
+
+ +
+
+ Box Size +
+ + + +
+
+
+
+
+
+
+
+
+ 100g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ 500g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ + Stock and Warehousing + +
+
+
+
+
+
+ Warehouses +
+
+ Based on your selections we will create 5 products. Use this step to customize price and stocks for your new products +
+
+ + + + +
+
+
+
+
+ Stock +
+
+ +
+
+
+ C our wares +
+
+ +
+ + +
+
+
+
+
+ Be stocked +
+
+ +
+ + +
+
+
+
+
+ Darkwares +
+
+ +
+ + +
+
+
+
+
+ +
+ +
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants / prices and SKUs apply to all when one warehouse 1`] = ` +
+
+
+
+ + Price + +
+
+
+
+
+
+ +
+
+ +
+ + USD + +
+
+
+ +
+
+
+
+
+ Choose attribute +
+
+
+
+ +
+
+ Box Size +
+ + + +
+
+
+
+
+
+
+
+
+ 100g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ 500g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ + Stock and Warehousing + +
+
+
+
+
+
+ Stock +
+
+ +
+
+
+ C our wares +
+
+ +
+ + +
+
+
+
+
+ +
+ +
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants / prices and SKUs apply to attribute 1`] = ` +
+
+
+
+ + Price + +
+
+
+
+
+
+ +
+
+ +
+ + USD + +
+
+
+ +
+
+
+
+
+ Choose attribute +
+
+
+
+ +
+
+ Box Size +
+ + + +
+
+
+
+
+
+
+
+
+ 100g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ 500g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ + Stock and Warehousing + +
+
+
+
+
+
+ Warehouses +
+
+ Based on your selections we will create 5 products. Use this step to customize price and stocks for your new products +
+
+ + + + +
+
+
+
+
+ Stock +
+
+ +
+ +
+
+ +
+
+ Box Size +
+ + + +
+
+
+
+
+
+
+
+ C our wares +
+
+ Be stocked +
+
+ Darkwares +
+
+ 100g +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ 500g +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ +
+
+
+
+
+`; + +exports[`Storyshots Views / Products / Create multiple variants / prices and SKUs apply to attribute when one warehouse 1`] = ` +
+
+
+
+ + Price + +
+
+
+
+
+
+ +
+
+ +
+ + USD + +
+
+
+ +
+
+
+
+
+ Choose attribute +
+
+
+
+ +
+
+ Box Size +
+ + + +
+
+
+
+
+
+
+
+
+ 100g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ 500g +
+
+
+
+ +
+ + USD + +
+
+
+
+
+
+
+
+
+ + Stock and Warehousing + +
+
+
+
+
+
+ Stock +
+
+ +
+ +
+
+ +
+
+ Box Size +
+ + + +
+
+
+
+
+
+
+
+ C our wares +
+
+ 100g +
+
+ +
+ + +
+
+
+ 500g +
+
+ +
+ + +
+
+
+
+
+
+
+ +
+
+
+
+
+`; + exports[`Storyshots Views / Products / Create multiple variants / summary default 1`] = `
Arabica - - Round -
Arabica - - Polo -
Arabica - - Round -
Arabica - - Polo -
Arabica - - Round -
Arabica - - Polo -
Arabica - - Round -
Arabica - - Polo -
-
-
- - Collar - -
-
-
-
-
- - - -
-
-
`; @@ -99687,6 +102649,11 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`] class="MuiTypography-root-id PageHeader-title-id MuiTypography-h5-id" > Choose Values +
+ Selected values will be used to create variants for the configurable product. +
+
@@ -99893,148 +102863,6 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
-
-
- - Brand - -
-
-
-
-
- -
-
-
-
-
- - Candy Box Size - -
-
-
-
-
- - - -
-
-
@@ -100106,98 +102934,6 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
-
-
- - Collar - -
-
-
-
-
- - - -
-
-
@@ -100269,1250 +103005,6 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
-
-
- - Cover - -
-
-
-
-
- - - - - - -
-
-
-
-
- - Flavor - -
-
-
-
-
- - -
-
-
-
-
- - Language - -
-
-
-
-
- - -
-
-
-
-
- - Publisher - -
-
-
-
-
- - -
-
-
-
-
- - Size - -
-
-
-
-
- - - - - - -
-
-
-
-
-`; - -exports[`Storyshots Views / Products / Create multiple variants prices and SKU 1`] = ` -
-
-
-
- - Price - -
-
-
-
-
-
- -
-
- -
- - USD - -
-
-
- -
-
-
-
-
- Choose attribute -
-
-
-
- -
-
- Box Size -
- - - -
-
-
-
-
-
-
-
-
- 100g -
-
-
-
- -
- - USD - -
-
-
-
-
-
-
-
-
- 500g -
-
-
-
- -
- - USD - -
-
-
-
-
-
-
-
-
- - Stock - -
-
-
-
-
-
- -
-
- -
- - -
-
-
- -
-
-
-
-
- Choose attribute -
-
-
-
- -
-
- Box Size -
- - - -
-
-
-
-
-
-
-
-
- 100g -
-
-
-
- -
- - -
-
-
-
-
-
-
-
-
- 500g -
-
-
-
- -
- - -
-
-
-
-
-
`; From 16fc30c66203c2f4c977108d25c7833129f44f7a Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 15 Apr 2020 18:59:52 +0200 Subject: [PATCH 65/88] Fix type --- src/components/PageHeader/PageHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PageHeader/PageHeader.tsx b/src/components/PageHeader/PageHeader.tsx index 580386798..f07b2089c 100644 --- a/src/components/PageHeader/PageHeader.tsx +++ b/src/components/PageHeader/PageHeader.tsx @@ -28,7 +28,7 @@ interface PageHeaderProps { children?: React.ReactNode; className?: string; inline?: boolean; - title?: string; + title?: React.ReactNode; } const PageHeader: React.FC = props => { From bcc4f96f827f2b102fe92d1c0dc7d81f64f85df7 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 16 Apr 2020 16:31:44 +0200 Subject: [PATCH 66/88] Enable assigning multiple warehouses to zone --- .../types/CreateMultipleVariantsData.ts | 1 + src/products/types/Product.ts | 2 +- src/products/types/ProductCreate.ts | 2 +- src/products/types/ProductDetails.ts | 2 +- src/products/types/ProductImageCreate.ts | 2 +- src/products/types/ProductImageUpdate.ts | 2 +- src/products/types/ProductUpdate.ts | 2 +- .../types/ProductVariantAttributesFragment.ts | 1 + src/products/types/SimpleProductUpdate.ts | 2 +- .../ShippingZoneDetailsPage.tsx | 27 ++- .../ShippingZoneWarehouses.tsx | 22 +-- src/shipping/mutations.ts | 25 +++ .../types/UnassignShippingZoneToWarehouse.ts | 4 +- .../views/ShippingZoneDetails/index.tsx | 63 +++++-- .../__snapshots__/Stories.test.ts.snap | 173 ++++++++++++++++-- 15 files changed, 276 insertions(+), 54 deletions(-) diff --git a/src/products/types/CreateMultipleVariantsData.ts b/src/products/types/CreateMultipleVariantsData.ts index 8b52f63e7..086d657b7 100644 --- a/src/products/types/CreateMultipleVariantsData.ts +++ b/src/products/types/CreateMultipleVariantsData.ts @@ -54,6 +54,7 @@ export interface CreateMultipleVariantsData_product_productType_variantAttribute export interface CreateMultipleVariantsData_product_productType { __typename: "ProductType"; + id: string; variantAttributes: (CreateMultipleVariantsData_product_productType_variantAttributes | null)[] | null; } diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index bf6d5b287..a0420a20a 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -54,8 +54,8 @@ export interface Product_productType_variantAttributes { export interface Product_productType { __typename: "ProductType"; - variantAttributes: (Product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (Product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index 07e21aa5a..f0b898c23 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -60,8 +60,8 @@ export interface ProductCreate_productCreate_product_productType_variantAttribut export interface ProductCreate_productCreate_product_productType { __typename: "ProductType"; - variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index 19b2b3e40..ed22c7264 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -54,8 +54,8 @@ export interface ProductDetails_product_productType_variantAttributes { export interface ProductDetails_product_productType { __typename: "ProductType"; - variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index 6c6d583a9..3c1ad318d 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -60,8 +60,8 @@ export interface ProductImageCreate_productImageCreate_product_productType_varia export interface ProductImageCreate_productImageCreate_product_productType { __typename: "ProductType"; - variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 5bb8acfea..becd44e2c 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -60,8 +60,8 @@ export interface ProductImageUpdate_productImageUpdate_product_productType_varia export interface ProductImageUpdate_productImageUpdate_product_productType { __typename: "ProductType"; - variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index f0b15d703..f9c8c7a7e 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -60,8 +60,8 @@ export interface ProductUpdate_productUpdate_product_productType_variantAttribut export interface ProductUpdate_productUpdate_product_productType { __typename: "ProductType"; - variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/products/types/ProductVariantAttributesFragment.ts b/src/products/types/ProductVariantAttributesFragment.ts index 462cbd1e6..02d1e7847 100644 --- a/src/products/types/ProductVariantAttributesFragment.ts +++ b/src/products/types/ProductVariantAttributesFragment.ts @@ -54,6 +54,7 @@ export interface ProductVariantAttributesFragment_productType_variantAttributes export interface ProductVariantAttributesFragment_productType { __typename: "ProductType"; + id: string; variantAttributes: (ProductVariantAttributesFragment_productType_variantAttributes | null)[] | null; } diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index adfa2075b..a6515ab73 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -60,8 +60,8 @@ export interface SimpleProductUpdate_productUpdate_product_productType_variantAt export interface SimpleProductUpdate_productUpdate_product_productType { __typename: "ProductType"; - variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; id: string; + variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; name: string; hasVariants: boolean; } diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index c8047c838..84167ace5 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -11,9 +11,10 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; -import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; +import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; +import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import { getStringOrPlaceholder } from "../../../misc"; import { FetchMoreProps, SearchProps } from "../../../types"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; @@ -27,7 +28,7 @@ import ShippingZoneWarehouses from "../ShippingZoneWarehouses"; export interface FormData { name: string; - warehouse: string; + warehouses: string[]; } export interface ShippingZoneDetailsPageProps @@ -86,20 +87,26 @@ const ShippingZoneDetailsPage: React.FC = ({ const initialForm: FormData = { name: shippingZone?.name || "", - warehouse: shippingZone?.warehouses[0]?.id || null + warehouses: shippingZone?.warehouses?.map(warehouse => warehouse.id) || [] }; - const [warehouseDisplayValue, setWarehouseDisplayValue] = useStateFromProps( - shippingZone?.warehouses[0]?.name || "" + const [warehouseDisplayValues, setWarehouseDisplayValues] = useStateFromProps< + MultiAutocompleteChoiceType[] + >( + shippingZone?.warehouses?.map(warehouse => ({ + label: warehouse.name, + value: warehouse.id + })) || [] ); const warehouseChoices = warehouses.map(warehouseToChoice); return (
- {({ change, data, hasChanged, submit }) => { - const handleWarehouseChange = createSingleAutocompleteSelectHandler( - change, - setWarehouseDisplayValue, + {({ change, data, hasChanged, submit, toggleValue }) => { + const handleWarehouseChange = createMultiAutocompleteSelectHandler( + toggleValue, + setWarehouseDisplayValues, + warehouseDisplayValues, warehouseChoices ); @@ -166,7 +173,7 @@ const ShippingZoneDetailsPage: React.FC = ({
void; } @@ -24,7 +24,7 @@ interface ShippingZonewWarehousesProps extends FetchMoreProps, SearchProps { export const ShippingZoneWarehouses: React.FC = props => { const { data, - displayValue, + displayValues, hasMore, loading, warehouses, @@ -44,7 +44,7 @@ export const ShippingZoneWarehouses: React.FC = pr })} /> - = pr onClick: onWarehouseAdd }} choices={warehouses} - displayValue={displayValue} + displayValues={displayValues} fetchChoices={onSearchChange} hasMore={hasMore} helperText={intl.formatMessage({ @@ -66,14 +66,14 @@ export const ShippingZoneWarehouses: React.FC = pr id: "shippingZoneWarehouses.autocomplete.label" })} loading={loading} - name="warehouse" + name="warehouses" onChange={onChange} onFetchMore={onFetchMore} placeholder={intl.formatMessage({ defaultMessage: "Select Warehouse", description: "input placeholder" })} - value={data.warehouse} + value={data.warehouses} /> diff --git a/src/shipping/mutations.ts b/src/shipping/mutations.ts index b5430e640..6a028ab5b 100644 --- a/src/shipping/mutations.ts +++ b/src/shipping/mutations.ts @@ -44,6 +44,10 @@ import { AssignShippingZoneToWarehouse, AssignShippingZoneToWarehouseVariables } from "./types/AssignShippingZoneToWarehouse"; +import { + UnassignShippingZoneToWarehouse, + UnassignShippingZoneToWarehouseVariables +} from "./types/UnassignShippingZoneToWarehouse"; export const shippingErrorFragment = gql` fragment ShippingErrorFragment on ShippingError { @@ -240,3 +244,24 @@ export const useAssignShippingZoneToWarehouse = makeMutation< AssignShippingZoneToWarehouse, AssignShippingZoneToWarehouseVariables >(assignShippingZoneToWarehouse); + +const unassignShippingZoneToWarehouse = gql` + ${warehouseErrorFragment} + mutation UnassignShippingZoneToWarehouse( + $warehouseId: ID! + $shippingZoneId: ID! + ) { + unassignWarehouseShippingZone( + id: $warehouseId + shippingZoneIds: [$shippingZoneId] + ) { + errors: warehouseErrors { + ...WarehouseErrorFragment + } + } + } +`; +export const useUnassignShippingZoneToWarehouse = makeMutation< + UnassignShippingZoneToWarehouse, + UnassignShippingZoneToWarehouseVariables +>(unassignShippingZoneToWarehouse); diff --git a/src/shipping/types/UnassignShippingZoneToWarehouse.ts b/src/shipping/types/UnassignShippingZoneToWarehouse.ts index 3004a8356..137a51c25 100644 --- a/src/shipping/types/UnassignShippingZoneToWarehouse.ts +++ b/src/shipping/types/UnassignShippingZoneToWarehouse.ts @@ -8,7 +8,7 @@ import { WarehouseErrorCode } from "./../../types/globalTypes"; // GraphQL mutation operation: UnassignShippingZoneToWarehouse // ==================================================== -export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors { +export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_errors { __typename: "WarehouseError"; code: WarehouseErrorCode; field: string | null; @@ -16,7 +16,7 @@ export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_w export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone { __typename: "WarehouseShippingZoneUnassign"; - warehouseErrors: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_warehouseErrors[]; + errors: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_errors[]; } export interface UnassignShippingZoneToWarehouse { diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 0dd6a6777..9b724292c 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -1,3 +1,4 @@ +import { diff } from "fast-array-diff"; import DialogContentText from "@material-ui/core/DialogContentText"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; @@ -14,7 +15,8 @@ import { useShippingRateDelete, useShippingZoneDelete, useShippingZoneUpdate, - useAssignShippingZoneToWarehouse + useAssignShippingZoneToWarehouse, + useUnassignShippingZoneToWarehouse } from "@saleor/shipping/mutations"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import ShippingZoneRateDialog from "@saleor/shipping/components/ShippingZoneRateDialog"; @@ -64,6 +66,7 @@ const ShippingZoneDetails: React.FC = ({ ); const [assignToWarehouse] = useAssignShippingZoneToWarehouse({}); + const [unassignToWarehouse] = useUnassignShippingZoneToWarehouse({}); const { data, loading } = useShippingZone({ displayLoader: true, @@ -144,27 +147,38 @@ const ShippingZoneDetails: React.FC = ({ } }); - const handleSubmit = async (data: FormData) => { + const handleSubmit = async (submitData: FormData) => { try { const updateResult = await updateShippingZone({ variables: { id, input: { - name: data.name + name: submitData.name } } }); const updateErrors = updateResult.data.shippingZoneUpdate.errors; if (updateErrors.length === 0) { - const assignResult = await assignToWarehouse({ - variables: { - shippingZoneId: id, - warehouseId: data.warehouse - } - }); - const assignErrors = - assignResult.data.assignWarehouseShippingZone.errors; + const warehouseDiff = diff( + data.shippingZone.warehouses.map(warehouse => warehouse.id), + submitData.warehouses + ); + const assignResults = await Promise.all( + warehouseDiff.added.map(warehouseId => + assignToWarehouse({ + variables: { + shippingZoneId: id, + warehouseId + } + }) + ) + ); + const assignErrors = assignResults + .map( + assignResult => assignResult.data.assignWarehouseShippingZone.errors + ) + .reduce((acc, errors) => [...acc, ...errors], []); if (assignErrors.length === 0) { notify({ @@ -175,6 +189,33 @@ const ShippingZoneDetails: React.FC = ({ `Assigning to warehouse failed: ${assignErrors[0].code}` ); } + + const unassignResults = await Promise.all( + warehouseDiff.removed.map(warehouseId => + unassignToWarehouse({ + variables: { + shippingZoneId: id, + warehouseId + } + }) + ) + ); + const unassignErrors = unassignResults + .map( + unassignResult => + unassignResult.data.unassignWarehouseShippingZone.errors + ) + .reduce((acc, errors) => [...acc, ...errors], []); + + if (unassignErrors.length === 0) { + notify({ + text: intl.formatMessage(commonMessages.savedChanges) + }); + } else { + throw new Error( + `Assigning to warehouse failed: ${unassignErrors[0].code}` + ); + } } else { throw new Error(`Updating failed: ${updateErrors[0].code}`); } diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 777989892..414ab8bd1 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -127398,7 +127398,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors > ​ @@ -128207,7 +128207,7 @@ exports[`Storyshots Views / Products / Product variant details when loaded data > ​ @@ -137544,14 +137544,14 @@ exports[`Storyshots Views / Shipping / Shipping zone details default 1`] = ` class="MuiCardContent-root-id" >
@@ -137567,7 +137567,7 @@ exports[`Storyshots Views / Shipping / Shipping zone details default 1`] = ` class="MuiInputBase-input-id MuiOutlinedInput-input-id MuiInputBase-inputAdornedEnd-id MuiOutlinedInput-inputAdornedEnd-id" placeholder="Select Warehouse" type="text" - value="C our wares" + value="" />

Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes.

+
+
+
+
+ C our wares +
+ +
+
+
+
+
+ Be stocked +
+ +
+
+
@@ -138267,14 +138339,14 @@ exports[`Storyshots Views / Shipping / Shipping zone details form errors 1`] = ` class="MuiCardContent-root-id" >
@@ -138290,7 +138362,7 @@ exports[`Storyshots Views / Shipping / Shipping zone details form errors 1`] = ` class="MuiInputBase-input-id MuiOutlinedInput-input-id MuiInputBase-inputAdornedEnd-id MuiOutlinedInput-inputAdornedEnd-id" placeholder="Select Warehouse" type="text" - value="C our wares" + value="" />

Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes.

+
+
+
+
+ C our wares +
+ +
+
+
+
+
+ Be stocked +
+ +
+
+
@@ -138884,7 +139028,7 @@ exports[`Storyshots Views / Shipping / Shipping zone details loading 1`] = ` class="MuiCardContent-root-id" >
+
From 1b3e304c795d9c18bb1186e8a198f45c97ebb3c5 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 22 Apr 2020 16:41:07 +0200 Subject: [PATCH 67/88] Enable submitting in variant creator --- schema.graphql | 2594 +++++-------------- src/products/mutations.ts | 4 - src/products/types/ProductCreate.ts | 1 - src/products/types/VariantUpdate.ts | 1 - src/products/views/ProductVariantCreate.tsx | 1 - src/types/globalTypes.ts | 5 +- 6 files changed, 594 insertions(+), 2012 deletions(-) diff --git a/schema.graphql b/schema.graphql index 7ef07e0b0..98993d3bb 100644 --- a/schema.graphql +++ b/schema.graphql @@ -4,40 +4,28 @@ schema { } type AccountAddressCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! address: Address } type AccountAddressDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! address: Address } type AccountAddressUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! address: Address } type AccountDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -64,6 +52,7 @@ enum AccountErrorCode { LEFT_NOT_MANAGEABLE_PERMISSION INVALID_CREDENTIALS NOT_FOUND + OUT_OF_SCOPE_SERVICE_ACCOUNT OUT_OF_SCOPE_USER OUT_OF_SCOPE_GROUP OUT_OF_SCOPE_PERMISSION @@ -83,10 +72,7 @@ input AccountInput { } type AccountRegister { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") requiresConfirmation: Boolean accountErrors: [AccountError!]! user: User @@ -99,36 +85,24 @@ input AccountRegisterInput { } type AccountRequestDeletion { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! } type AccountSetDefaultAddress { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } type AccountUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } type AccountUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -151,20 +125,14 @@ type Address implements Node { } type AddressCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! address: Address } type AddressDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! address: Address @@ -185,10 +153,7 @@ input AddressInput { } type AddressSetDefault { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } @@ -199,10 +164,7 @@ enum AddressTypeEnum { } type AddressUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! address: Address @@ -228,39 +190,126 @@ type AddressValidationData { postalCodePrefix: String } +type App implements Node & ObjectWithMetadata { + id: ID! + name: String + created: DateTime + isActive: Boolean + permissions: [Permission] + tokens: [AppToken] + privateMetadata: [MetadataItem]! + metadata: [MetadataItem]! + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") + webhooks: [Webhook] +} + +type AppCountableConnection { + pageInfo: PageInfo! + edges: [AppCountableEdge!]! + totalCount: Int +} + +type AppCountableEdge { + node: App! + cursor: String! +} + +type AppCreate { + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") + authToken: String + appErrors: [AppError!]! + app: App +} + +type AppDelete { + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") + appErrors: [AppError!]! + app: App +} + +type AppError { + field: String + message: String + code: AppErrorCode! + permissions: [PermissionEnum!] +} + +enum AppErrorCode { + GRAPHQL_ERROR + INVALID + NOT_FOUND + REQUIRED + UNIQUE + OUT_OF_SCOPE_APP + OUT_OF_SCOPE_PERMISSION +} + +input AppFilterInput { + search: String + isActive: Boolean +} + +input AppInput { + name: String + isActive: Boolean + permissions: [PermissionEnum] +} + +enum AppSortField { + NAME + CREATION_DATE +} + +input AppSortingInput { + direction: OrderDirection! + field: AppSortField! +} + +type AppToken implements Node { + name: String + authToken: String + id: ID! +} + +type AppTokenCreate { + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") + authToken: String + appErrors: [AppError!]! + appToken: AppToken +} + +type AppTokenDelete { + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") + appErrors: [AppError!]! + appToken: AppToken +} + +input AppTokenInput { + name: String + app: ID! +} + +type AppUpdate { + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") + appErrors: [AppError!]! + app: App +} + type AssignNavigation { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menu: Menu menuErrors: [MenuError!]! } type Attribute implements Node & ObjectWithMetadata { id: ID! - productTypes( - before: String - after: String - first: Int - last: Int - ): ProductTypeCountableConnection! - productVariantTypes( - before: String - after: String - first: Int - last: Int - ): ProductTypeCountableConnection! + productTypes(before: String, after: String, first: Int, last: Int): ProductTypeCountableConnection! + productVariantTypes(before: String, after: String, first: Int, last: Int): ProductTypeCountableConnection! privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") inputType: AttributeInputTypeEnum name: String slug: String @@ -275,10 +324,7 @@ type Attribute implements Node & ObjectWithMetadata { } type AttributeAssign { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productType: ProductType productErrors: [ProductAttributeError!]! } @@ -289,28 +335,19 @@ input AttributeAssignInput { } type AttributeBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type AttributeClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! attribute: Attribute } type AttributeClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! attribute: Attribute } @@ -327,10 +364,7 @@ type AttributeCountableEdge { } type AttributeCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") attribute: Attribute productErrors: [ProductError!]! } @@ -350,10 +384,7 @@ input AttributeCreateInput { } type AttributeDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! attribute: Attribute } @@ -383,10 +414,7 @@ enum AttributeInputTypeEnum { } type AttributeReorderValues { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") attribute: Attribute productErrors: [ProductError!]! } @@ -416,10 +444,7 @@ type AttributeTranslatableContent implements Node { } type AttributeTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! attribute: Attribute } @@ -436,19 +461,13 @@ enum AttributeTypeEnum { } type AttributeUnassign { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productType: ProductType productErrors: [ProductError!]! } type AttributeUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") attribute: Attribute productErrors: [ProductError!]! } @@ -468,19 +487,13 @@ input AttributeUpdateInput { } type AttributeUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! attribute: Attribute } type AttributeUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! attribute: Attribute } @@ -495,19 +508,13 @@ type AttributeValue implements Node { } type AttributeValueBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type AttributeValueCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") attribute: Attribute productErrors: [ProductError!]! attributeValue: AttributeValue @@ -518,10 +525,7 @@ input AttributeValueCreateInput { } type AttributeValueDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") attribute: Attribute productErrors: [ProductError!]! attributeValue: AttributeValue @@ -540,10 +544,7 @@ type AttributeValueTranslatableContent implements Node { } type AttributeValueTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! attributeValue: AttributeValue } @@ -562,10 +563,7 @@ enum AttributeValueType { } type AttributeValueUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") attribute: Attribute productErrors: [ProductError!]! attributeValue: AttributeValue @@ -577,20 +575,14 @@ type AuthorizationKey { } type AuthorizationKeyAdd { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") authorizationKey: AuthorizationKey shop: Shop shopErrors: [ShopError!]! } type AuthorizationKeyDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") authorizationKey: AuthorizationKey shop: Shop shopErrors: [ShopError!]! @@ -611,6 +603,7 @@ type BulkProductError { message: String code: ProductErrorCode! index: Int + warehouses: [ID!] } type BulkStockError { @@ -638,61 +631,30 @@ type Category implements Node & ObjectWithMetadata { level: Int! privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) - ancestors( - before: String - after: String - first: Int - last: Int - ): CategoryCountableConnection - products( - before: String - after: String - first: Int - last: Int - ): ProductCountableConnection - url: String - @deprecated(reason: "This field will be removed after 2020-07-31.") - children( - before: String - after: String - first: Int - last: Int - ): CategoryCountableConnection + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") + ancestors(before: String, after: String, first: Int, last: Int): CategoryCountableConnection + products(before: String, after: String, first: Int, last: Int): ProductCountableConnection + url: String @deprecated(reason: "This field will be removed after 2020-07-31.") + children(before: String, after: String, first: Int, last: Int): CategoryCountableConnection backgroundImage(size: Int): Image translation(languageCode: LanguageCodeEnum!): CategoryTranslation } type CategoryBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type CategoryClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } type CategoryClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } @@ -709,19 +671,13 @@ type CategoryCountableEdge { } type CategoryCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } type CategoryDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } @@ -764,10 +720,7 @@ type CategoryTranslatableContent implements Node { } type CategoryTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! category: Category } @@ -783,28 +736,19 @@ type CategoryTranslation implements Node { } type CategoryUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } type CategoryUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } type CategoryUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! category: Category } @@ -827,14 +771,8 @@ type Checkout implements Node & ObjectWithMetadata { id: ID! privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") availableShippingMethods: [ShippingMethod]! availablePaymentGateways: [PaymentGateway]! email: String! @@ -846,46 +784,31 @@ type Checkout implements Node & ObjectWithMetadata { } type CheckoutAddPromoCode { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutBillingAddressUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkoutErrors: [CheckoutError!]! checkout: Checkout } type CheckoutClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkoutErrors: [CheckoutError!]! checkout: Checkout } type CheckoutComplete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order confirmationNeeded: Boolean! checkoutErrors: [CheckoutError!]! @@ -903,10 +826,7 @@ type CheckoutCountableEdge { } type CheckoutCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") created: Boolean checkoutErrors: [CheckoutError!]! checkout: Checkout @@ -920,28 +840,19 @@ input CheckoutCreateInput { } type CheckoutCustomerAttach { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutCustomerDetach { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutEmailUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } @@ -993,10 +904,7 @@ type CheckoutLineCountableEdge { } type CheckoutLineDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } @@ -1007,74 +915,50 @@ input CheckoutLineInput { } type CheckoutLinesAdd { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutLinesUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutPaymentCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout payment: Payment paymentErrors: [PaymentError!]! } type CheckoutRemovePromoCode { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutShippingAddressUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutShippingMethodUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkout: Checkout checkoutErrors: [CheckoutError!]! } type CheckoutUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkoutErrors: [CheckoutError!]! checkout: Checkout } type CheckoutUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") checkoutErrors: [CheckoutError!]! checkout: Checkout } @@ -1096,65 +980,39 @@ type Collection implements Node & ObjectWithMetadata { slug: String! privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) - products( - before: String - after: String - first: Int - last: Int - ): ProductCountableConnection + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") + products(before: String, after: String, first: Int, last: Int): ProductCountableConnection backgroundImage(size: Int): Image translation(languageCode: LanguageCodeEnum!): CollectionTranslation } type CollectionAddProducts { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") collection: Collection productErrors: [ProductError!]! } type CollectionBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type CollectionBulkPublish { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type CollectionClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } type CollectionClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } @@ -1171,10 +1029,7 @@ type CollectionCountableEdge { } type CollectionCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } @@ -1193,10 +1048,7 @@ input CollectionCreateInput { } type CollectionDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } @@ -1225,19 +1077,13 @@ enum CollectionPublished { } type CollectionRemoveProducts { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") collection: Collection productErrors: [ProductError!]! } type CollectionReorderProducts { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") collection: Collection productErrors: [ProductError!]! } @@ -1265,10 +1111,7 @@ type CollectionTranslatableContent implements Node { } type CollectionTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! collection: Collection } @@ -1284,28 +1127,19 @@ type CollectionTranslation implements Node { } type CollectionUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } type CollectionUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } type CollectionUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! collection: Collection } @@ -1331,19 +1165,13 @@ enum ConfigurationTypeFieldEnum { } type ConfirmAccount { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } type ConfirmEmailChange { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } @@ -1609,10 +1437,7 @@ type CountryDisplay { type CreateToken { token: String - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -1626,28 +1451,19 @@ type CreditCard { } type CustomerBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! accountErrors: [AccountError!]! } type CustomerCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } type CustomerDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -1698,10 +1514,7 @@ input CustomerInput { } type CustomerUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -1723,19 +1536,13 @@ input DateTimeRangeInput { scalar Decimal type DeleteMetadata { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") metadataErrors: [MetadataError!]! item: ObjectWithMetadata } type DeletePrivateMetadata { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") metadataErrors: [MetadataError!]! item: ObjectWithMetadata } @@ -1751,14 +1558,8 @@ type DigitalContent implements Node & ObjectWithMetadata { id: ID! privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") } type DigitalContentCountableConnection { @@ -1773,20 +1574,14 @@ type DigitalContentCountableEdge { } type DigitalContentCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") variant: ProductVariant content: DigitalContent productErrors: [ProductError!]! } type DigitalContentDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") variant: ProductVariant productErrors: [ProductError!]! } @@ -1799,10 +1594,7 @@ input DigitalContentInput { } type DigitalContentUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") variant: ProductVariant content: DigitalContent productErrors: [ProductError!]! @@ -1826,10 +1618,7 @@ type DigitalContentUrl implements Node { } type DigitalContentUrlCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! digitalContentUrl: DigitalContentUrl } @@ -1871,28 +1660,19 @@ type Domain { } type DraftOrderBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! orderErrors: [OrderError!]! } type DraftOrderComplete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } type DraftOrderCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") orderErrors: [OrderError!]! order: Order } @@ -1910,10 +1690,7 @@ input DraftOrderCreateInput { } type DraftOrderDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") orderErrors: [OrderError!]! order: Order } @@ -1930,49 +1707,34 @@ input DraftOrderInput { } type DraftOrderLineDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderLine: OrderLine orderErrors: [OrderError!]! } type DraftOrderLineUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! orderLine: OrderLine } type DraftOrderLinesBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! orderErrors: [OrderError!]! } type DraftOrderLinesCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderLines: [OrderLine!] orderErrors: [OrderError!]! } type DraftOrderUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") orderErrors: [OrderError!]! order: Order } @@ -1990,101 +1752,57 @@ type Fulfillment implements Node & ObjectWithMetadata { created: DateTime! privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") lines: [FulfillmentLine] statusDisplay: String + warehouse: Warehouse } type FulfillmentCancel { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") fulfillment: Fulfillment order: Order orderErrors: [OrderError!]! } input FulfillmentCancelInput { - restock: Boolean + warehouseId: ID! } type FulfillmentClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") fulfillment: Fulfillment } type FulfillmentClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") fulfillment: Fulfillment } -type FulfillmentCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) - fulfillment: Fulfillment - order: Order - orderErrors: [OrderError!]! -} - -input FulfillmentCreateInput { - trackingNumber: String - notifyCustomer: Boolean - lines: [FulfillmentLineInput]! -} - type FulfillmentLine implements Node { id: ID! quantity: Int! orderLine: OrderLine } -input FulfillmentLineInput { - orderLineId: ID - quantity: Int -} - enum FulfillmentStatus { FULFILLED CANCELED } type FulfillmentUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") fulfillment: Fulfillment } type FulfillmentUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") fulfillment: Fulfillment } type FulfillmentUpdateTracking { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") fulfillment: Fulfillment order: Order orderErrors: [OrderError!]! @@ -2121,10 +1839,7 @@ type GiftCard implements Node { } type GiftCardActivate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") giftCard: GiftCard giftCardErrors: [GiftCardError!]! } @@ -2141,10 +1856,7 @@ type GiftCardCountableEdge { } type GiftCardCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") giftCardErrors: [GiftCardError!]! giftCard: GiftCard } @@ -2158,10 +1870,7 @@ input GiftCardCreateInput { } type GiftCardDeactivate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") giftCard: GiftCard giftCardErrors: [GiftCardError!]! } @@ -2182,10 +1891,7 @@ enum GiftCardErrorCode { } type GiftCardUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") giftCardErrors: [GiftCardError!]! giftCard: GiftCard } @@ -2217,10 +1923,7 @@ type GroupCountableEdge { } type HomepageCollectionUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shop: Shop shopErrors: [ShopError!]! } @@ -2300,10 +2003,7 @@ type Menu implements Node { } type MenuBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! menuErrors: [MenuError!]! } @@ -2320,10 +2020,7 @@ type MenuCountableEdge { } type MenuCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menuErrors: [MenuError!]! menu: Menu } @@ -2334,10 +2031,7 @@ input MenuCreateInput { } type MenuDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menuErrors: [MenuError!]! menu: Menu } @@ -2383,10 +2077,7 @@ type MenuItem implements Node { } type MenuItemBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! menuErrors: [MenuError!]! } @@ -2403,10 +2094,7 @@ type MenuItemCountableEdge { } type MenuItemCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menuErrors: [MenuError!]! menuItem: MenuItem } @@ -2422,10 +2110,7 @@ input MenuItemCreateInput { } type MenuItemDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menuErrors: [MenuError!]! menuItem: MenuItem } @@ -2443,10 +2128,7 @@ input MenuItemInput { } type MenuItemMove { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menu: Menu menuErrors: [MenuError!]! } @@ -2470,10 +2152,7 @@ type MenuItemTranslatableContent implements Node { } type MenuItemTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! menuItem: MenuItem } @@ -2485,10 +2164,7 @@ type MenuItemTranslation implements Node { } type MenuItemUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menuErrors: [MenuError!]! menuItem: MenuItem } @@ -2508,10 +2184,7 @@ input MenuSortingInput { } type MenuUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") menuErrors: [MenuError!]! menu: Menu } @@ -2569,10 +2242,7 @@ type MetadataItem { type Money { currency: String! amount: Float! - localized: String! - @deprecated( - reason: "Price formatting according to the current locale should be handled by the frontend client. This field will be removed after 2020-07-31." - ) + localized: String! @deprecated(reason: "Price formatting according to the current locale should be handled by the frontend client. This field will be removed after 2020-07-31.") } type MoneyRange { @@ -2592,324 +2262,108 @@ type Mutation { createWarehouse(input: WarehouseCreateInput!): WarehouseCreate updateWarehouse(id: ID!, input: WarehouseUpdateInput!): WarehouseUpdate deleteWarehouse(id: ID!): WarehouseDelete - assignWarehouseShippingZone( - id: ID! - shippingZoneIds: [ID!]! - ): WarehouseShippingZoneAssign - unassignWarehouseShippingZone( - id: ID! - shippingZoneIds: [ID!]! - ): WarehouseShippingZoneUnassign - authorizationKeyAdd( - input: AuthorizationKeyInput! - keyType: AuthorizationKeyType! - ): AuthorizationKeyAdd + assignWarehouseShippingZone(id: ID!, shippingZoneIds: [ID!]!): WarehouseShippingZoneAssign + unassignWarehouseShippingZone(id: ID!, shippingZoneIds: [ID!]!): WarehouseShippingZoneUnassign + authorizationKeyAdd(input: AuthorizationKeyInput!, keyType: AuthorizationKeyType!): AuthorizationKeyAdd authorizationKeyDelete(keyType: AuthorizationKeyType!): AuthorizationKeyDelete - staffNotificationRecipientCreate( - input: StaffNotificationRecipientInput! - ): StaffNotificationRecipientCreate - staffNotificationRecipientUpdate( - id: ID! - input: StaffNotificationRecipientInput! - ): StaffNotificationRecipientUpdate + staffNotificationRecipientCreate(input: StaffNotificationRecipientInput!): StaffNotificationRecipientCreate + staffNotificationRecipientUpdate(id: ID!, input: StaffNotificationRecipientInput!): StaffNotificationRecipientUpdate staffNotificationRecipientDelete(id: ID!): StaffNotificationRecipientDelete homepageCollectionUpdate(collection: ID): HomepageCollectionUpdate shopDomainUpdate(input: SiteDomainInput): ShopDomainUpdate shopSettingsUpdate(input: ShopSettingsInput!): ShopSettingsUpdate shopFetchTaxRates: ShopFetchTaxRates - shopSettingsTranslate( - input: ShopSettingsTranslationInput! - languageCode: LanguageCodeEnum! - ): ShopSettingsTranslate + shopSettingsTranslate(input: ShopSettingsTranslationInput!, languageCode: LanguageCodeEnum!): ShopSettingsTranslate shopAddressUpdate(input: AddressInput): ShopAddressUpdate shippingPriceCreate(input: ShippingPriceInput!): ShippingPriceCreate shippingPriceDelete(id: ID!): ShippingPriceDelete shippingPriceBulkDelete(ids: [ID]!): ShippingPriceBulkDelete shippingPriceUpdate(id: ID!, input: ShippingPriceInput!): ShippingPriceUpdate - shippingPriceTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): ShippingPriceTranslate + shippingPriceTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): ShippingPriceTranslate shippingZoneCreate(input: ShippingZoneCreateInput!): ShippingZoneCreate shippingZoneDelete(id: ID!): ShippingZoneDelete shippingZoneBulkDelete(ids: [ID]!): ShippingZoneBulkDelete - shippingZoneUpdate( - id: ID! - input: ShippingZoneUpdateInput! - ): ShippingZoneUpdate + shippingZoneUpdate(id: ID!, input: ShippingZoneUpdateInput!): ShippingZoneUpdate attributeCreate(input: AttributeCreateInput!): AttributeCreate attributeDelete(id: ID!): AttributeDelete attributeBulkDelete(ids: [ID]!): AttributeBulkDelete - attributeAssign( - operations: [AttributeAssignInput]! - productTypeId: ID! - ): AttributeAssign + attributeAssign(operations: [AttributeAssignInput]!, productTypeId: ID!): AttributeAssign attributeUnassign(attributeIds: [ID]!, productTypeId: ID!): AttributeUnassign attributeUpdate(id: ID!, input: AttributeUpdateInput!): AttributeUpdate - attributeTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): AttributeTranslate - attributeUpdateMetadata(id: ID!, input: MetaInput!): AttributeUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - attributeClearMetadata(id: ID!, input: MetaPath!): AttributeClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - attributeUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): AttributeUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - attributeClearPrivateMetadata( - id: ID! - input: MetaPath! - ): AttributeClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - attributeValueCreate( - attribute: ID! - input: AttributeValueCreateInput! - ): AttributeValueCreate + attributeTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): AttributeTranslate + attributeUpdateMetadata(id: ID!, input: MetaInput!): AttributeUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + attributeClearMetadata(id: ID!, input: MetaPath!): AttributeClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + attributeUpdatePrivateMetadata(id: ID!, input: MetaInput!): AttributeUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + attributeClearPrivateMetadata(id: ID!, input: MetaPath!): AttributeClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + attributeValueCreate(attribute: ID!, input: AttributeValueCreateInput!): AttributeValueCreate attributeValueDelete(id: ID!): AttributeValueDelete attributeValueBulkDelete(ids: [ID]!): AttributeValueBulkDelete - attributeValueUpdate( - id: ID! - input: AttributeValueCreateInput! - ): AttributeValueUpdate - attributeValueTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): AttributeValueTranslate - attributeReorderValues( - attributeId: ID! - moves: [ReorderInput]! - ): AttributeReorderValues + attributeValueUpdate(id: ID!, input: AttributeValueCreateInput!): AttributeValueUpdate + attributeValueTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): AttributeValueTranslate + attributeReorderValues(attributeId: ID!, moves: [ReorderInput]!): AttributeReorderValues categoryCreate(input: CategoryInput!, parent: ID): CategoryCreate categoryDelete(id: ID!): CategoryDelete categoryBulkDelete(ids: [ID]!): CategoryBulkDelete categoryUpdate(id: ID!, input: CategoryInput!): CategoryUpdate - categoryTranslate( - id: ID! - input: TranslationInput! - languageCode: LanguageCodeEnum! - ): CategoryTranslate - categoryUpdateMetadata(id: ID!, input: MetaInput!): CategoryUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - categoryClearMetadata(id: ID!, input: MetaPath!): CategoryClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - categoryUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): CategoryUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - categoryClearPrivateMetadata( - id: ID! - input: MetaPath! - ): CategoryClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - collectionAddProducts( - collectionId: ID! - products: [ID]! - ): CollectionAddProducts + categoryTranslate(id: ID!, input: TranslationInput!, languageCode: LanguageCodeEnum!): CategoryTranslate + categoryUpdateMetadata(id: ID!, input: MetaInput!): CategoryUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + categoryClearMetadata(id: ID!, input: MetaPath!): CategoryClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + categoryUpdatePrivateMetadata(id: ID!, input: MetaInput!): CategoryUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + categoryClearPrivateMetadata(id: ID!, input: MetaPath!): CategoryClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + collectionAddProducts(collectionId: ID!, products: [ID]!): CollectionAddProducts collectionCreate(input: CollectionCreateInput!): CollectionCreate collectionDelete(id: ID!): CollectionDelete - collectionReorderProducts( - collectionId: ID! - moves: [MoveProductInput]! - ): CollectionReorderProducts + collectionReorderProducts(collectionId: ID!, moves: [MoveProductInput]!): CollectionReorderProducts collectionBulkDelete(ids: [ID]!): CollectionBulkDelete - collectionBulkPublish( - ids: [ID]! - isPublished: Boolean! - ): CollectionBulkPublish - collectionRemoveProducts( - collectionId: ID! - products: [ID]! - ): CollectionRemoveProducts + collectionBulkPublish(ids: [ID]!, isPublished: Boolean!): CollectionBulkPublish + collectionRemoveProducts(collectionId: ID!, products: [ID]!): CollectionRemoveProducts collectionUpdate(id: ID!, input: CollectionInput!): CollectionUpdate - collectionTranslate( - id: ID! - input: TranslationInput! - languageCode: LanguageCodeEnum! - ): CollectionTranslate - collectionUpdateMetadata(id: ID!, input: MetaInput!): CollectionUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - collectionClearMetadata(id: ID!, input: MetaPath!): CollectionClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - collectionUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): CollectionUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - collectionClearPrivateMetadata( - id: ID! - input: MetaPath! - ): CollectionClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) + collectionTranslate(id: ID!, input: TranslationInput!, languageCode: LanguageCodeEnum!): CollectionTranslate + collectionUpdateMetadata(id: ID!, input: MetaInput!): CollectionUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + collectionClearMetadata(id: ID!, input: MetaPath!): CollectionClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + collectionUpdatePrivateMetadata(id: ID!, input: MetaInput!): CollectionUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + collectionClearPrivateMetadata(id: ID!, input: MetaPath!): CollectionClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") productCreate(input: ProductCreateInput!): ProductCreate productDelete(id: ID!): ProductDelete productBulkDelete(ids: [ID]!): ProductBulkDelete productBulkPublish(ids: [ID]!, isPublished: Boolean!): ProductBulkPublish productUpdate(id: ID!, input: ProductInput!): ProductUpdate - productTranslate( - id: ID! - input: TranslationInput! - languageCode: LanguageCodeEnum! - ): ProductTranslate - productUpdateMetadata(id: ID!, input: MetaInput!): ProductUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productClearMetadata(id: ID!, input: MetaPath!): ProductClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): ProductUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productClearPrivateMetadata( - id: ID! - input: MetaPath! - ): ProductClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) + productTranslate(id: ID!, input: TranslationInput!, languageCode: LanguageCodeEnum!): ProductTranslate + productUpdateMetadata(id: ID!, input: MetaInput!): ProductUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + productClearMetadata(id: ID!, input: MetaPath!): ProductClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + productUpdatePrivateMetadata(id: ID!, input: MetaInput!): ProductUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + productClearPrivateMetadata(id: ID!, input: MetaPath!): ProductClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") productImageCreate(input: ProductImageCreateInput!): ProductImageCreate productImageDelete(id: ID!): ProductImageDelete productImageBulkDelete(ids: [ID]!): ProductImageBulkDelete productImageReorder(imagesIds: [ID]!, productId: ID!): ProductImageReorder - productImageUpdate( - id: ID! - input: ProductImageUpdateInput! - ): ProductImageUpdate + productImageUpdate(id: ID!, input: ProductImageUpdateInput!): ProductImageUpdate productTypeCreate(input: ProductTypeInput!): ProductTypeCreate productTypeDelete(id: ID!): ProductTypeDelete productTypeBulkDelete(ids: [ID]!): ProductTypeBulkDelete productTypeUpdate(id: ID!, input: ProductTypeInput!): ProductTypeUpdate - productTypeReorderAttributes( - moves: [ReorderInput]! - productTypeId: ID! - type: AttributeTypeEnum! - ): ProductTypeReorderAttributes - productTypeUpdateMetadata(id: ID!, input: MetaInput!): ProductTypeUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productTypeClearMetadata(id: ID!, input: MetaPath!): ProductTypeClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productTypeUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): ProductTypeUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productTypeClearPrivateMetadata( - id: ID! - input: MetaPath! - ): ProductTypeClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - digitalContentCreate( - input: DigitalContentUploadInput! - variantId: ID! - ): DigitalContentCreate + productTypeReorderAttributes(moves: [ReorderInput]!, productTypeId: ID!, type: AttributeTypeEnum!): ProductTypeReorderAttributes + productTypeUpdateMetadata(id: ID!, input: MetaInput!): ProductTypeUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + productTypeClearMetadata(id: ID!, input: MetaPath!): ProductTypeClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + productTypeUpdatePrivateMetadata(id: ID!, input: MetaInput!): ProductTypeUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + productTypeClearPrivateMetadata(id: ID!, input: MetaPath!): ProductTypeClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + digitalContentCreate(input: DigitalContentUploadInput!, variantId: ID!): DigitalContentCreate digitalContentDelete(variantId: ID!): DigitalContentDelete - digitalContentUpdate( - input: DigitalContentInput! - variantId: ID! - ): DigitalContentUpdate - digitalContentUrlCreate( - input: DigitalContentUrlCreateInput! - ): DigitalContentUrlCreate + digitalContentUpdate(input: DigitalContentInput!, variantId: ID!): DigitalContentUpdate + digitalContentUrlCreate(input: DigitalContentUrlCreateInput!): DigitalContentUrlCreate productVariantCreate(input: ProductVariantCreateInput!): ProductVariantCreate productVariantDelete(id: ID!): ProductVariantDelete - productVariantBulkCreate( - product: ID! - variants: [ProductVariantBulkCreateInput]! - ): ProductVariantBulkCreate + productVariantBulkCreate(product: ID!, variants: [ProductVariantBulkCreateInput]!): ProductVariantBulkCreate productVariantBulkDelete(ids: [ID]!): ProductVariantBulkDelete - productVariantStocksCreate( - stocks: [StockInput!]! - variantId: ID! - ): ProductVariantStocksCreate - productVariantStocksDelete( - variantId: ID! - warehouseIds: [ID!] - ): ProductVariantStocksDelete - productVariantStocksUpdate( - stocks: [StockInput!]! - variantId: ID! - ): ProductVariantStocksUpdate - productVariantUpdate( - id: ID! - input: ProductVariantInput! - ): ProductVariantUpdate - productVariantTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): ProductVariantTranslate - productVariantUpdateMetadata( - id: ID! - input: MetaInput! - ): ProductVariantUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productVariantClearMetadata( - id: ID! - input: MetaPath! - ): ProductVariantClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productVariantUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): ProductVariantUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - productVariantClearPrivateMetadata( - id: ID! - input: MetaPath! - ): ProductVariantClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) + productVariantStocksCreate(stocks: [StockInput!]!, variantId: ID!): ProductVariantStocksCreate + productVariantStocksDelete(variantId: ID!, warehouseIds: [ID!]): ProductVariantStocksDelete + productVariantStocksUpdate(stocks: [StockInput!]!, variantId: ID!): ProductVariantStocksUpdate + productVariantUpdate(id: ID!, input: ProductVariantInput!): ProductVariantUpdate + productVariantTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): ProductVariantTranslate + productVariantUpdateMetadata(id: ID!, input: MetaInput!): ProductVariantUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + productVariantClearMetadata(id: ID!, input: MetaPath!): ProductVariantClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + productVariantUpdatePrivateMetadata(id: ID!, input: MetaInput!): ProductVariantUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + productVariantClearPrivateMetadata(id: ID!, input: MetaPath!): ProductVariantClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") variantImageAssign(imageId: ID!, variantId: ID!): VariantImageAssign variantImageUnassign(imageId: ID!, variantId: ID!): VariantImageUnassign paymentCapture(amount: Decimal, paymentId: ID!): PaymentCapture @@ -2921,92 +2375,40 @@ type Mutation { pageBulkDelete(ids: [ID]!): PageBulkDelete pageBulkPublish(ids: [ID]!, isPublished: Boolean!): PageBulkPublish pageUpdate(id: ID!, input: PageInput!): PageUpdate - pageTranslate( - id: ID! - input: PageTranslationInput! - languageCode: LanguageCodeEnum! - ): PageTranslate + pageTranslate(id: ID!, input: PageTranslationInput!, languageCode: LanguageCodeEnum!): PageTranslate draftOrderComplete(id: ID!): DraftOrderComplete draftOrderCreate(input: DraftOrderCreateInput!): DraftOrderCreate draftOrderDelete(id: ID!): DraftOrderDelete draftOrderBulkDelete(ids: [ID]!): DraftOrderBulkDelete draftOrderLinesBulkDelete(ids: [ID]!): DraftOrderLinesBulkDelete - draftOrderLinesCreate( - id: ID! - input: [OrderLineCreateInput]! - ): DraftOrderLinesCreate + draftOrderLinesCreate(id: ID!, input: [OrderLineCreateInput]!): DraftOrderLinesCreate draftOrderLineDelete(id: ID!): DraftOrderLineDelete draftOrderLineUpdate(id: ID!, input: OrderLineInput!): DraftOrderLineUpdate draftOrderUpdate(id: ID!, input: DraftOrderInput!): DraftOrderUpdate orderAddNote(order: ID!, input: OrderAddNoteInput!): OrderAddNote - orderCancel(id: ID!, restock: Boolean!): OrderCancel + orderCancel(id: ID!): OrderCancel orderCapture(amount: Decimal!, id: ID!): OrderCapture - orderClearPrivateMeta(id: ID!, input: MetaPath!): OrderClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderClearMeta(input: MetaPath!, token: UUID!): OrderClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderFulfillmentCancel( - id: ID! - input: FulfillmentCancelInput! - ): FulfillmentCancel - orderFulfillmentCreate( - input: FulfillmentCreateInput! - order: ID - ): FulfillmentCreate - orderFulfillmentUpdateTracking( - id: ID! - input: FulfillmentUpdateTrackingInput! - ): FulfillmentUpdateTracking - orderFulfillmentClearMeta(id: ID!, input: MetaPath!): FulfillmentClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderFulfillmentClearPrivateMeta( - id: ID! - input: MetaPath! - ): FulfillmentClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderFulfillmentUpdateMeta(id: ID!, input: MetaInput!): FulfillmentUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderFulfillmentUpdatePrivateMeta( - id: ID! - input: MetaInput! - ): FulfillmentUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) + orderClearPrivateMeta(id: ID!, input: MetaPath!): OrderClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderClearMeta(input: MetaPath!, token: UUID!): OrderClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderFulfill(input: OrderFulfillInput!, order: ID): OrderFulfill + orderFulfillmentCancel(id: ID!, input: FulfillmentCancelInput!): FulfillmentCancel + orderFulfillmentUpdateTracking(id: ID!, input: FulfillmentUpdateTrackingInput!): FulfillmentUpdateTracking + orderFulfillmentClearMeta(id: ID!, input: MetaPath!): FulfillmentClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderFulfillmentClearPrivateMeta(id: ID!, input: MetaPath!): FulfillmentClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderFulfillmentUpdateMeta(id: ID!, input: MetaInput!): FulfillmentUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderFulfillmentUpdatePrivateMeta(id: ID!, input: MetaInput!): FulfillmentUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") orderMarkAsPaid(id: ID!): OrderMarkAsPaid orderRefund(amount: Decimal!, id: ID!): OrderRefund orderUpdate(id: ID!, input: OrderUpdateInput!): OrderUpdate - orderUpdateMeta(input: MetaInput!, token: UUID!): OrderUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderUpdatePrivateMeta(id: ID!, input: MetaInput!): OrderUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31." - ) - orderUpdateShipping( - order: ID! - input: OrderUpdateShippingInput - ): OrderUpdateShipping + orderUpdateMeta(input: MetaInput!, token: UUID!): OrderUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderUpdatePrivateMeta(id: ID!, input: MetaInput!): OrderUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation instead. This field will be removed after 2020-07-31.") + orderUpdateShipping(order: ID!, input: OrderUpdateShippingInput): OrderUpdateShipping orderVoid(id: ID!): OrderVoid - orderBulkCancel(ids: [ID]!, restock: Boolean!): OrderBulkCancel + orderBulkCancel(ids: [ID]!): OrderBulkCancel deleteMetadata(id: ID!, keys: [String!]!): DeleteMetadata deletePrivateMetadata(id: ID!, keys: [String!]!): DeletePrivateMetadata updateMetadata(id: ID!, input: [MetadataInput!]!): UpdateMetadata - updatePrivateMetadata( - id: ID! - input: [MetadataInput!]! - ): UpdatePrivateMetadata + updatePrivateMetadata(id: ID!, input: [MetadataInput!]!): UpdatePrivateMetadata assignNavigation(menu: ID, navigationType: NavigationType!): AssignNavigation menuCreate(input: MenuCreateInput!): MenuCreate menuDelete(id: ID!): MenuDelete @@ -3016,11 +2418,7 @@ type Mutation { menuItemDelete(id: ID!): MenuItemDelete menuItemBulkDelete(ids: [ID]!): MenuItemBulkDelete menuItemUpdate(id: ID!, input: MenuItemInput!): MenuItemUpdate - menuItemTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): MenuItemTranslate + menuItemTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): MenuItemTranslate menuItemMove(menu: ID!, moves: [MenuItemMoveInput]!): MenuItemMove giftCardActivate(id: ID!): GiftCardActivate giftCardCreate(input: GiftCardCreateInput!): GiftCardCreate @@ -3033,134 +2431,59 @@ type Mutation { saleUpdate(id: ID!, input: SaleInput!): SaleUpdate saleCataloguesAdd(id: ID!, input: CatalogueInput!): SaleAddCatalogues saleCataloguesRemove(id: ID!, input: CatalogueInput!): SaleRemoveCatalogues - saleTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): SaleTranslate + saleTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): SaleTranslate voucherCreate(input: VoucherInput!): VoucherCreate voucherDelete(id: ID!): VoucherDelete voucherBulkDelete(ids: [ID]!): VoucherBulkDelete voucherUpdate(id: ID!, input: VoucherInput!): VoucherUpdate voucherCataloguesAdd(id: ID!, input: CatalogueInput!): VoucherAddCatalogues - voucherCataloguesRemove( - id: ID! - input: CatalogueInput! - ): VoucherRemoveCatalogues - voucherTranslate( - id: ID! - input: NameTranslationInput! - languageCode: LanguageCodeEnum! - ): VoucherTranslate + voucherCataloguesRemove(id: ID!, input: CatalogueInput!): VoucherRemoveCatalogues + voucherTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): VoucherTranslate tokenCreate(email: String!, password: String!): CreateToken - tokenRefresh(token: String!): Refresh + tokenRefresh(token: String!): RefreshToken tokenVerify(token: String!): VerifyToken - checkoutAddPromoCode( - checkoutId: ID! - promoCode: String! - ): CheckoutAddPromoCode - checkoutBillingAddressUpdate( - billingAddress: AddressInput! - checkoutId: ID! - ): CheckoutBillingAddressUpdate - checkoutComplete( - checkoutId: ID! - redirectUrl: String - storeSource: Boolean = false - ): CheckoutComplete + checkoutAddPromoCode(checkoutId: ID!, promoCode: String!): CheckoutAddPromoCode + checkoutBillingAddressUpdate(billingAddress: AddressInput!, checkoutId: ID!): CheckoutBillingAddressUpdate + checkoutComplete(checkoutId: ID!, redirectUrl: String, storeSource: Boolean = false): CheckoutComplete checkoutCreate(input: CheckoutCreateInput!): CheckoutCreate - checkoutCustomerAttach( - checkoutId: ID! - customerId: ID - ): CheckoutCustomerAttach + checkoutCustomerAttach(checkoutId: ID!, customerId: ID): CheckoutCustomerAttach checkoutCustomerDetach(checkoutId: ID!): CheckoutCustomerDetach checkoutEmailUpdate(checkoutId: ID, email: String!): CheckoutEmailUpdate checkoutLineDelete(checkoutId: ID!, lineId: ID): CheckoutLineDelete - checkoutLinesAdd( - checkoutId: ID! - lines: [CheckoutLineInput]! - ): CheckoutLinesAdd - checkoutLinesUpdate( - checkoutId: ID! - lines: [CheckoutLineInput]! - ): CheckoutLinesUpdate - checkoutRemovePromoCode( - checkoutId: ID! - promoCode: String! - ): CheckoutRemovePromoCode - checkoutPaymentCreate( - checkoutId: ID! - input: PaymentInput! - ): CheckoutPaymentCreate - checkoutShippingAddressUpdate( - checkoutId: ID! - shippingAddress: AddressInput! - ): CheckoutShippingAddressUpdate - checkoutShippingMethodUpdate( - checkoutId: ID - shippingMethodId: ID! - ): CheckoutShippingMethodUpdate - checkoutUpdateMetadata(id: ID!, input: MetaInput!): CheckoutUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation. This field will be removed after 2020-07-31." - ) - checkoutClearMetadata(id: ID!, input: MetaPath!): CheckoutClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation. This field will be removed after 2020-07-31." - ) - checkoutUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): CheckoutUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation. This field will be removed after 2020-07-31." - ) - checkoutClearPrivateMetadata( - id: ID! - input: MetaPath! - ): CheckoutClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation. This field will be removed after 2020-07-31." - ) - requestPasswordReset( - email: String! - redirectUrl: String! - ): RequestPasswordReset + checkoutLinesAdd(checkoutId: ID!, lines: [CheckoutLineInput]!): CheckoutLinesAdd + checkoutLinesUpdate(checkoutId: ID!, lines: [CheckoutLineInput]!): CheckoutLinesUpdate + checkoutRemovePromoCode(checkoutId: ID!, promoCode: String!): CheckoutRemovePromoCode + checkoutPaymentCreate(checkoutId: ID!, input: PaymentInput!): CheckoutPaymentCreate + checkoutShippingAddressUpdate(checkoutId: ID!, shippingAddress: AddressInput!): CheckoutShippingAddressUpdate + checkoutShippingMethodUpdate(checkoutId: ID, shippingMethodId: ID!): CheckoutShippingMethodUpdate + checkoutUpdateMetadata(id: ID!, input: MetaInput!): CheckoutUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation. This field will be removed after 2020-07-31.") + checkoutClearMetadata(id: ID!, input: MetaPath!): CheckoutClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation. This field will be removed after 2020-07-31.") + checkoutUpdatePrivateMetadata(id: ID!, input: MetaInput!): CheckoutUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation. This field will be removed after 2020-07-31.") + checkoutClearPrivateMetadata(id: ID!, input: MetaPath!): CheckoutClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation. This field will be removed after 2020-07-31.") + appCreate(input: AppInput!): AppCreate + appUpdate(id: ID!, input: AppInput!): AppUpdate + appDelete(id: ID!): AppDelete + appTokenCreate(input: AppTokenInput!): AppTokenCreate + appTokenDelete(id: ID!): AppTokenDelete + requestPasswordReset(email: String!, redirectUrl: String!): RequestPasswordReset confirmAccount(email: String!, token: String!): ConfirmAccount setPassword(token: String!, email: String!, password: String!): SetPassword passwordChange(newPassword: String!, oldPassword: String!): PasswordChange - requestEmailChange( - newEmail: String! - password: String! - redirectUrl: String! - ): RequestEmailChange + requestEmailChange(newEmail: String!, password: String!, redirectUrl: String!): RequestEmailChange confirmEmailChange(token: String!): ConfirmEmailChange - accountAddressCreate( - input: AddressInput! - type: AddressTypeEnum - ): AccountAddressCreate + accountAddressCreate(input: AddressInput!, type: AddressTypeEnum): AccountAddressCreate accountAddressUpdate(id: ID!, input: AddressInput!): AccountAddressUpdate accountAddressDelete(id: ID!): AccountAddressDelete - accountSetDefaultAddress( - id: ID! - type: AddressTypeEnum! - ): AccountSetDefaultAddress + accountSetDefaultAddress(id: ID!, type: AddressTypeEnum!): AccountSetDefaultAddress accountRegister(input: AccountRegisterInput!): AccountRegister accountUpdate(input: AccountInput!): AccountUpdate accountRequestDeletion(redirectUrl: String!): AccountRequestDeletion accountDelete(token: String!): AccountDelete - accountUpdateMeta(input: MetaInput!): AccountUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation. This field will be removed after 2020-07-31." - ) + accountUpdateMeta(input: MetaInput!): AccountUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation. This field will be removed after 2020-07-31.") addressCreate(input: AddressInput!, userId: ID!): AddressCreate addressUpdate(id: ID!, input: AddressInput!): AddressUpdate addressDelete(id: ID!): AddressDelete - addressSetDefault( - addressId: ID! - type: AddressTypeEnum! - userId: ID! - ): AddressSetDefault + addressSetDefault(addressId: ID!, type: AddressTypeEnum!, userId: ID!): AddressSetDefault customerCreate(input: UserCreateInput!): CustomerCreate customerUpdate(id: ID!, input: CustomerInput!): CustomerUpdate customerDelete(id: ID!): CustomerDelete @@ -3172,53 +2495,19 @@ type Mutation { userAvatarUpdate(image: Upload!): UserAvatarUpdate userAvatarDelete: UserAvatarDelete userBulkSetActive(ids: [ID]!, isActive: Boolean!): UserBulkSetActive - userUpdateMetadata(id: ID!, input: MetaInput!): UserUpdateMeta - @deprecated( - reason: "Use the `updateMetadata` mutation. This field will be removed after 2020-07-31." - ) - userClearMetadata(id: ID!, input: MetaPath!): UserClearMeta - @deprecated( - reason: "Use the `deleteMetadata` mutation. This field will be removed after 2020-07-31." - ) - userUpdatePrivateMetadata(id: ID!, input: MetaInput!): UserUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation. This field will be removed after 2020-07-31." - ) - userClearPrivateMetadata(id: ID!, input: MetaPath!): UserClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation. This field will be removed after 2020-07-31." - ) - serviceAccountCreate(input: ServiceAccountInput!): ServiceAccountCreate - serviceAccountUpdate( - id: ID! - input: ServiceAccountInput! - ): ServiceAccountUpdate - serviceAccountDelete(id: ID!): ServiceAccountDelete - serviceAccountUpdatePrivateMetadata( - id: ID! - input: MetaInput! - ): ServiceAccountUpdatePrivateMeta - @deprecated( - reason: "Use the `updatePrivateMetadata` mutation. This field will be removed after 2020-07-31." - ) - serviceAccountClearPrivateMetadata( - id: ID! - input: MetaPath! - ): ServiceAccountClearPrivateMeta - @deprecated( - reason: "Use the `deletePrivateMetadata` mutation. This field will be removed after 2020-07-31." - ) - serviceAccountTokenCreate( - input: ServiceAccountTokenInput! - ): ServiceAccountTokenCreate - serviceAccountTokenDelete(id: ID!): ServiceAccountTokenDelete - permissionGroupCreate( - input: PermissionGroupCreateInput! - ): PermissionGroupCreate - permissionGroupUpdate( - id: ID! - input: PermissionGroupUpdateInput! - ): PermissionGroupUpdate + userUpdateMetadata(id: ID!, input: MetaInput!): UserUpdateMeta @deprecated(reason: "Use the `updateMetadata` mutation. This field will be removed after 2020-07-31.") + userClearMetadata(id: ID!, input: MetaPath!): UserClearMeta @deprecated(reason: "Use the `deleteMetadata` mutation. This field will be removed after 2020-07-31.") + userUpdatePrivateMetadata(id: ID!, input: MetaInput!): UserUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation. This field will be removed after 2020-07-31.") + userClearPrivateMetadata(id: ID!, input: MetaPath!): UserClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation. This field will be removed after 2020-07-31.") + serviceAccountCreate(input: ServiceAccountInput!): ServiceAccountCreate @deprecated(reason: "Use the `appCreate` mutation instead. This field will be removed after 2020-07-31.") + serviceAccountUpdate(id: ID!, input: ServiceAccountInput!): ServiceAccountUpdate @deprecated(reason: "Use the `appUpdate` mutation instead. This field will be removed after 2020-07-31.") + serviceAccountDelete(id: ID!): ServiceAccountDelete @deprecated(reason: "Use the `appDelete` mutation instead. This field will be removed after 2020-07-31.") + serviceAccountUpdatePrivateMetadata(id: ID!, input: MetaInput!): ServiceAccountUpdatePrivateMeta @deprecated(reason: "Use the `updatePrivateMetadata` mutation with App instead.This field will be removed after 2020-07-31.") + serviceAccountClearPrivateMetadata(id: ID!, input: MetaPath!): ServiceAccountClearPrivateMeta @deprecated(reason: "Use the `deletePrivateMetadata` mutation with App instead.This field will be removed after 2020-07-31.") + serviceAccountTokenCreate(input: ServiceAccountTokenInput!): ServiceAccountTokenCreate @deprecated(reason: "Use the `appTokenCreate` mutation instead. This field will be removed after 2020-07-31.") + serviceAccountTokenDelete(id: ID!): ServiceAccountTokenDelete @deprecated(reason: "Use the `appTokenDelete` mutation instead. This field will be removed after 2020-07-31.") + permissionGroupCreate(input: PermissionGroupCreateInput!): PermissionGroupCreate + permissionGroupUpdate(id: ID!, input: PermissionGroupUpdateInput!): PermissionGroupUpdate permissionGroupDelete(id: ID!): PermissionGroupDelete } @@ -3243,14 +2532,8 @@ interface Node { interface ObjectWithMetadata { privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") } type Order implements Node & ObjectWithMetadata { @@ -3276,14 +2559,8 @@ type Order implements Node & ObjectWithMetadata { weight: Weight privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") fulfillments: [Fulfillment]! lines: [OrderLine]! actions: [OrderAction]! @@ -3313,10 +2590,7 @@ enum OrderAction { } type OrderAddNote { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order event: OrderEvent orderErrors: [OrderError!]! @@ -3327,45 +2601,30 @@ input OrderAddNoteInput { } type OrderBulkCancel { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! orderErrors: [OrderError!]! } type OrderCancel { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } type OrderCapture { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } type OrderClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order } type OrderClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order } @@ -3395,6 +2654,8 @@ type OrderError { field: String message: String code: OrderErrorCode! + warehouse: ID + orderLine: ID } enum OrderErrorCode { @@ -3419,6 +2680,7 @@ enum OrderErrorCode { VOID_INACTIVE_PAYMENT ZERO_QUANTITY INSUFFICIENT_STOCK + DUPLICATED_INPUT_ITEM } type OrderEvent implements Node { @@ -3438,6 +2700,7 @@ type OrderEvent implements Node { oversoldItems: [String] lines: [OrderEventOrderLineObject] fulfilledItems: [FulfillmentLine] + warehouse: Warehouse } type OrderEventCountableConnection { @@ -3498,6 +2761,28 @@ input OrderFilterInput { search: String } +type OrderFulfill { + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") + fulfillments: [Fulfillment] + order: Order + orderErrors: [OrderError!]! +} + +input OrderFulfillInput { + lines: [OrderFulfillLineInput!]! + notifyCustomer: Boolean +} + +input OrderFulfillLineInput { + orderLineId: ID + stocks: [OrderFulfillStockInput!]! +} + +input OrderFulfillStockInput { + quantity: Int + warehouse: ID +} + type OrderLine implements Node { id: ID! productName: String! @@ -3525,19 +2810,13 @@ input OrderLineInput { } type OrderMarkAsPaid { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } type OrderRefund { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } @@ -3574,10 +2853,7 @@ enum OrderStatusFilter { } type OrderUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") orderErrors: [OrderError!]! order: Order } @@ -3589,26 +2865,17 @@ input OrderUpdateInput { } type OrderUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order } type OrderUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order } type OrderUpdateShipping { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } @@ -3618,10 +2885,7 @@ input OrderUpdateShippingInput { } type OrderVoid { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") order: Order orderErrors: [OrderError!]! } @@ -3641,19 +2905,13 @@ type Page implements Node { } type PageBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! pageErrors: [PageError!]! } type PageBulkPublish { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! pageErrors: [PageError!]! } @@ -3670,19 +2928,13 @@ type PageCountableEdge { } type PageCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") pageErrors: [PageError!]! page: Page } type PageDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") pageErrors: [PageError!]! page: Page } @@ -3747,10 +2999,7 @@ type PageTranslatableContent implements Node { } type PageTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! page: PageTranslatableContent } @@ -3774,19 +3023,13 @@ input PageTranslationInput { } type PageUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") pageErrors: [PageError!]! page: Page } type PasswordChange { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } @@ -3815,10 +3058,7 @@ type Payment implements Node { } type PaymentCapture { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") payment: Payment paymentErrors: [PaymentError!]! } @@ -3872,19 +3112,13 @@ input PaymentInput { } type PaymentRefund { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") payment: Payment paymentErrors: [PaymentError!]! } type PaymentSecureConfirm { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") payment: Payment paymentErrors: [PaymentError!]! } @@ -3895,10 +3129,7 @@ type PaymentSource { } type PaymentVoid { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") payment: Payment paymentErrors: [PaymentError!]! } @@ -3928,10 +3159,7 @@ enum PermissionEnum { } type PermissionGroupCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") group: Group permissionGroupErrors: [PermissionGroupError!]! } @@ -3943,10 +3171,7 @@ input PermissionGroupCreateInput { } type PermissionGroupDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") permissionGroupErrors: [PermissionGroupError!]! group: Group } @@ -3984,10 +3209,7 @@ input PermissionGroupSortingInput { } type PermissionGroupUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") group: Group permissionGroupErrors: [PermissionGroupError!]! } @@ -4050,10 +3272,7 @@ input PluginSortingInput { } type PluginUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") plugin: Plugin pluginsErrors: [PluginError!]! } @@ -4085,16 +3304,9 @@ type Product implements Node & ObjectWithMetadata { weight: Weight privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) - url: String! - @deprecated(reason: "This field will be removed after 2020-07-31.") + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") + url: String! @deprecated(reason: "This field will be removed after 2020-07-31.") thumbnail(size: Int): Image pricing: ProductPricingInfo isAvailable: Boolean @@ -4119,37 +3331,25 @@ type ProductAttributeError { } type ProductBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type ProductBulkPublish { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type ProductClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } type ProductClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } @@ -4166,10 +3366,7 @@ type ProductCountableEdge { } type ProductCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } @@ -4190,17 +3387,13 @@ input ProductCreateInput { seo: SeoInput weight: WeightScalar sku: String - quantity: Int trackInventory: Boolean productType: ID! stocks: [StockInput!] } type ProductDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } @@ -4249,19 +3442,13 @@ type ProductImage implements Node { } type ProductImageBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type ProductImageCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") product: Product image: ProductImage productErrors: [ProductError!]! @@ -4274,30 +3461,21 @@ input ProductImageCreateInput { } type ProductImageDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") product: Product image: ProductImage productErrors: [ProductError!]! } type ProductImageReorder { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") product: Product images: [ProductImage] productErrors: [ProductError!]! } type ProductImageUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") product: Product image: ProductImage productErrors: [ProductError!]! @@ -4323,7 +3501,6 @@ input ProductInput { seo: SeoInput weight: WeightScalar sku: String - quantity: Int trackInventory: Boolean } @@ -4368,10 +3545,7 @@ type ProductTranslatableContent implements Node { } type ProductTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! product: Product } @@ -4396,56 +3570,30 @@ type ProductType implements Node & ObjectWithMetadata { weight: Weight privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) - products( - before: String - after: String - first: Int - last: Int - ): ProductCountableConnection + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") + products(before: String, after: String, first: Int, last: Int): ProductCountableConnection taxRate: TaxRateType taxType: TaxType variantAttributes: [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 } type ProductTypeBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type ProductTypeClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } type ProductTypeClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } @@ -4467,19 +3615,13 @@ type ProductTypeCountableEdge { } type ProductTypeCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } type ProductTypeDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } @@ -4509,10 +3651,7 @@ input ProductTypeInput { } type ProductTypeReorderAttributes { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productType: ProductType productErrors: [ProductError!]! } @@ -4529,55 +3668,37 @@ input ProductTypeSortingInput { } type ProductTypeUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } type ProductTypeUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } type ProductTypeUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productType: ProductType } type ProductUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } type ProductUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } type ProductUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! product: Product } @@ -4591,32 +3712,14 @@ type ProductVariant implements Node & ObjectWithMetadata { weight: Weight privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) - quantity: Int! - @deprecated( - reason: "Use the stock field instead. This field will be removed after 2020-07-31." - ) - quantityAllocated: Int - @deprecated( - reason: "Use the stock field instead. This field will be removed after 2020-07-31." - ) - stockQuantity: Int! - @deprecated( - reason: "Use the stock field instead. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") + quantity: Int! @deprecated(reason: "Use the stock field instead. This field will be removed after 2020-07-31.") + quantityAllocated: Int @deprecated(reason: "Use the stock field instead. This field will be removed after 2020-07-31.") + stockQuantity: Int! @deprecated(reason: "Use the stock field instead. This field will be removed after 2020-07-31.") priceOverride: Money pricing: VariantPricingInfo - isAvailable: Boolean - @deprecated( - reason: "Use the stock field instead. This field will be removed after 2020-07-31." - ) + isAvailable: Boolean @deprecated(reason: "Use the stock field instead. This field will be removed after 2020-07-31.") attributes: [SelectedAttribute!]! costPrice: Money margin: Int @@ -4629,10 +3732,7 @@ type ProductVariant implements Node & ObjectWithMetadata { } type ProductVariantBulkCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productVariants: [ProductVariant!]! bulkProductErrors: [BulkProductError!]! @@ -4643,34 +3743,25 @@ input ProductVariantBulkCreateInput { costPrice: Decimal priceOverride: Decimal sku: String! - stocks: [StockInput!]! trackInventory: Boolean weight: WeightScalar + stocks: [StockInput!] } type ProductVariantBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! productErrors: [ProductError!]! } type ProductVariantClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } type ProductVariantClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } @@ -4687,10 +3778,7 @@ type ProductVariantCountableEdge { } type ProductVariantCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } @@ -4700,7 +3788,6 @@ input ProductVariantCreateInput { costPrice: Decimal priceOverride: Decimal sku: String - quantity: Int trackInventory: Boolean weight: WeightScalar product: ID! @@ -4708,10 +3795,7 @@ input ProductVariantCreateInput { } type ProductVariantDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } @@ -4721,34 +3805,24 @@ input ProductVariantInput { costPrice: Decimal priceOverride: Decimal sku: String - quantity: Int trackInventory: Boolean weight: WeightScalar } type ProductVariantStocksCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productVariant: ProductVariant bulkStockErrors: [BulkStockError!]! } type ProductVariantStocksDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productVariant: ProductVariant stockErrors: [StockError!]! } type ProductVariantStocksUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productVariant: ProductVariant bulkStockErrors: [BulkStockError!]! } @@ -4761,10 +3835,7 @@ type ProductVariantTranslatableContent implements Node { } type ProductVariantTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! productVariant: ProductVariant } @@ -4776,301 +3847,90 @@ type ProductVariantTranslation implements Node { } type ProductVariantUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } type ProductVariantUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } type ProductVariantUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productErrors: [ProductError!]! productVariant: ProductVariant } type Query { webhook(id: ID!): Webhook - webhooks( - sortBy: WebhookSortingInput - filter: WebhookFilterInput - before: String - after: String - first: Int - last: Int - ): WebhookCountableConnection + webhooks(sortBy: WebhookSortingInput, filter: WebhookFilterInput, before: String, after: String, first: Int, last: Int): WebhookCountableConnection @deprecated(reason: "Use webhooks field on app(s) query instead. This field will be removed after 2020-07-31.") webhookEvents: [WebhookEvent] webhookSamplePayload(eventType: WebhookSampleEventTypeEnum!): JSONString warehouse(id: ID!): Warehouse - warehouses( - filter: WarehouseFilterInput - sortBy: WarehouseSortingInput - before: String - after: String - first: Int - last: Int - ): WarehouseCountableConnection - translations( - kind: TranslatableKinds! - before: String - after: String - first: Int - last: Int - ): TranslatableItemConnection + warehouses(filter: WarehouseFilterInput, sortBy: WarehouseSortingInput, before: String, after: String, first: Int, last: Int): WarehouseCountableConnection + translations(kind: TranslatableKinds!, before: String, after: String, first: Int, last: Int): TranslatableItemConnection translation(id: ID!, kind: TranslatableKinds!): TranslatableItem stock(id: ID!): Stock - stocks( - filter: StockFilterInput - before: String - after: String - first: Int - last: Int - ): StockCountableConnection + stocks(filter: StockFilterInput, before: String, after: String, first: Int, last: Int): StockCountableConnection shop: Shop! shippingZone(id: ID!): ShippingZone - shippingZones( - before: String - after: String - first: Int - last: Int - ): ShippingZoneCountableConnection + shippingZones(before: String, after: String, first: Int, last: Int): ShippingZoneCountableConnection digitalContent(id: ID!): DigitalContent - digitalContents( - before: String - after: String - first: Int - last: Int - ): DigitalContentCountableConnection - attributes( - filter: AttributeFilterInput - sortBy: AttributeSortingInput - before: String - after: String - first: Int - last: Int - ): AttributeCountableConnection + digitalContents(before: String, after: String, first: Int, last: Int): DigitalContentCountableConnection + attributes(filter: AttributeFilterInput, sortBy: AttributeSortingInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection attribute(id: ID!): Attribute - categories( - filter: CategoryFilterInput - sortBy: CategorySortingInput - level: Int - before: String - after: String - first: Int - last: Int - ): CategoryCountableConnection + categories(filter: CategoryFilterInput, sortBy: CategorySortingInput, level: Int, before: String, after: String, first: Int, last: Int): CategoryCountableConnection category(id: ID!): Category collection(id: ID!): Collection - collections( - filter: CollectionFilterInput - sortBy: CollectionSortingInput - before: String - after: String - first: Int - last: Int - ): CollectionCountableConnection + collections(filter: CollectionFilterInput, sortBy: CollectionSortingInput, before: String, after: String, first: Int, last: Int): CollectionCountableConnection product(id: ID!): Product - products( - filter: ProductFilterInput - sortBy: ProductOrder - stockAvailability: StockAvailability - before: String - after: String - first: Int - last: Int - ): ProductCountableConnection + products(filter: ProductFilterInput, sortBy: ProductOrder, stockAvailability: StockAvailability, before: String, after: String, first: Int, last: Int): ProductCountableConnection productType(id: ID!): ProductType - productTypes( - filter: ProductTypeFilterInput - sortBy: ProductTypeSortingInput - before: String - after: String - first: Int - last: Int - ): ProductTypeCountableConnection + productTypes(filter: ProductTypeFilterInput, sortBy: ProductTypeSortingInput, before: String, after: String, first: Int, last: Int): ProductTypeCountableConnection productVariant(id: ID!): ProductVariant - productVariants( - ids: [ID] - before: String - after: String - first: Int - last: Int - ): ProductVariantCountableConnection - reportProductSales( - period: ReportingPeriod! - before: String - after: String - first: Int - last: Int - ): ProductVariantCountableConnection + productVariants(ids: [ID], before: String, after: String, first: Int, last: Int): ProductVariantCountableConnection + reportProductSales(period: ReportingPeriod!, before: String, after: String, first: Int, last: Int): ProductVariantCountableConnection payment(id: ID!): Payment - payments( - before: String - after: String - first: Int - last: Int - ): PaymentCountableConnection + payments(before: String, after: String, first: Int, last: Int): PaymentCountableConnection page(id: ID, slug: String): Page - pages( - sortBy: PageSortingInput - filter: PageFilterInput - before: String - after: String - first: Int - last: Int - ): PageCountableConnection - homepageEvents( - before: String - after: String - first: Int - last: Int - ): OrderEventCountableConnection + pages(sortBy: PageSortingInput, filter: PageFilterInput, before: String, after: String, first: Int, last: Int): PageCountableConnection + homepageEvents(before: String, after: String, first: Int, last: Int): OrderEventCountableConnection order(id: ID!): Order - orders( - sortBy: OrderSortingInput - filter: OrderFilterInput - created: ReportingPeriod - status: OrderStatusFilter - before: String - after: String - first: Int - last: Int - ): OrderCountableConnection - draftOrders( - sortBy: OrderSortingInput - filter: OrderDraftFilterInput - created: ReportingPeriod - before: String - after: String - first: Int - last: Int - ): OrderCountableConnection + orders(sortBy: OrderSortingInput, filter: OrderFilterInput, created: ReportingPeriod, status: OrderStatusFilter, before: String, after: String, first: Int, last: Int): OrderCountableConnection + draftOrders(sortBy: OrderSortingInput, filter: OrderDraftFilterInput, created: ReportingPeriod, before: String, after: String, first: Int, last: Int): OrderCountableConnection ordersTotal(period: ReportingPeriod): TaxedMoney orderByToken(token: UUID!): Order menu(id: ID, name: String): Menu - menus( - sortBy: MenuSortingInput - filter: MenuFilterInput - before: String - after: String - first: Int - last: Int - ): MenuCountableConnection + menus(sortBy: MenuSortingInput, filter: MenuFilterInput, before: String, after: String, first: Int, last: Int): MenuCountableConnection menuItem(id: ID!): MenuItem - menuItems( - sortBy: MenuItemSortingInput - filter: MenuItemFilterInput - before: String - after: String - first: Int - last: Int - ): MenuItemCountableConnection + menuItems(sortBy: MenuItemSortingInput, filter: MenuItemFilterInput, before: String, after: String, first: Int, last: Int): MenuItemCountableConnection giftCard(id: ID!): GiftCard - giftCards( - before: String - after: String - first: Int - last: Int - ): GiftCardCountableConnection + giftCards(before: String, after: String, first: Int, last: Int): GiftCardCountableConnection plugin(id: ID!): Plugin - plugins( - filter: PluginFilterInput - sortBy: PluginSortingInput - before: String - after: String - first: Int - last: Int - ): PluginCountableConnection + plugins(filter: PluginFilterInput, sortBy: PluginSortingInput, before: String, after: String, first: Int, last: Int): PluginCountableConnection sale(id: ID!): Sale - sales( - filter: SaleFilterInput - sortBy: SaleSortingInput - query: String - before: String - after: String - first: Int - last: Int - ): SaleCountableConnection + sales(filter: SaleFilterInput, sortBy: SaleSortingInput, query: String, before: String, after: String, first: Int, last: Int): SaleCountableConnection voucher(id: ID!): Voucher - vouchers( - filter: VoucherFilterInput - sortBy: VoucherSortingInput - query: String - before: String - after: String - first: Int - last: Int - ): VoucherCountableConnection + vouchers(filter: VoucherFilterInput, sortBy: VoucherSortingInput, query: String, before: String, after: String, first: Int, last: Int): VoucherCountableConnection taxTypes: [TaxType] checkout(token: UUID): Checkout - checkouts( - before: String - after: String - first: Int - last: Int - ): CheckoutCountableConnection + checkouts(before: String, after: String, first: Int, last: Int): CheckoutCountableConnection checkoutLine(id: ID): CheckoutLine - checkoutLines( - before: String - after: String - first: Int - last: Int - ): CheckoutLineCountableConnection - addressValidationRules( - countryCode: CountryCode! - countryArea: String - city: String - cityArea: String - ): AddressValidationData + checkoutLines(before: String, after: String, first: Int, last: Int): CheckoutLineCountableConnection + apps(filter: AppFilterInput, sortBy: AppSortingInput, before: String, after: String, first: Int, last: Int): AppCountableConnection + app(id: ID!): App + addressValidationRules(countryCode: CountryCode!, countryArea: String, city: String, cityArea: String): AddressValidationData address(id: ID!): Address - customers( - filter: CustomerFilterInput - sortBy: UserSortingInput - before: String - after: String - first: Int - last: Int - ): UserCountableConnection - permissionGroups( - filter: PermissionGroupFilterInput - sortBy: PermissionGroupSortingInput - before: String - after: String - first: Int - last: Int - ): GroupCountableConnection + customers(filter: CustomerFilterInput, sortBy: UserSortingInput, before: String, after: String, first: Int, last: Int): UserCountableConnection + permissionGroups(filter: PermissionGroupFilterInput, sortBy: PermissionGroupSortingInput, before: String, after: String, first: Int, last: Int): GroupCountableConnection permissionGroup(id: ID!): Group me: User - staffUsers( - filter: StaffUserInput - sortBy: UserSortingInput - before: String - after: String - first: Int - last: Int - ): UserCountableConnection - serviceAccounts( - filter: ServiceAccountFilterInput - sortBy: ServiceAccountSortingInput - before: String - after: String - first: Int - last: Int - ): ServiceAccountCountableConnection - serviceAccount(id: ID!): ServiceAccount + staffUsers(filter: StaffUserInput, sortBy: UserSortingInput, before: String, after: String, first: Int, last: Int): UserCountableConnection + serviceAccounts(filter: ServiceAccountFilterInput, sortBy: ServiceAccountSortingInput, before: String, after: String, first: Int, last: Int): ServiceAccountCountableConnection @deprecated(reason: "Use the `apps` query instead. This field will be removed after 2020-07-31.") + serviceAccount(id: ID!): ServiceAccount @deprecated(reason: "Use the `app` query instead. This field will be removed after 2020-07-31.") user(id: ID!): User _entities(representations: [_Any]): [_Entity] _service: _Service @@ -5081,7 +3941,7 @@ type ReducedRate { rateType: TaxRateType! } -type Refresh { +type RefreshToken { token: String payload: GenericScalar } @@ -5097,19 +3957,13 @@ enum ReportingPeriod { } type RequestEmailChange { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } type RequestPasswordReset { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! } @@ -5120,41 +3974,20 @@ type Sale implements Node { value: Float! startDate: DateTime! endDate: DateTime - categories( - before: String - after: String - first: Int - last: Int - ): CategoryCountableConnection - collections( - before: String - after: String - first: Int - last: Int - ): CollectionCountableConnection - products( - before: String - after: String - first: Int - last: Int - ): ProductCountableConnection + categories(before: String, after: String, first: Int, last: Int): CategoryCountableConnection + collections(before: String, after: String, first: Int, last: Int): CollectionCountableConnection + products(before: String, after: String, first: Int, last: Int): ProductCountableConnection translation(languageCode: LanguageCodeEnum!): SaleTranslation } type SaleAddCatalogues { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") sale: Sale discountErrors: [DiscountError!]! } type SaleBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! discountErrors: [DiscountError!]! } @@ -5171,19 +4004,13 @@ type SaleCountableEdge { } type SaleCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") discountErrors: [DiscountError!]! sale: Sale } type SaleDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") discountErrors: [DiscountError!]! sale: Sale } @@ -5207,10 +4034,7 @@ input SaleInput { } type SaleRemoveCatalogues { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") sale: Sale discountErrors: [DiscountError!]! } @@ -5236,10 +4060,7 @@ type SaleTranslatableContent implements Node { } type SaleTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! sale: Sale } @@ -5256,10 +4077,7 @@ enum SaleType { } type SaleUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") discountErrors: [DiscountError!]! sale: Sale } @@ -5283,21 +4101,12 @@ type ServiceAccount implements Node & ObjectWithMetadata { tokens: [ServiceAccountToken] privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") } type ServiceAccountClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! serviceAccount: ServiceAccount } @@ -5314,20 +4123,14 @@ type ServiceAccountCountableEdge { } type ServiceAccountCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") authToken: String accountErrors: [AccountError!]! serviceAccount: ServiceAccount } type ServiceAccountDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! serviceAccount: ServiceAccount } @@ -5360,20 +4163,14 @@ type ServiceAccountToken implements Node { } type ServiceAccountTokenCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") authToken: String accountErrors: [AccountError!]! serviceAccountToken: ServiceAccountToken } type ServiceAccountTokenDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! serviceAccountToken: ServiceAccountToken } @@ -5384,29 +4181,20 @@ input ServiceAccountTokenInput { } type ServiceAccountUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! serviceAccount: ServiceAccount } type ServiceAccountUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! serviceAccount: ServiceAccount } type SetPassword { token: String - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -5460,29 +4248,20 @@ enum ShippingMethodTypeEnum { } type ShippingPriceBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! shippingErrors: [ShippingError!]! } type ShippingPriceCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shippingZone: ShippingZone shippingErrors: [ShippingError!]! shippingMethod: ShippingMethod } type ShippingPriceDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shippingMethod: ShippingMethod shippingZone: ShippingZone shippingErrors: [ShippingError!]! @@ -5500,19 +4279,13 @@ input ShippingPriceInput { } type ShippingPriceTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! shippingMethod: ShippingMethod } type ShippingPriceUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shippingZone: ShippingZone shippingErrors: [ShippingError!]! shippingMethod: ShippingMethod @@ -5529,10 +4302,7 @@ type ShippingZone implements Node { } type ShippingZoneBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! shippingErrors: [ShippingError!]! } @@ -5549,10 +4319,7 @@ type ShippingZoneCountableEdge { } type ShippingZoneCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shippingZone: ShippingZone shippingErrors: [ShippingError!]! } @@ -5565,19 +4332,13 @@ input ShippingZoneCreateInput { } type ShippingZoneDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shippingErrors: [ShippingError!]! shippingZone: ShippingZone } type ShippingZoneUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shippingZone: ShippingZone shippingErrors: [ShippingError!]! } @@ -5623,19 +4384,13 @@ type Shop { } type ShopAddressUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shop: Shop shopErrors: [ShopError!]! } type ShopDomainUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shop: Shop shopErrors: [ShopError!]! } @@ -5657,10 +4412,7 @@ enum ShopErrorCode { } type ShopFetchTaxRates { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shop: Shop shopErrors: [ShopError!]! } @@ -5682,10 +4434,7 @@ input ShopSettingsInput { } type ShopSettingsTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shop: Shop translationErrors: [TranslationError!]! } @@ -5696,10 +4445,7 @@ input ShopSettingsTranslationInput { } type ShopSettingsUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shop: Shop shopErrors: [ShopError!]! } @@ -5717,19 +4463,13 @@ input SiteDomainInput { } type StaffBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! staffErrors: [StaffError!]! } type StaffCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") staffErrors: [StaffError!]! user: User } @@ -5745,10 +4485,7 @@ input StaffCreateInput { } type StaffDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") staffErrors: [StaffError!]! user: User } @@ -5775,19 +4512,13 @@ type StaffNotificationRecipient implements Node { } type StaffNotificationRecipientCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shopErrors: [ShopError!]! staffNotificationRecipient: StaffNotificationRecipient } type StaffNotificationRecipientDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shopErrors: [ShopError!]! staffNotificationRecipient: StaffNotificationRecipient } @@ -5799,19 +4530,13 @@ input StaffNotificationRecipientInput { } type StaffNotificationRecipientUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") shopErrors: [ShopError!]! staffNotificationRecipient: StaffNotificationRecipient } type StaffUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") staffErrors: [StaffError!]! user: User } @@ -5835,9 +4560,9 @@ type Stock implements Node { warehouse: Warehouse! productVariant: ProductVariant! quantity: Int! - quantityAllocated: Int! id: ID! stockQuantity: Int! + quantityAllocated: Int! } enum StockAvailability { @@ -5873,7 +4598,6 @@ enum StockErrorCode { input StockFilterInput { quantity: Float - quantityAllocated: Float search: String } @@ -5960,18 +4684,7 @@ enum TransactionKind { CONFIRM } -union TranslatableItem = - ProductTranslatableContent - | CollectionTranslatableContent - | CategoryTranslatableContent - | AttributeTranslatableContent - | AttributeValueTranslatableContent - | ProductVariantTranslatableContent - | PageTranslatableContent - | ShippingMethodTranslatableContent - | SaleTranslatableContent - | VoucherTranslatableContent - | MenuItemTranslatableContent +union TranslatableItem = ProductTranslatableContent | CollectionTranslatableContent | CategoryTranslatableContent | AttributeTranslatableContent | AttributeValueTranslatableContent | ProductVariantTranslatableContent | PageTranslatableContent | ShippingMethodTranslatableContent | SaleTranslatableContent | VoucherTranslatableContent | MenuItemTranslatableContent type TranslatableItemConnection { pageInfo: PageInfo! @@ -6021,19 +4734,13 @@ input TranslationInput { scalar UUID type UpdateMetadata { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") metadataErrors: [MetadataError!]! item: ObjectWithMetadata } type UpdatePrivateMetadata { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") metadataErrors: [MetadataError!]! item: ObjectWithMetadata } @@ -6054,32 +4761,13 @@ type User implements Node & ObjectWithMetadata { defaultBillingAddress: Address privateMetadata: [MetadataItem]! metadata: [MetadataItem]! - privateMeta: [MetaStore]! - @deprecated( - reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31." - ) - meta: [MetaStore]! - @deprecated( - reason: "Use the `metadata` field. This field will be removed after 2020-07-31." - ) + privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.") + meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.") addresses: [Address] checkout: Checkout - giftCards( - before: String - after: String - first: Int - last: Int - ): GiftCardCountableConnection - orders( - before: String - after: String - first: Int - last: Int - ): OrderCountableConnection - permissions: [Permission] - @deprecated( - reason: "Will be removed in Saleor 2.11.Use the `userPermissions` instead." - ) + giftCards(before: String, after: String, first: Int, last: Int): GiftCardCountableConnection + orders(before: String, after: String, first: Int, last: Int): OrderCountableConnection + permissions: [Permission] @deprecated(reason: "Will be removed in Saleor 2.11.Use the `userPermissions` instead.") userPermissions: [UserPermission] permissionGroups: [Group] editableGroups: [Group] @@ -6089,46 +4777,31 @@ type User implements Node & ObjectWithMetadata { } type UserAvatarDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } type UserAvatarUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") user: User accountErrors: [AccountError!]! } type UserBulkSetActive { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! accountErrors: [AccountError!]! } type UserClearMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } type UserClearPrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -6174,19 +4847,13 @@ input UserSortingInput { } type UserUpdateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } type UserUpdatePrivateMeta { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") accountErrors: [AccountError!]! user: User } @@ -6198,20 +4865,14 @@ type VAT { } type VariantImageAssign { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productVariant: ProductVariant image: ProductImage productErrors: [ProductError!]! } type VariantImageUnassign { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") productVariant: ProductVariant image: ProductImage productErrors: [ProductError!]! @@ -6246,42 +4907,21 @@ type Voucher implements Node { discountValue: Float! minSpent: Money minCheckoutItemsQuantity: Int - categories( - before: String - after: String - first: Int - last: Int - ): CategoryCountableConnection - collections( - before: String - after: String - first: Int - last: Int - ): CollectionCountableConnection - products( - before: String - after: String - first: Int - last: Int - ): ProductCountableConnection + categories(before: String, after: String, first: Int, last: Int): CategoryCountableConnection + collections(before: String, after: String, first: Int, last: Int): CollectionCountableConnection + products(before: String, after: String, first: Int, last: Int): ProductCountableConnection countries: [CountryDisplay] translation(languageCode: LanguageCodeEnum!): VoucherTranslation } type VoucherAddCatalogues { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") voucher: Voucher discountErrors: [DiscountError!]! } type VoucherBulkDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") count: Int! discountErrors: [DiscountError!]! } @@ -6298,19 +4938,13 @@ type VoucherCountableEdge { } type VoucherCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") discountErrors: [DiscountError!]! voucher: Voucher } type VoucherDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") discountErrors: [DiscountError!]! voucher: Voucher } @@ -6349,10 +4983,7 @@ input VoucherInput { } type VoucherRemoveCatalogues { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") voucher: Voucher discountErrors: [DiscountError!]! } @@ -6380,10 +5011,7 @@ type VoucherTranslatableContent implements Node { } type VoucherTranslate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") translationErrors: [TranslationError!]! voucher: Voucher } @@ -6401,10 +5029,7 @@ enum VoucherTypeEnum { } type VoucherUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") discountErrors: [DiscountError!]! voucher: Voucher } @@ -6414,12 +5039,7 @@ type Warehouse implements Node { name: String! slug: String! companyName: String! - shippingZones( - before: String - after: String - first: Int - last: Int - ): ShippingZoneCountableConnection! + shippingZones(before: String, after: String, first: Int, last: Int): ShippingZoneCountableConnection! address: Address! email: String! } @@ -6447,10 +5067,7 @@ type WarehouseCountableEdge { } type WarehouseCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") warehouseErrors: [WarehouseError!]! warehouse: Warehouse } @@ -6465,10 +5082,7 @@ input WarehouseCreateInput { } type WarehouseDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") warehouseErrors: [WarehouseError!]! warehouse: Warehouse } @@ -6494,19 +5108,13 @@ input WarehouseFilterInput { } type WarehouseShippingZoneAssign { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") warehouse: Warehouse warehouseErrors: [WarehouseError!]! } type WarehouseShippingZoneUnassign { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") warehouse: Warehouse warehouseErrors: [WarehouseError!]! } @@ -6521,10 +5129,7 @@ input WarehouseSortingInput { } type WarehouseUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") warehouseErrors: [WarehouseError!]! warehouse: Warehouse } @@ -6539,12 +5144,13 @@ input WarehouseUpdateInput { type Webhook implements Node { name: String! - serviceAccount: ServiceAccount! targetUrl: String! isActive: Boolean! secretKey: String id: ID! events: [WebhookEvent!]! + serviceAccount: ServiceAccount! @deprecated(reason: "Use the `app` field instead. This field will be removed after 2020-07-31.") + app: App! } type WebhookCountableConnection { @@ -6559,10 +5165,7 @@ type WebhookCountableEdge { } type WebhookCreate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") webhookErrors: [WebhookError!]! webhook: Webhook } @@ -6572,15 +5175,13 @@ input WebhookCreateInput { targetUrl: String events: [WebhookEventTypeEnum] serviceAccount: ID + app: ID isActive: Boolean secretKey: String } type WebhookDelete { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") webhook: Webhook webhookErrors: [WebhookError!]! } @@ -6638,6 +5239,7 @@ enum WebhookSortField { NAME SERVICE_ACCOUNT TARGET_URL + APP } input WebhookSortingInput { @@ -6646,10 +5248,7 @@ input WebhookSortingInput { } type WebhookUpdate { - errors: [Error!]! - @deprecated( - reason: "Use typed errors with error codes. This field will be removed after 2020-07-31." - ) + errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") webhook: Webhook webhookErrors: [WebhookError!]! } @@ -6659,6 +5258,7 @@ input WebhookUpdateInput { targetUrl: String events: [WebhookEventTypeEnum] serviceAccount: ID + app: ID isActive: Boolean secretKey: String } @@ -6679,17 +5279,7 @@ enum WeightUnitsEnum { scalar _Any -union _Entity = - Address - | ServiceAccount - | User - | Group - | ProductVariant - | Product - | ProductType - | Collection - | Category - | ProductImage +union _Entity = Address | User | Group | ServiceAccount | App | ProductVariant | Product | ProductType | Collection | Category | ProductImage type _Service { sdl: String diff --git a/src/products/mutations.ts b/src/products/mutations.ts index f90b9c313..2206e56a0 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -300,7 +300,6 @@ export const productCreateMutation = gql` $basePrice: Decimal $productType: ID! $sku: String - $stockQuantity: Int $seo: SeoInput $stocks: [StockInput!]! $trackInventory: Boolean! @@ -318,7 +317,6 @@ export const productCreateMutation = gql` basePrice: $basePrice productType: $productType sku: $sku - quantity: $stockQuantity seo: $seo stocks: $stocks trackInventory: $trackInventory @@ -366,7 +364,6 @@ export const variantUpdateMutation = gql` $costPrice: Decimal $priceOverride: Decimal $sku: String - $quantity: Int $trackInventory: Boolean! $stocks: [StockInput!]! ) { @@ -377,7 +374,6 @@ export const variantUpdateMutation = gql` costPrice: $costPrice priceOverride: $priceOverride sku: $sku - quantity: $quantity trackInventory: $trackInventory } ) { diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index f0b898c23..f85cef9c8 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -224,7 +224,6 @@ export interface ProductCreateVariables { basePrice?: any | null; productType: string; sku?: string | null; - stockQuantity?: number | null; seo?: SeoInput | null; stocks: StockInput[]; trackInventory: boolean; diff --git a/src/products/types/VariantUpdate.ts b/src/products/types/VariantUpdate.ts index 27546842c..ca646c23d 100644 --- a/src/products/types/VariantUpdate.ts +++ b/src/products/types/VariantUpdate.ts @@ -264,7 +264,6 @@ export interface VariantUpdateVariables { costPrice?: any | null; priceOverride?: any | null; sku?: string | null; - quantity?: number | null; trackInventory: boolean; stocks: StockInput[]; } diff --git a/src/products/views/ProductVariantCreate.tsx b/src/products/views/ProductVariantCreate.tsx index 5c69cc919..aeeb3643a 100644 --- a/src/products/views/ProductVariantCreate.tsx +++ b/src/products/views/ProductVariantCreate.tsx @@ -98,7 +98,6 @@ export const ProductVariant: React.FC = ({ costPrice: decimal(formData.costPrice), priceOverride: decimal(formData.priceOverride), product: productId, - quantity: parseInt(formData.quantity, 0), sku: formData.sku, stocks: formData.stocks.map(stock => ({ quantity: parseInt(stock.value, 0), diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index b9656c878..5ba44dd88 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -1223,9 +1223,9 @@ export interface ProductVariantBulkCreateInput { costPrice?: any | null; priceOverride?: any | null; sku: string; - stocks: StockInput[]; trackInventory?: boolean | null; weight?: any | null; + stocks?: StockInput[] | null; } export interface ProductVariantCreateInput { @@ -1233,7 +1233,6 @@ export interface ProductVariantCreateInput { costPrice?: any | null; priceOverride?: any | null; sku?: string | null; - quantity?: number | null; trackInventory?: boolean | null; weight?: any | null; product: string; @@ -1245,7 +1244,6 @@ export interface ProductVariantInput { costPrice?: any | null; priceOverride?: any | null; sku?: string | null; - quantity?: number | null; trackInventory?: boolean | null; weight?: any | null; } @@ -1459,6 +1457,7 @@ export interface WarehouseCreateInput { export interface WarehouseFilterInput { search?: string | null; + ids?: (string | null)[] | null; } export interface WarehouseSortingInput { From 596cc41a7f98fe5b63b16a18d8e5305e24496f0f Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 22 Apr 2020 00:37:06 +0200 Subject: [PATCH 68/88] Add warehouse info --- .../OrderFulfillment/OrderFulfillment.tsx | 58 +++++++++++++++---- src/orders/fixtures.ts | 2 +- src/orders/queries.ts | 29 ++++++---- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx index 2a43cd0c7..1f778f5e4 100644 --- a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx +++ b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx @@ -9,6 +9,7 @@ import TableRow from "@material-ui/core/TableRow"; import Typography from "@material-ui/core/Typography"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; +import classNames from "classnames"; import CardMenu from "@saleor/components/CardMenu"; import CardTitle from "@saleor/components/CardTitle"; @@ -46,7 +47,15 @@ const useStyles = makeStyles( textAlign: "right", width: 120 }, - + infoLabel: { + display: "inline-block" + }, + infoLabelWithMargin: { + marginBottom: theme.spacing() + }, + infoRow: { + padding: theme.spacing(2, 3) + }, orderNumber: { display: "inline", marginLeft: theme.spacing(1) @@ -68,7 +77,7 @@ interface OrderFulfillmentProps { onTrackingCodeAdd: () => void; } -const numberOfColumns = 3; +const numberOfColumns = 4; const OrderFulfillment: React.FC = props => { const { @@ -216,18 +225,47 @@ const OrderFulfillment: React.FC = props => { ))} - {maybe(() => fulfillment.trackingNumber) && ( - - + + + + default + + ) }} /> - - - )} + + + {fulfillment?.trackingNumber && ( + + {fulfillment.trackingNumber} + + ) + }} + /> + )} + + + {status === FulfillmentStatus.FULFILLED && !fulfillment.trackingNumber && ( diff --git a/src/orders/fixtures.ts b/src/orders/fixtures.ts index a07af34ac..c08cf001f 100644 --- a/src/orders/fixtures.ts +++ b/src/orders/fixtures.ts @@ -905,7 +905,7 @@ export const order = (placeholder: string): OrderDetails_order => ({ } ], status: FulfillmentStatus.FULFILLED, - trackingNumber: "" + trackingNumber: "01nn12399su12nndfsy" } ], id: "T3JkZXI6OQ==", diff --git a/src/orders/queries.ts b/src/orders/queries.ts index 896a2f665..b69b3c65c 100644 --- a/src/orders/queries.ts +++ b/src/orders/queries.ts @@ -73,11 +73,28 @@ export const fragmentOrderLine = gql` } } `; +export const fulfillmentFragment = gql` + ${fragmentOrderLine} + fragment FulfillmentFragment on Fulfillment { + id + lines { + id + quantity + orderLine { + ...OrderLineFragment + } + } + fulfillmentOrder + status + trackingNumber + } +`; export const fragmentOrderDetails = gql` ${fragmentAddress} ${fragmentOrderEvent} ${fragmentOrderLine} + ${fulfillmentFragment} fragment OrderDetailsFragment on Order { id billingAddress { @@ -90,17 +107,7 @@ export const fragmentOrderDetails = gql` ...OrderEventFragment } fulfillments { - id - lines { - id - quantity - orderLine { - ...OrderLineFragment - } - } - fulfillmentOrder - status - trackingNumber + ...FulfillmentFragment } lines { ...OrderLineFragment From 7cc3492e71a7d8509ad372330171f28d4199a601 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 22 Apr 2020 01:09:51 +0200 Subject: [PATCH 69/88] Add warehouse selection to restock items --- src/intl.ts | 4 + .../OrderFulfillment/OrderFulfillment.tsx | 2 +- .../OrderFulfillmentCancelDialog.tsx | 155 +++++++++++------- .../orders/OrderFulfillmentCancelDialog.tsx | 4 +- 4 files changed, 102 insertions(+), 63 deletions(-) diff --git a/src/intl.ts b/src/intl.ts index 2f8841205..68b4efd27 100644 --- a/src/intl.ts +++ b/src/intl.ts @@ -81,6 +81,10 @@ export const commonMessages = defineMessages({ }); export const buttonMessages = defineMessages({ + accept: { + defaultMessage: "Accept", + description: "button" + }, back: { defaultMessage: "Back", description: "button" diff --git a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx index 1f778f5e4..435cf5b59 100644 --- a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx +++ b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx @@ -144,7 +144,7 @@ const OrderFulfillment: React.FC = props => { menuItems={[ { label: intl.formatMessage({ - defaultMessage: "Cancel shipment", + defaultMessage: "Cancel Fulfillment", description: "button" }), onSelect: onOrderFulfillmentCancel diff --git a/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx b/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx index 69eab23d3..4c24797ee 100644 --- a/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx +++ b/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx @@ -11,25 +11,29 @@ import { FormattedMessage, useIntl } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox"; import Form from "@saleor/components/Form"; import { buttonMessages } from "@saleor/intl"; import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment"; import FormSpacer from "@saleor/components/FormSpacer"; import getOrderErrorMessage from "@saleor/utils/errors/order"; +import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; +import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField"; +import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; -export interface FormData { - restock: boolean; +export interface OrderFulfillmentCancelDialogFormData { + warehouse: string; } const useStyles = makeStyles( theme => ({ - deleteButton: { - "&:hover": { - backgroundColor: theme.palette.error.main - }, - backgroundColor: theme.palette.error.main, - color: theme.palette.error.contrastText + enableOverflow: { + overflow: "visible" + }, + paragraph: { + marginBottom: theme.spacing(2) + }, + selectCcontainer: { + width: "60%" } }), { name: "OrderFulfillmentCancelDialog" } @@ -39,69 +43,98 @@ export interface OrderFulfillmentCancelDialogProps { confirmButtonState: ConfirmButtonTransitionState; errors: OrderErrorFragment[]; open: boolean; + warehouses: WarehouseFragment[]; onClose(); - onConfirm(data: FormData); + onConfirm(data: OrderFulfillmentCancelDialogFormData); } const OrderFulfillmentCancelDialog: React.FC = props => { - const { confirmButtonState, errors, open, onConfirm, onClose } = props; + const { + confirmButtonState, + errors, + open, + warehouses, + onConfirm, + onClose + } = props; const classes = useStyles(props); const intl = useIntl(); + const [displayValue, setDisplayValue] = React.useState(""); + + const choices = warehouses?.map(warehouse => ({ + label: warehouse.name, + value: warehouse.id + })); return ( - - - {({ change, data, submit }) => ( - <> - - - - - - - - - {errors.length > 0 && ( - <> - - {errors.map(err => ( - - {getOrderErrorMessage(err, intl)} - - ))} - - )} - - - - + + + {({ change, data: formData, submit }) => { + const handleChange = createSingleAutocompleteSelectHandler( + change, + setDisplayValue, + choices + ); + return ( + <> + - - - - )} + + + + + +
+ +
+ {errors.length > 0 && ( + <> + + {errors.map(err => ( + + {getOrderErrorMessage(err, intl)} + + ))} + + )} +
+ + + + + + + + ); + }}
); diff --git a/src/storybook/stories/orders/OrderFulfillmentCancelDialog.tsx b/src/storybook/stories/orders/OrderFulfillmentCancelDialog.tsx index 33277fbaa..eb9fd4f3c 100644 --- a/src/storybook/stories/orders/OrderFulfillmentCancelDialog.tsx +++ b/src/storybook/stories/orders/OrderFulfillmentCancelDialog.tsx @@ -2,6 +2,7 @@ import { storiesOf } from "@storybook/react"; import React from "react"; import { OrderErrorCode } from "@saleor/types/globalTypes"; +import { warehouseList } from "@saleor/warehouses/fixtures"; import OrderFulfillmentCancelDialog, { OrderFulfillmentCancelDialogProps } from "../../../orders/components/OrderFulfillmentCancelDialog"; @@ -12,7 +13,8 @@ const props: OrderFulfillmentCancelDialogProps = { errors: [], onClose: () => undefined, onConfirm: () => undefined, - open: true + open: true, + warehouses: warehouseList }; storiesOf("Orders / OrderFulfillmentCancelDialog", module) From bc15224fcd362b4ccdf9c43199cbf87ccfec4dfa Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 22 Apr 2020 01:14:04 +0200 Subject: [PATCH 70/88] Refactor message and remove restock checkbox --- .../OrderCancelDialog/OrderCancelDialog.tsx | 121 ++++++------------ 1 file changed, 38 insertions(+), 83 deletions(-) diff --git a/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx b/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx index b65368c00..dc2a21fc9 100644 --- a/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx +++ b/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx @@ -4,45 +4,25 @@ import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import DialogContentText from "@material-ui/core/DialogContentText"; import DialogTitle from "@material-ui/core/DialogTitle"; -import { makeStyles } from "@material-ui/core/styles"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; -import Form from "@saleor/components/Form"; import { buttonMessages } from "@saleor/intl"; import { OrderErrorFragment } from "@saleor/orders/types/OrderErrorFragment"; import FormSpacer from "@saleor/components/FormSpacer"; import getOrderErrorMessage from "@saleor/utils/errors/order"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; -export interface FormData { - restock: boolean; -} - -const useStyles = makeStyles( - theme => ({ - deleteButton: { - "&:hover": { - backgroundColor: theme.palette.error.main - }, - backgroundColor: theme.palette.error.main, - color: theme.palette.error.contrastText - } - }), - { name: "OrderCancelDialog" } -); - export interface OrderCancelDialogProps { confirmButtonState: ConfirmButtonTransitionState; errors: OrderErrorFragment[]; number: string; open: boolean; onClose?(); - onSubmit(data: FormData); + onSubmit(); } const OrderCancelDialog: React.FC = props => { @@ -55,76 +35,51 @@ const OrderCancelDialog: React.FC = props => { onClose } = props; - const classes = useStyles(props); const intl = useIntl(); const errors = useModalDialogErrors(apiErrors, open); return ( - -
- {({ data, change }) => ( + + + + + + + + + {errors.length > 0 && ( <> - - - - - - - + + {errors.map(err => ( + + {getOrderErrorMessage(err, intl)} - {errors.length > 0 && ( - <> - - {errors.map(err => ( - - {getOrderErrorMessage(err, intl)} - - ))} - - )} - - - - - - - + ))} )} - + + + + + + +
); }; From 27a740ed6b6c62b5561d1b0841670abb666fc809 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 27 Apr 2020 16:26:57 +0200 Subject: [PATCH 71/88] Fix warehouse selection --- .../components/OrderFulfillment/OrderFulfillment.tsx | 4 ++-- .../OrderFulfillmentCancelDialog.tsx | 9 +++++---- src/orders/views/OrderDetails/index.tsx | 12 ++++++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx index 435cf5b59..73d1d0ddf 100644 --- a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx +++ b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx @@ -116,8 +116,8 @@ const OrderFulfillment: React.FC = props => { ) : intl.formatMessage( { - defaultMessage: "Fulfilled ({quantity})", - description: "section header" + defaultMessage: "Cancelled ({quantity})", + description: "cancelled fulfillment, section header" }, { quantity diff --git a/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx b/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx index 4c24797ee..653b865b1 100644 --- a/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx +++ b/src/orders/components/OrderFulfillmentCancelDialog/OrderFulfillmentCancelDialog.tsx @@ -21,7 +21,7 @@ import SingleAutocompleteSelectField from "@saleor/components/SingleAutocomplete import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; export interface OrderFulfillmentCancelDialogFormData { - warehouse: string; + warehouseId: string; } const useStyles = makeStyles( @@ -77,7 +77,7 @@ const OrderFulfillmentCancelDialog: React.FC fullWidth maxWidth="sm" > -
+ {({ change, data: formData, submit }) => { const handleChange = createSingleAutocompleteSelectHandler( change, @@ -104,8 +104,8 @@ const OrderFulfillmentCancelDialog: React.FC defaultMessage: "Select Warehouse", description: "select warehouse to restock items" })} - name="warehouse" - value={formData.warehouse} + name="warehouseId" + value={formData.warehouseId} onChange={handleChange} />
@@ -125,6 +125,7 @@ const OrderFulfillmentCancelDialog: React.FC = ({ id, params }) => { } = useOrderVariantSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); + const warehouses = useWarehouseList({ + displayLoader: true, + variables: { + first: 30 + } + }); const intl = useIntl(); const [openModal, closeModal] = createDialogActionHandlers< @@ -339,6 +346,11 @@ export const OrderDetails: React.FC = ({ id, params }) => { ?.orderFulfillmentCancel.errors || [] } open={params.action === "cancel-fulfillment"} + warehouses={ + warehouses.data?.warehouses.edges.map( + edge => edge.node + ) || [] + } onConfirm={variables => orderFulfillmentCancel.mutate({ id: params.id, From 9812277e9a41b5ce5ba565191b509a471d607757 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 20 Apr 2020 11:37:32 +0200 Subject: [PATCH 72/88] wip --- src/hooks/useFormset.ts | 4 +- .../OrderFulfillPage.stories.tsx | 28 ++ .../OrderFulfillPage/OrderFulfillPage.tsx | 270 ++++++++++++++++++ .../components/OrderFulfillPage/fixtures.ts | 163 +++++++++++ .../components/OrderFulfillPage/index.ts | 2 + src/orders/queries.ts | 45 +++ src/orders/types/OrderFulfillData.ts | 70 +++++ .../views/OrderFulfill/OrderFulfill.tsx | 0 src/orders/views/OrderFulfill/index.ts | 0 9 files changed, 580 insertions(+), 2 deletions(-) create mode 100644 src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx create mode 100644 src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx create mode 100644 src/orders/components/OrderFulfillPage/fixtures.ts create mode 100644 src/orders/components/OrderFulfillPage/index.ts create mode 100644 src/orders/types/OrderFulfillData.ts create mode 100644 src/orders/views/OrderFulfill/OrderFulfill.tsx create mode 100644 src/orders/views/OrderFulfill/index.ts diff --git a/src/hooks/useFormset.ts b/src/hooks/useFormset.ts index 8891d48b5..eb506e272 100644 --- a/src/hooks/useFormset.ts +++ b/src/hooks/useFormset.ts @@ -18,8 +18,8 @@ export interface UseFormsetOutput { set: (data: FormsetData) => void; } function useFormset( - initial: FormsetData -): UseFormsetOutput { + initial: FormsetData +): UseFormsetOutput { const [data, setData] = useStateFromProps>( initial || [] ); diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx new file mode 100644 index 000000000..58e12a34b --- /dev/null +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx @@ -0,0 +1,28 @@ +import { storiesOf } from "@storybook/react"; +import React from "react"; + +import Decorator from "@saleor/storybook/Decorator"; +import { warehouseList } from "@saleor/warehouses/fixtures"; +import OrderFulfillPage, { OrderFulfillPageProps } from "./OrderFulfillPage"; +import { orderToFulfill } from "./fixtures"; + +const props: OrderFulfillPageProps = { + disabled: false, + onBack: () => undefined, + onSubmit: () => undefined, + order: orderToFulfill, + saveButtonBar: "default", + warehouses: warehouseList +}; + +storiesOf("Views / Orders / Fulfill order", module) + .addDecorator(Decorator) + .add("default", () => ) + .add("loading", () => ( + + )); diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx new file mode 100644 index 000000000..fecf6dcda --- /dev/null +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -0,0 +1,270 @@ +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; +import Card from "@material-ui/core/Card"; +import Typography from "@material-ui/core/Typography"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableHead from "@material-ui/core/TableHead"; +import TableRow from "@material-ui/core/TableRow"; +import TextField from "@material-ui/core/TextField"; +import classNames from "classnames"; + +import useFormset, { FormsetData } from "@saleor/hooks/useFormset"; +import { StockInput } from "@saleor/types/globalTypes"; +import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; +import TableCellAvatar, { + AVATAR_MARGIN +} from "@saleor/components/TableCellAvatar"; +import Container from "@saleor/components/Container"; +import PageHeader from "@saleor/components/PageHeader"; +import SaveButtonBar from "@saleor/components/SaveButtonBar"; +import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; +import Form from "@saleor/components/Form"; +import { OrderFulfillData_order } from "@saleor/orders/types/OrderFulfillData"; +import CardTitle from "@saleor/components/CardTitle"; +import ResponsiveTable from "@saleor/components/ResponsiveTable"; +import makeStyles from "@material-ui/core/styles/makeStyles"; + +const useStyles = makeStyles( + theme => ({ + colName: { + width: 300 + }, + colNameLabel: { + marginLeft: AVATAR_MARGIN + }, + colQuantity: { + textAlign: "right", + width: 200 + }, + colQuantityContent: { + alignItems: "center", + display: "inline-flex" + }, + colQuantityTotal: { + textAlign: "right", + width: 180 + }, + colSku: { + textAlign: "right", + width: 120 + }, + error: { + color: theme.palette.error.main + }, + quantityInput: { + width: "4rem" + }, + remainingQuantity: { + marginLeft: theme.spacing(), + paddingTop: 14 + }, + table: { + "&&": { + tableLayout: "fixed" + } + } + }), + { name: "OrderFulfillPage" } +); + +interface OrderFulfillFormData { + sendInfo: boolean; +} +interface OrderFulfillSubmitData extends OrderFulfillFormData { + items: FormsetData; +} +export interface OrderFulfillPageProps { + disabled: boolean; + order: OrderFulfillData_order; + saveButtonBar: ConfirmButtonTransitionState; + warehouses: WarehouseFragment[]; + onBack: () => undefined; + onSubmit: (data: OrderFulfillSubmitData) => void; +} + +const initialFormData: OrderFulfillFormData = { + sendInfo: true +}; + +const OrderFulfillPage: React.FC = ({ + disabled, + order, + saveButtonBar, + warehouses, + onBack, + onSubmit +}) => { + const intl = useIntl(); + const classes = useStyles({}); + + const { change, data: formsetData } = useFormset( + order?.lines.map(line => ({ + data: null, + id: line.id, + label: line.variant.attributes + .map(attribute => + attribute.values + .map(attributeValue => attributeValue.name) + .join(" , ") + ) + .join(" / "), + value: line.variant.stocks.map(stock => ({ + quantity: 0, + warehouse: stock.warehouse.id + })) + })) + ); + + const handleSubmit = (formData: OrderFulfillFormData) => + onSubmit({ + ...formData, + items: formsetData + }); + + return ( + + + + {({ change, data, submit }) => ( + <> + + + + + + + + + + + + + + {warehouses.map(warehouse => ( + + {warehouse.name} + + ))} + + + + + + + {order?.lines.map((line, lineIndex) => { + const remainingQuantity = + line.quantity - line.quantityFulfilled; + + return ( + + + {line.productName} + + + {line.variant.sku} + + {warehouses.map(warehouse => { + const warehouseStock = line.variant.stocks.find( + stock => stock.warehouse.id === warehouse.id + ); + if (!warehouseStock) { + return ( + + + + ); + } + + return ( + +
+ undefined} + error={ + remainingQuantity < + formsetData[lineIndex].value[0] + .quantity || + formsetData[lineIndex].value[0].quantity > + warehouseStock.quantity + } + /> +
+ / {warehouseStock.quantity} +
+
+
+ ); + })} + + {formsetData[lineIndex].value.reduce( + (acc, stock) => acc + stock.quantity, + 0 + )}{" "} + / {remainingQuantity} + +
+ ); + })} +
+
+
+ + + )} + +
+ ); +}; + +OrderFulfillPage.displayName = "OrderFulfillPage"; +export default OrderFulfillPage; diff --git a/src/orders/components/OrderFulfillPage/fixtures.ts b/src/orders/components/OrderFulfillPage/fixtures.ts new file mode 100644 index 000000000..1e72213aa --- /dev/null +++ b/src/orders/components/OrderFulfillPage/fixtures.ts @@ -0,0 +1,163 @@ +/* eslint-disable sort-keys */ + +import { OrderFulfillData_order } from "@saleor/orders/types/OrderFulfillData"; +import { warehouseList } from "@saleor/warehouses/fixtures"; +import * as placeholderImage from "@assets/images/sample-product.jpg"; + +export const orderToFulfill: OrderFulfillData_order = { + __typename: "Order", + id: "T3JkZXI6Mg==", + lines: [ + { + __typename: "OrderLine", + id: "T3JkZXJMaW5lOjQ=", + isShippingRequired: true, + productName: "T-Shirt", + quantity: 3, + quantityFulfilled: 1, + variant: { + __typename: "ProductVariant", + id: "UHJvZHVjdFZhcmlhbnQ6Mjk2", + name: "S", + sku: "62783187", + attributes: [ + { + __typename: "SelectedAttribute", + values: [ + { + __typename: "AttributeValue", + id: "QXR0cmlidXRlVmFsdWU6MzY=", + name: "S" + } + ] + } + ], + stocks: [ + { + __typename: "Stock", + id: "U3RvY2s6NTIy", + warehouse: warehouseList[0], + quantity: 1217 + }, + { + __typename: "Stock", + id: "U3RvY2s6NTIx", + warehouse: warehouseList[1], + quantity: 1217 + }, + { + __typename: "Stock", + id: "U3RvY2s6NTIz", + warehouse: warehouseList[2], + quantity: 1217 + }, + { + __typename: "Stock", + id: "U3RvY2s6NTI0", + warehouse: warehouseList[3], + quantity: 1220 + } + ] + }, + thumbnail: { + __typename: "Image", + url: placeholderImage + } + }, + { + __typename: "OrderLine", + id: "T3JkZXJMaW5lOjU=", + isShippingRequired: true, + productName: "Lemon Juice", + quantity: 4, + quantityFulfilled: 0, + variant: { + __typename: "ProductVariant", + id: "UHJvZHVjdFZhcmlhbnQ6MTgx", + name: "2.5l", + sku: "998323583", + attributes: [ + { + __typename: "SelectedAttribute", + values: [ + { + __typename: "AttributeValue", + id: "QXR0cmlidXRlVmFsdWU6NjE=", + name: "2.5l" + } + ] + } + ], + stocks: [ + { + __typename: "Stock", + id: "U3RvY2s6NTI=", + warehouse: warehouseList[1], + quantity: 760 + }, + { + __typename: "Stock", + id: "U3RvY2s6NTE=", + warehouse: warehouseList[2], + quantity: 760 + }, + { + __typename: "Stock", + id: "U3RvY2s6NTM=", + warehouse: warehouseList[3], + quantity: 760 + } + ] + }, + thumbnail: { + __typename: "Image", + url: placeholderImage + } + }, + { + __typename: "OrderLine", + id: "T3JkZXJMaW5lOjY=", + isShippingRequired: true, + productName: "Orange Juice", + quantity: 3, + quantityFulfilled: 2, + variant: { + __typename: "ProductVariant", + id: "UHJvZHVjdFZhcmlhbnQ6MTgy", + name: "5l", + sku: "998323584", + attributes: [ + { + __typename: "SelectedAttribute", + values: [ + { + __typename: "AttributeValue", + id: "QXR0cmlidXRlVmFsdWU6NjI=", + name: "5l" + } + ] + } + ], + stocks: [ + { + __typename: "Stock", + id: "U3RvY2s6NTc=", + warehouse: warehouseList[0], + quantity: 587 + }, + { + __typename: "Stock", + id: "U3RvY2s6NTY=", + warehouse: warehouseList[2], + quantity: 587 + } + ] + }, + thumbnail: { + __typename: "Image", + url: placeholderImage + } + } + ], + number: "9123" +}; diff --git a/src/orders/components/OrderFulfillPage/index.ts b/src/orders/components/OrderFulfillPage/index.ts new file mode 100644 index 000000000..064e689ba --- /dev/null +++ b/src/orders/components/OrderFulfillPage/index.ts @@ -0,0 +1,2 @@ +export * from "./OrderFulfillPage"; +export { default } from "./OrderFulfillPage"; diff --git a/src/orders/queries.ts b/src/orders/queries.ts index b69b3c65c..4089d9ded 100644 --- a/src/orders/queries.ts +++ b/src/orders/queries.ts @@ -13,6 +13,10 @@ import { SearchOrderVariant as SearchOrderVariantType, SearchOrderVariantVariables } from "./types/SearchOrderVariant"; +import { + OrderFulfillData, + OrderFulfillDataVariables +} from "./types/OrderFulfillData"; export const fragmentOrderEvent = gql` fragment OrderEventFragment on OrderEvent { @@ -334,3 +338,44 @@ export const useOrderVariantSearch = makeTopLevelSearch< SearchOrderVariantType, SearchOrderVariantVariables >(searchOrderVariant); + +const orderFulfillData = gql` + query OrderFulfillData($orderId: ID!) { + order(id: $orderId) { + id + lines { + id + isShippingRequired + productName + quantity + quantityFulfilled + variant { + id + name + sku + attributes { + values { + id + name + } + } + stocks { + id + warehouse { + id + } + quantity + } + } + thumbnail(size: 64) { + url + } + } + number + } + } +`; +export const useOrderFulfillData = makeQuery< + OrderFulfillData, + OrderFulfillDataVariables +>(orderFulfillData); diff --git a/src/orders/types/OrderFulfillData.ts b/src/orders/types/OrderFulfillData.ts new file mode 100644 index 000000000..b9fbf9bf4 --- /dev/null +++ b/src/orders/types/OrderFulfillData.ts @@ -0,0 +1,70 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: OrderFulfillData +// ==================================================== + +export interface OrderFulfillData_order_lines_variant_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; +} + +export interface OrderFulfillData_order_lines_variant_attributes { + __typename: "SelectedAttribute"; + values: (OrderFulfillData_order_lines_variant_attributes_values | null)[]; +} + +export interface OrderFulfillData_order_lines_variant_stocks_warehouse { + __typename: "Warehouse"; + id: string; +} + +export interface OrderFulfillData_order_lines_variant_stocks { + __typename: "Stock"; + id: string; + warehouse: OrderFulfillData_order_lines_variant_stocks_warehouse; + quantity: number; +} + +export interface OrderFulfillData_order_lines_variant { + __typename: "ProductVariant"; + id: string; + name: string; + sku: string; + attributes: OrderFulfillData_order_lines_variant_attributes[]; + stocks: (OrderFulfillData_order_lines_variant_stocks | null)[] | null; +} + +export interface OrderFulfillData_order_lines_thumbnail { + __typename: "Image"; + url: string; +} + +export interface OrderFulfillData_order_lines { + __typename: "OrderLine"; + id: string; + isShippingRequired: boolean; + productName: string; + quantity: number; + quantityFulfilled: number; + variant: OrderFulfillData_order_lines_variant | null; + thumbnail: OrderFulfillData_order_lines_thumbnail | null; +} + +export interface OrderFulfillData_order { + __typename: "Order"; + id: string; + lines: (OrderFulfillData_order_lines | null)[]; + number: string | null; +} + +export interface OrderFulfillData { + order: OrderFulfillData_order | null; +} + +export interface OrderFulfillDataVariables { + orderId: string; +} diff --git a/src/orders/views/OrderFulfill/OrderFulfill.tsx b/src/orders/views/OrderFulfill/OrderFulfill.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/orders/views/OrderFulfill/index.ts b/src/orders/views/OrderFulfill/index.ts new file mode 100644 index 000000000..e69de29bb From a5c1c9d544205a50b036d706cc2387229371e9e2 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 20 Apr 2020 18:23:54 +0200 Subject: [PATCH 73/88] Create fulfillment page --- .../OrderFulfillPage/OrderFulfillPage.tsx | 116 ++++++++++++++---- .../OrderFulfillmentDialog.tsx | 2 +- 2 files changed, 91 insertions(+), 27 deletions(-) diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx index fecf6dcda..b2cd30842 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -1,20 +1,19 @@ import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; import Card from "@material-ui/core/Card"; -import Typography from "@material-ui/core/Typography"; +import CardActions from "@material-ui/core/CardActions"; import TableBody from "@material-ui/core/TableBody"; import TableCell from "@material-ui/core/TableCell"; import TableHead from "@material-ui/core/TableHead"; import TableRow from "@material-ui/core/TableRow"; import TextField from "@material-ui/core/TextField"; import classNames from "classnames"; +import Typography from "@material-ui/core/Typography"; import useFormset, { FormsetData } from "@saleor/hooks/useFormset"; import { StockInput } from "@saleor/types/globalTypes"; import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; -import TableCellAvatar, { - AVATAR_MARGIN -} from "@saleor/components/TableCellAvatar"; +import TableCellAvatar from "@saleor/components/TableCellAvatar"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; @@ -24,18 +23,21 @@ import { OrderFulfillData_order } from "@saleor/orders/types/OrderFulfillData"; import CardTitle from "@saleor/components/CardTitle"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import makeStyles from "@material-ui/core/styles/makeStyles"; +import { update } from "@saleor/utils/lists"; +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; const useStyles = makeStyles( theme => ({ + actionBar: { + flexDirection: "row", + paddingLeft: theme.spacing(2) + 2 + }, colName: { width: 300 }, - colNameLabel: { - marginLeft: AVATAR_MARGIN - }, colQuantity: { textAlign: "right", - width: 200 + width: 210 }, colQuantityContent: { alignItems: "center", @@ -52,12 +54,17 @@ const useStyles = makeStyles( error: { color: theme.palette.error.main }, + full: { + fontWeight: 600 + }, + quantityInnerInput: { + padding: "16px 0 14px 12px" + }, quantityInput: { - width: "4rem" + width: 100 }, remainingQuantity: { - marginLeft: theme.spacing(), - paddingTop: 14 + marginLeft: theme.spacing() }, table: { "&&": { @@ -98,7 +105,10 @@ const OrderFulfillPage: React.FC = ({ const intl = useIntl(); const classes = useStyles({}); - const { change, data: formsetData } = useFormset( + const { change: formsetChange, data: formsetData } = useFormset< + null, + StockInput[] + >( order?.lines.map(line => ({ data: null, id: line.id, @@ -149,9 +159,7 @@ const OrderFulfillPage: React.FC = ({ - - - + = ({ {order?.lines.map((line, lineIndex) => { const remainingQuantity = line.quantity - line.quantityFulfilled; + const quantityToFulfill = formsetData[ + lineIndex + ].value.reduce( + (quantityToFulfill, lineInput) => + quantityToFulfill + lineInput.quantity, + 0 + ); + const overfulfill = remainingQuantity < quantityToFulfill; return ( @@ -187,6 +203,15 @@ const OrderFulfillPage: React.FC = ({ thumbnail={line?.thumbnail?.url} > {line.productName} + + {line.variant.attributes + .map(attribute => + attribute.values + .map(attributeValue => attributeValue.name) + .join(", ") + ) + .join(" / ")} + {line.variant.sku} @@ -195,6 +220,10 @@ const OrderFulfillPage: React.FC = ({ const warehouseStock = line.variant.stocks.find( stock => stock.warehouse.id === warehouse.id ); + const formsetStock = formsetData[ + lineIndex + ].value.find(line => line.warehouse === warehouse.id); + if (!warehouseStock) { return ( = ({ + formsetChange( + line.id, + update( + { + quantity: parseInt( + event.target.value, + 10 + ), + warehouse: warehouse.id + }, + formsetData[lineIndex].value, + (a, b) => a.warehouse === b.warehouse + ) + ) } - onChange={event => undefined} error={ - remainingQuantity < - formsetData[lineIndex].value[0] - .quantity || - formsetData[lineIndex].value[0].quantity > + overfulfill || + formsetStock.quantity > warehouseStock.quantity } /> @@ -241,10 +283,15 @@ const OrderFulfillPage: React.FC = ({ ); })} - {formsetData[lineIndex].value.reduce( - (acc, stock) => acc + stock.quantity, - 0 - )}{" "} + + {quantityToFulfill} + {" "} / {remainingQuantity} @@ -252,9 +299,26 @@ const OrderFulfillPage: React.FC = ({ })} + + + Date: Mon, 20 Apr 2020 19:18:20 +0200 Subject: [PATCH 74/88] Add fulfillment view --- .../OrderFulfillPage/OrderFulfillPage.tsx | 32 +++++++++++++-- src/orders/index.tsx | 9 +++- src/orders/urls.ts | 6 ++- src/orders/views/OrderDetails/index.tsx | 39 ++---------------- .../views/OrderFulfill/OrderFulfill.tsx | 41 +++++++++++++++++++ src/orders/views/OrderFulfill/index.ts | 2 + 6 files changed, 87 insertions(+), 42 deletions(-) diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx index b2cd30842..2e6ff2c74 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -25,6 +25,8 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable"; import makeStyles from "@material-ui/core/styles/makeStyles"; import { update } from "@saleor/utils/lists"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import { renderCollection } from "@saleor/misc"; +import Skeleton from "@saleor/components/Skeleton"; const useStyles = makeStyles( theme => ({ @@ -86,7 +88,7 @@ export interface OrderFulfillPageProps { order: OrderFulfillData_order; saveButtonBar: ConfirmButtonTransitionState; warehouses: WarehouseFragment[]; - onBack: () => undefined; + onBack: () => void; onSubmit: (data: OrderFulfillSubmitData) => void; } @@ -167,7 +169,7 @@ const OrderFulfillPage: React.FC = ({ description="product's sku" /> - {warehouses.map(warehouse => ( + {warehouses?.map(warehouse => ( = ({ - {order?.lines.map((line, lineIndex) => { + {renderCollection(order?.lines, (line, lineIndex) => { + if (!line) { + return ( + + + + + + + + {warehouses?.map(() => ( + + + + ))} + + {" "} + + + + ); + } + const remainingQuantity = line.quantity - line.quantityFulfilled; const quantityToFulfill = formsetData[ @@ -216,7 +240,7 @@ const OrderFulfillPage: React.FC = ({ {line.variant.sku} - {warehouses.map(warehouse => { + {warehouses?.map(warehouse => { const warehouseStock = line.variant.stocks.find( stock => stock.warehouse.id === warehouse.id ); diff --git a/src/orders/index.tsx b/src/orders/index.tsx index 608cba793..c8db1246e 100644 --- a/src/orders/index.tsx +++ b/src/orders/index.tsx @@ -14,9 +14,11 @@ import { orderPath, OrderUrlQueryParams, OrderDraftListUrlSortField, - OrderListUrlSortField + OrderListUrlSortField, + orderFulfillPath } from "./urls"; import OrderDetailsComponent from "./views/OrderDetails"; +import OrderFulfillComponent from "./views/OrderFulfill"; import OrderDraftListComponent from "./views/OrderDraftList"; import OrderListComponent from "./views/OrderList"; @@ -57,6 +59,10 @@ const OrderDetails: React.FC> = ({ ); }; +const OrderFulfill: React.FC> = ({ match }) => ( + +); + const Component = () => { const intl = useIntl(); @@ -66,6 +72,7 @@ const Component = () => { + diff --git a/src/orders/urls.ts b/src/orders/urls.ts index c8e7e3af7..d500f7f12 100644 --- a/src/orders/urls.ts +++ b/src/orders/urls.ts @@ -97,10 +97,14 @@ export type OrderUrlDialog = | "edit-shipping" | "edit-shipping-address" | "finalize" - | "fulfill" | "mark-paid" | "refund" | "void"; export type OrderUrlQueryParams = Dialog & SingleAction; export const orderUrl = (id: string, params?: OrderUrlQueryParams) => orderPath(encodeURIComponent(id)) + "?" + stringifyQs(params); + +export const orderFulfillPath = (id: string) => + urlJoin(orderPath(id), "fulfill"); +export const orderFulfillUrl = (id: string) => + orderFulfillPath(encodeURIComponent(id)); diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index 928c44239..67fb571ff 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -26,7 +26,6 @@ import OrderDraftFinalizeDialog, { } from "../../components/OrderDraftFinalizeDialog"; import OrderDraftPage from "../../components/OrderDraftPage"; import OrderFulfillmentCancelDialog from "../../components/OrderFulfillmentCancelDialog"; -import OrderFulfillmentDialog from "../../components/OrderFulfillmentDialog"; import OrderFulfillmentTrackingDialog from "../../components/OrderFulfillmentTrackingDialog"; import OrderMarkAsPaidDialog from "../../components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog"; import OrderPaymentDialog from "../../components/OrderPaymentDialog"; @@ -40,7 +39,8 @@ import { orderListUrl, orderUrl, OrderUrlQueryParams, - OrderUrlDialog + OrderUrlDialog, + orderFulfillUrl } from "../../urls"; import { OrderDetailsMessages } from "./OrderDetailsMessages"; @@ -154,7 +154,6 @@ export const OrderDetails: React.FC = ({ id, params }) => { {({ orderAddNote, orderCancel, - orderCreateFulfillment, orderDraftUpdate, orderLinesAdd, orderLineDelete, @@ -201,7 +200,7 @@ export const OrderDetails: React.FC = ({ id, params }) => { )} userPermissions={user?.userPermissions || []} onOrderCancel={() => openModal("cancel")} - onOrderFulfill={() => openModal("fulfill")} + onOrderFulfill={() => navigate(orderFulfillUrl(id))} onFulfillmentCancel={fulfillmentId => navigate( orderUrl(id, { @@ -305,38 +304,6 @@ export const OrderDetails: React.FC = ({ id, params }) => { }) } /> - order.lines, []).filter( - line => line.quantityFulfilled < line.quantity - )} - onClose={closeModal} - onSubmit={variables => - orderCreateFulfillment.mutate({ - input: { - ...variables, - lines: maybe(() => order.lines, []) - .filter( - line => - line.quantityFulfilled < line.quantity - ) - .map((line, lineIndex) => ({ - orderLineId: line.id, - quantity: variables.lines[lineIndex] - })) - .filter(line => line.quantity > 0) - }, - order: order.id - }) - } - /> = ({ orderId }) => { + const navigate = useNavigator(); + const { data, loading } = useOrderFulfillData({ + displayLoader: true, + variables: { + orderId + } + }); + const { data: warehouseData, loading: warehousesLoading } = useWarehouseList({ + displayLoader: true, + variables: { + first: 20 + } + }); + + return ( + navigate(orderUrl(orderId))} + onSubmit={() => undefined} + order={data?.order} + saveButtonBar="default" + warehouses={warehouseData?.warehouses.edges.map(edge => edge.node)} + /> + ); +}; + +OrderFulfill.displayName = "OrderFulfill"; +export default OrderFulfill; diff --git a/src/orders/views/OrderFulfill/index.ts b/src/orders/views/OrderFulfill/index.ts index e69de29bb..62368b27d 100644 --- a/src/orders/views/OrderFulfill/index.ts +++ b/src/orders/views/OrderFulfill/index.ts @@ -0,0 +1,2 @@ +export * from "./OrderFulfill"; +export { default } from "./OrderFulfill"; From 0f52e427cbecae73b9dfb1a4eb9216e8248cb975 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 20 Apr 2020 19:24:54 +0200 Subject: [PATCH 75/88] Add back button --- .../OrderFulfillPage/OrderFulfillPage.tsx | 17 ++++++++ .../views/OrderFulfill/OrderFulfill.tsx | 39 +++++++++++++++---- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx index 2e6ff2c74..fe3977e45 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -27,6 +27,7 @@ import { update } from "@saleor/utils/lists"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import { renderCollection } from "@saleor/misc"; import Skeleton from "@saleor/components/Skeleton"; +import AppHeader from "@saleor/components/AppHeader"; const useStyles = makeStyles( theme => ({ @@ -136,6 +137,22 @@ const OrderFulfillPage: React.FC = ({ return ( + + {order?.number + ? intl.formatMessage( + { + defaultMessage: "Order #{orderNumber}", + description: "page header with order number" + }, + { + orderNumber: order.number + } + ) + : intl.formatMessage({ + defaultMessage: "Order", + description: "page header" + })} + = ({ orderId }) => { const navigate = useNavigator(); + const intl = useIntl(); const { data, loading } = useOrderFulfillData({ displayLoader: true, variables: { @@ -26,14 +29,34 @@ const OrderFulfill: React.FC = ({ orderId }) => { }); return ( - navigate(orderUrl(orderId))} - onSubmit={() => undefined} - order={data?.order} - saveButtonBar="default" - warehouses={warehouseData?.warehouses.edges.map(edge => edge.node)} - /> + <> + + navigate(orderUrl(orderId))} + onSubmit={() => undefined} + order={data?.order} + saveButtonBar="default" + warehouses={warehouseData?.warehouses.edges.map(edge => edge.node)} + /> + ); }; From c4fdfd2498fff14b5e5c9f6adc06ee9266ba8605 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 20 Apr 2020 19:29:00 +0200 Subject: [PATCH 76/88] Update stories --- .../__snapshots__/Stories.test.ts.snap | 853 ++++++++++++++++++ 1 file changed, 853 insertions(+) diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 414ab8bd1..8377e828e 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -64308,6 +64308,859 @@ exports[`Storyshots Views / Orders / Draft order list when no data 1`] = `
`; +exports[`Storyshots Views / Orders / Fulfill order default 1`] = ` +
+
+
+
+ Order no. 9123 - Add Fulfillment +
+
+
+
+
+
+
+
+ + Items ready to ship + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Product name + + SKU + + C our wares + + Be stocked + + A Warehouse + + Darkwares + + Quantity to fulfill +
+
+
+ +
+
+ T-Shirt +
+ S +
+
+
+
+ 62783187 + +
+
+
+ + +
+
+
+ / 1217 +
+
+
+
+
+
+ + +
+
+
+ / 1217 +
+
+
+
+
+
+ + +
+
+
+ / 1217 +
+
+
+
+
+
+ + +
+
+
+ / 1220 +
+
+
+ + 0 + + / 2 +
+
+
+ +
+
+ Lemon Juice +
+ 2.5l +
+
+
+
+ 998323583 + + No Stock + +
+
+
+ + +
+
+
+ / 760 +
+
+
+
+
+
+ + +
+
+
+ / 760 +
+
+
+
+
+
+ + +
+
+
+ / 760 +
+
+
+ + 0 + + / 4 +
+
+
+ +
+
+ Orange Juice +
+ 5l +
+
+
+
+ 998323584 + +
+
+
+ + +
+
+
+ / 587 +
+
+
+ No Stock + +
+
+
+ + +
+
+
+ / 587 +
+
+
+ No Stock + + + 0 + + / 1 +
+
+
+ +
+
+ +
+
+`; + +exports[`Storyshots Views / Orders / Fulfill order loading 1`] = ` +
+
+
+
+ Order no. - Add Fulfillment +
+
+
+
+
+
+
+
+ + Items ready to ship + +
+
+
+
+
+ + + + + + + + + + + + + + + +
+ Product name + + SKU + + Quantity to fulfill +
+
+
+ +
+
+ + ‌ + +
+
+
+ + ‌ + + + + + ‌ + +
+
+
+ +
+
+ +
+
+`; + exports[`Storyshots Views / Orders / Order details cancelled 1`] = `
Date: Tue, 21 Apr 2020 13:13:39 +0200 Subject: [PATCH 77/88] Use quantityAllocated --- .../OrderFulfillPage/OrderFulfillPage.tsx | 11 +++++--- .../components/OrderFulfillPage/fixtures.ts | 27 ++++++++++++------- src/orders/queries.ts | 1 + src/orders/types/OrderFulfillData.ts | 1 + .../__snapshots__/Stories.test.ts.snap | 16 +++++------ 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx index fe3977e45..a0c30050d 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -232,7 +232,7 @@ const OrderFulfillPage: React.FC = ({ lineIndex ].value.reduce( (quantityToFulfill, lineInput) => - quantityToFulfill + lineInput.quantity, + quantityToFulfill + (lineInput.quantity || 0), 0 ); const overfulfill = remainingQuantity < quantityToFulfill; @@ -281,6 +281,10 @@ const OrderFulfillPage: React.FC = ({ ); } + const availableQuantity = + warehouseStock.quantity - + warehouseStock.quantityAllocated; + return (
@@ -312,12 +316,11 @@ const OrderFulfillPage: React.FC = ({ } error={ overfulfill || - formsetStock.quantity > - warehouseStock.quantity + formsetStock.quantity > availableQuantity } />
- / {warehouseStock.quantity} + / {availableQuantity}
diff --git a/src/orders/components/OrderFulfillPage/fixtures.ts b/src/orders/components/OrderFulfillPage/fixtures.ts index 1e72213aa..fdb2857bc 100644 --- a/src/orders/components/OrderFulfillPage/fixtures.ts +++ b/src/orders/components/OrderFulfillPage/fixtures.ts @@ -37,25 +37,29 @@ export const orderToFulfill: OrderFulfillData_order = { __typename: "Stock", id: "U3RvY2s6NTIy", warehouse: warehouseList[0], - quantity: 1217 + quantity: 1217, + quantityAllocated: 10 }, { __typename: "Stock", id: "U3RvY2s6NTIx", warehouse: warehouseList[1], - quantity: 1217 + quantity: 1217, + quantityAllocated: 20 }, { __typename: "Stock", id: "U3RvY2s6NTIz", warehouse: warehouseList[2], - quantity: 1217 + quantity: 1217, + quantityAllocated: 4 }, { __typename: "Stock", id: "U3RvY2s6NTI0", warehouse: warehouseList[3], - quantity: 1220 + quantity: 1220, + quantityAllocated: 7 } ] }, @@ -93,19 +97,22 @@ export const orderToFulfill: OrderFulfillData_order = { __typename: "Stock", id: "U3RvY2s6NTI=", warehouse: warehouseList[1], - quantity: 760 + quantity: 760, + quantityAllocated: 2 }, { __typename: "Stock", id: "U3RvY2s6NTE=", warehouse: warehouseList[2], - quantity: 760 + quantity: 760, + quantityAllocated: 33 }, { __typename: "Stock", id: "U3RvY2s6NTM=", warehouse: warehouseList[3], - quantity: 760 + quantity: 760, + quantityAllocated: 4 } ] }, @@ -143,13 +150,15 @@ export const orderToFulfill: OrderFulfillData_order = { __typename: "Stock", id: "U3RvY2s6NTc=", warehouse: warehouseList[0], - quantity: 587 + quantity: 587, + quantityAllocated: 0 }, { __typename: "Stock", id: "U3RvY2s6NTY=", warehouse: warehouseList[2], - quantity: 587 + quantity: 587, + quantityAllocated: 1 } ] }, diff --git a/src/orders/queries.ts b/src/orders/queries.ts index 4089d9ded..8ecb5ff8d 100644 --- a/src/orders/queries.ts +++ b/src/orders/queries.ts @@ -365,6 +365,7 @@ const orderFulfillData = gql` id } quantity + quantityAllocated } } thumbnail(size: 64) { diff --git a/src/orders/types/OrderFulfillData.ts b/src/orders/types/OrderFulfillData.ts index b9fbf9bf4..1bc8412b8 100644 --- a/src/orders/types/OrderFulfillData.ts +++ b/src/orders/types/OrderFulfillData.ts @@ -27,6 +27,7 @@ export interface OrderFulfillData_order_lines_variant_stocks { id: string; warehouse: OrderFulfillData_order_lines_variant_stocks_warehouse; quantity: number; + quantityAllocated: number; } export interface OrderFulfillData_order_lines_variant { diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 8377e828e..5f068e403 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -64486,7 +64486,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 1217 + / 1207
@@ -64530,7 +64530,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 1217 + / 1197
@@ -64574,7 +64574,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 1217 + / 1213
@@ -64618,7 +64618,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 1220 + / 1213
@@ -64712,7 +64712,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 760 + / 758
@@ -64756,7 +64756,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 760 + / 727
@@ -64800,7 +64800,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 760 + / 756
@@ -64889,7 +64889,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 587 + / 586
From 0c09d4b11dad45558133130aeb3bf9de78689012 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 22 Apr 2020 00:03:23 +0200 Subject: [PATCH 78/88] wip --- src/orders/mutations.ts | 18 ++ src/orders/types/FulfillOrder.ts | 282 ++++++++++++++++++ .../views/OrderFulfill/OrderFulfill.tsx | 30 +- 3 files changed, 328 insertions(+), 2 deletions(-) create mode 100644 src/orders/types/FulfillOrder.ts diff --git a/src/orders/mutations.ts b/src/orders/mutations.ts index 3ee96f82e..8966ac6a1 100644 --- a/src/orders/mutations.ts +++ b/src/orders/mutations.ts @@ -22,6 +22,7 @@ import { OrderDraftBulkCancel, OrderDraftBulkCancelVariables } from "./types/OrderDraftBulkCancel"; +import { FulfillOrder, FulfillOrderVariables } from "./types/FulfillOrder"; import { OrderDraftCancel, OrderDraftCancelVariables @@ -477,3 +478,20 @@ export const TypedOrderLineUpdateMutation = TypedMutation< OrderLineUpdate, OrderLineUpdateVariables >(orderLineUpdateMutation); + +const fulfillOrder = gql` + mutation FulfillOrder($orderId: ID!, $input: FulfillmentCreateInput!) { + orderFulfillmentCreate(order: $orderId, input: $input) { + errors: orderErrors { + ...OrderErrorFragment + } + order { + ...OrderDetailsFragment + } + } + } +`; +export const useOrderFulfill = makeMutation< + FulfillOrder, + FulfillOrderVariables +>(fulfillOrder); diff --git a/src/orders/types/FulfillOrder.ts b/src/orders/types/FulfillOrder.ts new file mode 100644 index 000000000..0764dc429 --- /dev/null +++ b/src/orders/types/FulfillOrder.ts @@ -0,0 +1,282 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { FulfillmentCreateInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL mutation operation: FulfillOrder +// ==================================================== + +export interface FulfillOrder_orderFulfillmentCreate_errors { + __typename: "OrderError"; + code: OrderErrorCode; + field: string | null; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_billingAddress_country { + __typename: "CountryDisplay"; + code: string; + country: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_billingAddress { + __typename: "Address"; + city: string; + cityArea: string; + companyName: string; + country: FulfillOrder_orderFulfillmentCreate_order_billingAddress_country; + countryArea: string; + firstName: string; + id: string; + lastName: string; + phone: string | null; + postalCode: string; + streetAddress1: string; + streetAddress2: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_events_user { + __typename: "User"; + id: string; + email: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_events { + __typename: "OrderEvent"; + id: string; + amount: number | null; + date: any | null; + email: string | null; + emailType: OrderEventsEmailsEnum | null; + message: string | null; + quantity: number | null; + type: OrderEventsEnum | null; + user: FulfillOrder_orderFulfillmentCreate_order_events_user | null; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_gross { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_net { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice { + __typename: "TaxedMoney"; + gross: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_gross; + net: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_net; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_thumbnail { + __typename: "Image"; + url: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine { + __typename: "OrderLine"; + id: string; + isShippingRequired: boolean; + productName: string; + productSku: string; + quantity: number; + quantityFulfilled: number; + unitPrice: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice | null; + thumbnail: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_thumbnail | null; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines { + __typename: "FulfillmentLine"; + id: string; + quantity: number; + orderLine: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine | null; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments { + __typename: "Fulfillment"; + id: string; + lines: (FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines | null)[] | null; + fulfillmentOrder: number; + status: FulfillmentStatus; + trackingNumber: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_gross { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_net { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice { + __typename: "TaxedMoney"; + gross: FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_gross; + net: FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_net; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_lines_thumbnail { + __typename: "Image"; + url: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_lines { + __typename: "OrderLine"; + id: string; + isShippingRequired: boolean; + productName: string; + productSku: string; + quantity: number; + quantityFulfilled: number; + unitPrice: FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice | null; + thumbnail: FulfillOrder_orderFulfillmentCreate_order_lines_thumbnail | null; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_shippingAddress_country { + __typename: "CountryDisplay"; + code: string; + country: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_shippingAddress { + __typename: "Address"; + city: string; + cityArea: string; + companyName: string; + country: FulfillOrder_orderFulfillmentCreate_order_shippingAddress_country; + countryArea: string; + firstName: string; + id: string; + lastName: string; + phone: string | null; + postalCode: string; + streetAddress1: string; + streetAddress2: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_shippingMethod { + __typename: "ShippingMethod"; + id: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_shippingPrice_gross { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_shippingPrice { + __typename: "TaxedMoney"; + gross: FulfillOrder_orderFulfillmentCreate_order_shippingPrice_gross; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_subtotal_gross { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_subtotal { + __typename: "TaxedMoney"; + gross: FulfillOrder_orderFulfillmentCreate_order_subtotal_gross; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_total_gross { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_total_tax { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_total { + __typename: "TaxedMoney"; + gross: FulfillOrder_orderFulfillmentCreate_order_total_gross; + tax: FulfillOrder_orderFulfillmentCreate_order_total_tax; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_totalAuthorized { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_totalCaptured { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_user { + __typename: "User"; + id: string; + email: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods_price { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods { + __typename: "ShippingMethod"; + id: string; + name: string; + price: FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods_price | null; +} + +export interface FulfillOrder_orderFulfillmentCreate_order { + __typename: "Order"; + id: string; + billingAddress: FulfillOrder_orderFulfillmentCreate_order_billingAddress | null; + canFinalize: boolean; + created: any; + customerNote: string; + events: (FulfillOrder_orderFulfillmentCreate_order_events | null)[] | null; + fulfillments: (FulfillOrder_orderFulfillmentCreate_order_fulfillments | null)[]; + lines: (FulfillOrder_orderFulfillmentCreate_order_lines | null)[]; + number: string | null; + paymentStatus: PaymentChargeStatusEnum | null; + shippingAddress: FulfillOrder_orderFulfillmentCreate_order_shippingAddress | null; + shippingMethod: FulfillOrder_orderFulfillmentCreate_order_shippingMethod | null; + shippingMethodName: string | null; + shippingPrice: FulfillOrder_orderFulfillmentCreate_order_shippingPrice | null; + status: OrderStatus; + subtotal: FulfillOrder_orderFulfillmentCreate_order_subtotal | null; + total: FulfillOrder_orderFulfillmentCreate_order_total | null; + actions: (OrderAction | null)[]; + totalAuthorized: FulfillOrder_orderFulfillmentCreate_order_totalAuthorized | null; + totalCaptured: FulfillOrder_orderFulfillmentCreate_order_totalCaptured | null; + user: FulfillOrder_orderFulfillmentCreate_order_user | null; + userEmail: string | null; + availableShippingMethods: (FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods | null)[] | null; +} + +export interface FulfillOrder_orderFulfillmentCreate { + __typename: "FulfillmentCreate"; + errors: FulfillOrder_orderFulfillmentCreate_errors[]; + order: FulfillOrder_orderFulfillmentCreate_order | null; +} + +export interface FulfillOrder { + orderFulfillmentCreate: FulfillOrder_orderFulfillmentCreate | null; +} + +export interface FulfillOrderVariables { + orderId: string; + input: FulfillmentCreateInput; +} diff --git a/src/orders/views/OrderFulfill/OrderFulfill.tsx b/src/orders/views/OrderFulfill/OrderFulfill.tsx index 01fcb5b9f..b1a50bbd7 100644 --- a/src/orders/views/OrderFulfill/OrderFulfill.tsx +++ b/src/orders/views/OrderFulfill/OrderFulfill.tsx @@ -7,6 +7,8 @@ import useNavigator from "@saleor/hooks/useNavigator"; import { orderUrl } from "@saleor/orders/urls"; import { useWarehouseList } from "@saleor/warehouses/queries"; import { WindowTitle } from "@saleor/components/WindowTitle"; +import { useOrderFulfill } from "@saleor/orders/mutations"; +import useNotifier from "@saleor/hooks/useNotifier"; export interface OrderFulfillProps { orderId: string; @@ -14,6 +16,7 @@ export interface OrderFulfillProps { const OrderFulfill: React.FC = ({ orderId }) => { const navigate = useNavigator(); + const notify = useNotifier(); const intl = useIntl(); const { data, loading } = useOrderFulfillData({ displayLoader: true, @@ -27,6 +30,19 @@ const OrderFulfill: React.FC = ({ orderId }) => { first: 20 } }); + const [fulfillOrder, fulfillOrderOpts] = useOrderFulfill({ + onCompleted: data => { + if (data.orderFulfillmentCreate.errors.length === 0) { + navigate(orderUrl(orderId)); + notify({ + text: intl.formatMessage({ + defaultMessage: "Fulfilled Items", + description: "order fulfilled success message" + }) + }); + } + } + }); return ( <> @@ -49,9 +65,19 @@ const OrderFulfill: React.FC = ({ orderId }) => { } /> navigate(orderUrl(orderId))} - onSubmit={() => undefined} + onSubmit={formData => + fulfillOrder({ + variables: { + input: { + lines: formData.items.map(line => line.value), + notifyCustomer: formData.sendInfo + }, + orderId + } + }) + } order={data?.order} saveButtonBar="default" warehouses={warehouseData?.warehouses.edges.map(edge => edge.node)} From 3922b315d555a87ff9f35898bc3791e7619fe1fc Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 24 Apr 2020 13:56:28 +0200 Subject: [PATCH 79/88] Hook up components with API --- .../OrderFulfillPage/OrderFulfillPage.tsx | 327 ++++++++++-------- src/orders/containers/OrderOperations.tsx | 226 ++++++------ src/orders/mutations.ts | 32 +- src/orders/types/FulfillOrder.ts | 142 ++++---- src/orders/types/OrderCreateFulfillment.ts | 282 --------------- .../OrderDetails/OrderDetailsMessages.tsx | 14 - src/orders/views/OrderDetails/index.tsx | 3 - .../views/OrderFulfill/OrderFulfill.tsx | 7 +- src/types/globalTypes.ts | 30 +- 9 files changed, 375 insertions(+), 688 deletions(-) delete mode 100644 src/orders/types/OrderCreateFulfillment.ts diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx index a0c30050d..88d6fe49b 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -11,7 +11,7 @@ import classNames from "classnames"; import Typography from "@material-ui/core/Typography"; import useFormset, { FormsetData } from "@saleor/hooks/useFormset"; -import { StockInput } from "@saleor/types/globalTypes"; +import { OrderFulfillStockInput } from "@saleor/types/globalTypes"; import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; import Container from "@saleor/components/Container"; @@ -19,7 +19,10 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; -import { OrderFulfillData_order } from "@saleor/orders/types/OrderFulfillData"; +import { + OrderFulfillData_order, + OrderFulfillData_order_lines +} from "@saleor/orders/types/OrderFulfillData"; import CardTitle from "@saleor/components/CardTitle"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import makeStyles from "@material-ui/core/styles/makeStyles"; @@ -36,23 +39,25 @@ const useStyles = makeStyles( paddingLeft: theme.spacing(2) + 2 }, colName: { - width: 300 + width: 250 }, colQuantity: { - textAlign: "right", width: 210 }, colQuantityContent: { alignItems: "center", display: "inline-flex" }, + colQuantityHeader: { + textAlign: "right" + }, colQuantityTotal: { textAlign: "right", width: 180 }, colSku: { textAlign: "right", - width: 120 + width: 150 }, error: { color: theme.palette.error.main @@ -82,7 +87,7 @@ interface OrderFulfillFormData { sendInfo: boolean; } interface OrderFulfillSubmitData extends OrderFulfillFormData { - items: FormsetData; + items: FormsetData; } export interface OrderFulfillPageProps { disabled: boolean; @@ -97,6 +102,10 @@ const initialFormData: OrderFulfillFormData = { sendInfo: true }; +function getRemainingQuantity(line: OrderFulfillData_order_lines): number { + return line.quantity - line.quantityFulfilled; +} + const OrderFulfillPage: React.FC = ({ disabled, order, @@ -110,23 +119,25 @@ const OrderFulfillPage: React.FC = ({ const { change: formsetChange, data: formsetData } = useFormset< null, - StockInput[] + OrderFulfillStockInput[] >( - order?.lines.map(line => ({ - data: null, - id: line.id, - label: line.variant.attributes - .map(attribute => - attribute.values - .map(attributeValue => attributeValue.name) - .join(" , ") - ) - .join(" / "), - value: line.variant.stocks.map(stock => ({ - quantity: 0, - warehouse: stock.warehouse.id + order?.lines + .filter(line => getRemainingQuantity(line) > 0) + .map(line => ({ + data: null, + id: line.id, + label: line.variant.attributes + .map(attribute => + attribute.values + .map(attributeValue => attributeValue.name) + .join(" , ") + ) + .join(" / "), + value: line.variant.stocks.map(stock => ({ + quantity: 0, + warehouse: stock.warehouse.id + })) })) - })) ); const handleSubmit = (formData: OrderFulfillFormData) => @@ -189,7 +200,10 @@ const OrderFulfillPage: React.FC = ({ {warehouses?.map(warehouse => ( {warehouse.name} @@ -203,144 +217,151 @@ const OrderFulfillPage: React.FC = ({ - {renderCollection(order?.lines, (line, lineIndex) => { - if (!line) { - return ( - - - - - - - - {warehouses?.map(() => ( - + {renderCollection( + order?.lines.filter(line => getRemainingQuantity(line) > 0), + (line, lineIndex) => { + if (!line) { + return ( + + + + + - ))} + {warehouses?.map(warehouse => ( + + + + ))} + + {" "} + + + + ); + } + + const remainingQuantity = getRemainingQuantity(line); + const quantityToFulfill = formsetData[ + lineIndex + ].value.reduce( + (quantityToFulfill, lineInput) => + quantityToFulfill + (lineInput.quantity || 0), + 0 + ); + const overfulfill = remainingQuantity < quantityToFulfill; + + return ( + + + {line.productName} + + {line.variant.attributes + .map(attribute => + attribute.values + .map(attributeValue => attributeValue.name) + .join(", ") + ) + .join(" / ")} + + + + {line.variant.sku} + + {warehouses?.map(warehouse => { + const warehouseStock = line.variant.stocks.find( + stock => stock.warehouse.id === warehouse.id + ); + const formsetStock = formsetData[ + lineIndex + ].value.find( + line => line.warehouse === warehouse.id + ); + + if (!warehouseStock) { + return ( + + + + ); + } + + const availableQuantity = + warehouseStock.quantity - + warehouseStock.quantityAllocated; + + return ( + +
+ + formsetChange( + line.id, + update( + { + quantity: parseInt( + event.target.value, + 10 + ), + warehouse: warehouse.id + }, + formsetData[lineIndex].value, + (a, b) => a.warehouse === b.warehouse + ) + ) + } + error={ + overfulfill || + formsetStock.quantity > availableQuantity + } + /> +
+ / {availableQuantity} +
+
+
+ ); + })} - {" "} - + + {quantityToFulfill} + {" "} + / {remainingQuantity}
); } - - const remainingQuantity = - line.quantity - line.quantityFulfilled; - const quantityToFulfill = formsetData[ - lineIndex - ].value.reduce( - (quantityToFulfill, lineInput) => - quantityToFulfill + (lineInput.quantity || 0), - 0 - ); - const overfulfill = remainingQuantity < quantityToFulfill; - - return ( - - - {line.productName} - - {line.variant.attributes - .map(attribute => - attribute.values - .map(attributeValue => attributeValue.name) - .join(", ") - ) - .join(" / ")} - - - - {line.variant.sku} - - {warehouses?.map(warehouse => { - const warehouseStock = line.variant.stocks.find( - stock => stock.warehouse.id === warehouse.id - ); - const formsetStock = formsetData[ - lineIndex - ].value.find(line => line.warehouse === warehouse.id); - - if (!warehouseStock) { - return ( - - - - ); - } - - const availableQuantity = - warehouseStock.quantity - - warehouseStock.quantityAllocated; - - return ( - -
- - formsetChange( - line.id, - update( - { - quantity: parseInt( - event.target.value, - 10 - ), - warehouse: warehouse.id - }, - formsetData[lineIndex].value, - (a, b) => a.warehouse === b.warehouse - ) - ) - } - error={ - overfulfill || - formsetStock.quantity > availableQuantity - } - /> -
- / {availableQuantity} -
-
-
- ); - })} - - - {quantityToFulfill} - {" "} - / {remainingQuantity} - -
- ); - })} + )}
diff --git a/src/orders/containers/OrderOperations.tsx b/src/orders/containers/OrderOperations.tsx index ca6c727d9..c134b21aa 100644 --- a/src/orders/containers/OrderOperations.tsx +++ b/src/orders/containers/OrderOperations.tsx @@ -6,7 +6,6 @@ import { TypedOrderAddNoteMutation, TypedOrderCancelMutation, TypedOrderCaptureMutation, - TypedOrderCreateFulfillmentMutation, TypedOrderDraftCancelMutation, TypedOrderDraftFinalizeMutation, TypedOrderDraftUpdateMutation, @@ -24,10 +23,6 @@ import { import { OrderAddNote, OrderAddNoteVariables } from "../types/OrderAddNote"; import { OrderCancel, OrderCancelVariables } from "../types/OrderCancel"; import { OrderCapture, OrderCaptureVariables } from "../types/OrderCapture"; -import { - OrderCreateFulfillment, - OrderCreateFulfillmentVariables -} from "../types/OrderCreateFulfillment"; import { OrderDraftCancel, OrderDraftCancelVariables @@ -80,10 +75,6 @@ interface OrderOperationsProps { OrderCancel, OrderCancelVariables >; - orderCreateFulfillment: PartialMutationProviderOutput< - OrderCreateFulfillment, - OrderCreateFulfillmentVariables - >; orderFulfillmentCancel: PartialMutationProviderOutput< OrderFulfillmentCancel, OrderFulfillmentCancelVariables @@ -139,7 +130,6 @@ interface OrderOperationsProps { >; }) => React.ReactNode; onOrderFulfillmentCancel: (data: OrderFulfillmentCancel) => void; - onOrderFulfillmentCreate: (data: OrderCreateFulfillment) => void; onOrderFulfillmentUpdate: (data: OrderFulfillmentUpdateTracking) => void; onOrderCancel: (data: OrderCancel) => void; onOrderVoid: (data: OrderVoid) => void; @@ -160,7 +150,6 @@ interface OrderOperationsProps { const OrderOperations: React.FC = ({ children, onDraftUpdate, - onOrderFulfillmentCreate, onNoteAdd, onOrderCancel, onOrderLinesAdd, @@ -185,151 +174,140 @@ const OrderOperations: React.FC = ({ {(...paymentCapture) => ( {(...paymentRefund) => ( - - {(...createFulfillment) => ( - - {(...addNote) => ( - - {(...update) => ( - + {(...addNote) => ( + + {(...update) => ( + + {(...updateDraft) => ( + - {(...updateDraft) => ( - ( + - {(...updateShippingMethod) => ( - ( + - {(...deleteOrderLine) => ( - ( + - {(...addOrderLine) => ( - ( + - {(...updateOrderLine) => ( - ( + - {(...cancelFulfillment) => ( - ( + - {( - ...updateTrackingNumber - ) => ( - ( + {( - ...finalizeDraft + ...cancelDraft ) => ( - {( - ...cancelDraft - ) => ( - - {( + ...markAsPaid + ) => + children({ + orderAddNote: getMutationProviderData( + ...addNote + ), + orderCancel: getMutationProviderData( + ...orderCancel + ), + orderDraftCancel: getMutationProviderData( + ...cancelDraft + ), + orderDraftFinalize: getMutationProviderData( + ...finalizeDraft + ), + orderDraftUpdate: getMutationProviderData( + ...updateDraft + ), + orderFulfillmentCancel: getMutationProviderData( + ...cancelFulfillment + ), + orderFulfillmentUpdateTracking: getMutationProviderData( + ...updateTrackingNumber + ), + orderLineDelete: getMutationProviderData( + ...deleteOrderLine + ), + orderLineUpdate: getMutationProviderData( + ...updateOrderLine + ), + orderLinesAdd: getMutationProviderData( + ...addOrderLine + ), + orderPaymentCapture: getMutationProviderData( + ...paymentCapture + ), + orderPaymentMarkAsPaid: getMutationProviderData( ...markAsPaid - ) => - children({ - orderAddNote: getMutationProviderData( - ...addNote - ), - orderCancel: getMutationProviderData( - ...orderCancel - ), - orderCreateFulfillment: getMutationProviderData( - ...createFulfillment - ), - orderDraftCancel: getMutationProviderData( - ...cancelDraft - ), - orderDraftFinalize: getMutationProviderData( - ...finalizeDraft - ), - orderDraftUpdate: getMutationProviderData( - ...updateDraft - ), - orderFulfillmentCancel: getMutationProviderData( - ...cancelFulfillment - ), - orderFulfillmentUpdateTracking: getMutationProviderData( - ...updateTrackingNumber - ), - orderLineDelete: getMutationProviderData( - ...deleteOrderLine - ), - orderLineUpdate: getMutationProviderData( - ...updateOrderLine - ), - orderLinesAdd: getMutationProviderData( - ...addOrderLine - ), - orderPaymentCapture: getMutationProviderData( - ...paymentCapture - ), - orderPaymentMarkAsPaid: getMutationProviderData( - ...markAsPaid - ), - orderPaymentRefund: getMutationProviderData( - ...paymentRefund - ), - orderShippingMethodUpdate: getMutationProviderData( - ...updateShippingMethod - ), - orderUpdate: getMutationProviderData( - ...update - ), - orderVoid: getMutationProviderData( - ...orderVoid - ) - }) - } - - )} - + ), + orderPaymentRefund: getMutationProviderData( + ...paymentRefund + ), + orderShippingMethodUpdate: getMutationProviderData( + ...updateShippingMethod + ), + orderUpdate: getMutationProviderData( + ...update + ), + orderVoid: getMutationProviderData( + ...orderVoid + ) + }) + } + )} - + )} - + )} - + )} - + )} - + )} - + )} - + )} - + )} - + )} - + )} - + )} )} diff --git a/src/orders/mutations.ts b/src/orders/mutations.ts index 8966ac6a1..ce0d09016 100644 --- a/src/orders/mutations.ts +++ b/src/orders/mutations.ts @@ -14,10 +14,6 @@ import { } from "./types/OrderBulkCancel"; import { OrderCancel, OrderCancelVariables } from "./types/OrderCancel"; import { OrderCapture, OrderCaptureVariables } from "./types/OrderCapture"; -import { - OrderCreateFulfillment, - OrderCreateFulfillmentVariables -} from "./types/OrderCreateFulfillment"; import { OrderDraftBulkCancel, OrderDraftBulkCancelVariables @@ -235,28 +231,6 @@ export const TypedOrderCaptureMutation = TypedMutation< OrderCaptureVariables >(orderCaptureMutation); -const orderCreateFulfillmentMutation = gql` - ${fragmentOrderDetails} - ${orderErrorFragment} - mutation OrderCreateFulfillment( - $order: ID! - $input: FulfillmentCreateInput! - ) { - orderFulfillmentCreate(order: $order, input: $input) { - errors: orderErrors { - ...OrderErrorFragment - } - order { - ...OrderDetailsFragment - } - } - } -`; -export const TypedOrderCreateFulfillmentMutation = TypedMutation< - OrderCreateFulfillment, - OrderCreateFulfillmentVariables ->(orderCreateFulfillmentMutation); - const orderFulfillmentUpdateTrackingMutation = gql` ${fragmentOrderDetails} ${orderErrorFragment} @@ -480,8 +454,10 @@ export const TypedOrderLineUpdateMutation = TypedMutation< >(orderLineUpdateMutation); const fulfillOrder = gql` - mutation FulfillOrder($orderId: ID!, $input: FulfillmentCreateInput!) { - orderFulfillmentCreate(order: $orderId, input: $input) { + ${fragmentOrderDetails} + ${orderErrorFragment} + mutation FulfillOrder($orderId: ID!, $input: OrderFulfillInput!) { + orderFulfill(order: $orderId, input: $input) { errors: orderErrors { ...OrderErrorFragment } diff --git a/src/orders/types/FulfillOrder.ts b/src/orders/types/FulfillOrder.ts index 0764dc429..83ccc4bf4 100644 --- a/src/orders/types/FulfillOrder.ts +++ b/src/orders/types/FulfillOrder.ts @@ -2,30 +2,30 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { FulfillmentCreateInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes"; +import { OrderFulfillInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: FulfillOrder // ==================================================== -export interface FulfillOrder_orderFulfillmentCreate_errors { +export interface FulfillOrder_orderFulfill_errors { __typename: "OrderError"; code: OrderErrorCode; field: string | null; } -export interface FulfillOrder_orderFulfillmentCreate_order_billingAddress_country { +export interface FulfillOrder_orderFulfill_order_billingAddress_country { __typename: "CountryDisplay"; code: string; country: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_billingAddress { +export interface FulfillOrder_orderFulfill_order_billingAddress { __typename: "Address"; city: string; cityArea: string; companyName: string; - country: FulfillOrder_orderFulfillmentCreate_order_billingAddress_country; + country: FulfillOrder_orderFulfill_order_billingAddress_country; countryArea: string; firstName: string; id: string; @@ -36,13 +36,13 @@ export interface FulfillOrder_orderFulfillmentCreate_order_billingAddress { streetAddress2: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_events_user { +export interface FulfillOrder_orderFulfill_order_events_user { __typename: "User"; id: string; email: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_events { +export interface FulfillOrder_orderFulfill_order_events { __typename: "OrderEvent"; id: string; amount: number | null; @@ -52,33 +52,33 @@ export interface FulfillOrder_orderFulfillmentCreate_order_events { message: string | null; quantity: number | null; type: OrderEventsEnum | null; - user: FulfillOrder_orderFulfillmentCreate_order_events_user | null; + user: FulfillOrder_orderFulfill_order_events_user | null; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_gross { +export interface FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitPrice_gross { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_net { +export interface FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitPrice_net { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice { +export interface FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitPrice { __typename: "TaxedMoney"; - gross: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_gross; - net: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_net; + gross: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitPrice_gross; + net: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitPrice_net; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_thumbnail { +export interface FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_thumbnail { __typename: "Image"; url: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine { +export interface FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine { __typename: "OrderLine"; id: string; isShippingRequired: boolean; @@ -86,50 +86,50 @@ export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_or productSku: string; quantity: number; quantityFulfilled: number; - unitPrice: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice | null; - thumbnail: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine_thumbnail | null; + unitPrice: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitPrice | null; + thumbnail: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_thumbnail | null; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines { +export interface FulfillOrder_orderFulfill_order_fulfillments_lines { __typename: "FulfillmentLine"; id: string; quantity: number; - orderLine: FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines_orderLine | null; + orderLine: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine | null; } -export interface FulfillOrder_orderFulfillmentCreate_order_fulfillments { +export interface FulfillOrder_orderFulfill_order_fulfillments { __typename: "Fulfillment"; id: string; - lines: (FulfillOrder_orderFulfillmentCreate_order_fulfillments_lines | null)[] | null; + lines: (FulfillOrder_orderFulfill_order_fulfillments_lines | null)[] | null; fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_gross { +export interface FulfillOrder_orderFulfill_order_lines_unitPrice_gross { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_net { +export interface FulfillOrder_orderFulfill_order_lines_unitPrice_net { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice { +export interface FulfillOrder_orderFulfill_order_lines_unitPrice { __typename: "TaxedMoney"; - gross: FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_gross; - net: FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice_net; + gross: FulfillOrder_orderFulfill_order_lines_unitPrice_gross; + net: FulfillOrder_orderFulfill_order_lines_unitPrice_net; } -export interface FulfillOrder_orderFulfillmentCreate_order_lines_thumbnail { +export interface FulfillOrder_orderFulfill_order_lines_thumbnail { __typename: "Image"; url: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_lines { +export interface FulfillOrder_orderFulfill_order_lines { __typename: "OrderLine"; id: string; isShippingRequired: boolean; @@ -137,22 +137,22 @@ export interface FulfillOrder_orderFulfillmentCreate_order_lines { productSku: string; quantity: number; quantityFulfilled: number; - unitPrice: FulfillOrder_orderFulfillmentCreate_order_lines_unitPrice | null; - thumbnail: FulfillOrder_orderFulfillmentCreate_order_lines_thumbnail | null; + unitPrice: FulfillOrder_orderFulfill_order_lines_unitPrice | null; + thumbnail: FulfillOrder_orderFulfill_order_lines_thumbnail | null; } -export interface FulfillOrder_orderFulfillmentCreate_order_shippingAddress_country { +export interface FulfillOrder_orderFulfill_order_shippingAddress_country { __typename: "CountryDisplay"; code: string; country: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_shippingAddress { +export interface FulfillOrder_orderFulfill_order_shippingAddress { __typename: "Address"; city: string; cityArea: string; companyName: string; - country: FulfillOrder_orderFulfillmentCreate_order_shippingAddress_country; + country: FulfillOrder_orderFulfill_order_shippingAddress_country; countryArea: string; firstName: string; id: string; @@ -163,120 +163,120 @@ export interface FulfillOrder_orderFulfillmentCreate_order_shippingAddress { streetAddress2: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_shippingMethod { +export interface FulfillOrder_orderFulfill_order_shippingMethod { __typename: "ShippingMethod"; id: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_shippingPrice_gross { +export interface FulfillOrder_orderFulfill_order_shippingPrice_gross { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_shippingPrice { +export interface FulfillOrder_orderFulfill_order_shippingPrice { __typename: "TaxedMoney"; - gross: FulfillOrder_orderFulfillmentCreate_order_shippingPrice_gross; + gross: FulfillOrder_orderFulfill_order_shippingPrice_gross; } -export interface FulfillOrder_orderFulfillmentCreate_order_subtotal_gross { +export interface FulfillOrder_orderFulfill_order_subtotal_gross { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_subtotal { +export interface FulfillOrder_orderFulfill_order_subtotal { __typename: "TaxedMoney"; - gross: FulfillOrder_orderFulfillmentCreate_order_subtotal_gross; + gross: FulfillOrder_orderFulfill_order_subtotal_gross; } -export interface FulfillOrder_orderFulfillmentCreate_order_total_gross { +export interface FulfillOrder_orderFulfill_order_total_gross { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_total_tax { +export interface FulfillOrder_orderFulfill_order_total_tax { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_total { +export interface FulfillOrder_orderFulfill_order_total { __typename: "TaxedMoney"; - gross: FulfillOrder_orderFulfillmentCreate_order_total_gross; - tax: FulfillOrder_orderFulfillmentCreate_order_total_tax; + gross: FulfillOrder_orderFulfill_order_total_gross; + tax: FulfillOrder_orderFulfill_order_total_tax; } -export interface FulfillOrder_orderFulfillmentCreate_order_totalAuthorized { +export interface FulfillOrder_orderFulfill_order_totalAuthorized { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_totalCaptured { +export interface FulfillOrder_orderFulfill_order_totalCaptured { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_user { +export interface FulfillOrder_orderFulfill_order_user { __typename: "User"; id: string; email: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods_price { +export interface FulfillOrder_orderFulfill_order_availableShippingMethods_price { __typename: "Money"; amount: number; currency: string; } -export interface FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods { +export interface FulfillOrder_orderFulfill_order_availableShippingMethods { __typename: "ShippingMethod"; id: string; name: string; - price: FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods_price | null; + price: FulfillOrder_orderFulfill_order_availableShippingMethods_price | null; } -export interface FulfillOrder_orderFulfillmentCreate_order { +export interface FulfillOrder_orderFulfill_order { __typename: "Order"; id: string; - billingAddress: FulfillOrder_orderFulfillmentCreate_order_billingAddress | null; + billingAddress: FulfillOrder_orderFulfill_order_billingAddress | null; canFinalize: boolean; created: any; customerNote: string; - events: (FulfillOrder_orderFulfillmentCreate_order_events | null)[] | null; - fulfillments: (FulfillOrder_orderFulfillmentCreate_order_fulfillments | null)[]; - lines: (FulfillOrder_orderFulfillmentCreate_order_lines | null)[]; + events: (FulfillOrder_orderFulfill_order_events | null)[] | null; + fulfillments: (FulfillOrder_orderFulfill_order_fulfillments | null)[]; + lines: (FulfillOrder_orderFulfill_order_lines | null)[]; number: string | null; paymentStatus: PaymentChargeStatusEnum | null; - shippingAddress: FulfillOrder_orderFulfillmentCreate_order_shippingAddress | null; - shippingMethod: FulfillOrder_orderFulfillmentCreate_order_shippingMethod | null; + shippingAddress: FulfillOrder_orderFulfill_order_shippingAddress | null; + shippingMethod: FulfillOrder_orderFulfill_order_shippingMethod | null; shippingMethodName: string | null; - shippingPrice: FulfillOrder_orderFulfillmentCreate_order_shippingPrice | null; + shippingPrice: FulfillOrder_orderFulfill_order_shippingPrice | null; status: OrderStatus; - subtotal: FulfillOrder_orderFulfillmentCreate_order_subtotal | null; - total: FulfillOrder_orderFulfillmentCreate_order_total | null; + subtotal: FulfillOrder_orderFulfill_order_subtotal | null; + total: FulfillOrder_orderFulfill_order_total | null; actions: (OrderAction | null)[]; - totalAuthorized: FulfillOrder_orderFulfillmentCreate_order_totalAuthorized | null; - totalCaptured: FulfillOrder_orderFulfillmentCreate_order_totalCaptured | null; - user: FulfillOrder_orderFulfillmentCreate_order_user | null; + totalAuthorized: FulfillOrder_orderFulfill_order_totalAuthorized | null; + totalCaptured: FulfillOrder_orderFulfill_order_totalCaptured | null; + user: FulfillOrder_orderFulfill_order_user | null; userEmail: string | null; - availableShippingMethods: (FulfillOrder_orderFulfillmentCreate_order_availableShippingMethods | null)[] | null; + availableShippingMethods: (FulfillOrder_orderFulfill_order_availableShippingMethods | null)[] | null; } -export interface FulfillOrder_orderFulfillmentCreate { - __typename: "FulfillmentCreate"; - errors: FulfillOrder_orderFulfillmentCreate_errors[]; - order: FulfillOrder_orderFulfillmentCreate_order | null; +export interface FulfillOrder_orderFulfill { + __typename: "OrderFulfill"; + errors: FulfillOrder_orderFulfill_errors[]; + order: FulfillOrder_orderFulfill_order | null; } export interface FulfillOrder { - orderFulfillmentCreate: FulfillOrder_orderFulfillmentCreate | null; + orderFulfill: FulfillOrder_orderFulfill | null; } export interface FulfillOrderVariables { orderId: string; - input: FulfillmentCreateInput; + input: OrderFulfillInput; } diff --git a/src/orders/types/OrderCreateFulfillment.ts b/src/orders/types/OrderCreateFulfillment.ts deleted file mode 100644 index edc4d54f1..000000000 --- a/src/orders/types/OrderCreateFulfillment.ts +++ /dev/null @@ -1,282 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// This file was automatically generated and should not be edited. - -import { FulfillmentCreateInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes"; - -// ==================================================== -// GraphQL mutation operation: OrderCreateFulfillment -// ==================================================== - -export interface OrderCreateFulfillment_orderFulfillmentCreate_errors { - __typename: "OrderError"; - code: OrderErrorCode; - field: string | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_billingAddress_country { - __typename: "CountryDisplay"; - code: string; - country: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_billingAddress { - __typename: "Address"; - city: string; - cityArea: string; - companyName: string; - country: OrderCreateFulfillment_orderFulfillmentCreate_order_billingAddress_country; - countryArea: string; - firstName: string; - id: string; - lastName: string; - phone: string | null; - postalCode: string; - streetAddress1: string; - streetAddress2: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_events_user { - __typename: "User"; - id: string; - email: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_events { - __typename: "OrderEvent"; - id: string; - amount: number | null; - date: any | null; - email: string | null; - emailType: OrderEventsEmailsEnum | null; - message: string | null; - quantity: number | null; - type: OrderEventsEnum | null; - user: OrderCreateFulfillment_orderFulfillmentCreate_order_events_user | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_gross { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_net { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice { - __typename: "TaxedMoney"; - gross: OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_gross; - net: OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice_net; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_thumbnail { - __typename: "Image"; - url: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine { - __typename: "OrderLine"; - id: string; - isShippingRequired: boolean; - productName: string; - productSku: string; - quantity: number; - quantityFulfilled: number; - unitPrice: OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_unitPrice | null; - thumbnail: OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine_thumbnail | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines { - __typename: "FulfillmentLine"; - id: string; - quantity: number; - orderLine: OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines_orderLine | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments { - __typename: "Fulfillment"; - id: string; - lines: (OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments_lines | null)[] | null; - fulfillmentOrder: number; - status: FulfillmentStatus; - trackingNumber: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_lines_unitPrice_gross { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_lines_unitPrice_net { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_lines_unitPrice { - __typename: "TaxedMoney"; - gross: OrderCreateFulfillment_orderFulfillmentCreate_order_lines_unitPrice_gross; - net: OrderCreateFulfillment_orderFulfillmentCreate_order_lines_unitPrice_net; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_lines_thumbnail { - __typename: "Image"; - url: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_lines { - __typename: "OrderLine"; - id: string; - isShippingRequired: boolean; - productName: string; - productSku: string; - quantity: number; - quantityFulfilled: number; - unitPrice: OrderCreateFulfillment_orderFulfillmentCreate_order_lines_unitPrice | null; - thumbnail: OrderCreateFulfillment_orderFulfillmentCreate_order_lines_thumbnail | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_shippingAddress_country { - __typename: "CountryDisplay"; - code: string; - country: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_shippingAddress { - __typename: "Address"; - city: string; - cityArea: string; - companyName: string; - country: OrderCreateFulfillment_orderFulfillmentCreate_order_shippingAddress_country; - countryArea: string; - firstName: string; - id: string; - lastName: string; - phone: string | null; - postalCode: string; - streetAddress1: string; - streetAddress2: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_shippingMethod { - __typename: "ShippingMethod"; - id: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_shippingPrice_gross { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_shippingPrice { - __typename: "TaxedMoney"; - gross: OrderCreateFulfillment_orderFulfillmentCreate_order_shippingPrice_gross; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_subtotal_gross { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_subtotal { - __typename: "TaxedMoney"; - gross: OrderCreateFulfillment_orderFulfillmentCreate_order_subtotal_gross; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_total_gross { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_total_tax { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_total { - __typename: "TaxedMoney"; - gross: OrderCreateFulfillment_orderFulfillmentCreate_order_total_gross; - tax: OrderCreateFulfillment_orderFulfillmentCreate_order_total_tax; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_totalAuthorized { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_totalCaptured { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_user { - __typename: "User"; - id: string; - email: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_availableShippingMethods_price { - __typename: "Money"; - amount: number; - currency: string; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order_availableShippingMethods { - __typename: "ShippingMethod"; - id: string; - name: string; - price: OrderCreateFulfillment_orderFulfillmentCreate_order_availableShippingMethods_price | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate_order { - __typename: "Order"; - id: string; - billingAddress: OrderCreateFulfillment_orderFulfillmentCreate_order_billingAddress | null; - canFinalize: boolean; - created: any; - customerNote: string; - events: (OrderCreateFulfillment_orderFulfillmentCreate_order_events | null)[] | null; - fulfillments: (OrderCreateFulfillment_orderFulfillmentCreate_order_fulfillments | null)[]; - lines: (OrderCreateFulfillment_orderFulfillmentCreate_order_lines | null)[]; - number: string | null; - paymentStatus: PaymentChargeStatusEnum | null; - shippingAddress: OrderCreateFulfillment_orderFulfillmentCreate_order_shippingAddress | null; - shippingMethod: OrderCreateFulfillment_orderFulfillmentCreate_order_shippingMethod | null; - shippingMethodName: string | null; - shippingPrice: OrderCreateFulfillment_orderFulfillmentCreate_order_shippingPrice | null; - status: OrderStatus; - subtotal: OrderCreateFulfillment_orderFulfillmentCreate_order_subtotal | null; - total: OrderCreateFulfillment_orderFulfillmentCreate_order_total | null; - actions: (OrderAction | null)[]; - totalAuthorized: OrderCreateFulfillment_orderFulfillmentCreate_order_totalAuthorized | null; - totalCaptured: OrderCreateFulfillment_orderFulfillmentCreate_order_totalCaptured | null; - user: OrderCreateFulfillment_orderFulfillmentCreate_order_user | null; - userEmail: string | null; - availableShippingMethods: (OrderCreateFulfillment_orderFulfillmentCreate_order_availableShippingMethods | null)[] | null; -} - -export interface OrderCreateFulfillment_orderFulfillmentCreate { - __typename: "FulfillmentCreate"; - errors: OrderCreateFulfillment_orderFulfillmentCreate_errors[]; - order: OrderCreateFulfillment_orderFulfillmentCreate_order | null; -} - -export interface OrderCreateFulfillment { - orderFulfillmentCreate: OrderCreateFulfillment_orderFulfillmentCreate | null; -} - -export interface OrderCreateFulfillmentVariables { - order: string; - input: FulfillmentCreateInput; -} diff --git a/src/orders/views/OrderDetails/OrderDetailsMessages.tsx b/src/orders/views/OrderDetails/OrderDetailsMessages.tsx index c9b5b9f00..a2162928f 100644 --- a/src/orders/views/OrderDetails/OrderDetailsMessages.tsx +++ b/src/orders/views/OrderDetails/OrderDetailsMessages.tsx @@ -7,7 +7,6 @@ import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandl import { OrderAddNote } from "../../types/OrderAddNote"; import { OrderCancel } from "../../types/OrderCancel"; import { OrderCapture } from "../../types/OrderCapture"; -import { OrderCreateFulfillment } from "../../types/OrderCreateFulfillment"; import { OrderDraftCancel } from "../../types/OrderDraftCancel"; import { OrderDraftFinalize } from "../../types/OrderDraftFinalize"; import { OrderDraftUpdate } from "../../types/OrderDraftUpdate"; @@ -31,7 +30,6 @@ interface OrderDetailsMessages { handleNoteAdd: (data: OrderAddNote) => void; handleOrderCancel: (data: OrderCancel) => void; handleOrderFulfillmentCancel: (data: OrderFulfillmentCancel) => void; - handleOrderFulfillmentCreate: (data: OrderCreateFulfillment) => void; handleOrderFulfillmentUpdate: ( data: OrderFulfillmentUpdateTracking ) => void; @@ -86,17 +84,6 @@ export const OrderDetailsMessages: React.FC = ({ closeModal(); } }; - const handleOrderFulfillmentCreate = (data: OrderCreateFulfillment) => { - const errs = data.orderFulfillmentCreate?.errors; - if (errs.length === 0) { - pushMessage({ - text: intl.formatMessage({ - defaultMessage: "Items successfully fulfilled" - }) - }); - closeModal(); - } - }; const handleOrderMarkAsPaid = (data: OrderMarkAsPaid) => { const errs = data.orderMarkAsPaid?.errors; if (errs.length === 0) { @@ -256,7 +243,6 @@ export const OrderDetailsMessages: React.FC = ({ handleNoteAdd, handleOrderCancel, handleOrderFulfillmentCancel, - handleOrderFulfillmentCreate, handleOrderFulfillmentUpdate, handleOrderLineDelete, handleOrderLineUpdate, diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index 67fb571ff..db37b4dab 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -125,9 +125,6 @@ export const OrderDetails: React.FC = ({ id, params }) => { {orderMessages => ( = ({ orderId }) => { }); const [fulfillOrder, fulfillOrderOpts] = useOrderFulfill({ onCompleted: data => { - if (data.orderFulfillmentCreate.errors.length === 0) { + if (data.orderFulfill.errors.length === 0) { navigate(orderUrl(orderId)); notify({ text: intl.formatMessage({ @@ -71,7 +71,10 @@ const OrderFulfill: React.FC = ({ orderId }) => { fulfillOrder({ variables: { input: { - lines: formData.items.map(line => line.value), + lines: formData.items.map(line => ({ + orderLineId: line.id, + stocks: line.value + })), notifyCustomer: formData.sendInfo }, orderId diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 5ba44dd88..b26319b99 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -456,6 +456,7 @@ export enum OrderErrorCode { CANNOT_DELETE = "CANNOT_DELETE", CANNOT_REFUND = "CANNOT_REFUND", CAPTURE_INACTIVE_PAYMENT = "CAPTURE_INACTIVE_PAYMENT", + DUPLICATED_INPUT_ITEM = "DUPLICATED_INPUT_ITEM", FULFILL_ORDER_LINE = "FULFILL_ORDER_LINE", GRAPHQL_ERROR = "GRAPHQL_ERROR", INSUFFICIENT_STOCK = "INSUFFICIENT_STOCK", @@ -790,6 +791,7 @@ export enum WebhookEventTypeEnum { } export enum WebhookSortField { + APP = "APP", NAME = "NAME", SERVICE_ACCOUNT = "SERVICE_ACCOUNT", TARGET_URL = "TARGET_URL", @@ -997,17 +999,6 @@ export interface FulfillmentCancelInput { restock?: boolean | null; } -export interface FulfillmentCreateInput { - trackingNumber?: string | null; - notifyCustomer?: boolean | null; - lines: (FulfillmentLineInput | null)[]; -} - -export interface FulfillmentLineInput { - orderLineId?: string | null; - quantity?: number | null; -} - export interface FulfillmentUpdateTrackingInput { trackingNumber?: string | null; notifyCustomer?: boolean | null; @@ -1074,6 +1065,21 @@ export interface OrderFilterInput { search?: string | null; } +export interface OrderFulfillInput { + lines: OrderFulfillLineInput[]; + notifyCustomer?: boolean | null; +} + +export interface OrderFulfillLineInput { + orderLineId?: string | null; + stocks: OrderFulfillStockInput[]; +} + +export interface OrderFulfillStockInput { + quantity?: number | null; + warehouse?: string | null; +} + export interface OrderLineCreateInput { quantity: number; variantId: string; @@ -1478,6 +1484,7 @@ export interface WebhookCreateInput { targetUrl?: string | null; events?: (WebhookEventTypeEnum | null)[] | null; serviceAccount?: string | null; + app?: string | null; isActive?: boolean | null; secretKey?: string | null; } @@ -1497,6 +1504,7 @@ export interface WebhookUpdateInput { targetUrl?: string | null; events?: (WebhookEventTypeEnum | null)[] | null; serviceAccount?: string | null; + app?: string | null; isActive?: boolean | null; secretKey?: string | null; } From 65b9dbc483e719198707636ddc765092128d8d12 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 24 Apr 2020 13:57:58 +0200 Subject: [PATCH 80/88] Do not let go back to fulfillment view after success --- src/orders/views/OrderFulfill/OrderFulfill.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/orders/views/OrderFulfill/OrderFulfill.tsx b/src/orders/views/OrderFulfill/OrderFulfill.tsx index 353a8a3c6..5ad743918 100644 --- a/src/orders/views/OrderFulfill/OrderFulfill.tsx +++ b/src/orders/views/OrderFulfill/OrderFulfill.tsx @@ -33,7 +33,7 @@ const OrderFulfill: React.FC = ({ orderId }) => { const [fulfillOrder, fulfillOrderOpts] = useOrderFulfill({ onCompleted: data => { if (data.orderFulfill.errors.length === 0) { - navigate(orderUrl(orderId)); + navigate(orderUrl(orderId), true); notify({ text: intl.formatMessage({ defaultMessage: "Fulfilled Items", From 037ace2a1b89025c5b36f8eec0bef270e3c23286 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Mon, 27 Apr 2020 15:42:56 +0200 Subject: [PATCH 81/88] Handle stock errors --- .../OrderFulfillPage/OrderFulfillPage.tsx | 18 ++++++++++++++++-- src/orders/mutations.ts | 2 ++ src/orders/types/FulfillOrder.ts | 2 ++ src/orders/views/OrderFulfill/OrderFulfill.tsx | 1 + src/types/globalTypes.ts | 3 ++- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx index 88d6fe49b..155eb421d 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.tsx @@ -11,7 +11,10 @@ import classNames from "classnames"; import Typography from "@material-ui/core/Typography"; import useFormset, { FormsetData } from "@saleor/hooks/useFormset"; -import { OrderFulfillStockInput } from "@saleor/types/globalTypes"; +import { + OrderFulfillStockInput, + OrderErrorCode +} from "@saleor/types/globalTypes"; import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment"; import TableCellAvatar from "@saleor/components/TableCellAvatar"; import Container from "@saleor/components/Container"; @@ -31,6 +34,7 @@ import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import { renderCollection } from "@saleor/misc"; import Skeleton from "@saleor/components/Skeleton"; import AppHeader from "@saleor/components/AppHeader"; +import { FulfillOrder_orderFulfill_errors } from "@saleor/orders/types/FulfillOrder"; const useStyles = makeStyles( theme => ({ @@ -91,6 +95,7 @@ interface OrderFulfillSubmitData extends OrderFulfillFormData { } export interface OrderFulfillPageProps { disabled: boolean; + errors: FulfillOrder_orderFulfill_errors[]; order: OrderFulfillData_order; saveButtonBar: ConfirmButtonTransitionState; warehouses: WarehouseFragment[]; @@ -108,6 +113,7 @@ function getRemainingQuantity(line: OrderFulfillData_order_lines): number { const OrderFulfillPage: React.FC = ({ disabled, + errors, order, saveButtonBar, warehouses, @@ -336,7 +342,15 @@ const OrderFulfillPage: React.FC = ({ } error={ overfulfill || - formsetStock.quantity > availableQuantity + formsetStock.quantity > + availableQuantity || + !!errors?.find( + err => + err.warehouse === warehouse.id && + err.orderLine === line.id && + err.code === + OrderErrorCode.INSUFFICIENT_STOCK + ) } />
diff --git a/src/orders/mutations.ts b/src/orders/mutations.ts index ce0d09016..28fe5cb35 100644 --- a/src/orders/mutations.ts +++ b/src/orders/mutations.ts @@ -460,6 +460,8 @@ const fulfillOrder = gql` orderFulfill(order: $orderId, input: $input) { errors: orderErrors { ...OrderErrorFragment + warehouse + orderLine } order { ...OrderDetailsFragment diff --git a/src/orders/types/FulfillOrder.ts b/src/orders/types/FulfillOrder.ts index 83ccc4bf4..9aa8810ab 100644 --- a/src/orders/types/FulfillOrder.ts +++ b/src/orders/types/FulfillOrder.ts @@ -12,6 +12,8 @@ export interface FulfillOrder_orderFulfill_errors { __typename: "OrderError"; code: OrderErrorCode; field: string | null; + warehouse: string | null; + orderLine: string | null; } export interface FulfillOrder_orderFulfill_order_billingAddress_country { diff --git a/src/orders/views/OrderFulfill/OrderFulfill.tsx b/src/orders/views/OrderFulfill/OrderFulfill.tsx index 5ad743918..39dd898d3 100644 --- a/src/orders/views/OrderFulfill/OrderFulfill.tsx +++ b/src/orders/views/OrderFulfill/OrderFulfill.tsx @@ -66,6 +66,7 @@ const OrderFulfill: React.FC = ({ orderId }) => { /> navigate(orderUrl(orderId))} onSubmit={formData => fulfillOrder({ diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index b26319b99..37cfba865 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -24,6 +24,7 @@ export enum AccountErrorCode { NOT_FOUND = "NOT_FOUND", OUT_OF_SCOPE_GROUP = "OUT_OF_SCOPE_GROUP", OUT_OF_SCOPE_PERMISSION = "OUT_OF_SCOPE_PERMISSION", + OUT_OF_SCOPE_SERVICE_ACCOUNT = "OUT_OF_SCOPE_SERVICE_ACCOUNT", OUT_OF_SCOPE_USER = "OUT_OF_SCOPE_USER", PASSWORD_ENTIRELY_NUMERIC = "PASSWORD_ENTIRELY_NUMERIC", PASSWORD_TOO_COMMON = "PASSWORD_TOO_COMMON", @@ -996,7 +997,7 @@ export interface DraftOrderInput { } export interface FulfillmentCancelInput { - restock?: boolean | null; + warehouseId: string; } export interface FulfillmentUpdateTrackingInput { From 932349a27aab7f79db5603f93da4920fbdc3447d Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 28 Apr 2020 03:09:31 +0200 Subject: [PATCH 82/88] Minor tweaks --- src/intl.ts | 4 ++ .../OrderBulkCancelDialog.tsx | 15 +---- .../OrderCancelDialog/OrderCancelDialog.tsx | 7 +- .../OrderCannotCancelOrderDialog.tsx | 57 ++++++++++++++++ .../OrderCannotCancelOrderDialog/index.ts | 2 + .../OrderFulfillPage.stories.tsx | 16 +++++ .../OrderFulfillment/OrderFulfillment.tsx | 2 +- src/orders/fixtures.ts | 7 +- src/orders/mutations.ts | 8 +-- src/orders/queries.ts | 5 ++ src/orders/types/FulfillOrder.ts | 7 ++ src/orders/types/FulfillmentFragment.ts | 67 +++++++++++++++++++ src/orders/types/OrderBulkCancel.ts | 1 - src/orders/types/OrderCancel.ts | 8 ++- src/orders/types/OrderCapture.ts | 7 ++ src/orders/types/OrderDetails.ts | 7 ++ src/orders/types/OrderDetailsFragment.ts | 7 ++ src/orders/types/OrderDraftCancel.ts | 7 ++ src/orders/types/OrderDraftFinalize.ts | 7 ++ src/orders/types/OrderDraftUpdate.ts | 7 ++ src/orders/types/OrderFulfillmentCancel.ts | 7 ++ .../types/OrderFulfillmentUpdateTracking.ts | 7 ++ src/orders/types/OrderLineDelete.ts | 7 ++ src/orders/types/OrderLineUpdate.ts | 7 ++ src/orders/types/OrderLinesAdd.ts | 7 ++ src/orders/types/OrderMarkAsPaid.ts | 7 ++ src/orders/types/OrderRefund.ts | 7 ++ src/orders/types/OrderVoid.ts | 7 ++ src/orders/views/OrderDetails/index.tsx | 19 ++++-- src/orders/views/OrderList/OrderList.tsx | 5 +- 30 files changed, 296 insertions(+), 32 deletions(-) create mode 100644 src/orders/components/OrderCannotCancelOrderDialog/OrderCannotCancelOrderDialog.tsx create mode 100644 src/orders/components/OrderCannotCancelOrderDialog/index.ts create mode 100644 src/orders/types/FulfillmentFragment.ts diff --git a/src/intl.ts b/src/intl.ts index 68b4efd27..458961851 100644 --- a/src/intl.ts +++ b/src/intl.ts @@ -121,6 +121,10 @@ export const buttonMessages = defineMessages({ defaultMessage: "Manage", description: "button" }, + ok: { + defaultMessage: "OK", + description: "button" + }, remove: { defaultMessage: "Remove", description: "button" diff --git a/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx b/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx index bbbc81e28..d8d073963 100644 --- a/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx +++ b/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.tsx @@ -4,14 +4,13 @@ import { FormattedMessage, useIntl } from "react-intl"; import ActionDialog from "@saleor/components/ActionDialog"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; -import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; export interface OrderBulkCancelDialogProps { confirmButtonState: ConfirmButtonTransitionState; numberOfOrders: string; open: boolean; onClose: () => void; - onConfirm: (restock: boolean) => void; + onConfirm: () => void; } const OrderBulkCancelDialog: React.FC = ({ @@ -22,7 +21,6 @@ const OrderBulkCancelDialog: React.FC = ({ onConfirm }) => { const intl = useIntl(); - const [restock, setRestock] = React.useState(true); return ( = ({ description: "dialog header" })} onClose={onClose} - onConfirm={() => onConfirm(restock)} + onConfirm={onConfirm} > = ({ }} /> - setRestock(event.target.value)} - /> ); }; diff --git a/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx b/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx index dc2a21fc9..34748e33b 100644 --- a/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx +++ b/src/orders/components/OrderCancelDialog/OrderCancelDialog.tsx @@ -21,8 +21,8 @@ export interface OrderCancelDialogProps { errors: OrderErrorFragment[]; number: string; open: boolean; - onClose?(); - onSubmit(); + onClose: () => void; + onSubmit: () => void; } const OrderCancelDialog: React.FC = props => { @@ -50,8 +50,9 @@ const OrderCancelDialog: React.FC = props => { {chunks}, orderNumber }} /> diff --git a/src/orders/components/OrderCannotCancelOrderDialog/OrderCannotCancelOrderDialog.tsx b/src/orders/components/OrderCannotCancelOrderDialog/OrderCannotCancelOrderDialog.tsx new file mode 100644 index 000000000..b2a515ea2 --- /dev/null +++ b/src/orders/components/OrderCannotCancelOrderDialog/OrderCannotCancelOrderDialog.tsx @@ -0,0 +1,57 @@ +import Button from "@material-ui/core/Button"; +import Dialog from "@material-ui/core/Dialog"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import DialogContentText from "@material-ui/core/DialogContentText"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import makeStyles from "@material-ui/core/styles/makeStyles"; +import React from "react"; +import { FormattedMessage } from "react-intl"; + +import { buttonMessages } from "@saleor/intl"; +import { DialogProps } from "@saleor/types"; + +const useStyles = makeStyles( + theme => ({ + button: { + backgroundColor: theme.palette.error.main + } + }), + { + name: "OrderCannotCancelOrderDialog" + } +); + +const OrderCannotCancelOrderDialog: React.FC = ({ + open, + onClose +}) => { + const classes = useStyles({}); + + return ( + + + + + + + + + + + + + + ); +}; +OrderCannotCancelOrderDialog.displayName = "OrderCannotCancelOrderDialog"; +export default OrderCannotCancelOrderDialog; diff --git a/src/orders/components/OrderCannotCancelOrderDialog/index.ts b/src/orders/components/OrderCannotCancelOrderDialog/index.ts new file mode 100644 index 000000000..7a5eb78e1 --- /dev/null +++ b/src/orders/components/OrderCannotCancelOrderDialog/index.ts @@ -0,0 +1,2 @@ +export { default } from "./OrderCannotCancelOrderDialog"; +export * from "./OrderCannotCancelOrderDialog"; diff --git a/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx b/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx index 58e12a34b..cbd11bbdc 100644 --- a/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx +++ b/src/orders/components/OrderFulfillPage/OrderFulfillPage.stories.tsx @@ -3,11 +3,13 @@ import React from "react"; import Decorator from "@saleor/storybook/Decorator"; import { warehouseList } from "@saleor/warehouses/fixtures"; +import { OrderErrorCode } from "@saleor/types/globalTypes"; import OrderFulfillPage, { OrderFulfillPageProps } from "./OrderFulfillPage"; import { orderToFulfill } from "./fixtures"; const props: OrderFulfillPageProps = { disabled: false, + errors: [], onBack: () => undefined, onSubmit: () => undefined, order: orderToFulfill, @@ -25,4 +27,18 @@ storiesOf("Views / Orders / Fulfill order", module) order={undefined} warehouses={undefined} /> + )) + .add("error", () => ( + )); diff --git a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx index 73d1d0ddf..ea85414ac 100644 --- a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx +++ b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx @@ -240,7 +240,7 @@ const OrderFulfillment: React.FC = props => { color="textPrimary" variant="body2" > - default + {fulfillment.warehouse.name} ) }} diff --git a/src/orders/fixtures.ts b/src/orders/fixtures.ts index c08cf001f..41279fd34 100644 --- a/src/orders/fixtures.ts +++ b/src/orders/fixtures.ts @@ -1,5 +1,6 @@ import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers"; import { MessageDescriptor } from "react-intl"; +import { warehouseList } from "@saleor/warehouses/fixtures"; import { transformOrderStatus, transformPaymentStatus } from "../misc"; import { FulfillmentStatus, @@ -865,7 +866,8 @@ export const order = (placeholder: string): OrderDetails_order => ({ } ], status: FulfillmentStatus.FULFILLED, - trackingNumber: "" + trackingNumber: "", + warehouse: warehouseList[1] }, { __typename: "Fulfillment", @@ -905,7 +907,8 @@ export const order = (placeholder: string): OrderDetails_order => ({ } ], status: FulfillmentStatus.FULFILLED, - trackingNumber: "01nn12399su12nndfsy" + trackingNumber: "01nn12399su12nndfsy", + warehouse: warehouseList[0] } ], id: "T3JkZXI6OQ==", diff --git a/src/orders/mutations.ts b/src/orders/mutations.ts index 28fe5cb35..9bd64447b 100644 --- a/src/orders/mutations.ts +++ b/src/orders/mutations.ts @@ -71,8 +71,8 @@ export const orderErrorFragment = gql` const orderCancelMutation = gql` ${fragmentOrderDetails} ${orderErrorFragment} - mutation OrderCancel($id: ID!, $restock: Boolean!) { - orderCancel(id: $id, restock: $restock) { + mutation OrderCancel($id: ID!) { + orderCancel(id: $id) { errors: orderErrors { ...OrderErrorFragment } @@ -89,8 +89,8 @@ export const TypedOrderCancelMutation = TypedMutation< const orderBulkCancelMutation = gql` ${orderErrorFragment} - mutation OrderBulkCancel($ids: [ID]!, $restock: Boolean!) { - orderBulkCancel(ids: $ids, restock: $restock) { + mutation OrderBulkCancel($ids: [ID]!) { + orderBulkCancel(ids: $ids) { errors: orderErrors { ...OrderErrorFragment } diff --git a/src/orders/queries.ts b/src/orders/queries.ts index 8ecb5ff8d..e5c4db3b8 100644 --- a/src/orders/queries.ts +++ b/src/orders/queries.ts @@ -2,6 +2,7 @@ import gql from "graphql-tag"; import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import makeQuery from "@saleor/hooks/makeQuery"; +import { warehouseFragment } from "@saleor/warehouses/queries"; import { TypedQuery } from "../queries"; import { OrderDetails, OrderDetailsVariables } from "./types/OrderDetails"; import { @@ -79,6 +80,7 @@ export const fragmentOrderLine = gql` `; export const fulfillmentFragment = gql` ${fragmentOrderLine} + ${warehouseFragment} fragment FulfillmentFragment on Fulfillment { id lines { @@ -91,6 +93,9 @@ export const fulfillmentFragment = gql` fulfillmentOrder status trackingNumber + warehouse { + ...WarehouseFragment + } } `; diff --git a/src/orders/types/FulfillOrder.ts b/src/orders/types/FulfillOrder.ts index 9aa8810ab..786ffb08c 100644 --- a/src/orders/types/FulfillOrder.ts +++ b/src/orders/types/FulfillOrder.ts @@ -99,6 +99,12 @@ export interface FulfillOrder_orderFulfill_order_fulfillments_lines { orderLine: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine | null; } +export interface FulfillOrder_orderFulfill_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface FulfillOrder_orderFulfill_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -106,6 +112,7 @@ export interface FulfillOrder_orderFulfill_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: FulfillOrder_orderFulfill_order_fulfillments_warehouse | null; } export interface FulfillOrder_orderFulfill_order_lines_unitPrice_gross { diff --git a/src/orders/types/FulfillmentFragment.ts b/src/orders/types/FulfillmentFragment.ts new file mode 100644 index 000000000..e8ac634b5 --- /dev/null +++ b/src/orders/types/FulfillmentFragment.ts @@ -0,0 +1,67 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { FulfillmentStatus } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: FulfillmentFragment +// ==================================================== + +export interface FulfillmentFragment_lines_orderLine_unitPrice_gross { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillmentFragment_lines_orderLine_unitPrice_net { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface FulfillmentFragment_lines_orderLine_unitPrice { + __typename: "TaxedMoney"; + gross: FulfillmentFragment_lines_orderLine_unitPrice_gross; + net: FulfillmentFragment_lines_orderLine_unitPrice_net; +} + +export interface FulfillmentFragment_lines_orderLine_thumbnail { + __typename: "Image"; + url: string; +} + +export interface FulfillmentFragment_lines_orderLine { + __typename: "OrderLine"; + id: string; + isShippingRequired: boolean; + productName: string; + productSku: string; + quantity: number; + quantityFulfilled: number; + unitPrice: FulfillmentFragment_lines_orderLine_unitPrice | null; + thumbnail: FulfillmentFragment_lines_orderLine_thumbnail | null; +} + +export interface FulfillmentFragment_lines { + __typename: "FulfillmentLine"; + id: string; + quantity: number; + orderLine: FulfillmentFragment_lines_orderLine | null; +} + +export interface FulfillmentFragment_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + +export interface FulfillmentFragment { + __typename: "Fulfillment"; + id: string; + lines: (FulfillmentFragment_lines | null)[] | null; + fulfillmentOrder: number; + status: FulfillmentStatus; + trackingNumber: string; + warehouse: FulfillmentFragment_warehouse | null; +} diff --git a/src/orders/types/OrderBulkCancel.ts b/src/orders/types/OrderBulkCancel.ts index c61e82ac7..1a838b957 100644 --- a/src/orders/types/OrderBulkCancel.ts +++ b/src/orders/types/OrderBulkCancel.ts @@ -25,5 +25,4 @@ export interface OrderBulkCancel { export interface OrderBulkCancelVariables { ids: (string | null)[]; - restock: boolean; } diff --git a/src/orders/types/OrderCancel.ts b/src/orders/types/OrderCancel.ts index 19db67e37..7258dbdb0 100644 --- a/src/orders/types/OrderCancel.ts +++ b/src/orders/types/OrderCancel.ts @@ -97,6 +97,12 @@ export interface OrderCancel_orderCancel_order_fulfillments_lines { orderLine: OrderCancel_orderCancel_order_fulfillments_lines_orderLine | null; } +export interface OrderCancel_orderCancel_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderCancel_orderCancel_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderCancel_orderCancel_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderCancel_orderCancel_order_fulfillments_warehouse | null; } export interface OrderCancel_orderCancel_order_lines_unitPrice_gross { @@ -278,5 +285,4 @@ export interface OrderCancel { export interface OrderCancelVariables { id: string; - restock: boolean; } diff --git a/src/orders/types/OrderCapture.ts b/src/orders/types/OrderCapture.ts index 502223d9d..5c3abf2ee 100644 --- a/src/orders/types/OrderCapture.ts +++ b/src/orders/types/OrderCapture.ts @@ -97,6 +97,12 @@ export interface OrderCapture_orderCapture_order_fulfillments_lines { orderLine: OrderCapture_orderCapture_order_fulfillments_lines_orderLine | null; } +export interface OrderCapture_orderCapture_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderCapture_orderCapture_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderCapture_orderCapture_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderCapture_orderCapture_order_fulfillments_warehouse | null; } export interface OrderCapture_orderCapture_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderDetails.ts b/src/orders/types/OrderDetails.ts index a668e4563..4ec01cdca 100644 --- a/src/orders/types/OrderDetails.ts +++ b/src/orders/types/OrderDetails.ts @@ -91,6 +91,12 @@ export interface OrderDetails_order_fulfillments_lines { orderLine: OrderDetails_order_fulfillments_lines_orderLine | null; } +export interface OrderDetails_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderDetails_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -98,6 +104,7 @@ export interface OrderDetails_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderDetails_order_fulfillments_warehouse | null; } export interface OrderDetails_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderDetailsFragment.ts b/src/orders/types/OrderDetailsFragment.ts index fc2f5d3ba..e01d64bbb 100644 --- a/src/orders/types/OrderDetailsFragment.ts +++ b/src/orders/types/OrderDetailsFragment.ts @@ -91,6 +91,12 @@ export interface OrderDetailsFragment_fulfillments_lines { orderLine: OrderDetailsFragment_fulfillments_lines_orderLine | null; } +export interface OrderDetailsFragment_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderDetailsFragment_fulfillments { __typename: "Fulfillment"; id: string; @@ -98,6 +104,7 @@ export interface OrderDetailsFragment_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderDetailsFragment_fulfillments_warehouse | null; } export interface OrderDetailsFragment_lines_unitPrice_gross { diff --git a/src/orders/types/OrderDraftCancel.ts b/src/orders/types/OrderDraftCancel.ts index 75c50fc0d..0d5f737d9 100644 --- a/src/orders/types/OrderDraftCancel.ts +++ b/src/orders/types/OrderDraftCancel.ts @@ -97,6 +97,12 @@ export interface OrderDraftCancel_draftOrderDelete_order_fulfillments_lines { orderLine: OrderDraftCancel_draftOrderDelete_order_fulfillments_lines_orderLine | null; } +export interface OrderDraftCancel_draftOrderDelete_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderDraftCancel_draftOrderDelete_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderDraftCancel_draftOrderDelete_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderDraftCancel_draftOrderDelete_order_fulfillments_warehouse | null; } export interface OrderDraftCancel_draftOrderDelete_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderDraftFinalize.ts b/src/orders/types/OrderDraftFinalize.ts index e4f7c715b..8b1ea1068 100644 --- a/src/orders/types/OrderDraftFinalize.ts +++ b/src/orders/types/OrderDraftFinalize.ts @@ -97,6 +97,12 @@ export interface OrderDraftFinalize_draftOrderComplete_order_fulfillments_lines orderLine: OrderDraftFinalize_draftOrderComplete_order_fulfillments_lines_orderLine | null; } +export interface OrderDraftFinalize_draftOrderComplete_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderDraftFinalize_draftOrderComplete_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderDraftFinalize_draftOrderComplete_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderDraftFinalize_draftOrderComplete_order_fulfillments_warehouse | null; } export interface OrderDraftFinalize_draftOrderComplete_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderDraftUpdate.ts b/src/orders/types/OrderDraftUpdate.ts index 6a54380da..77f764948 100644 --- a/src/orders/types/OrderDraftUpdate.ts +++ b/src/orders/types/OrderDraftUpdate.ts @@ -97,6 +97,12 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_fulfillments_lines { orderLine: OrderDraftUpdate_draftOrderUpdate_order_fulfillments_lines_orderLine | null; } +export interface OrderDraftUpdate_draftOrderUpdate_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderDraftUpdate_draftOrderUpdate_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderDraftUpdate_draftOrderUpdate_order_fulfillments_warehouse | null; } export interface OrderDraftUpdate_draftOrderUpdate_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderFulfillmentCancel.ts b/src/orders/types/OrderFulfillmentCancel.ts index 667f4a9f8..014908b9e 100644 --- a/src/orders/types/OrderFulfillmentCancel.ts +++ b/src/orders/types/OrderFulfillmentCancel.ts @@ -97,6 +97,12 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillment orderLine: OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillments_lines_orderLine | null; } +export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillment fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillments_warehouse | null; } export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderFulfillmentUpdateTracking.ts b/src/orders/types/OrderFulfillmentUpdateTracking.ts index 83b44ed82..0a0e5cca1 100644 --- a/src/orders/types/OrderFulfillmentUpdateTracking.ts +++ b/src/orders/types/OrderFulfillmentUpdateTracking.ts @@ -97,6 +97,12 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o orderLine: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_fulfillments_lines_orderLine | null; } +export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_fulfillments_warehouse | null; } export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderLineDelete.ts b/src/orders/types/OrderLineDelete.ts index 96c7b2548..8205439ea 100644 --- a/src/orders/types/OrderLineDelete.ts +++ b/src/orders/types/OrderLineDelete.ts @@ -97,6 +97,12 @@ export interface OrderLineDelete_draftOrderLineDelete_order_fulfillments_lines { orderLine: OrderLineDelete_draftOrderLineDelete_order_fulfillments_lines_orderLine | null; } +export interface OrderLineDelete_draftOrderLineDelete_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderLineDelete_draftOrderLineDelete_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderLineDelete_draftOrderLineDelete_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderLineDelete_draftOrderLineDelete_order_fulfillments_warehouse | null; } export interface OrderLineDelete_draftOrderLineDelete_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderLineUpdate.ts b/src/orders/types/OrderLineUpdate.ts index 3651a5cce..948b0beac 100644 --- a/src/orders/types/OrderLineUpdate.ts +++ b/src/orders/types/OrderLineUpdate.ts @@ -97,6 +97,12 @@ export interface OrderLineUpdate_draftOrderLineUpdate_order_fulfillments_lines { orderLine: OrderLineUpdate_draftOrderLineUpdate_order_fulfillments_lines_orderLine | null; } +export interface OrderLineUpdate_draftOrderLineUpdate_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderLineUpdate_draftOrderLineUpdate_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderLineUpdate_draftOrderLineUpdate_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderLineUpdate_draftOrderLineUpdate_order_fulfillments_warehouse | null; } export interface OrderLineUpdate_draftOrderLineUpdate_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderLinesAdd.ts b/src/orders/types/OrderLinesAdd.ts index 20ecbd7fa..b2cd429e8 100644 --- a/src/orders/types/OrderLinesAdd.ts +++ b/src/orders/types/OrderLinesAdd.ts @@ -97,6 +97,12 @@ export interface OrderLinesAdd_draftOrderLinesCreate_order_fulfillments_lines { orderLine: OrderLinesAdd_draftOrderLinesCreate_order_fulfillments_lines_orderLine | null; } +export interface OrderLinesAdd_draftOrderLinesCreate_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderLinesAdd_draftOrderLinesCreate_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderLinesAdd_draftOrderLinesCreate_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderLinesAdd_draftOrderLinesCreate_order_fulfillments_warehouse | null; } export interface OrderLinesAdd_draftOrderLinesCreate_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderMarkAsPaid.ts b/src/orders/types/OrderMarkAsPaid.ts index 4047ef0b9..898cf9a99 100644 --- a/src/orders/types/OrderMarkAsPaid.ts +++ b/src/orders/types/OrderMarkAsPaid.ts @@ -97,6 +97,12 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments_lines { orderLine: OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments_lines_orderLine | null; } +export interface OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments_warehouse | null; } export interface OrderMarkAsPaid_orderMarkAsPaid_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderRefund.ts b/src/orders/types/OrderRefund.ts index 29eee9ef3..6f764f9e6 100644 --- a/src/orders/types/OrderRefund.ts +++ b/src/orders/types/OrderRefund.ts @@ -97,6 +97,12 @@ export interface OrderRefund_orderRefund_order_fulfillments_lines { orderLine: OrderRefund_orderRefund_order_fulfillments_lines_orderLine | null; } +export interface OrderRefund_orderRefund_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderRefund_orderRefund_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderRefund_orderRefund_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderRefund_orderRefund_order_fulfillments_warehouse | null; } export interface OrderRefund_orderRefund_order_lines_unitPrice_gross { diff --git a/src/orders/types/OrderVoid.ts b/src/orders/types/OrderVoid.ts index 3ee9caec1..880598c78 100644 --- a/src/orders/types/OrderVoid.ts +++ b/src/orders/types/OrderVoid.ts @@ -97,6 +97,12 @@ export interface OrderVoid_orderVoid_order_fulfillments_lines { orderLine: OrderVoid_orderVoid_order_fulfillments_lines_orderLine | null; } +export interface OrderVoid_orderVoid_order_fulfillments_warehouse { + __typename: "Warehouse"; + id: string; + name: string; +} + export interface OrderVoid_orderVoid_order_fulfillments { __typename: "Fulfillment"; id: string; @@ -104,6 +110,7 @@ export interface OrderVoid_orderVoid_order_fulfillments { fulfillmentOrder: number; status: FulfillmentStatus; trackingNumber: string; + warehouse: OrderVoid_orderVoid_order_fulfillments_warehouse | null; } export interface OrderVoid_orderVoid_order_lines_unitPrice_gross { diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index db37b4dab..50c369b6c 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -9,6 +9,7 @@ import useCustomerSearch from "@saleor/searches/useCustomerSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import NotFoundPage from "@saleor/components/NotFoundPage"; import { useWarehouseList } from "@saleor/warehouses/queries"; +import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog"; import { customerUrl } from "../../../customers/urls"; import { maybe, @@ -16,7 +17,7 @@ import { getStringOrPlaceholder } from "../../../misc"; import { productUrl } from "../../../products/urls"; -import { OrderStatus } from "../../../types/globalTypes"; +import { OrderStatus, FulfillmentStatus } from "../../../types/globalTypes"; import OrderAddressEditDialog from "../../components/OrderAddressEditDialog"; import OrderCancelDialog from "../../components/OrderCancelDialog"; import OrderDetailsPage from "../../components/OrderDetailsPage"; @@ -229,6 +230,17 @@ export const OrderDetails: React.FC = ({ id, params }) => { navigate(customerUrl(order.user.id)) } /> + + fulfillment.status === + FulfillmentStatus.FULFILLED + ) + } + /> = ({ id, params }) => { number={order?.number} open={params.action === "cancel"} onClose={closeModal} - onSubmit={variables => + onSubmit={() => orderCancel.mutate({ - id, - ...variables + id }) } /> diff --git a/src/orders/views/OrderList/OrderList.tsx b/src/orders/views/OrderList/OrderList.tsx index eccc47b8f..672539522 100644 --- a/src/orders/views/OrderList/OrderList.tsx +++ b/src/orders/views/OrderList/OrderList.tsx @@ -164,11 +164,10 @@ export const OrderList: React.FC = ({ params }) => { return ( {(orderBulkCancel, orderBulkCancelOpts) => { - const onOrderBulkCancel = (restock: boolean) => + const onOrderBulkCancel = () => orderBulkCancel({ variables: { - ids: params.ids, - restock + ids: params.ids } }); From 5a3afa84a561fc7889c32540ac23e0992c9d87df Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 28 Apr 2020 03:17:58 +0200 Subject: [PATCH 83/88] Display warehouse from which items were fulfilled --- src/orders/components/OrderFulfillment/OrderFulfillment.tsx | 4 ++-- src/orders/queries.ts | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx index ea85414ac..c52c85845 100644 --- a/src/orders/components/OrderFulfillment/OrderFulfillment.tsx +++ b/src/orders/components/OrderFulfillment/OrderFulfillment.tsx @@ -20,7 +20,7 @@ import StatusLabel from "@saleor/components/StatusLabel"; import TableCellAvatar, { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar"; -import { maybe, renderCollection } from "../../../misc"; +import { maybe, renderCollection, getStringOrPlaceholder } from "../../../misc"; import { FulfillmentStatus } from "../../../types/globalTypes"; import { OrderDetails_order_fulfillments } from "../../types/OrderDetails"; @@ -240,7 +240,7 @@ const OrderFulfillment: React.FC = props => { color="textPrimary" variant="body2" > - {fulfillment.warehouse.name} + {getStringOrPlaceholder(fulfillment?.warehouse?.name)} ) }} diff --git a/src/orders/queries.ts b/src/orders/queries.ts index e5c4db3b8..2c49a87b3 100644 --- a/src/orders/queries.ts +++ b/src/orders/queries.ts @@ -2,7 +2,6 @@ import gql from "graphql-tag"; import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch"; import makeQuery from "@saleor/hooks/makeQuery"; -import { warehouseFragment } from "@saleor/warehouses/queries"; import { TypedQuery } from "../queries"; import { OrderDetails, OrderDetailsVariables } from "./types/OrderDetails"; import { @@ -80,7 +79,6 @@ export const fragmentOrderLine = gql` `; export const fulfillmentFragment = gql` ${fragmentOrderLine} - ${warehouseFragment} fragment FulfillmentFragment on Fulfillment { id lines { @@ -94,7 +92,8 @@ export const fulfillmentFragment = gql` status trackingNumber warehouse { - ...WarehouseFragment + id + name } } `; From 3a81eaaf3d561f674e71f2bd6fbee3f8e0859a2c Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 28 Apr 2020 10:59:40 +0200 Subject: [PATCH 84/88] Remove order bulk cancel --- src/orders/components/OrderList/OrderList.tsx | 163 +++++++----------- .../OrderListPage/OrderListPage.tsx | 8 +- src/orders/mutations.ts | 19 -- src/orders/types/OrderBulkCancel.ts | 28 --- src/orders/views/OrderList/OrderList.tsx | 154 +++++------------ 5 files changed, 110 insertions(+), 262 deletions(-) delete mode 100644 src/orders/types/OrderBulkCancel.ts diff --git a/src/orders/components/OrderList/OrderList.tsx b/src/orders/components/OrderList/OrderList.tsx index 45a9f7cc9..b119bf771 100644 --- a/src/orders/components/OrderList/OrderList.tsx +++ b/src/orders/components/OrderList/OrderList.tsx @@ -3,16 +3,15 @@ import TableBody from "@material-ui/core/TableBody"; import TableCell from "@material-ui/core/TableCell"; import TableFooter from "@material-ui/core/TableFooter"; import TableRow from "@material-ui/core/TableRow"; +import TableHead from "@material-ui/core/TableHead"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import Checkbox from "@saleor/components/Checkbox"; import { DateTime } from "@saleor/components/Date"; import Money from "@saleor/components/Money"; import ResponsiveTable from "@saleor/components/ResponsiveTable"; import Skeleton from "@saleor/components/Skeleton"; import StatusLabel from "@saleor/components/StatusLabel"; -import TableHead from "@saleor/components/TableHead"; import TablePagination from "@saleor/components/TablePagination"; import { maybe, @@ -20,7 +19,7 @@ import { transformOrderStatus, transformPaymentStatus } from "@saleor/misc"; -import { ListActions, ListProps, SortPage } from "@saleor/types"; +import { ListProps, SortPage } from "@saleor/types"; import { OrderListUrlSortField } from "@saleor/orders/urls"; import TableCellHeader from "@saleor/components/TableCellHeader"; import { getArrowDirection } from "@saleor/utils/sort"; @@ -59,14 +58,11 @@ const useStyles = makeStyles( { name: "OrderList" } ); -interface OrderListProps - extends ListProps, - ListActions, - SortPage { +interface OrderListProps extends ListProps, SortPage { orders: OrderList_orders_edges_node[]; } -const numberOfColumns = 7; +const numberOfColumns = 6; export const OrderList: React.FC = props => { const { @@ -79,12 +75,7 @@ export const OrderList: React.FC = props => { onUpdateListSettings, onRowClick, onSort, - isChecked, - selected, - sort, - toggle, - toggleAll, - toolbar + sort } = props; const classes = useStyles(props); @@ -99,14 +90,7 @@ export const OrderList: React.FC = props => { : undefined; return ( - + = props => { {renderCollection( orderList, - order => { - const isSelected = order ? isChecked(order.id) : false; - - return ( - - - toggle(order.id)} - /> - - - {maybe(() => order.number) ? ( - "#" + order.number - ) : ( - - )} - - - {maybe(() => order.created) ? ( - - ) : ( - - )} - - - {maybe(() => order.billingAddress) ? ( - <> - {order.billingAddress.firstName} -   - {order.billingAddress.lastName} - - ) : maybe(() => order.userEmail) !== undefined ? ( - order.userEmail - ) : ( - - )} - - - {maybe(() => order.paymentStatus.status) !== undefined ? ( - order.paymentStatus.status === null ? null : ( - - ) - ) : ( - - )} - - - {maybe(() => order.status) ? ( + order => ( + + + {maybe(() => order.number) ? "#" + order.number : } + + + {maybe(() => order.created) ? ( + + ) : ( + + )} + + + {maybe(() => order.billingAddress) ? ( + <> + {order.billingAddress.firstName} +   + {order.billingAddress.lastName} + + ) : maybe(() => order.userEmail) !== undefined ? ( + order.userEmail + ) : ( + + )} + + + {maybe(() => order.paymentStatus.status) !== undefined ? ( + order.paymentStatus.status === null ? null : ( - ) : ( - - )} - - - {maybe(() => order.total.gross) ? ( - - ) : ( - - )} - - - ); - }, + ) + ) : ( + + )} + + + {maybe(() => order.status) ? ( + + ) : ( + + )} + + + {maybe(() => order.total.gross) ? ( + + ) : ( + + )} + + + ), () => ( diff --git a/src/orders/components/OrderListPage/OrderListPage.tsx b/src/orders/components/OrderListPage/OrderListPage.tsx index 525380a0d..aaf2e7141 100644 --- a/src/orders/components/OrderListPage/OrderListPage.tsx +++ b/src/orders/components/OrderListPage/OrderListPage.tsx @@ -7,12 +7,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; import { sectionNames } from "@saleor/intl"; -import { - FilterPageProps, - ListActions, - PageListProps, - SortPage -} from "@saleor/types"; +import { FilterPageProps, PageListProps, SortPage } from "@saleor/types"; import { OrderListUrlSortField } from "@saleor/orders/urls"; import FilterBar from "@saleor/components/FilterBar"; import { OrderList_orders_edges_node } from "../../types/OrderList"; @@ -25,7 +20,6 @@ import { export interface OrderListPageProps extends PageListProps, - ListActions, FilterPageProps, SortPage { orders: OrderList_orders_edges_node[]; diff --git a/src/orders/mutations.ts b/src/orders/mutations.ts index 9bd64447b..d94c3f8ff 100644 --- a/src/orders/mutations.ts +++ b/src/orders/mutations.ts @@ -8,10 +8,6 @@ import { fragmentOrderEvent } from "./queries"; import { OrderAddNote, OrderAddNoteVariables } from "./types/OrderAddNote"; -import { - OrderBulkCancel, - OrderBulkCancelVariables -} from "./types/OrderBulkCancel"; import { OrderCancel, OrderCancelVariables } from "./types/OrderCancel"; import { OrderCapture, OrderCaptureVariables } from "./types/OrderCapture"; import { @@ -87,21 +83,6 @@ export const TypedOrderCancelMutation = TypedMutation< OrderCancelVariables >(orderCancelMutation); -const orderBulkCancelMutation = gql` - ${orderErrorFragment} - mutation OrderBulkCancel($ids: [ID]!) { - orderBulkCancel(ids: $ids) { - errors: orderErrors { - ...OrderErrorFragment - } - } - } -`; -export const TypedOrderBulkCancelMutation = TypedMutation< - OrderBulkCancel, - OrderBulkCancelVariables ->(orderBulkCancelMutation); - const orderDraftCancelMutation = gql` ${fragmentOrderDetails} ${orderErrorFragment} diff --git a/src/orders/types/OrderBulkCancel.ts b/src/orders/types/OrderBulkCancel.ts deleted file mode 100644 index 1a838b957..000000000 --- a/src/orders/types/OrderBulkCancel.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// This file was automatically generated and should not be edited. - -import { OrderErrorCode } from "./../../types/globalTypes"; - -// ==================================================== -// GraphQL mutation operation: OrderBulkCancel -// ==================================================== - -export interface OrderBulkCancel_orderBulkCancel_errors { - __typename: "OrderError"; - code: OrderErrorCode; - field: string | null; -} - -export interface OrderBulkCancel_orderBulkCancel { - __typename: "OrderBulkCancel"; - errors: OrderBulkCancel_orderBulkCancel_errors[]; -} - -export interface OrderBulkCancel { - orderBulkCancel: OrderBulkCancel_orderBulkCancel | null; -} - -export interface OrderBulkCancelVariables { - ids: (string | null)[]; -} diff --git a/src/orders/views/OrderList/OrderList.tsx b/src/orders/views/OrderList/OrderList.tsx index 672539522..d08881d2b 100644 --- a/src/orders/views/OrderList/OrderList.tsx +++ b/src/orders/views/OrderList/OrderList.tsx @@ -1,12 +1,10 @@ -import Button from "@material-ui/core/Button"; import React from "react"; -import { FormattedMessage, useIntl } from "react-intl"; +import { useIntl } from "react-intl"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import SaveFilterTabDialog, { SaveFilterTabDialogFormData } from "@saleor/components/SaveFilterTabDialog"; -import useBulkActions from "@saleor/hooks/useBulkActions"; import useListSettings from "@saleor/hooks/useListSettings"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; @@ -14,20 +12,15 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; -import { maybe } from "@saleor/misc"; +import { maybe, getStringOrPlaceholder } from "@saleor/misc"; import { ListViews } from "@saleor/types"; import createSortHandler from "@saleor/utils/handlers/sortHandler"; import { getSortParams } from "@saleor/utils/sort"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createFilterHandlers from "@saleor/utils/handlers/filterHandlers"; -import OrderBulkCancelDialog from "../../components/OrderBulkCancelDialog"; import OrderListPage from "../../components/OrderListPage/OrderListPage"; -import { - TypedOrderBulkCancelMutation, - useOrderDraftCreateMutation -} from "../../mutations"; +import { useOrderDraftCreateMutation } from "../../mutations"; import { useOrderListQuery } from "../../queries"; -import { OrderBulkCancel } from "../../types/OrderBulkCancel"; import { OrderDraftCreate } from "../../types/OrderDraftCreate"; import { orderListUrl, @@ -56,9 +49,6 @@ export const OrderList: React.FC = ({ params }) => { const notify = useNotifier(); const paginate = usePaginator(); const shop = useShop(); - const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( - params.ids - ); const { updateListSettings, settings } = useListSettings( ListViews.ORDER_LIST ); @@ -91,7 +81,6 @@ export const OrderList: React.FC = ({ params }) => { resetFilters, handleSearchChange ] = createFilterHandlers({ - cleanupFn: reset, createUrl: orderListUrl, getFilterQueryParam, navigate, @@ -103,19 +92,16 @@ export const OrderList: React.FC = ({ params }) => { OrderListUrlQueryParams >(navigate, orderListUrl, params); - const handleTabChange = (tab: number) => { - reset(); + const handleTabChange = (tab: number) => navigate( orderListUrl({ activeTab: tab.toString(), ...getFilterTabs()[tab - 1].data }) ); - }; const handleFilterTabDelete = () => { deleteFilterTab(currentTab); - reset(); navigate(orderListUrl()); }; @@ -135,7 +121,7 @@ export const OrderList: React.FC = ({ params }) => { }), [params, settings.rowNumber] ); - const { data, loading, refetch } = useOrderListQuery({ + const { data, loading } = useOrderListQuery({ displayLoader: true, variables: queryVariables }); @@ -146,100 +132,48 @@ export const OrderList: React.FC = ({ params }) => { params ); - const handleOrderBulkCancel = (data: OrderBulkCancel) => { - if (data.orderBulkCancel.errors.length === 0) { - notify({ - text: intl.formatMessage({ - defaultMessage: "Orders cancelled" - }) - }); - reset(); - refetch(); - closeModal(); - } - }; - const handleSort = createSortHandler(navigate, orderListUrl, params); return ( - - {(orderBulkCancel, orderBulkCancelOpts) => { - const onOrderBulkCancel = () => - orderBulkCancel({ - variables: { - ids: params.ids - } - }); - - return ( - <> - data.orders.edges.map(edge => edge.node))} - pageInfo={pageInfo} - sort={getSortParams(params)} - onAdd={createOrder} - onNextPage={loadNextPage} - onPreviousPage={loadPreviousPage} - onUpdateListSettings={updateListSettings} - onRowClick={id => () => navigate(orderUrl(id))} - onSort={handleSort} - isChecked={isSelected} - selected={listElements.length} - toggle={toggle} - toggleAll={toggleAll} - toolbar={ - - } - onSearchChange={handleSearchChange} - onFilterChange={changeFilters} - onTabSave={() => openModal("save-search")} - onTabDelete={() => openModal("delete-search")} - onTabChange={handleTabChange} - initialSearch={params.query || ""} - tabs={getFilterTabs().map(tab => tab.name)} - onAll={resetFilters} - /> - params.ids.length.toString(), "...")} - onClose={closeModal} - onConfirm={onOrderBulkCancel} - open={params.action === "cancel"} - /> - - tabs[currentTab - 1].name, "...")} - /> - - ); - }} - + <> + data.orders.edges.map(edge => edge.node))} + pageInfo={pageInfo} + sort={getSortParams(params)} + onAdd={createOrder} + onNextPage={loadNextPage} + onPreviousPage={loadPreviousPage} + onUpdateListSettings={updateListSettings} + onRowClick={id => () => navigate(orderUrl(id))} + onSort={handleSort} + onSearchChange={handleSearchChange} + onFilterChange={changeFilters} + onTabSave={() => openModal("save-search")} + onTabDelete={() => openModal("delete-search")} + onTabChange={handleTabChange} + initialSearch={params.query || ""} + tabs={getFilterTabs().map(tab => tab.name)} + onAll={resetFilters} + /> + + + ); }; From 3f5474659fa6087355ae543db360d8023c900729 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 28 Apr 2020 11:07:12 +0200 Subject: [PATCH 85/88] Update snapshots --- .../__snapshots__/Stories.test.ts.snap | 1934 ++++++++++++----- 1 file changed, 1383 insertions(+), 551 deletions(-) diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 5f068e403..d110e1f55 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -64378,25 +64378,25 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = ` SKU C our wares Be stocked A Warehouse Darkwares @@ -64633,6 +64633,415 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = ` / 2 + + +
+
+ +
+
+ Lemon Juice +
+ 2.5l +
+
+
+ + + 998323583 + + + No Stock + + + + 0 + + / 1 + + + + +
+
+ +
+
+ +
+
+`; + +exports[`Storyshots Views / Orders / Fulfill order error 1`] = ` +
+
+
+
+ Order no. 9123 - Add Fulfillment +
+
+
+
+
+
+
+
+ + Items ready to ship + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + @@ -64849,6 +65258,281 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = ` > 998323584 + + + + + + + + + + + + @@ -65332,7 +66016,7 @@ exports[`Storyshots Views / Orders / Order details cancelled 1`] = `
- Fulfilled (1) + Cancelled (1)
@@ -65435,6 +66119,28 @@ exports[`Storyshots Views / Orders / Order details cancelled 1`] = ` $79.71
+ + +
+ Product name + + SKU + + C our wares + + Be stocked + + A Warehouse + + Darkwares + + Quantity to fulfill +
+
+
+ +
+
+ T-Shirt +
+ S +
+
+
+
+ 62783187 + +
+
+
+ + +
+
+
+ / 1207 +
+
+
+
+
+
+ + +
+
+
+ / 1197 +
+
+
+
+
+
+ + +
+
+
+ / 1213 +
+
+
+
+
+
+ + +
+
+
+ / 1213 +
+
+
+ + 0 + + / 2 +
+
+
+
+ + +
+
+
+ / 587 +
+
+
+ No Stock + +
+
+
+ + +
+
+
+ / 758 +
+
+
+
+
+
+ + +
+
+
+ / 727 +
+
+
+
+
+
+ + +
+
+
+ / 756 +
+
+
+ + 0 + + / 4 +
+
+
+ +
+
+ Orange Juice +
+ 5l +
+
+
+
+ 998323584 + +
+
+
+ + +
+
+
+ / 587 +
+
+
+ No Stock + @@ -64938,7 +65622,7 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = `
- / 587 + / 586
+
+ Fulfilled from: +
+ Be stocked +
+
+
+
@@ -65454,7 +66160,7 @@ exports[`Storyshots Views / Orders / Order details cancelled 1`] = `
- Fulfilled (1) + Cancelled (1)
@@ -65557,6 +66263,35 @@ exports[`Storyshots Views / Orders / Order details cancelled 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
@@ -66288,6 +67023,28 @@ exports[`Storyshots Views / Orders / Order details default 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -66451,24 +67208,38 @@ exports[`Storyshots Views / Orders / Order details default 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -67441,24 +68234,38 @@ exports[`Storyshots Views / Orders / Order details fulfilled 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ ... +
+
+
+ +
@@ -68816,6 +69645,28 @@ exports[`Storyshots Views / Orders / Order details no customer note 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -68979,24 +69830,38 @@ exports[`Storyshots Views / Orders / Order details no customer note 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -69969,24 +70856,38 @@ exports[`Storyshots Views / Orders / Order details no payment 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -70959,24 +71882,38 @@ exports[`Storyshots Views / Orders / Order details no shipping address 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -71949,24 +72908,38 @@ exports[`Storyshots Views / Orders / Order details partially fulfilled 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -72939,24 +73934,38 @@ exports[`Storyshots Views / Orders / Order details payment confirmed 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -73929,24 +74960,38 @@ exports[`Storyshots Views / Orders / Order details payment error 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -74919,24 +75986,38 @@ exports[`Storyshots Views / Orders / Order details pending payment 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -75909,24 +77012,38 @@ exports[`Storyshots Views / Orders / Order details refunded payment 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -76899,24 +78038,38 @@ exports[`Storyshots Views / Orders / Order details rejected payment 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
+ + +
+ Fulfilled from: +
+ Be stocked +
+
+
+ +
@@ -77889,24 +79064,38 @@ exports[`Storyshots Views / Orders / Order details unfulfilled 1`] = ` $79.71 + + +
+ Fulfilled from: +
+ C our wares +
+
+
+ Tracking Number: +
+ 01nn12399su12nndfsy +
+
+ +
-
- -
- - - - +
- - - @@ -80772,21 +81928,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -80835,21 +81976,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -80898,21 +82024,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -80961,21 +82072,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81024,21 +82120,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81087,21 +82168,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81150,21 +82216,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81213,21 +82264,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81276,21 +82312,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81339,21 +82360,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81402,21 +82408,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81465,21 +82456,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81528,21 +82504,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81591,21 +82552,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81654,21 +82600,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81717,21 +82648,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81780,21 +82696,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81843,21 +82744,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -81906,21 +82792,6 @@ exports[`Storyshots Views / Orders / Order list default 1`] = ` - - - @@ -82116,27 +82987,7 @@ exports[`Storyshots Views / Orders / Order list loading 1`] = ` - - - - +
- - - @@ -82573,9 +83407,7 @@ exports[`Storyshots Views / Orders / Order list when no data 1`] = ` - +
No orders found From 57038445c928bc22497ff57d8cb826832bdd6b50 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 28 Apr 2020 17:00:52 +0200 Subject: [PATCH 86/88] Update snapshots --- .../__snapshots__/Stories.test.ts.snap | 562 +++++++++--------- 1 file changed, 281 insertions(+), 281 deletions(-) diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index d110e1f55..7d474c182 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -64672,6 +64672,281 @@ exports[`Storyshots Views / Orders / Fulfill order default 1`] = ` > No Stock + +
+
+
+ + +
+
+
+ / 758 +
+
+ + +
+
+
+ + +
+
+
+ / 727 +
+
+ + +
+
+
+ + +
+
+
+ / 756 +
+
+ + + + 0 + + / 4 + + + + +
+
+ +
+
+ Orange Juice +
+ 5l +
+
+
+ + + 998323584 + + +
+
+
+ + +
+
+
+ / 587 +
+
+ + + No Stock + + +
+
+
+ + +
+
+
+ / 586 +
+
+ + + No Stock + @@ -65307,281 +65582,6 @@ exports[`Storyshots Views / Orders / Fulfill order error 1`] = ` > No Stock - -
-
-
- - -
-
-
- / 758 -
-
- - -
-
-
- - -
-
-
- / 727 -
-
- - -
-
-
- - -
-
-
- / 756 -
-
- - - - 0 - - / 4 - - - - -
-
- -
-
- Orange Juice -
- 5l -
-
-
- - - 998323584 - - -
-
-
- - -
-
-
- / 587 -
-
- - - No Stock - - -
-
-
- - -
-
-
- / 586 -
-
- - - No Stock - @@ -99289,7 +99289,7 @@ exports[`Storyshots Views / Products / Create multiple variants / prices and SKU > ​ @@ -101232,7 +101232,7 @@ exports[`Storyshots Views / Products / Create multiple variants / prices and SKU > ​ @@ -129083,7 +129083,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors > ​ @@ -129892,7 +129892,7 @@ exports[`Storyshots Views / Products / Product variant details when loaded data > ​ @@ -139278,7 +139278,7 @@ exports[`Storyshots Views / Shipping / Shipping zone details default 1`] = ` > ​ @@ -140073,7 +140073,7 @@ exports[`Storyshots Views / Shipping / Shipping zone details form errors 1`] = ` > ​ From d69c1fe916111a597d301c35d3405e7f58a454c0 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 28 Apr 2020 11:26:58 +0200 Subject: [PATCH 87/88] Use dedicated mutations to assign warehouses --- src/shipping/mutations.ts | 51 ---------- .../types/AssignShippingZoneToWarehouse.ts | 29 ------ .../types/UnassignShippingZoneToWarehouse.ts | 29 ------ .../views/ShippingZoneDetails/index.tsx | 96 +++---------------- 4 files changed, 15 insertions(+), 190 deletions(-) delete mode 100644 src/shipping/types/AssignShippingZoneToWarehouse.ts delete mode 100644 src/shipping/types/UnassignShippingZoneToWarehouse.ts diff --git a/src/shipping/mutations.ts b/src/shipping/mutations.ts index 6a028ab5b..83ffa811a 100644 --- a/src/shipping/mutations.ts +++ b/src/shipping/mutations.ts @@ -1,7 +1,6 @@ import gql from "graphql-tag"; import makeMutation from "@saleor/hooks/makeMutation"; -import { warehouseErrorFragment } from "@saleor/warehouses/mutations"; import { countryFragment } from "../taxes/queries"; import { shippingMethodFragment, shippingZoneDetailsFragment } from "./queries"; import { @@ -40,14 +39,6 @@ import { UpdateShippingZone, UpdateShippingZoneVariables } from "./types/UpdateShippingZone"; -import { - AssignShippingZoneToWarehouse, - AssignShippingZoneToWarehouseVariables -} from "./types/AssignShippingZoneToWarehouse"; -import { - UnassignShippingZoneToWarehouse, - UnassignShippingZoneToWarehouseVariables -} from "./types/UnassignShippingZoneToWarehouse"; export const shippingErrorFragment = gql` fragment ShippingErrorFragment on ShippingError { @@ -223,45 +214,3 @@ export const useShippingRateBulkDelete = makeMutation< BulkDeleteShippingRate, BulkDeleteShippingRateVariables >(bulkDeleteShippingRate); - -const assignShippingZoneToWarehouse = gql` - ${warehouseErrorFragment} - mutation AssignShippingZoneToWarehouse( - $warehouseId: ID! - $shippingZoneId: ID! - ) { - assignWarehouseShippingZone( - id: $warehouseId - shippingZoneIds: [$shippingZoneId] - ) { - errors: warehouseErrors { - ...WarehouseErrorFragment - } - } - } -`; -export const useAssignShippingZoneToWarehouse = makeMutation< - AssignShippingZoneToWarehouse, - AssignShippingZoneToWarehouseVariables ->(assignShippingZoneToWarehouse); - -const unassignShippingZoneToWarehouse = gql` - ${warehouseErrorFragment} - mutation UnassignShippingZoneToWarehouse( - $warehouseId: ID! - $shippingZoneId: ID! - ) { - unassignWarehouseShippingZone( - id: $warehouseId - shippingZoneIds: [$shippingZoneId] - ) { - errors: warehouseErrors { - ...WarehouseErrorFragment - } - } - } -`; -export const useUnassignShippingZoneToWarehouse = makeMutation< - UnassignShippingZoneToWarehouse, - UnassignShippingZoneToWarehouseVariables ->(unassignShippingZoneToWarehouse); diff --git a/src/shipping/types/AssignShippingZoneToWarehouse.ts b/src/shipping/types/AssignShippingZoneToWarehouse.ts deleted file mode 100644 index ae104a3a4..000000000 --- a/src/shipping/types/AssignShippingZoneToWarehouse.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// This file was automatically generated and should not be edited. - -import { WarehouseErrorCode } from "./../../types/globalTypes"; - -// ==================================================== -// GraphQL mutation operation: AssignShippingZoneToWarehouse -// ==================================================== - -export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone_errors { - __typename: "WarehouseError"; - code: WarehouseErrorCode; - field: string | null; -} - -export interface AssignShippingZoneToWarehouse_assignWarehouseShippingZone { - __typename: "WarehouseShippingZoneAssign"; - errors: AssignShippingZoneToWarehouse_assignWarehouseShippingZone_errors[]; -} - -export interface AssignShippingZoneToWarehouse { - assignWarehouseShippingZone: AssignShippingZoneToWarehouse_assignWarehouseShippingZone | null; -} - -export interface AssignShippingZoneToWarehouseVariables { - warehouseId: string; - shippingZoneId: string; -} diff --git a/src/shipping/types/UnassignShippingZoneToWarehouse.ts b/src/shipping/types/UnassignShippingZoneToWarehouse.ts deleted file mode 100644 index 137a51c25..000000000 --- a/src/shipping/types/UnassignShippingZoneToWarehouse.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// This file was automatically generated and should not be edited. - -import { WarehouseErrorCode } from "./../../types/globalTypes"; - -// ==================================================== -// GraphQL mutation operation: UnassignShippingZoneToWarehouse -// ==================================================== - -export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_errors { - __typename: "WarehouseError"; - code: WarehouseErrorCode; - field: string | null; -} - -export interface UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone { - __typename: "WarehouseShippingZoneUnassign"; - errors: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone_errors[]; -} - -export interface UnassignShippingZoneToWarehouse { - unassignWarehouseShippingZone: UnassignShippingZoneToWarehouse_unassignWarehouseShippingZone | null; -} - -export interface UnassignShippingZoneToWarehouseVariables { - warehouseId: string; - shippingZoneId: string; -} diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 9b724292c..5bb5f6791 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -14,9 +14,7 @@ import { useShippingRateUpdate, useShippingRateDelete, useShippingZoneDelete, - useShippingZoneUpdate, - useAssignShippingZoneToWarehouse, - useUnassignShippingZoneToWarehouse + useShippingZoneUpdate } from "@saleor/shipping/mutations"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import ShippingZoneRateDialog from "@saleor/shipping/components/ShippingZoneRateDialog"; @@ -65,9 +63,6 @@ const ShippingZoneDetails: React.FC = ({ } ); - const [assignToWarehouse] = useAssignShippingZoneToWarehouse({}); - const [unassignToWarehouse] = useUnassignShippingZoneToWarehouse({}); - const { data, loading } = useShippingZone({ displayLoader: true, variables: { id } @@ -147,83 +142,22 @@ const ShippingZoneDetails: React.FC = ({ } }); - const handleSubmit = async (submitData: FormData) => { - try { - const updateResult = await updateShippingZone({ - variables: { - id, - input: { - name: submitData.name - } + const handleSubmit = (submitData: FormData) => { + const warehouseDiff = diff( + data.shippingZone.warehouses.map(warehouse => warehouse.id), + submitData.warehouses + ); + + updateShippingZone({ + variables: { + id, + input: { + addWarehouses: warehouseDiff.added, + name: submitData.name, + removeWarehouses: warehouseDiff.removed } - }); - const updateErrors = updateResult.data.shippingZoneUpdate.errors; - - if (updateErrors.length === 0) { - const warehouseDiff = diff( - data.shippingZone.warehouses.map(warehouse => warehouse.id), - submitData.warehouses - ); - const assignResults = await Promise.all( - warehouseDiff.added.map(warehouseId => - assignToWarehouse({ - variables: { - shippingZoneId: id, - warehouseId - } - }) - ) - ); - const assignErrors = assignResults - .map( - assignResult => assignResult.data.assignWarehouseShippingZone.errors - ) - .reduce((acc, errors) => [...acc, ...errors], []); - - if (assignErrors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - } else { - throw new Error( - `Assigning to warehouse failed: ${assignErrors[0].code}` - ); - } - - const unassignResults = await Promise.all( - warehouseDiff.removed.map(warehouseId => - unassignToWarehouse({ - variables: { - shippingZoneId: id, - warehouseId - } - }) - ) - ); - const unassignErrors = unassignResults - .map( - unassignResult => - unassignResult.data.unassignWarehouseShippingZone.errors - ) - .reduce((acc, errors) => [...acc, ...errors], []); - - if (unassignErrors.length === 0) { - notify({ - text: intl.formatMessage(commonMessages.savedChanges) - }); - } else { - throw new Error( - `Assigning to warehouse failed: ${unassignErrors[0].code}` - ); - } - } else { - throw new Error(`Updating failed: ${updateErrors[0].code}`); } - } catch (err) { - notify({ - text: intl.formatMessage(commonMessages.somethingWentWrong) - }); - } + }); }; if (data?.shippingZone === null) { From ce38bb835293b23783a3d23049388a4fcf9f6bb8 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 29 Apr 2020 03:47:07 +0200 Subject: [PATCH 88/88] Update messages --- locale/defaultMessages.json | 546 ++++++++++++------ .../ProductVariantCreatorStock.tsx | 3 +- 2 files changed, 374 insertions(+), 175 deletions(-) diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json index f656ec321..cf600f637 100644 --- a/locale/defaultMessages.json +++ b/locale/defaultMessages.json @@ -1,8 +1,4 @@ { - "OrderCancelDialogButton": { - "context": "button", - "string": "Cancel Order" - }, "OrderCancelDialogHeader": { "context": "dialog header", "string": "Cancel Order" @@ -34,6 +30,9 @@ "configurationMenuTaxes": { "string": "Manage how your store charges tax" }, + "configurationMenuWarehouses": { + "string": "Manage and update your warehouse information" + }, "configurationPluginsPages": { "string": "View and update your plugins and their settings." }, @@ -206,10 +205,6 @@ "context": "vat not included in order price", "string": "does not apply" }, - "prodictStockInventoryLabel": { - "context": "product stock", - "string": "Inventory" - }, "productStatusLabel": { "context": "product", "string": "Published" @@ -240,13 +235,17 @@ "context": "variant price", "string": "Price" }, - "productVariantCreatePricesSetStockPlaceholder": { - "context": "variant stock", - "string": "Stock" - }, "productVariantCreatePricesStockInputLabel": { "string": "Stock" }, + "productVariantCreatorStockSectionHeader": { + "context": "variant stock, header", + "string": "Stock" + }, + "productVariantCreatorWarehouseSectionHeader": { + "context": "header", + "string": "Warehouses" + }, "productVariantPriceOptionalCostPriceField": { "context": "optional field", "string": "Optional" @@ -287,10 +286,18 @@ "context": "delete shipping zone", "string": "Are you sure you want to delete {name}?" }, + "shippingZoneWarehouses_dot_autocomplete_dot_label": { + "context": "autocomplete select label", + "string": "Warehouse" + }, "siteSettingsMailingHelperText": { "context": "helper text", "string": "Mailing Configuration" }, + "src_dot_accept": { + "context": "button", + "string": "Accept" + }, "src_dot_attributes": { "context": "attributes section name", "string": "Attributes" @@ -1020,6 +1027,30 @@ "context": "pick columns to display", "string": "{numberOfSelected} columns selected out of {numberOfTotal}" }, + "src_dot_components_dot_CompanyAddressInput_dot_1139500589": { + "string": "Country" + }, + "src_dot_components_dot_CompanyAddressInput_dot_1271289966": { + "string": "Phone" + }, + "src_dot_components_dot_CompanyAddressInput_dot_1363074570": { + "string": "Address line 1" + }, + "src_dot_components_dot_CompanyAddressInput_dot_253031977": { + "string": "City" + }, + "src_dot_components_dot_CompanyAddressInput_dot_2965971965": { + "string": "ZIP / Postal code" + }, + "src_dot_components_dot_CompanyAddressInput_dot_3121963259": { + "string": "Address line 2" + }, + "src_dot_components_dot_CompanyAddressInput_dot_3570415321": { + "string": "Company" + }, + "src_dot_components_dot_CompanyAddressInput_dot_944851093": { + "string": "Country area" + }, "src_dot_components_dot_ConfirmButton_dot_2845142593": { "context": "button", "string": "Error" @@ -2191,6 +2222,10 @@ "src_dot_no": { "string": "No" }, + "src_dot_ok": { + "context": "button", + "string": "OK" + }, "src_dot_optionalField": { "context": "field is optional", "string": "Optional" @@ -2211,19 +2246,18 @@ "context": "dialog header", "string": "Cancel Orders" }, - "src_dot_orders_dot_components_dot_OrderBulkCancelDialog_dot_187921539": { - "context": "switch button", - "string": "Release all stock allocated to these orders" - }, "src_dot_orders_dot_components_dot_OrderBulkCancelDialog_dot_4224885638": { "string": "{counter,plural,one{Are you sure you want to cancel this order?} other{Are you sure you want to cancel {displayQuantity} orders?}}" }, - "src_dot_orders_dot_components_dot_OrderCancelDialog_dot_3981375672": { - "string": "Are you sure you want to cancel order #{orderNumber}?" + "src_dot_orders_dot_components_dot_OrderCancelDialog_dot_4059738695": { + "string": "Cancelling this order will release unfulfilled stocks, so they can be bought by other customers. Order will not be refunded when cancelling order - You need to do it manually. Are you sure you want to cancel this order?" }, - "src_dot_orders_dot_components_dot_OrderCancelDialog_dot_944150063": { - "context": "switch button", - "string": "Release all stock allocated to this order" + "src_dot_orders_dot_components_dot_OrderCannotCancelOrderDialog_dot_1561587911": { + "context": "dialog header", + "string": "Saleor couldn’t cancel order" + }, + "src_dot_orders_dot_components_dot_OrderCannotCancelOrderDialog_dot_775268031": { + "string": "There are still fulfillments created for this order. Cancel the fulfillments first before you cancel the order." }, "src_dot_orders_dot_components_dot_OrderCustomerNote_dot_1505053535": { "string": "No notes from customer" @@ -2392,16 +2426,51 @@ "context": "button", "string": "Finalize" }, - "src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_2569854889": { - "string": "Are you sure you want to cancel this fulfillment?" + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_1608534452": { + "context": "page header", + "string": "Order no. {orderNumber} - Add Fulfillment" }, - "src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_3515223857": { - "context": "switch button", - "string": "Restock items?" + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_2094985970": { + "context": "quantity of fulfilled products", + "string": "Quantity to fulfill" }, - "src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_675709443": { - "context": "button", - "string": "Cancel fulfillment" + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_2095687440": { + "context": "fulfill order, button", + "string": "Fulfill" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_2588284040": { + "context": "no variant stock in warehouse", + "string": "No Stock" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_3244948255": { + "context": "header", + "string": "Items ready to ship" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_3620521256": { + "context": "page header", + "string": "Order" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_4046223826": { + "string": "Product name" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_4251997263": { + "context": "checkbox", + "string": "Send shipment details to customer" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_580490159": { + "context": "page header with order number", + "string": "Order #{orderNumber}" + }, + "src_dot_orders_dot_components_dot_OrderFulfillPage_dot_693960049": { + "context": "product's sku", + "string": "SKU" + }, + "src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_1097287358": { + "string": "Are you sure you want to cancel fulfillment? Canceling a fulfillment will restock products at a selected warehouse." + }, + "src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_46197273": { + "context": "select warehouse to restock items", + "string": "Select Warehouse" }, "src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_732594284": { "context": "dialog header", @@ -2456,9 +2525,17 @@ "context": "section header", "string": "Fulfilled ({quantity})" }, - "src_dot_orders_dot_components_dot_OrderFulfillment_dot_662203348": { + "src_dot_orders_dot_components_dot_OrderFulfillment_dot_4039425374": { + "context": "cancelled fulfillment, section header", + "string": "Cancelled ({quantity})" + }, + "src_dot_orders_dot_components_dot_OrderFulfillment_dot_732594284": { "context": "button", - "string": "Cancel shipment" + "string": "Cancel Fulfillment" + }, + "src_dot_orders_dot_components_dot_OrderFulfillment_dot_77179533": { + "context": "fulfillment group", + "string": "Fulfilled from: {warehouseName}" }, "src_dot_orders_dot_components_dot_OrderFulfillment_dot_878013594": { "context": "order line total price", @@ -2766,9 +2843,6 @@ "src_dot_orders_dot_views_dot_OrderDetails_dot_3367579693": { "string": "Order successfully updated" }, - "src_dot_orders_dot_views_dot_OrderDetails_dot_4245651107": { - "string": "Items successfully fulfilled" - }, "src_dot_orders_dot_views_dot_OrderDetails_dot_580490159": { "context": "window title", "string": "Order #{orderNumber}" @@ -2800,16 +2874,21 @@ "context": "dialog content", "string": "{counter,plural,one{Are you sure you want to delete this order draft?} other{Are you sure you want to delete {displayQuantity} order drafts?}}" }, - "src_dot_orders_dot_views_dot_OrderList_dot_1136302661": { - "string": "Orders cancelled" + "src_dot_orders_dot_views_dot_OrderFulfill_dot_1186021594": { + "context": "window title", + "string": "Fulfill Order #{orderNumber}" + }, + "src_dot_orders_dot_views_dot_OrderFulfill_dot_1892156526": { + "context": "order fulfilled success message", + "string": "Fulfilled Items" + }, + "src_dot_orders_dot_views_dot_OrderFulfill_dot_3754102871": { + "context": "window title", + "string": "Fulfill Order" }, "src_dot_orders_dot_views_dot_OrderList_dot_1738939038": { "string": "Order draft successfully created" }, - "src_dot_orders_dot_views_dot_OrderList_dot_3528672691": { - "context": "cancel orders, button", - "string": "Cancel" - }, "src_dot_pages": { "context": "pages section name", "string": "Pages" @@ -3520,13 +3599,35 @@ "src_dot_products_dot_components_dot_ProductPricing_dot_3015886868": { "string": "Charge taxes for this item" }, - "src_dot_products_dot_components_dot_ProductStock_dot_1680952454": { - "context": "allocated product stock", - "string": "Allocated: {quantity}" - }, - "src_dot_products_dot_components_dot_ProductStock_dot_2585918415": { + "src_dot_products_dot_components_dot_ProductStocks_dot_2585918415": { "string": "SKU (Stock Keeping Unit)" }, + "src_dot_products_dot_components_dot_ProductStocks_dot_2622674857": { + "context": "tabel column header", + "string": "Warehouse Name" + }, + "src_dot_products_dot_components_dot_ProductStocks_dot_2729628316": { + "context": "tabel column header", + "string": "Quantity Available" + }, + "src_dot_products_dot_components_dot_ProductStocks_dot_2796503714": { + "context": "header", + "string": "Quantity" + }, + "src_dot_products_dot_components_dot_ProductStocks_dot_3143542809": { + "string": "This product doesn't have any stock. You can add it here." + }, + "src_dot_products_dot_components_dot_ProductStocks_dot_3482985373": { + "context": "button", + "string": "Edit Warehouses" + }, + "src_dot_products_dot_components_dot_ProductStocks_dot_3633706025": { + "context": "product inventory, checkbox", + "string": "Track Inventory" + }, + "src_dot_products_dot_components_dot_ProductStocks_dot_849869830": { + "string": "Active inventory tracking will automatically calculate changes of stock" + }, "src_dot_products_dot_components_dot_ProductUpdatePage_dot_1815688500": { "context": "product", "string": "since {date}" @@ -3546,81 +3647,6 @@ "context": "product attribute error", "string": "This variant already exists" }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_1009678918": { - "context": "header", - "string": "You will create variants below" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_1134347598": { - "context": "variant price", - "string": "Price" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_168343345": { - "context": "variant attribute", - "string": "Attribute" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_2478977538": { - "context": "attribute values, variant creation step", - "string": "Select Values" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_2670525734": { - "context": "variant attribute", - "string": "Choose attribute" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_2745385064": { - "context": "variant creation step", - "string": "Summary" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_2783195765": { - "string": "Apply single price to all SKUs" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3387090508": { - "string": "Apply unique stock by attribute to each SKU" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3490038570": { - "context": "variant stock amount", - "string": "Inventory" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3528672691": { - "context": "button", - "string": "Cancel" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3570949907": { - "string": "Apply unique prices by attribute to each SKU" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3601538615": { - "string": "Apply single stock to all SKUs" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3673120330": { - "context": "button", - "string": "Next" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3841616483": { - "context": "variant stock, header", - "string": "Stock" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_3922579741": { - "context": "dialog header", - "string": "Assign Attribute" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_4120989039": { - "context": "create multiple variants, button", - "string": "Create" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_693960049": { - "string": "SKU" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_705096461": { - "context": "variant creation step", - "string": "Prices and SKU" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_904693740": { - "context": "previous step, button", - "string": "Previous" - }, - "src_dot_products_dot_components_dot_ProductVariantCreateDialog_dot_998917294": { - "context": "variant name", - "string": "Variant" - }, "src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_2853608829": { "context": "button", "string": "Save variant" @@ -3629,6 +3655,96 @@ "context": "button", "string": "Delete Variant" }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_1134347598": { + "context": "variant price", + "string": "Price" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_1346828628": { + "string": "Selected values will be used to create variants for the configurable product." + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_168343345": { + "context": "variant attribute", + "string": "Attribute" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_1808330403": { + "context": "variant attribute", + "string": "Select Attribute" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2002684673": { + "context": "page title", + "string": "Price and SKUs" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2020618004": { + "context": "variant stock, header", + "string": "Stock and Warehousing" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2158649399": { + "context": "product attribute values, page title", + "string": "Choose Values" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2478977538": { + "context": "attribute values, variant creation step", + "string": "Select Values" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2670525734": { + "context": "variant attribute", + "string": "Choose attribute" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2745385064": { + "context": "variant creation step", + "string": "Summary" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_2783195765": { + "string": "Apply single price to all SKUs" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_3387090508": { + "string": "Apply unique stock by attribute to each SKU" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_3570949907": { + "string": "Apply unique prices by attribute to each SKU" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_3601538615": { + "string": "Apply single stock to all SKUs" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_3673120330": { + "context": "button", + "string": "Next" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_3699389906": { + "string": "Here is the summary of variants that will be created. You can change prices, stocks an SKU for each one created." + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_3896519183": { + "string": "Skip stock for now" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_4120989039": { + "context": "create multiple variants, button", + "string": "Create" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_520980261": { + "context": "variant creator summary card header", + "string": "Created Variants" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_551319747": { + "string": "Based on your selections we will create {numberOfProducts} products. Use this step to customize price and stocks for your new products" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_693960049": { + "string": "SKU" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_705096461": { + "context": "variant creation step", + "string": "Prices and SKU" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_860603977": { + "string": "Based on your selections we will create 8 products. Use this step to customize price and stocks for your new products." + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_904693740": { + "context": "previous step, button", + "string": "Previous" + }, + "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_998917294": { + "context": "variant name", + "string": "Variant" + }, "src_dot_products_dot_components_dot_ProductVariantDeleteDialog_dot_1583616500": { "context": "button", "string": "Delete variant" @@ -3678,23 +3794,12 @@ "src_dot_products_dot_components_dot_ProductVariantPrice_dot_2238565650": { "string": "Selling price override" }, - "src_dot_products_dot_components_dot_ProductVariantStock_dot_1680952454": { - "context": "variant allocated stock", - "string": "Allocated: {quantity}" - }, - "src_dot_products_dot_components_dot_ProductVariantStock_dot_2585918415": { - "string": "SKU (Stock Keeping Unit)" - }, - "src_dot_products_dot_components_dot_ProductVariantStock_dot_3490038570": { - "context": "product variant stock", - "string": "Inventory" - }, - "src_dot_products_dot_components_dot_ProductVariantStock_dot_3841616483": { - "context": "product variant stock, section header", - "string": "Stock" + "src_dot_products_dot_components_dot_ProductVariants_dot_1001303107": { + "context": "product variant inventory", + "string": "Unavailable in all locations" }, "src_dot_products_dot_components_dot_ProductVariants_dot_1033175132": { - "context": "product variant status", + "context": "product variant inventory", "string": "Unavailable" }, "src_dot_products_dot_components_dot_ProductVariants_dot_1134347598": { @@ -3705,32 +3810,55 @@ "context": "button", "string": "Create variants" }, - "src_dot_products_dot_components_dot_ProductVariants_dot_1756106276": { - "context": "product variant status", - "string": "Status" - }, "src_dot_products_dot_components_dot_ProductVariants_dot_2153006789": { "context": "section header", "string": "Variants" }, - "src_dot_products_dot_components_dot_ProductVariants_dot_2157131639": { - "context": "product variant status", - "string": "Available" + "src_dot_products_dot_components_dot_ProductVariants_dot_2496096212": { + "context": "product variant inventory", + "string": "{numLocations,plural,one{{numAvailable} available at {numLocations} location} other{{numAvailable} available at {numLocations} locations}}" }, "src_dot_products_dot_components_dot_ProductVariants_dot_277989856": { "string": "Use variants for products that come in a variety of versions for example different sizes or colors" }, + "src_dot_products_dot_components_dot_ProductVariants_dot_3203451491": { + "context": "filtering option", + "string": "All Warehouses" + }, + "src_dot_products_dot_components_dot_ProductVariants_dot_3284706946": { + "context": "variant stock status", + "string": "Available inventoty at:" + }, + "src_dot_products_dot_components_dot_ProductVariants_dot_3490038570": { + "context": "product variant inventory status", + "string": "Inventory" + }, + "src_dot_products_dot_components_dot_ProductVariants_dot_387066717": { + "context": "product variant inventory", + "string": "{stockQuantity,plural,other{{stockQuantity} available}}" + }, "src_dot_products_dot_components_dot_ProductVariants_dot_3989383405": { "context": "button", "string": "Create variant" }, - "src_dot_products_dot_components_dot_ProductVariants_dot_636461959": { - "context": "product variant name", - "string": "Name" + "src_dot_products_dot_components_dot_ProductVariants_dot_4017567521": { + "context": "product variant inventory", + "string": "Not stocked" }, "src_dot_products_dot_components_dot_ProductVariants_dot_693960049": { "string": "SKU" }, + "src_dot_products_dot_components_dot_ProductVariants_dot_998917294": { + "context": "product variant name", + "string": "Variant" + }, + "src_dot_products_dot_components_dot_ProductWarehousesDialog_dot_3482985373": { + "context": "dialog header", + "string": "Edit Warehouses" + }, + "src_dot_products_dot_components_dot_ProductWarehousesDialog_dot_4112406382": { + "string": "Select warehouses that stock selected product" + }, "src_dot_products_dot_views_dot_1542417144": { "context": "window title", "string": "Create Product" @@ -3811,6 +3939,14 @@ "context": "dialog header", "string": "Delete Product" }, + "src_dot_products_dot_views_dot_ProductVariantCreator_dot_2292700443": { + "context": "success message", + "string": "Successfully created variants" + }, + "src_dot_products_dot_views_dot_ProductVariantCreator_dot_830692292": { + "context": "window title", + "string": "Create Variants" + }, "src_dot_properties": { "string": "Properties" }, @@ -4014,6 +4150,13 @@ "src_dot_shipping_dot_components_dot_ShippingWeightUnitForm_dot_549146363": { "string": "Shipping Weight Unit" }, + "src_dot_shipping_dot_components_dot_ShippingZoneAddWarehouseDialog_dot_2622674857": { + "string": "Warehouse Name" + }, + "src_dot_shipping_dot_components_dot_ShippingZoneAddWarehouseDialog_dot_3173942020": { + "context": "header, dialog", + "string": "Create New Warehouse" + }, "src_dot_shipping_dot_components_dot_ShippingZoneCountriesAssignDialog_dot_1003092716": { "string": "Rest of the World" }, @@ -4184,6 +4327,21 @@ "context": "shipping method name", "string": "Name" }, + "src_dot_shipping_dot_components_dot_ShippingZoneWarehouses_dot_1221560277": { + "context": "section header", + "string": "Warehouse" + }, + "src_dot_shipping_dot_components_dot_ShippingZoneWarehouses_dot_2304484478": { + "context": "button", + "string": "Add New Warehouse" + }, + "src_dot_shipping_dot_components_dot_ShippingZoneWarehouses_dot_3852102652": { + "string": "Select warehouse from which you will ship products for this shipping zone. This warehouse address will also be used to calculate taxes." + }, + "src_dot_shipping_dot_components_dot_ShippingZoneWarehouses_dot_46197273": { + "context": "input placeholder", + "string": "Select Warehouse" + }, "src_dot_shipping_dot_components_dot_ShippingZonesListPage_dot_1325966144": { "context": "header", "string": "Shipping" @@ -4245,34 +4403,6 @@ "context": "site settings section name", "string": "Site Settings" }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_1139500589": { - "string": "Country" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_1271289966": { - "string": "Phone" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_1363074570": { - "string": "Address line 1" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_229184360": { - "context": "section header", - "string": "Store Information" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_253031977": { - "string": "City" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_2965971965": { - "string": "ZIP / Postal code" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_3121963259": { - "string": "Address line 2" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_3570415321": { - "string": "Company" - }, - "src_dot_siteSettings_dot_components_dot_SiteSettingsAddress_dot_944851093": { - "string": "Country area" - }, "src_dot_siteSettings_dot_components_dot_SiteSettingsDetails_dot_1008586926": { "string": "Name of your store is shown on tab in web browser" }, @@ -4359,6 +4489,10 @@ "src_dot_siteSettings_dot_components_dot_SiteSettingsPage_dot_1214877701": { "string": "Authentication method defines additional ways that customers can log in to your ecommerce." }, + "src_dot_siteSettings_dot_components_dot_SiteSettingsPage_dot_229184360": { + "context": "section header", + "string": "Store Information" + }, "src_dot_siteSettings_dot_components_dot_SiteSettingsPage_dot_2768400497": { "context": "section header", "string": "Company Information" @@ -4980,6 +5114,10 @@ "context": "bulk variant create error", "string": "SKUs must be unique" }, + "src_dot_utils_dot_errors_dot_slugUnique": { + "context": "error message", + "string": "Slug must be unique for each warehouse" + }, "src_dot_utils_dot_errors_dot_tooCommon": { "string": "This password is too commonly used" }, @@ -5002,6 +5140,68 @@ "context": "vouchers section name", "string": "Vouchers" }, + "src_dot_warehouses": { + "context": "warehouses section name", + "string": "Warehouses" + }, + "src_dot_warehouses_dot_components_dot_WarehouseCreatePage_dot_1967111456": { + "context": "warehouse", + "string": "Address Information" + }, + "src_dot_warehouses_dot_components_dot_WarehouseCreatePage_dot_934572530": { + "context": "header", + "string": "Create Warehouse" + }, + "src_dot_warehouses_dot_components_dot_WarehouseDeleteDialog_dot_1355303260": { + "context": "dialog content", + "string": "Are you sure you want to delete {warehouseName}?" + }, + "src_dot_warehouses_dot_components_dot_WarehouseDeleteDialog_dot_3857661071": { + "context": "dialog title", + "string": "Delete Warehouse" + }, + "src_dot_warehouses_dot_components_dot_WarehouseDetailsPage_dot_1967111456": { + "context": "warehouse", + "string": "Address Information" + }, + "src_dot_warehouses_dot_components_dot_WarehouseInfo_dot_2622674857": { + "string": "Warehouse Name" + }, + "src_dot_warehouses_dot_components_dot_WarehouseListPage_dot_2304765290": { + "string": "Search Warehouse" + }, + "src_dot_warehouses_dot_components_dot_WarehouseListPage_dot_3203451491": { + "context": "tab name", + "string": "All Warehouses" + }, + "src_dot_warehouses_dot_components_dot_WarehouseListPage_dot_934572530": { + "context": "button", + "string": "Create Warehouse" + }, + "src_dot_warehouses_dot_components_dot_WarehouseList_dot_1225932315": { + "string": "Shipping Zones" + }, + "src_dot_warehouses_dot_components_dot_WarehouseList_dot_3787396469": { + "string": "No warehouses found" + }, + "src_dot_warehouses_dot_components_dot_WarehouseList_dot_4190792473": { + "string": "Actions" + }, + "src_dot_warehouses_dot_components_dot_WarehouseList_dot_636461959": { + "context": "warehouse", + "string": "Name" + }, + "src_dot_warehouses_dot_components_dot_WarehouseZones_dot_1225932315": { + "context": "zones that warehouse sends to", + "string": "Shipping Zones" + }, + "src_dot_warehouses_dot_components_dot_WarehouseZones_dot_2423245141": { + "string": "This warehouse has no shipping zones assigned." + }, + "src_dot_warehouses_dot_views_dot_WarehouseCreate_dot_934572530": { + "context": "header", + "string": "Create Warehouse" + }, "src_dot_webhooks": { "context": "webhooks section name", "string": "Webhooks" diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx index 50b5d99f0..b087073a9 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorStock.tsx @@ -129,13 +129,12 @@ const ProductVariantCreatorStock: React.FC = pr acc + attr.values.length,