Add warehouse list view
This commit is contained in:
parent
e7f6bd1e77
commit
414f6d7a3d
25 changed files with 954 additions and 10 deletions
|
@ -21,6 +21,7 @@ import { staffListUrl } from "@saleor/staff/urls";
|
||||||
import { countryListUrl } from "@saleor/taxes/urls";
|
import { countryListUrl } from "@saleor/taxes/urls";
|
||||||
import { languageListUrl } from "@saleor/translations/urls";
|
import { languageListUrl } from "@saleor/translations/urls";
|
||||||
import { webhookListUrl } from "@saleor/webhooks/urls";
|
import { webhookListUrl } from "@saleor/webhooks/urls";
|
||||||
|
import { warehouseListUrl } from "@saleor/warehouses/urls";
|
||||||
import { QuickSearchActionInput } from "../../types";
|
import { QuickSearchActionInput } from "../../types";
|
||||||
|
|
||||||
interface View {
|
interface View {
|
||||||
|
@ -116,6 +117,10 @@ function searchInViews(
|
||||||
{
|
{
|
||||||
label: intl.formatMessage(sectionNames.webhooks),
|
label: intl.formatMessage(sectionNames.webhooks),
|
||||||
url: webhookListUrl()
|
url: webhookListUrl()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.warehouses),
|
||||||
|
url: warehouseListUrl()
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ export interface AppListViewSettings {
|
||||||
[ListViews.STAFF_MEMBERS_LIST]: ListSettings;
|
[ListViews.STAFF_MEMBERS_LIST]: ListSettings;
|
||||||
[ListViews.PERMISSION_GROUP_LIST]: ListSettings;
|
[ListViews.PERMISSION_GROUP_LIST]: ListSettings;
|
||||||
[ListViews.VOUCHER_LIST]: ListSettings;
|
[ListViews.VOUCHER_LIST]: ListSettings;
|
||||||
|
[ListViews.WAREHOUSE_LIST]: ListSettings;
|
||||||
[ListViews.WEBHOOK_LIST]: ListSettings;
|
[ListViews.WEBHOOK_LIST]: ListSettings;
|
||||||
}
|
}
|
||||||
export const defaultListSettings: AppListViewSettings = {
|
export const defaultListSettings: AppListViewSettings = {
|
||||||
|
@ -80,6 +81,9 @@ export const defaultListSettings: AppListViewSettings = {
|
||||||
[ListViews.VOUCHER_LIST]: {
|
[ListViews.VOUCHER_LIST]: {
|
||||||
rowNumber: PAGINATE_BY
|
rowNumber: PAGINATE_BY
|
||||||
},
|
},
|
||||||
|
[ListViews.WAREHOUSE_LIST]: {
|
||||||
|
rowNumber: PAGINATE_BY
|
||||||
|
},
|
||||||
[ListViews.WEBHOOK_LIST]: {
|
[ListViews.WEBHOOK_LIST]: {
|
||||||
rowNumber: PAGINATE_BY
|
rowNumber: PAGINATE_BY
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import { permissionGroupListUrl } from "@saleor/permissionGroups/urls";
|
||||||
import { taxSection } from "@saleor/taxes/urls";
|
import { taxSection } from "@saleor/taxes/urls";
|
||||||
import { PermissionEnum } from "@saleor/types/globalTypes";
|
import { PermissionEnum } from "@saleor/types/globalTypes";
|
||||||
import { webhookListUrl } from "@saleor/webhooks/urls";
|
import { webhookListUrl } from "@saleor/webhooks/urls";
|
||||||
|
import Warehouses from "@saleor/icons/Warehouses";
|
||||||
|
import { warehouseSection } from "@saleor/warehouses/urls";
|
||||||
import ConfigurationPage, { MenuSection } from "./ConfigurationPage";
|
import ConfigurationPage, { MenuSection } from "./ConfigurationPage";
|
||||||
|
|
||||||
export function createConfigurationMenu(intl: IntlShape): MenuSection[] {
|
export function createConfigurationMenu(intl: IntlShape): MenuSection[] {
|
||||||
|
@ -67,16 +69,6 @@ export function createConfigurationMenu(intl: IntlShape): MenuSection[] {
|
||||||
defaultMessage: "Product Settings"
|
defaultMessage: "Product Settings"
|
||||||
}),
|
}),
|
||||||
menuItems: [
|
menuItems: [
|
||||||
{
|
|
||||||
description: intl.formatMessage({
|
|
||||||
defaultMessage: "Manage how you ship out orders",
|
|
||||||
id: "configurationMenuShipping"
|
|
||||||
}),
|
|
||||||
icon: <ShippingMethods fontSize="inherit" viewBox="0 0 44 44" />,
|
|
||||||
permission: PermissionEnum.MANAGE_SHIPPING,
|
|
||||||
title: intl.formatMessage(sectionNames.shipping),
|
|
||||||
url: shippingZonesListUrl()
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: intl.formatMessage({
|
description: intl.formatMessage({
|
||||||
defaultMessage: "Manage how your store charges tax",
|
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: <ShippingMethods fontSize="inherit" viewBox="0 0 44 44" />,
|
||||||
|
permission: PermissionEnum.MANAGE_SHIPPING,
|
||||||
|
title: intl.formatMessage(sectionNames.shipping),
|
||||||
|
url: shippingZonesListUrl()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: intl.formatMessage({
|
||||||
|
defaultMessage: "Manage and update your warehouse information",
|
||||||
|
id: "configurationMenuWarehouses"
|
||||||
|
}),
|
||||||
|
icon: <Warehouses fontSize="inherit" viewBox="0 0 44 44" />,
|
||||||
|
permission: PermissionEnum.MANAGE_PRODUCTS,
|
||||||
|
title: intl.formatMessage(sectionNames.warehouses),
|
||||||
|
url: warehouseSection
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: intl.formatMessage({
|
label: intl.formatMessage({
|
||||||
defaultMessage: "Miscellaneous"
|
defaultMessage: "Miscellaneous"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
import useLocalStorage from "@saleor/hooks/useLocalStorage";
|
import useLocalStorage from "@saleor/hooks/useLocalStorage";
|
||||||
import { AppListViewSettings, defaultListSettings } from "./../config";
|
import { AppListViewSettings, defaultListSettings } from "./../config";
|
||||||
import { ListSettings, ListViews } from "./../types";
|
import { ListSettings, ListViews } from "./../types";
|
||||||
|
@ -14,6 +15,15 @@ export default function useListSettings<TColumns extends string = string>(
|
||||||
defaultListSettings
|
defaultListSettings
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (settings[listName] === undefined) {
|
||||||
|
setListSettings(settings => ({
|
||||||
|
...settings,
|
||||||
|
[listName]: defaultListSettings[listName]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const updateListSettings = (key: keyof ListSettings, value: any) =>
|
const updateListSettings = (key: keyof ListSettings, value: any) =>
|
||||||
setListSettings(settings => ({
|
setListSettings(settings => ({
|
||||||
...settings,
|
...settings,
|
||||||
|
|
16
src/icons/Warehouses.tsx
Normal file
16
src/icons/Warehouses.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import createSvgIcon from "@material-ui/icons/utils/createSvgIcon";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Warehouses = createSvgIcon(
|
||||||
|
<>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M5.23438 15.2344H34.7656V38.4375H38.2812V12.3121L19.9219 1.80048L1.5625 12.3121V38.4375H5.23438V15.2344ZM6.79688 40H0V11.4062L19.9219 0L39.8438 11.4062V40H33.2031V16.7969H6.79688V40ZM23.8281 9.84375H16.1719V11.7188H23.8281V9.84375ZM14.6094 8.28125V13.2812H25.3906V8.28125H14.6094ZM15.8594 32.3438H21.6406V38.4375H15.8594V32.3438ZM21.6406 30.7812V23.125H30.5469V30.7812V32.3438V40H23.2031H21.6406H14.2969V30.7812H21.6406ZM28.9844 32.3438H23.2031V38.4375H28.9844V32.3438ZM28.9844 30.7812V24.6875H23.2031V30.7812H28.9844Z"
|
||||||
|
fill="#06847B"
|
||||||
|
/>
|
||||||
|
</>,
|
||||||
|
"Warehouses"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Warehouses;
|
|
@ -55,6 +55,8 @@ import TaxesSection from "./taxes";
|
||||||
import TranslationsSection from "./translations";
|
import TranslationsSection from "./translations";
|
||||||
import { PermissionEnum } from "./types/globalTypes";
|
import { PermissionEnum } from "./types/globalTypes";
|
||||||
import WebhooksSection from "./webhooks";
|
import WebhooksSection from "./webhooks";
|
||||||
|
import { warehouseSection } from "./warehouses/urls";
|
||||||
|
import WarehouseSection from "./warehouses";
|
||||||
|
|
||||||
interface ResponseError extends ErrorResponse {
|
interface ResponseError extends ErrorResponse {
|
||||||
networkError?: Error & {
|
networkError?: Error & {
|
||||||
|
@ -263,6 +265,11 @@ const Routes: React.FC = () => {
|
||||||
path={serviceSection}
|
path={serviceSection}
|
||||||
component={ServiceSection}
|
component={ServiceSection}
|
||||||
/>
|
/>
|
||||||
|
<SectionRoute
|
||||||
|
permissions={[PermissionEnum.MANAGE_PRODUCTS]}
|
||||||
|
path={warehouseSection}
|
||||||
|
component={WarehouseSection}
|
||||||
|
/>
|
||||||
{createConfigurationMenu(intl).filter(menu =>
|
{createConfigurationMenu(intl).filter(menu =>
|
||||||
menu.menuItems.map(item =>
|
menu.menuItems.map(item =>
|
||||||
hasPermission(item.permission, user)
|
hasPermission(item.permission, user)
|
||||||
|
|
|
@ -224,6 +224,10 @@ export const sectionNames = defineMessages({
|
||||||
defaultMessage: "Vouchers",
|
defaultMessage: "Vouchers",
|
||||||
description: "vouchers section name"
|
description: "vouchers section name"
|
||||||
},
|
},
|
||||||
|
warehouses: {
|
||||||
|
defaultMessage: "Warehouses",
|
||||||
|
description: "warehouses section name"
|
||||||
|
},
|
||||||
webhooks: {
|
webhooks: {
|
||||||
defaultMessage: "Webhooks",
|
defaultMessage: "Webhooks",
|
||||||
description: "webhooks section name"
|
description: "webhooks section name"
|
||||||
|
|
22
src/products/types/StockFragment.ts
Normal file
22
src/products/types/StockFragment.ts
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ export enum ListViews {
|
||||||
SHIPPING_METHODS_LIST = "SHIPPING_METHODS_LIST",
|
SHIPPING_METHODS_LIST = "SHIPPING_METHODS_LIST",
|
||||||
STAFF_MEMBERS_LIST = "STAFF_MEMBERS_LIST",
|
STAFF_MEMBERS_LIST = "STAFF_MEMBERS_LIST",
|
||||||
VOUCHER_LIST = "VOUCHER_LIST",
|
VOUCHER_LIST = "VOUCHER_LIST",
|
||||||
|
WAREHOUSE_LIST = "WAREHOUSE_LIST",
|
||||||
WEBHOOK_LIST = "WEBHOOK_LIST"
|
WEBHOOK_LIST = "WEBHOOK_LIST"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -746,6 +746,10 @@ export enum VoucherTypeEnum {
|
||||||
SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT",
|
SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum WarehouseSortField {
|
||||||
|
NAME = "NAME",
|
||||||
|
}
|
||||||
|
|
||||||
export enum WebhookErrorCode {
|
export enum WebhookErrorCode {
|
||||||
GRAPHQL_ERROR = "GRAPHQL_ERROR",
|
GRAPHQL_ERROR = "GRAPHQL_ERROR",
|
||||||
INVALID = "INVALID",
|
INVALID = "INVALID",
|
||||||
|
@ -1415,6 +1419,15 @@ export interface VoucherSortingInput {
|
||||||
field: VoucherSortField;
|
field: VoucherSortField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WarehouseFilterInput {
|
||||||
|
search?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WarehouseSortingInput {
|
||||||
|
direction: OrderDirection;
|
||||||
|
field: WarehouseSortField;
|
||||||
|
}
|
||||||
|
|
||||||
export interface WebhookCreateInput {
|
export interface WebhookCreateInput {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
targetUrl?: string | null;
|
targetUrl?: string | null;
|
||||||
|
|
178
src/warehouses/components/WarehouseList/WarehouseList.tsx
Normal file
178
src/warehouses/components/WarehouseList/WarehouseList.tsx
Normal file
|
@ -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<WarehouseListUrlSortField> {
|
||||||
|
warehouses: WarehouseFragment[];
|
||||||
|
onAdd: () => void;
|
||||||
|
onRemove: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberOfColumns = 3;
|
||||||
|
|
||||||
|
const WarehouseList: React.FC<WarehouseListProps> = props => {
|
||||||
|
const {
|
||||||
|
warehouses,
|
||||||
|
disabled,
|
||||||
|
settings,
|
||||||
|
sort,
|
||||||
|
pageInfo,
|
||||||
|
onNextPage,
|
||||||
|
onPreviousPage,
|
||||||
|
onUpdateListSettings,
|
||||||
|
onRemove,
|
||||||
|
onRowClick,
|
||||||
|
onSort
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResponsiveTable>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCellHeader
|
||||||
|
direction={
|
||||||
|
sort.sort === WarehouseListUrlSortField.name
|
||||||
|
? getArrowDirection(sort.asc)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
arrowPosition="right"
|
||||||
|
className={classes.colName}
|
||||||
|
onClick={() => onSort(WarehouseListUrlSortField.name)}
|
||||||
|
>
|
||||||
|
<FormattedMessage defaultMessage="Name" description="warehouse" />
|
||||||
|
</TableCellHeader>
|
||||||
|
<TableCell className={classes.colZones}>
|
||||||
|
<FormattedMessage defaultMessage="Shipping Zones" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActions}>
|
||||||
|
<FormattedMessage defaultMessage="Actions" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableFooter>
|
||||||
|
<TableRow>
|
||||||
|
<TablePagination
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
settings={settings}
|
||||||
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
onUpdateListSettings={onUpdateListSettings}
|
||||||
|
hasPreviousPage={
|
||||||
|
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||||
|
}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
</TableFooter>
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(
|
||||||
|
warehouses,
|
||||||
|
warehouse => (
|
||||||
|
<TableRow
|
||||||
|
className={classes.tableRow}
|
||||||
|
hover={!!warehouse}
|
||||||
|
onClick={warehouse ? onRowClick(warehouse.id) : undefined}
|
||||||
|
key={warehouse ? warehouse.id : "skeleton"}
|
||||||
|
data-tc="id"
|
||||||
|
data-tc-id={maybe(() => warehouse.id)}
|
||||||
|
>
|
||||||
|
<TableCell className={classes.colName} data-tc="name">
|
||||||
|
{maybe<React.ReactNode>(() => warehouse.name, <Skeleton />)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colZones} data-tc="zones">
|
||||||
|
{maybe<React.ReactNode>(
|
||||||
|
() =>
|
||||||
|
warehouse.shippingZones.edges
|
||||||
|
.map(edge => edge.node.name)
|
||||||
|
.join(", "),
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActions}>
|
||||||
|
<div className={classes.actions}>
|
||||||
|
<IconButton color="primary">
|
||||||
|
<EditIcon />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
color="primary"
|
||||||
|
onClick={() => onRemove(warehouse.id)}
|
||||||
|
>
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
),
|
||||||
|
() => (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={numberOfColumns}>
|
||||||
|
<FormattedMessage defaultMessage="No warehouses found" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</ResponsiveTable>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
WarehouseList.displayName = "WarehouseList";
|
||||||
|
export default WarehouseList;
|
2
src/warehouses/components/WarehouseList/index.ts
Normal file
2
src/warehouses/components/WarehouseList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./WarehouseList";
|
||||||
|
export * from "./WarehouseList";
|
|
@ -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", () => <WarehouseListPage {...props} />)
|
||||||
|
.add("loading", () => (
|
||||||
|
<WarehouseListPage {...props} disabled={true} warehouses={undefined} />
|
||||||
|
))
|
||||||
|
.add("no data", () => <WarehouseListPage {...props} warehouses={[]} />);
|
|
@ -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<WarehouseListUrlSortField>,
|
||||||
|
TabPageProps {
|
||||||
|
warehouses: WarehouseFragment[];
|
||||||
|
onBack: () => void;
|
||||||
|
onRemove: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WarehouseListPage: React.FC<WarehouseListPageProps> = ({
|
||||||
|
warehouses,
|
||||||
|
currentTab,
|
||||||
|
disabled,
|
||||||
|
initialSearch,
|
||||||
|
pageInfo,
|
||||||
|
settings,
|
||||||
|
tabs,
|
||||||
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onBack,
|
||||||
|
onNextPage,
|
||||||
|
onPreviousPage,
|
||||||
|
onRemove,
|
||||||
|
onRowClick,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
onUpdateListSettings,
|
||||||
|
...listProps
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<AppHeader onBack={onBack}>
|
||||||
|
<FormattedMessage {...sectionNames.configuration} />
|
||||||
|
</AppHeader>
|
||||||
|
<PageHeader title={intl.formatMessage(sectionNames.warehouses)}>
|
||||||
|
<Button color="primary" variant="contained" onClick={onAdd}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Create Warehouse"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</PageHeader>
|
||||||
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Warehouses",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Warehouse"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
|
<WarehouseList
|
||||||
|
warehouses={warehouses}
|
||||||
|
disabled={disabled}
|
||||||
|
pageInfo={pageInfo}
|
||||||
|
settings={settings}
|
||||||
|
onAdd={onAdd}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
onRemove={onRemove}
|
||||||
|
onRowClick={onRowClick}
|
||||||
|
onUpdateListSettings={onUpdateListSettings}
|
||||||
|
{...listProps}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
WarehouseListPage.displayName = "WarehouseListPage";
|
||||||
|
export default WarehouseListPage;
|
2
src/warehouses/components/WarehouseListPage/index.ts
Normal file
2
src/warehouses/components/WarehouseListPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./WarehouseListPage";
|
||||||
|
export * from "./WarehouseListPage";
|
53
src/warehouses/fixtures.ts
Normal file
53
src/warehouses/fixtures.ts
Normal file
|
@ -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
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
66
src/warehouses/index.tsx
Normal file
66
src/warehouses/index.tsx
Normal file
|
@ -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<RouteComponentProps> = ({ location }) => {
|
||||||
|
const qs = parseQs(location.search.substr(1));
|
||||||
|
const params: WarehouseListUrlQueryParams = asSortParams(
|
||||||
|
qs,
|
||||||
|
WarehouseListUrlSortField
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
// }) => {
|
||||||
|
// const qs = parseQs(location.search.substr(1));
|
||||||
|
// const params: WarehouseUrlQueryParams = qs;
|
||||||
|
// return (
|
||||||
|
// <WarehouseDetailsComponent
|
||||||
|
// id={decodeURIComponent(match.params.id)}
|
||||||
|
// params={params}
|
||||||
|
// />
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const WarehouseSection: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<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} /> */}
|
||||||
|
</Switch>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default WarehouseSection;
|
55
src/warehouses/queries.ts
Normal file
55
src/warehouses/queries.ts
Normal file
|
@ -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);
|
30
src/warehouses/types/WarehouseFragment.ts
Normal file
30
src/warehouses/types/WarehouseFragment.ts
Normal file
|
@ -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;
|
||||||
|
}
|
64
src/warehouses/types/WarehouseList.ts
Normal file
64
src/warehouses/types/WarehouseList.ts
Normal file
|
@ -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;
|
||||||
|
}
|
42
src/warehouses/urls.ts
Normal file
42
src/warehouses/urls.ts
Normal file
|
@ -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<WarehouseListUrlFiltersEnum>;
|
||||||
|
export type WarehouseListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export enum WarehouseListUrlSortField {
|
||||||
|
name = "name"
|
||||||
|
}
|
||||||
|
export type WarehouseListUrlSort = Sort<WarehouseListUrlSortField>;
|
||||||
|
export type WarehouseListUrlQueryParams = ActiveTab &
|
||||||
|
Dialog<WarehouseListUrlDialog> &
|
||||||
|
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<WarehouseUrlDialog> & SingleAction;
|
||||||
|
export const warehouseUrl = (id: string, params?: WarehouseUrlQueryParams) =>
|
||||||
|
warehousePath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||||
|
|
||||||
|
export const warehouseAddPath = urlJoin(warehouseSection, "add");
|
||||||
|
export const warehouseAddUrl = warehouseAddPath;
|
160
src/warehouses/views/WarehouseList/WarehouseList.tsx
Normal file
160
src/warehouses/views/WarehouseList/WarehouseList.tsx
Normal file
|
@ -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<WarehouseListProps> = ({ 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 (
|
||||||
|
<>
|
||||||
|
<WindowTitle title={intl.formatMessage(sectionNames.warehouses)} />
|
||||||
|
<WarehouseListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={handleSearchChange}
|
||||||
|
onAll={resetFilters}
|
||||||
|
onBack={() => 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)}
|
||||||
|
/>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
WarehouseList.displayName = "WarehouseList";
|
||||||
|
export default WarehouseList;
|
31
src/warehouses/views/WarehouseList/filters.ts
Normal file
31
src/warehouses/views/WarehouseList/filters.ts
Normal file
|
@ -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<WarehouseListUrlFilters>(WAREHOUSE_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
WarehouseListUrlQueryParams,
|
||||||
|
WarehouseListUrlFilters
|
||||||
|
>(WarehouseListUrlFiltersEnum);
|
2
src/warehouses/views/WarehouseList/index.ts
Normal file
2
src/warehouses/views/WarehouseList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./WarehouseList";
|
||||||
|
export * from "./WarehouseList";
|
18
src/warehouses/views/WarehouseList/sort.ts
Normal file
18
src/warehouses/views/WarehouseList/sort.ts
Normal file
|
@ -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
|
||||||
|
);
|
Loading…
Reference in a new issue