Add warehouse choice
This commit is contained in:
parent
e57c081cce
commit
0b5c9e35eb
5 changed files with 308 additions and 79 deletions
|
@ -3,6 +3,7 @@ import {
|
||||||
ExportErrorCode,
|
ExportErrorCode,
|
||||||
ExportProductsInput
|
ExportProductsInput
|
||||||
} from "@saleor/types/globalTypes";
|
} from "@saleor/types/globalTypes";
|
||||||
|
import { warehouseList } from "@saleor/warehouses/fixtures";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -30,7 +31,8 @@ const props: ProductExportDialogProps = {
|
||||||
all: 100,
|
all: 100,
|
||||||
filter: 32
|
filter: 32
|
||||||
},
|
},
|
||||||
selectedProducts: 18
|
selectedProducts: 18,
|
||||||
|
warehouses: warehouseList
|
||||||
};
|
};
|
||||||
|
|
||||||
storiesOf("Views / Products / Export / Export settings", module)
|
storiesOf("Views / Products / Export / Export settings", module)
|
||||||
|
|
|
@ -25,11 +25,13 @@ import {
|
||||||
import getExportErrorMessage from "@saleor/utils/errors/export";
|
import getExportErrorMessage from "@saleor/utils/errors/export";
|
||||||
import { toggle } from "@saleor/utils/lists";
|
import { toggle } from "@saleor/utils/lists";
|
||||||
import { mapNodeToChoice } from "@saleor/utils/maps";
|
import { mapNodeToChoice } from "@saleor/utils/maps";
|
||||||
|
import { WarehouseList_warehouses_edges_node } from "@saleor/warehouses/types/WarehouseList";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ProductExportDialogInfo, {
|
import ProductExportDialogInfo, {
|
||||||
attributeNamePrefix
|
attributeNamePrefix,
|
||||||
|
warehouseNamePrefix
|
||||||
} from "./ProductExportDialogInfo";
|
} from "./ProductExportDialogInfo";
|
||||||
import ProductExportDialogSettings, {
|
import ProductExportDialogSettings, {
|
||||||
ProductQuantity
|
ProductQuantity
|
||||||
|
@ -64,7 +66,8 @@ function useSteps(): Array<Step<ProductExportStep>> {
|
||||||
const initialForm: ExportProductsInput = {
|
const initialForm: ExportProductsInput = {
|
||||||
exportInfo: {
|
exportInfo: {
|
||||||
attributes: [],
|
attributes: [],
|
||||||
fields: []
|
fields: [],
|
||||||
|
warehouses: []
|
||||||
},
|
},
|
||||||
fileType: FileTypesEnum.CSV,
|
fileType: FileTypesEnum.CSV,
|
||||||
scope: ExportScope.ALL
|
scope: ExportScope.ALL
|
||||||
|
@ -78,6 +81,7 @@ export interface ProductExportDialogProps extends DialogProps, FetchMoreProps {
|
||||||
errors: ExportErrorFragment[];
|
errors: ExportErrorFragment[];
|
||||||
productQuantity: ProductQuantity;
|
productQuantity: ProductQuantity;
|
||||||
selectedProducts: number;
|
selectedProducts: number;
|
||||||
|
warehouses: WarehouseList_warehouses_edges_node[];
|
||||||
onFetch: (query: string) => void;
|
onFetch: (query: string) => void;
|
||||||
onSubmit: (data: ExportProductsInput) => void;
|
onSubmit: (data: ExportProductsInput) => void;
|
||||||
}
|
}
|
||||||
|
@ -91,6 +95,7 @@ const ProductExportDialog: React.FC<ProductExportDialogProps> = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
open,
|
open,
|
||||||
selectedProducts,
|
selectedProducts,
|
||||||
|
warehouses,
|
||||||
...fetchMoreProps
|
...fetchMoreProps
|
||||||
}) => {
|
}) => {
|
||||||
const [step, { next, prev, set: setStep }] = useWizard(
|
const [step, { next, prev, set: setStep }] = useWizard(
|
||||||
|
@ -114,6 +119,7 @@ const ProductExportDialog: React.FC<ProductExportDialogProps> = ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const attributeChoices = mapNodeToChoice(attributes);
|
const attributeChoices = mapNodeToChoice(attributes);
|
||||||
|
const warehouseChoices = mapNodeToChoice(warehouses);
|
||||||
|
|
||||||
const handleAttributeSelect: FormChange = event => {
|
const handleAttributeSelect: FormChange = event => {
|
||||||
const id = event.target.name.substr(attributeNamePrefix.length);
|
const id = event.target.name.substr(attributeNamePrefix.length);
|
||||||
|
@ -135,6 +141,35 @@ const ProductExportDialog: React.FC<ProductExportDialogProps> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleWarehouseSelect: FormChange = event =>
|
||||||
|
change({
|
||||||
|
target: {
|
||||||
|
name: "exportInfo",
|
||||||
|
value: {
|
||||||
|
...data.exportInfo,
|
||||||
|
warehouses: toggle(
|
||||||
|
event.target.name.substr(warehouseNamePrefix.length),
|
||||||
|
data.exportInfo.warehouses,
|
||||||
|
(a, b) => a === b
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleToggleAllWarehouses: FormChange = () =>
|
||||||
|
change({
|
||||||
|
target: {
|
||||||
|
name: "exportInfo",
|
||||||
|
value: {
|
||||||
|
...data.exportInfo,
|
||||||
|
warehouses:
|
||||||
|
data.exportInfo.warehouses.length === warehouses.length
|
||||||
|
? []
|
||||||
|
: warehouses.map(warehouse => warehouse.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={onClose} open={open} maxWidth="sm" fullWidth>
|
<Dialog onClose={onClose} open={open} maxWidth="sm" fullWidth>
|
||||||
<>
|
<>
|
||||||
|
@ -156,7 +191,10 @@ const ProductExportDialog: React.FC<ProductExportDialogProps> = ({
|
||||||
data={data}
|
data={data}
|
||||||
selectedAttributes={selectedAttributes}
|
selectedAttributes={selectedAttributes}
|
||||||
onAttrtibuteSelect={handleAttributeSelect}
|
onAttrtibuteSelect={handleAttributeSelect}
|
||||||
|
onWarehouseSelect={handleWarehouseSelect}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
|
warehouses={warehouseChoices}
|
||||||
|
onSelectAllWarehouses={handleToggleAllWarehouses}
|
||||||
{...fetchMoreProps}
|
{...fetchMoreProps}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import Checkbox from "@saleor/components/Checkbox";
|
||||||
import Chip from "@saleor/components/Chip";
|
import Chip from "@saleor/components/Chip";
|
||||||
import Hr from "@saleor/components/Hr";
|
import Hr from "@saleor/components/Hr";
|
||||||
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
|
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
|
||||||
import { ChangeEvent } from "@saleor/hooks/useForm";
|
import { ChangeEvent, FormChange } from "@saleor/hooks/useForm";
|
||||||
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { FetchMoreProps } from "@saleor/types";
|
import { FetchMoreProps } from "@saleor/types";
|
||||||
|
@ -22,9 +22,18 @@ import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import useProductExportFieldMessages from "./messages";
|
||||||
|
|
||||||
export const attributeNamePrefix = "attribute-";
|
export const attributeNamePrefix = "attribute-";
|
||||||
|
export const warehouseNamePrefix = "warehouse-";
|
||||||
const maxChips = 4;
|
const maxChips = 4;
|
||||||
|
|
||||||
|
const inventoryFields = [
|
||||||
|
ProductFieldEnum.PRODUCT_WEIGHT,
|
||||||
|
ProductFieldEnum.VARIANT_SKU,
|
||||||
|
ProductFieldEnum.VARIANT_WEIGHT
|
||||||
|
];
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
accordion: {
|
accordion: {
|
||||||
|
@ -45,12 +54,23 @@ const useStyles = makeStyles(
|
||||||
marginBottom: theme.spacing(3),
|
marginBottom: theme.spacing(3),
|
||||||
marginTop: theme.spacing(3)
|
marginTop: theme.spacing(3)
|
||||||
},
|
},
|
||||||
|
hrWarehouses: {
|
||||||
|
marginBottom: theme.spacing(3),
|
||||||
|
marginTop: theme.spacing(1)
|
||||||
|
},
|
||||||
label: {
|
label: {
|
||||||
"&&": {
|
"&&": {
|
||||||
overflow: "visible"
|
overflow: "visible"
|
||||||
},
|
},
|
||||||
|
"&:first-of-type": {
|
||||||
|
paddingTop: 0
|
||||||
|
},
|
||||||
|
"&:not(:last-of-type)": {
|
||||||
|
borderBottom: `1px solid ${theme.palette.divider}`
|
||||||
|
},
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
margin: theme.spacing(0),
|
margin: theme.spacing(0),
|
||||||
|
padding: theme.spacing(1, 0),
|
||||||
width: "100%"
|
width: "100%"
|
||||||
},
|
},
|
||||||
loadMoreContainer: {
|
loadMoreContainer: {
|
||||||
|
@ -62,8 +82,14 @@ const useStyles = makeStyles(
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
marginBottom: theme.spacing()
|
marginBottom: theme.spacing()
|
||||||
},
|
},
|
||||||
|
optionLabel: {
|
||||||
|
marginLeft: 0
|
||||||
|
},
|
||||||
quickPeekContainer: {
|
quickPeekContainer: {
|
||||||
marginBottom: theme.spacing(-1)
|
marginBottom: theme.spacing(-1)
|
||||||
|
},
|
||||||
|
warehousesLabel: {
|
||||||
|
marginBottom: theme.spacing(2)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -80,6 +106,9 @@ const Option: React.FC<{
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
|
classes={{
|
||||||
|
label: classes.optionLabel
|
||||||
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
@ -103,66 +132,7 @@ const FieldAccordion: React.FC<AccordionProps & {
|
||||||
onToggleAll: (field: ProductFieldEnum[], setTo: boolean) => void;
|
onToggleAll: (field: ProductFieldEnum[], setTo: boolean) => void;
|
||||||
}> = ({ data, fields, onChange, onToggleAll, ...props }) => {
|
}> = ({ data, fields, onChange, onToggleAll, ...props }) => {
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
const intl = useIntl();
|
const getFieldLabel = useProductExportFieldMessages();
|
||||||
|
|
||||||
const fieldNames: Record<ProductFieldEnum, string> = {
|
|
||||||
[ProductFieldEnum.CATEGORY]: intl.formatMessage({
|
|
||||||
defaultMessage: "Category",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.CHARGE_TAXES]: intl.formatMessage({
|
|
||||||
defaultMessage: "Charge Taxes",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.COLLECTIONS]: intl.formatMessage({
|
|
||||||
defaultMessage: "Collections",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.COST_PRICE]: intl.formatMessage({
|
|
||||||
defaultMessage: "Cost Price",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.DESCRIPTION]: intl.formatMessage({
|
|
||||||
defaultMessage: "Description",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.NAME]: intl.formatMessage({
|
|
||||||
defaultMessage: "Name",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.PRODUCT_IMAGES]: intl.formatMessage({
|
|
||||||
defaultMessage: "Product Images",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.PRODUCT_TYPE]: intl.formatMessage({
|
|
||||||
defaultMessage: "Type",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.PRODUCT_WEIGHT]: intl.formatMessage({
|
|
||||||
defaultMessage: "Weight",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.VARIANT_IMAGES]: intl.formatMessage({
|
|
||||||
defaultMessage: "Variant Images",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.VARIANT_PRICE]: intl.formatMessage({
|
|
||||||
defaultMessage: "Variant Price",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.VARIANT_SKU]: intl.formatMessage({
|
|
||||||
defaultMessage: "SKU",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.VARIANT_WEIGHT]: intl.formatMessage({
|
|
||||||
defaultMessage: "Variant Weight",
|
|
||||||
description: "product field"
|
|
||||||
}),
|
|
||||||
[ProductFieldEnum.VISIBLE]: intl.formatMessage({
|
|
||||||
defaultMessage: "Visibility",
|
|
||||||
description: "product field"
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectedAll = fields.every(field =>
|
const selectedAll = fields.every(field =>
|
||||||
data.exportInfo.fields.includes(field)
|
data.exportInfo.fields.includes(field)
|
||||||
|
@ -180,7 +150,7 @@ const FieldAccordion: React.FC<AccordionProps & {
|
||||||
{selectedFields.slice(0, maxChips).map(field => (
|
{selectedFields.slice(0, maxChips).map(field => (
|
||||||
<Chip
|
<Chip
|
||||||
className={classes.chip}
|
className={classes.chip}
|
||||||
label={fieldNames[field]}
|
label={getFieldLabel(field)}
|
||||||
onClose={() =>
|
onClose={() =>
|
||||||
onChange({
|
onChange({
|
||||||
target: {
|
target: {
|
||||||
|
@ -225,7 +195,7 @@ const FieldAccordion: React.FC<AccordionProps & {
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
key={field}
|
key={field}
|
||||||
>
|
>
|
||||||
{fieldNames[field]}
|
{getFieldLabel(field)}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
@ -234,11 +204,14 @@ const FieldAccordion: React.FC<AccordionProps & {
|
||||||
|
|
||||||
export interface ProductExportDialogInfoProps extends FetchMoreProps {
|
export interface ProductExportDialogInfoProps extends FetchMoreProps {
|
||||||
attributes: MultiAutocompleteChoiceType[];
|
attributes: MultiAutocompleteChoiceType[];
|
||||||
|
warehouses: MultiAutocompleteChoiceType[];
|
||||||
data: ExportProductsInput;
|
data: ExportProductsInput;
|
||||||
selectedAttributes: MultiAutocompleteChoiceType[];
|
selectedAttributes: MultiAutocompleteChoiceType[];
|
||||||
onAttrtibuteSelect: (event: ChangeEvent) => void;
|
onAttrtibuteSelect: FormChange;
|
||||||
onChange: (event: ChangeEvent) => void;
|
onWarehouseSelect: FormChange;
|
||||||
|
onChange: FormChange;
|
||||||
onFetch: (query: string) => void;
|
onFetch: (query: string) => void;
|
||||||
|
onSelectAllWarehouses: FormChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductExportDialogInfo: React.FC<ProductExportDialogInfoProps> = ({
|
const ProductExportDialogInfo: React.FC<ProductExportDialogInfoProps> = ({
|
||||||
|
@ -247,14 +220,18 @@ const ProductExportDialogInfo: React.FC<ProductExportDialogInfoProps> = ({
|
||||||
hasMore,
|
hasMore,
|
||||||
selectedAttributes,
|
selectedAttributes,
|
||||||
loading,
|
loading,
|
||||||
|
warehouses,
|
||||||
onAttrtibuteSelect,
|
onAttrtibuteSelect,
|
||||||
|
onWarehouseSelect,
|
||||||
onChange,
|
onChange,
|
||||||
onFetch,
|
onFetch,
|
||||||
onFetchMore
|
onFetchMore,
|
||||||
|
onSelectAllWarehouses
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [query, onQueryChange] = useSearchQuery(onFetch);
|
const [query, onQueryChange] = useSearchQuery(onFetch);
|
||||||
|
const getFieldLabel = useProductExportFieldMessages();
|
||||||
|
|
||||||
const handleFieldChange = (event: ChangeEvent) =>
|
const handleFieldChange = (event: ChangeEvent) =>
|
||||||
onChange({
|
onChange({
|
||||||
|
@ -289,6 +266,12 @@ const ProductExportDialogInfo: React.FC<ProductExportDialogInfoProps> = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedInventoryFields = data.exportInfo.fields.filter(field =>
|
||||||
|
inventoryFields.includes(field)
|
||||||
|
);
|
||||||
|
const selectedAllInventoryFields =
|
||||||
|
selectedInventoryFields.length === inventoryFields.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography className={classes.dialogLabel}>
|
<Typography className={classes.dialogLabel}>
|
||||||
|
@ -409,22 +392,134 @@ const ProductExportDialogInfo: React.FC<ProductExportDialogInfoProps> = ({
|
||||||
onToggleAll={handleToggleAllFields}
|
onToggleAll={handleToggleAllFields}
|
||||||
data-test="financial"
|
data-test="financial"
|
||||||
/>
|
/>
|
||||||
<FieldAccordion
|
<Accordion
|
||||||
className={classes.accordion}
|
className={classes.accordion}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
defaultMessage: "Inventory Information",
|
defaultMessage: "Inventory Information",
|
||||||
description: "informations about product stock, header"
|
description: "informations about product stock, header"
|
||||||
})}
|
})}
|
||||||
data={data}
|
quickPeek={
|
||||||
fields={[
|
(data.exportInfo.warehouses.length > 0 ||
|
||||||
ProductFieldEnum.PRODUCT_WEIGHT,
|
selectedInventoryFields.length > 0) && (
|
||||||
ProductFieldEnum.VARIANT_SKU,
|
<div className={classes.quickPeekContainer}>
|
||||||
ProductFieldEnum.VARIANT_WEIGHT
|
{selectedInventoryFields.slice(0, maxChips).map(field => (
|
||||||
]}
|
<Chip
|
||||||
onChange={handleFieldChange}
|
className={classes.chip}
|
||||||
onToggleAll={handleToggleAllFields}
|
label={getFieldLabel(field)}
|
||||||
|
onClose={() =>
|
||||||
|
onChange({
|
||||||
|
target: {
|
||||||
|
name: field,
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{data.exportInfo.warehouses
|
||||||
|
.slice(0, maxChips - selectedInventoryFields.length)
|
||||||
|
.map(warehouseId => (
|
||||||
|
<Chip
|
||||||
|
className={classes.chip}
|
||||||
|
label={
|
||||||
|
warehouses.find(
|
||||||
|
warehouse => warehouse.value === warehouseId
|
||||||
|
).label
|
||||||
|
}
|
||||||
|
onClose={() =>
|
||||||
|
onWarehouseSelect({
|
||||||
|
target: {
|
||||||
|
name: warehouseNamePrefix + warehouseId,
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{data.exportInfo.warehouses.length +
|
||||||
|
selectedInventoryFields.length >
|
||||||
|
maxChips && (
|
||||||
|
<Typography className={classes.moreLabel} variant="caption">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="and {number} more"
|
||||||
|
description="there are more elements of list that are hidden"
|
||||||
|
values={{
|
||||||
|
number:
|
||||||
|
data.exportInfo.warehouses.length +
|
||||||
|
selectedInventoryFields.length -
|
||||||
|
maxChips
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
data-test="inventory"
|
data-test="inventory"
|
||||||
/>
|
>
|
||||||
|
<div>
|
||||||
|
<Option
|
||||||
|
checked={selectedAllInventoryFields}
|
||||||
|
name="all"
|
||||||
|
onChange={() =>
|
||||||
|
handleToggleAllFields(
|
||||||
|
inventoryFields,
|
||||||
|
!selectedAllInventoryFields
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Select All"
|
||||||
|
description="selectt all options"
|
||||||
|
/>
|
||||||
|
</Option>
|
||||||
|
{inventoryFields.map(field => (
|
||||||
|
<Option
|
||||||
|
checked={data.exportInfo.fields.includes(field)}
|
||||||
|
name={field}
|
||||||
|
onChange={handleFieldChange}
|
||||||
|
key={field}
|
||||||
|
>
|
||||||
|
{getFieldLabel(field)}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Hr className={classes.hrWarehouses} />
|
||||||
|
<Typography>
|
||||||
|
<FormattedMessage defaultMessage="Export Product Stock Quantity to CSV" />
|
||||||
|
</Typography>
|
||||||
|
<div>
|
||||||
|
<Option
|
||||||
|
checked={warehouses.every(warehouse =>
|
||||||
|
data.exportInfo.warehouses.includes(warehouse.value)
|
||||||
|
)}
|
||||||
|
name="all-warehouses"
|
||||||
|
onChange={onSelectAllWarehouses}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Export stock for all warehouses"
|
||||||
|
description="option"
|
||||||
|
/>
|
||||||
|
</Option>
|
||||||
|
</div>
|
||||||
|
<Hr className={classes.hrWarehouses} />
|
||||||
|
<Typography className={classes.warehousesLabel} variant="subtitle1">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Warehouses A to Z"
|
||||||
|
description="list of warehouses"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
{warehouses.map(warehouse => (
|
||||||
|
<Option
|
||||||
|
checked={data.exportInfo.warehouses.includes(warehouse.value)}
|
||||||
|
name={warehouseNamePrefix + warehouse.value}
|
||||||
|
onChange={onWarehouseSelect}
|
||||||
|
key={warehouse.value}
|
||||||
|
>
|
||||||
|
{warehouse.label}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Accordion>
|
||||||
<FieldAccordion
|
<FieldAccordion
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
defaultMessage: "SEO Information",
|
defaultMessage: "SEO Information",
|
||||||
|
|
83
src/products/components/ProductExportDialog/messages.ts
Normal file
83
src/products/components/ProductExportDialog/messages.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import { ProductFieldEnum } from "@saleor/types/globalTypes";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
function useProductExportFieldMessages() {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const messages = {
|
||||||
|
[ProductFieldEnum.CATEGORY]: {
|
||||||
|
defaultMessage: "Category",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldCategory"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.CHARGE_TAXES]: {
|
||||||
|
defaultMessage: "Charge Taxes",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldTaxes"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.COLLECTIONS]: {
|
||||||
|
defaultMessage: "Collections",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldCollections"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.COST_PRICE]: {
|
||||||
|
defaultMessage: "Cost Price",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldPrice"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.DESCRIPTION]: {
|
||||||
|
defaultMessage: "Description",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldDescription"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.NAME]: {
|
||||||
|
defaultMessage: "Name",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldName"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.PRODUCT_IMAGES]: {
|
||||||
|
defaultMessage: "Product Images",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldProductImages"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.PRODUCT_TYPE]: {
|
||||||
|
defaultMessage: "Type",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldType"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.PRODUCT_WEIGHT]: {
|
||||||
|
defaultMessage: "Export Product Weight",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldProductWeight"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.VARIANT_IMAGES]: {
|
||||||
|
defaultMessage: "Variant Images",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldVariantImages"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.VARIANT_PRICE]: {
|
||||||
|
defaultMessage: "Variant Price",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldVariantPrice"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.VARIANT_SKU]: {
|
||||||
|
defaultMessage: "Export Variant SKU",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldVariantSku"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.VARIANT_WEIGHT]: {
|
||||||
|
defaultMessage: "Export Variant Weight",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldVariantWeight"
|
||||||
|
},
|
||||||
|
[ProductFieldEnum.VISIBLE]: {
|
||||||
|
defaultMessage: "Visibility",
|
||||||
|
description: "product field",
|
||||||
|
id: "productExportFieldVisibility"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (field: ProductFieldEnum) => intl.formatMessage(messages[field]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useProductExportFieldMessages;
|
|
@ -39,6 +39,7 @@ import { ListViews } from "@saleor/types";
|
||||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||||
import createFilterHandlers from "@saleor/utils/handlers/filterHandlers";
|
import createFilterHandlers from "@saleor/utils/handlers/filterHandlers";
|
||||||
import { getSortUrlVariables } from "@saleor/utils/sort";
|
import { getSortUrlVariables } from "@saleor/utils/sort";
|
||||||
|
import { useWarehouseList } from "@saleor/warehouses/queries";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
@ -124,6 +125,11 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
first: 10
|
first: 10
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const warehouses = useWarehouseList({
|
||||||
|
variables: {
|
||||||
|
first: 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
() =>
|
() =>
|
||||||
|
@ -551,6 +557,11 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
filter: data?.products.totalCount
|
filter: data?.products.totalCount
|
||||||
}}
|
}}
|
||||||
selectedProducts={listElements.length}
|
selectedProducts={listElements.length}
|
||||||
|
warehouses={
|
||||||
|
warehouses.data?.warehouses.edges.map(
|
||||||
|
edge => edge.node
|
||||||
|
) || []
|
||||||
|
}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onSubmit={data =>
|
onSubmit={data =>
|
||||||
exportProducts({
|
exportProducts({
|
||||||
|
|
Loading…
Reference in a new issue