Add warehouse create action button
This commit is contained in:
parent
3d838d8428
commit
60ec16961c
9 changed files with 108 additions and 9 deletions
|
@ -12,7 +12,8 @@ import Debounce, { DebounceProps } from "@saleor/components/Debounce";
|
||||||
import ArrowDropdownIcon from "@saleor/icons/ArrowDropdown";
|
import ArrowDropdownIcon from "@saleor/icons/ArrowDropdown";
|
||||||
import { FetchMoreProps } from "@saleor/types";
|
import { FetchMoreProps } from "@saleor/types";
|
||||||
import MultiAutocompleteSelectFieldContent, {
|
import MultiAutocompleteSelectFieldContent, {
|
||||||
MultiAutocompleteChoiceType
|
MultiAutocompleteChoiceType,
|
||||||
|
MultiAutocompleteActionType
|
||||||
} from "./MultiAutocompleteSelectFieldContent";
|
} from "./MultiAutocompleteSelectFieldContent";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -71,6 +72,7 @@ const useStyles = makeStyles(
|
||||||
|
|
||||||
export interface MultiAutocompleteSelectFieldProps
|
export interface MultiAutocompleteSelectFieldProps
|
||||||
extends Partial<FetchMoreProps> {
|
extends Partial<FetchMoreProps> {
|
||||||
|
add: MultiAutocompleteActionType;
|
||||||
allowCustomValues?: boolean;
|
allowCustomValues?: boolean;
|
||||||
displayValues: MultiAutocompleteChoiceType[];
|
displayValues: MultiAutocompleteChoiceType[];
|
||||||
error?: boolean;
|
error?: boolean;
|
||||||
|
@ -166,6 +168,13 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
|
||||||
/>
|
/>
|
||||||
{isOpen && (!!inputValue || !!choices.length) && (
|
{isOpen && (!!inputValue || !!choices.length) && (
|
||||||
<MultiAutocompleteSelectFieldContent
|
<MultiAutocompleteSelectFieldContent
|
||||||
|
add={{
|
||||||
|
...add,
|
||||||
|
onClick: () => {
|
||||||
|
add.onClick();
|
||||||
|
closeMenu();
|
||||||
|
}
|
||||||
|
}}
|
||||||
choices={choices.filter(
|
choices={choices.filter(
|
||||||
choice => !value.includes(choice.value)
|
choice => !value.includes(choice.value)
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { FormattedMessage } from "react-intl";
|
||||||
import chevronDown from "@assets/images/ChevronDown.svg";
|
import chevronDown from "@assets/images/ChevronDown.svg";
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import AddIcon from "@material-ui/icons/Add";
|
import AddIcon from "@material-ui/icons/Add";
|
||||||
|
@ -22,6 +23,10 @@ const menuItemHeight = 46;
|
||||||
const maxMenuItems = 5;
|
const maxMenuItems = 5;
|
||||||
const offset = 24;
|
const offset = 24;
|
||||||
|
|
||||||
|
export interface MultiAutocompleteActionType {
|
||||||
|
label: string;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
export interface MultiAutocompleteChoiceType {
|
export interface MultiAutocompleteChoiceType {
|
||||||
label: string;
|
label: string;
|
||||||
value: any;
|
value: any;
|
||||||
|
@ -29,6 +34,7 @@ export interface MultiAutocompleteChoiceType {
|
||||||
}
|
}
|
||||||
export interface MultiAutocompleteSelectFieldContentProps
|
export interface MultiAutocompleteSelectFieldContentProps
|
||||||
extends Partial<FetchMoreProps> {
|
extends Partial<FetchMoreProps> {
|
||||||
|
add: MultiAutocompleteActionType;
|
||||||
choices: MultiAutocompleteChoiceType[];
|
choices: MultiAutocompleteChoiceType[];
|
||||||
displayCustomValue: boolean;
|
displayCustomValue: boolean;
|
||||||
displayValues: MultiAutocompleteChoiceType[];
|
displayValues: MultiAutocompleteChoiceType[];
|
||||||
|
@ -145,6 +151,7 @@ function getChoiceIndex(
|
||||||
|
|
||||||
const MultiAutocompleteSelectFieldContent: React.FC<MultiAutocompleteSelectFieldContentProps> = props => {
|
const MultiAutocompleteSelectFieldContent: React.FC<MultiAutocompleteSelectFieldContentProps> = props => {
|
||||||
const {
|
const {
|
||||||
|
add,
|
||||||
choices,
|
choices,
|
||||||
displayCustomValue,
|
displayCustomValue,
|
||||||
displayValues,
|
displayValues,
|
||||||
|
@ -156,6 +163,10 @@ const MultiAutocompleteSelectFieldContent: React.FC<MultiAutocompleteSelectField
|
||||||
onFetchMore
|
onFetchMore
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
if (!!add && !!displayCustomValue) {
|
||||||
|
throw new Error("Add and custom value cannot be displayed simultaneously");
|
||||||
|
}
|
||||||
|
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
const scrollPosition = useElementScroll(anchor);
|
const scrollPosition = useElementScroll(anchor);
|
||||||
|
@ -183,6 +194,20 @@ const MultiAutocompleteSelectFieldContent: React.FC<MultiAutocompleteSelectField
|
||||||
displayValues.length > 0 ||
|
displayValues.length > 0 ||
|
||||||
displayCustomValue ? (
|
displayCustomValue ? (
|
||||||
<>
|
<>
|
||||||
|
{add && (
|
||||||
|
<MenuItem
|
||||||
|
className={classes.menuItem}
|
||||||
|
component="div"
|
||||||
|
{...getItemProps({
|
||||||
|
item: inputValue
|
||||||
|
})}
|
||||||
|
data-tc="multiautocomplete-select-option-add"
|
||||||
|
onClick={add.onClick}
|
||||||
|
>
|
||||||
|
<AddIcon color="primary" className={classes.addIcon} />
|
||||||
|
<Typography color="primary">{add.label}</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
{displayCustomValue && (
|
{displayCustomValue && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={classes.menuItem}
|
className={classes.menuItem}
|
||||||
|
|
|
@ -69,6 +69,7 @@ const Story: React.FC<Partial<
|
||||||
};
|
};
|
||||||
|
|
||||||
const contentProps: SingleAutocompleteSelectFieldContentProps = {
|
const contentProps: SingleAutocompleteSelectFieldContentProps = {
|
||||||
|
add: undefined,
|
||||||
choices: suggestions.slice(0, 10),
|
choices: suggestions.slice(0, 10),
|
||||||
displayCustomValue: false,
|
displayCustomValue: false,
|
||||||
emptyOption: false,
|
emptyOption: false,
|
||||||
|
@ -88,6 +89,15 @@ storiesOf("Generics / Select with autocomplete", module)
|
||||||
.add("default", () => (
|
.add("default", () => (
|
||||||
<SingleAutocompleteSelectFieldContent {...contentProps} />
|
<SingleAutocompleteSelectFieldContent {...contentProps} />
|
||||||
))
|
))
|
||||||
|
.add("with add", () => (
|
||||||
|
<SingleAutocompleteSelectFieldContent
|
||||||
|
{...contentProps}
|
||||||
|
add={{
|
||||||
|
label: "Add New Collection",
|
||||||
|
onClick: () => undefined
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))
|
||||||
.add("can load more", () => (
|
.add("can load more", () => (
|
||||||
<SingleAutocompleteSelectFieldContent {...contentProps} hasMore={true} />
|
<SingleAutocompleteSelectFieldContent {...contentProps} hasMore={true} />
|
||||||
))
|
))
|
||||||
|
|
|
@ -10,7 +10,8 @@ import { FetchMoreProps } from "@saleor/types";
|
||||||
import ArrowDropdownIcon from "../../icons/ArrowDropdown";
|
import ArrowDropdownIcon from "../../icons/ArrowDropdown";
|
||||||
import Debounce, { DebounceProps } from "../Debounce";
|
import Debounce, { DebounceProps } from "../Debounce";
|
||||||
import SingleAutocompleteSelectFieldContent, {
|
import SingleAutocompleteSelectFieldContent, {
|
||||||
SingleAutocompleteChoiceType
|
SingleAutocompleteChoiceType,
|
||||||
|
SingleAutocompleteActionType
|
||||||
} from "./SingleAutocompleteSelectFieldContent";
|
} from "./SingleAutocompleteSelectFieldContent";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -25,6 +26,7 @@ const useStyles = makeStyles(
|
||||||
|
|
||||||
export interface SingleAutocompleteSelectFieldProps
|
export interface SingleAutocompleteSelectFieldProps
|
||||||
extends Partial<FetchMoreProps> {
|
extends Partial<FetchMoreProps> {
|
||||||
|
add: SingleAutocompleteActionType;
|
||||||
error?: boolean;
|
error?: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
displayValue: string;
|
displayValue: string;
|
||||||
|
@ -47,6 +49,7 @@ const DebounceAutocomplete: React.ComponentType<DebounceProps<
|
||||||
|
|
||||||
const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectFieldProps> = props => {
|
const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectFieldProps> = props => {
|
||||||
const {
|
const {
|
||||||
|
add,
|
||||||
allowCustomValues,
|
allowCustomValues,
|
||||||
choices,
|
choices,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -144,6 +147,13 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
|
||||||
/>
|
/>
|
||||||
{isOpen && (!!inputValue || !!choices.length) && (
|
{isOpen && (!!inputValue || !!choices.length) && (
|
||||||
<SingleAutocompleteSelectFieldContent
|
<SingleAutocompleteSelectFieldContent
|
||||||
|
add={{
|
||||||
|
...add,
|
||||||
|
onClick: () => {
|
||||||
|
add.onClick();
|
||||||
|
closeMenu();
|
||||||
|
}
|
||||||
|
}}
|
||||||
choices={choices}
|
choices={choices}
|
||||||
displayCustomValue={displayCustomValue}
|
displayCustomValue={displayCustomValue}
|
||||||
emptyOption={emptyOption}
|
emptyOption={emptyOption}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
|
import Add from "@material-ui/icons/Add";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
@ -24,8 +25,13 @@ export interface SingleAutocompleteChoiceType {
|
||||||
label: string;
|
label: string;
|
||||||
value: any;
|
value: any;
|
||||||
}
|
}
|
||||||
|
export interface SingleAutocompleteActionType {
|
||||||
|
label: string;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
export interface SingleAutocompleteSelectFieldContentProps
|
export interface SingleAutocompleteSelectFieldContentProps
|
||||||
extends Partial<FetchMoreProps> {
|
extends Partial<FetchMoreProps> {
|
||||||
|
add: SingleAutocompleteActionType;
|
||||||
choices: SingleAutocompleteChoiceType[];
|
choices: SingleAutocompleteChoiceType[];
|
||||||
displayCustomValue: boolean;
|
displayCustomValue: boolean;
|
||||||
emptyOption: boolean;
|
emptyOption: boolean;
|
||||||
|
@ -38,6 +44,14 @@ export interface SingleAutocompleteSelectFieldContentProps
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
add: {
|
||||||
|
background: theme.palette.background.default,
|
||||||
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
|
borderRadius: "100%",
|
||||||
|
height: 24,
|
||||||
|
marginRight: theme.spacing(),
|
||||||
|
width: 24
|
||||||
|
},
|
||||||
arrowContainer: {
|
arrowContainer: {
|
||||||
position: "relative"
|
position: "relative"
|
||||||
},
|
},
|
||||||
|
@ -109,10 +123,9 @@ function getChoiceIndex(
|
||||||
return choiceIndex;
|
return choiceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SingleAutocompleteSelectFieldContent: React.FC<
|
const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFieldContentProps> = props => {
|
||||||
SingleAutocompleteSelectFieldContentProps
|
|
||||||
> = props => {
|
|
||||||
const {
|
const {
|
||||||
|
add,
|
||||||
choices,
|
choices,
|
||||||
displayCustomValue,
|
displayCustomValue,
|
||||||
emptyOption,
|
emptyOption,
|
||||||
|
@ -125,6 +138,10 @@ const SingleAutocompleteSelectFieldContent: React.FC<
|
||||||
onFetchMore
|
onFetchMore
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
if (!!add && !!displayCustomValue) {
|
||||||
|
throw new Error("Add and custom value cannot be displayed simultaneously");
|
||||||
|
}
|
||||||
|
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
const scrollPosition = useElementScroll(anchor);
|
const scrollPosition = useElementScroll(anchor);
|
||||||
|
@ -164,6 +181,20 @@ const SingleAutocompleteSelectFieldContent: React.FC<
|
||||||
</Typography>
|
</Typography>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
|
{add && (
|
||||||
|
<MenuItem
|
||||||
|
className={classes.menuItem}
|
||||||
|
component="div"
|
||||||
|
{...getItemProps({
|
||||||
|
item: inputValue
|
||||||
|
})}
|
||||||
|
data-tc="singleautocomplete-select-option-add"
|
||||||
|
onClick={add.onClick}
|
||||||
|
>
|
||||||
|
<Add color="primary" className={classes.add} />
|
||||||
|
<Typography color="primary">{add.label}</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
{displayCustomValue && (
|
{displayCustomValue && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={classes.menuItem}
|
className={classes.menuItem}
|
||||||
|
@ -184,14 +215,14 @@ const SingleAutocompleteSelectFieldContent: React.FC<
|
||||||
/>
|
/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
{choices.length > 0 && displayCustomValue && (
|
{choices.length > 0 && (!!add || displayCustomValue) && (
|
||||||
<Hr className={classes.hr} />
|
<Hr className={classes.hr} />
|
||||||
)}
|
)}
|
||||||
{choices.map((suggestion, index) => {
|
{choices.map((suggestion, index) => {
|
||||||
const choiceIndex = getChoiceIndex(
|
const choiceIndex = getChoiceIndex(
|
||||||
index,
|
index,
|
||||||
emptyOption,
|
emptyOption,
|
||||||
displayCustomValue
|
!!add || displayCustomValue
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -43,6 +43,7 @@ export interface ShippingZoneDetailsPageProps {
|
||||||
onPriceRateEdit: (id: string) => void;
|
onPriceRateEdit: (id: string) => void;
|
||||||
onRateRemove: (rateId: string) => void;
|
onRateRemove: (rateId: string) => void;
|
||||||
onSubmit: (data: FormData) => void;
|
onSubmit: (data: FormData) => void;
|
||||||
|
onWarehouseAdd: () => void;
|
||||||
onWeightRateAdd: () => void;
|
onWeightRateAdd: () => void;
|
||||||
onWeightRateEdit: (id: string) => void;
|
onWeightRateEdit: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +68,7 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
|
||||||
onPriceRateEdit,
|
onPriceRateEdit,
|
||||||
onRateRemove,
|
onRateRemove,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
onWarehouseAdd,
|
||||||
onWeightRateAdd,
|
onWeightRateAdd,
|
||||||
onWeightRateEdit,
|
onWeightRateEdit,
|
||||||
saveButtonBarState,
|
saveButtonBarState,
|
||||||
|
@ -165,9 +167,10 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
|
||||||
displayValue={warehouseDisplayValues}
|
displayValue={warehouseDisplayValues}
|
||||||
hasMore={false}
|
hasMore={false}
|
||||||
loading={false}
|
loading={false}
|
||||||
|
warehouses={warehouseChoices}
|
||||||
onChange={handleWarehouseChange}
|
onChange={handleWarehouseChange}
|
||||||
onFetchMore={() => undefined}
|
onFetchMore={() => undefined}
|
||||||
warehouses={warehouseChoices}
|
onWarehouseAdd={onWarehouseAdd}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -18,6 +18,7 @@ interface ShippingZonewWarehousesProps extends FetchMoreProps {
|
||||||
displayValue: MultiAutocompleteChoiceType[];
|
displayValue: MultiAutocompleteChoiceType[];
|
||||||
warehouses: MultiAutocompleteChoiceType[];
|
warehouses: MultiAutocompleteChoiceType[];
|
||||||
onChange: FormChange;
|
onChange: FormChange;
|
||||||
|
onWarehouseAdd: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShippingZoneWarehouses: React.FC<ShippingZonewWarehousesProps> = props => {
|
export const ShippingZoneWarehouses: React.FC<ShippingZonewWarehousesProps> = props => {
|
||||||
|
@ -26,9 +27,10 @@ export const ShippingZoneWarehouses: React.FC<ShippingZonewWarehousesProps> = pr
|
||||||
displayValue,
|
displayValue,
|
||||||
hasMore,
|
hasMore,
|
||||||
loading,
|
loading,
|
||||||
|
warehouses,
|
||||||
onChange,
|
onChange,
|
||||||
onFetchMore,
|
onFetchMore,
|
||||||
warehouses
|
onWarehouseAdd
|
||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
@ -42,6 +44,13 @@ export const ShippingZoneWarehouses: React.FC<ShippingZonewWarehousesProps> = pr
|
||||||
/>
|
/>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<MultiAutocompleteSelectField
|
<MultiAutocompleteSelectField
|
||||||
|
add={{
|
||||||
|
label: intl.formatMessage({
|
||||||
|
defaultMessage: "Add New Warehouse",
|
||||||
|
description: "button"
|
||||||
|
}),
|
||||||
|
onClick: onWarehouseAdd
|
||||||
|
}}
|
||||||
choices={warehouses}
|
choices={warehouses}
|
||||||
displayValues={displayValue}
|
displayValues={displayValue}
|
||||||
fetchChoices={() => undefined}
|
fetchChoices={() => undefined}
|
||||||
|
|
|
@ -20,6 +20,7 @@ export const shippingZonePath = (id: string) =>
|
||||||
urlJoin(shippingZonesListPath, id);
|
urlJoin(shippingZonesListPath, id);
|
||||||
export type ShippingZoneUrlDialog =
|
export type ShippingZoneUrlDialog =
|
||||||
| "add-rate"
|
| "add-rate"
|
||||||
|
| "add-warehouse"
|
||||||
| "assign-country"
|
| "assign-country"
|
||||||
| "edit-rate"
|
| "edit-rate"
|
||||||
| "remove"
|
| "remove"
|
||||||
|
|
|
@ -176,6 +176,7 @@ const ShippingZoneDetails: React.FC<ShippingZoneDetailsProps> = ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
onWarehouseAdd={() => openModal("add-warehouse")}
|
||||||
onWeightRateAdd={() =>
|
onWeightRateAdd={() =>
|
||||||
openModal("add-rate", {
|
openModal("add-rate", {
|
||||||
type: ShippingMethodTypeEnum.WEIGHT
|
type: ShippingMethodTypeEnum.WEIGHT
|
||||||
|
|
Loading…
Reference in a new issue