Add warehouse create

This commit is contained in:
dominik-zeglen 2020-01-30 15:34:27 +01:00
parent 74ea099824
commit 2a7829c0f7
14 changed files with 491 additions and 9 deletions

View file

@ -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"
};

View file

@ -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;
}

View file

@ -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", () => <WarehouseCreatePage {...props} />)
.add("loading", () => (
<WarehouseCreatePage {...props} service={undefined} disabled={true} />
))
.add("form errors", () => (
<WarehouseCreatePage
{...props}
errors={([
"name",
"city",
"cityArea",
"companyName",
"country",
"countryArea",
"phone",
"postalCode",
"streetAddress1",
"streetAddress2"
] as Array<keyof WarehouseCreatePageFormData>).map(field =>
formError(field)
)}
/>
));

View file

@ -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<WarehouseCreatePageProps> = ({
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<WarehouseCreatePageFormData>(onSubmit);
return (
<Form
initial={initialForm}
errors={[...apiErrors, ...validationErrors]}
onSubmit={handleSubmit}
>
{({ change, data, errors, submit }) => {
const countryChoices = mapCountriesToChoices(
maybe(() => shop.countries, [])
);
const handleCountryChange = createSingleAutocompleteSelectHandler(
change,
setDisplayCountry,
countryChoices
);
return (
<Container>
<Grid>
<div>
<WarehouseInfo
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<CompanyAddressInput
countries={countryChoices}
data={data}
disabled={disabled}
displayCountry={displayCountry}
errors={errors}
header={intl.formatMessage({
defaultMessage: "Address Information",
description: "warehouse"
})}
onChange={change}
onCountryChange={handleCountryChange}
/>
</div>
</Grid>
<SaveButtonBar
disabled={disabled}
onCancel={onBack}
onSave={submit}
state={saveButtonBarState}
/>
</Container>
);
}}
</Form>
);
};
WarehouseCreatePage.displayName = "WarehouseCreatePage";
export default WarehouseCreatePage;

View file

@ -0,0 +1,2 @@
export { default } from "./WarehouseCreatePage";
export * from "./WarehouseCreatePage";

View file

@ -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<WarehouseInfoProps> = ({
data,
disabled,
errors,
onChange
}) => {
const intl = useIntl();
return (
<Card>
<CardTitle
title={intl.formatMessage(commonMessages.generalInformations)}
/>
<CardContent>
<TextField
disabled={disabled}
error={!!errors.name}
fullWidth
helperText={errors.name}
label={intl.formatMessage({
defaultMessage: "Warehouse Name"
})}
name={"name" as keyof typeof data}
value={data.name}
onChange={onChange}
/>
</CardContent>
</Card>
);
};
WarehouseInfo.displayName = "WarehouseInfo";
export default WarehouseInfo;

View file

@ -0,0 +1,2 @@
export { default } from "./WarehouseInfo";
export * from "./WarehouseInfo";

View file

@ -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<RouteComponentProps> = ({ location }) => {
const qs = parseQs(location.search.substr(1));
@ -29,12 +31,6 @@ const WarehouseList: React.FC<RouteComponentProps> = ({ location }) => {
return <WarehouseListComponent params={params} />;
};
// const WarehouseCreate: React.FC<RouteComponentProps<{}>> = ({ location }) => {
// const qs = parseQs(location.search.substr(1));
// const params: WarehouseAddUrlQueryParams = qs;
// return <WarehouseCreateComponent params={params} />;
// };
// const WarehouseDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
// location,
// match
@ -57,8 +53,8 @@ export const WarehouseSection: React.FC = () => {
<WindowTitle title={intl.formatMessage(sectionNames.warehouses)} />
<Switch>
<Route exact path={warehouseListPath} component={WarehouseList} />
{/* <Route exact path={warehouseAddPath} component={WarehouseCreate} />
<Route path={warehousePath(":id")} component={WarehouseDetails} /> */}
<Route exact path={warehouseAddPath} component={WarehouseCreate} />
{/* <Route path={warehousePath(":id")} component={WarehouseDetails} /> */}
</Switch>
</>
);

View file

@ -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);

View file

@ -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}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 (
<WarehouseCreatePage
onBack={() => 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;

View file

@ -0,0 +1,2 @@
export { default } from "./WarehouseCreate";
export * from "./WarehouseCreate";