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 + ), + [] + )} />