Add global channel picker (#841)

* Move theme switch to user menu

* Add global channel picker

* Fix picker styles

* Use app channel state

* Improve prop naming to indicate id vs slug

* Disable picker if no reason to pick channel

* Remove settings modal leftovers

* Remove channel settings dialog

* Remove unused props

* Skip channel fetching if user is not authenticated

* Remove channel selection from components

* Update messages

* Fix e2e tests

* Remove channel picker leftover

* Revert ChannelSettingsDialog deletion

* Update snapshots

* Update messages
This commit is contained in:
Dominik Żegleń 2020-11-23 10:39:24 +01:00 committed by GitHub
parent 607eba6a10
commit a175fb9497
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
88 changed files with 501 additions and 1809 deletions

View file

@ -1,6 +1,5 @@
import { LEFT_MENU_SELECTORS } from "../elements/account/left-menu/left-menu-selectors"; import { LEFT_MENU_SELECTORS } from "../elements/account/left-menu/left-menu-selectors";
import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors"; import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors";
import { BUTTON_SELECTORS } from "../elements/shared/button-selectors";
// <reference types="cypress" /> // <reference types="cypress" />
describe("Products", () => { describe("Products", () => {
@ -14,8 +13,6 @@ describe("Products", () => {
.click() .click()
.get(PRODUCTS_SELECTORS.products) .get(PRODUCTS_SELECTORS.products)
.click() .click()
.get(BUTTON_SELECTORS.submit)
.click()
.get(PRODUCTS_SELECTORS.createProductBtn) .get(PRODUCTS_SELECTORS.createProductBtn)
.click() .click()
.get(PRODUCTS_SELECTORS.productNameInput) .get(PRODUCTS_SELECTORS.productNameInput)

View file

@ -1325,10 +1325,6 @@
"context": "field is optional", "context": "field is optional",
"string": "(Optional)" "string": "(Optional)"
}, },
"src_dot_collections_dot_components_dot_CollectionListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_collections_dot_components_dot_CollectionListPage_dot_1631917001": { "src_dot_collections_dot_components_dot_CollectionListPage_dot_1631917001": {
"context": "tab name", "context": "tab name",
"string": "All Collections" "string": "All Collections"
@ -1651,10 +1647,6 @@
"context": "section header button", "context": "section header button",
"string": "Manage" "string": "Manage"
}, },
"src_dot_components_dot_ChannelsSelect_dot_4183335632": {
"context": "channel select label",
"string": "Channel:"
},
"src_dot_components_dot_ColumnPicker_dot_1483881697": { "src_dot_components_dot_ColumnPicker_dot_1483881697": {
"context": "button", "context": "button",
"string": "Reset" "string": "Reset"
@ -2062,6 +2054,10 @@
"context": "button", "context": "button",
"string": "Account Settings" "string": "Account Settings"
}, },
"src_dot_components_dot_UserChip_dot_85001470": {
"context": "button",
"string": "Enable Dark Mode"
},
"src_dot_components_dot_VisibilityCard_dot_1311467573": { "src_dot_components_dot_VisibilityCard_dot_1311467573": {
"string": "Show in product listings" "string": "Show in product listings"
}, },
@ -2496,10 +2492,6 @@
"context": "sale name", "context": "sale name",
"string": "Name" "string": "Name"
}, },
"src_dot_discounts_dot_components_dot_SaleListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_discounts_dot_components_dot_SaleListPage_dot_1866913828": { "src_dot_discounts_dot_components_dot_SaleListPage_dot_1866913828": {
"string": "Search Sale" "string": "Search Sale"
}, },
@ -2660,10 +2652,6 @@
"context": "tab name", "context": "tab name",
"string": "All Vouchers" "string": "All Vouchers"
}, },
"src_dot_discounts_dot_components_dot_VoucherListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_discounts_dot_components_dot_VoucherListPage_dot_1930485532": { "src_dot_discounts_dot_components_dot_VoucherListPage_dot_1930485532": {
"string": "Search Voucher" "string": "Search Voucher"
}, },
@ -3004,9 +2992,6 @@
"src_dot_home_dot_components_dot_HomeActivityCard_dot_placed": { "src_dot_home_dot_components_dot_HomeActivityCard_dot_placed": {
"string": "Order #{orderId} was placed" "string": "Order #{orderId} was placed"
}, },
"src_dot_home_dot_components_dot_HomeHeader_dot_4019698341": {
"string": "Channel"
},
"src_dot_hooks_dot_3382262667": { "src_dot_hooks_dot_3382262667": {
"string": "Variant {name} has been set as default." "string": "Variant {name} has been set as default."
}, },
@ -3163,10 +3148,6 @@
"context": "button", "context": "button",
"string": "Add products" "string": "Add products"
}, },
"src_dot_orders_dot_components_dot_OrderDraftListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_orders_dot_components_dot_OrderDraftListPage_dot_2826235371": { "src_dot_orders_dot_components_dot_OrderDraftListPage_dot_2826235371": {
"context": "button", "context": "button",
"string": "Create order" "string": "Create order"
@ -3491,10 +3472,6 @@
"context": "generate invoice button", "context": "generate invoice button",
"string": "Generate" "string": "Generate"
}, },
"src_dot_orders_dot_components_dot_OrderListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_orders_dot_components_dot_OrderListPage_dot_2826235371": { "src_dot_orders_dot_components_dot_OrderListPage_dot_2826235371": {
"context": "button", "context": "button",
"string": "Create order" "string": "Create order"
@ -4561,10 +4538,6 @@
"context": "product price", "context": "product price",
"string": "Price" "string": "Price"
}, },
"src_dot_products_dot_components_dot_ProductListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_products_dot_components_dot_ProductListPage_dot_1542417144": { "src_dot_products_dot_components_dot_ProductListPage_dot_1542417144": {
"context": "button", "context": "button",
"string": "Create Product" "string": "Create Product"
@ -5296,10 +5269,6 @@
"context": "header", "context": "header",
"string": "Shipping" "string": "Shipping"
}, },
"src_dot_shipping_dot_components_dot_ShippingZonesListPage_dot_1391686013": {
"context": "button",
"string": "Settings"
},
"src_dot_shipping_dot_components_dot_ShippingZonesList_dot_120574110": { "src_dot_shipping_dot_components_dot_ShippingZonesList_dot_120574110": {
"context": "sort shipping methods by zone, section header", "context": "sort shipping methods by zone, section header",
"string": "Shipping By Zone" "string": "Shipping By Zone"

View file

@ -14,7 +14,7 @@ import TableCellAvatar, {
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types"; import { ChannelProps, ListActions, ListProps } from "@saleor/types";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@ -70,9 +70,11 @@ const useStyles = makeStyles(
} }
); );
interface CategoryProductListProps extends ListProps, ListActions { interface CategoryProductListProps
extends ListProps,
ListActions,
ChannelProps {
channelsCount: number; channelsCount: number;
selectedChannel: string;
products: CategoryDetails_category_products_edges_node[]; products: CategoryDetails_category_products_edges_node[];
} }
@ -90,7 +92,7 @@ export const CategoryProductList: React.FC<CategoryProductListProps> = props =>
onNextPage, onNextPage,
onPreviousPage, onPreviousPage,
onRowClick, onRowClick,
selectedChannel selectedChannelId
} = props; } = props;
const classes = useStyles(props); const classes = useStyles(props);
@ -158,7 +160,7 @@ export const CategoryProductList: React.FC<CategoryProductListProps> = props =>
product => { product => {
const isSelected = product ? isChecked(product.id) : false; const isSelected = product ? isChecked(product.id) : false;
const channel = product?.channelListings.find( const channel = product?.channelListings.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
return ( return (

View file

@ -1,36 +1,25 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import { makeStyles } from "@material-ui/core/styles";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import { ChannelsSelect } from "@saleor/components/ChannelsSelect";
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
import useStateFromProps from "@saleor/hooks/useStateFromProps";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { ListActions, PageListProps } from "../../../types"; import { ChannelProps, ListActions, PageListProps } from "../../../types";
import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails"; import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails";
import CategoryProductList from "../CategoryProductList"; import CategoryProductList from "../CategoryProductList";
interface CategoryProductsProps extends PageListProps, ListActions { interface CategoryProductsProps
extends PageListProps,
ListActions,
ChannelProps {
products: CategoryDetails_category_products_edges_node[]; products: CategoryDetails_category_products_edges_node[];
channelChoices: SingleAutocompleteChoiceType[]; channelChoices: SingleAutocompleteChoiceType[];
channelsCount: number; channelsCount: number;
categoryName: string; categoryName: string;
} }
const useStyles = makeStyles(
theme => ({
channelsSelectContainer: {
paddingTop: theme.spacing(2)
}
}),
{ name: "CategoryProducts" }
);
export const CategoryProducts: React.FC<CategoryProductsProps> = ({ export const CategoryProducts: React.FC<CategoryProductsProps> = ({
channelChoices,
channelsCount, channelsCount,
products, products,
disabled, disabled,
@ -42,16 +31,12 @@ export const CategoryProducts: React.FC<CategoryProductsProps> = ({
categoryName, categoryName,
isChecked, isChecked,
selected, selected,
selectedChannelId,
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({});
const [channelChoice, setChannelChoice] = useStateFromProps(
channelChoices?.length ? channelChoices[0]?.value : ""
);
return ( return (
<Card> <Card>
@ -72,16 +57,9 @@ export const CategoryProducts: React.FC<CategoryProductsProps> = ({
</Button> </Button>
} }
/> />
<CardContent className={classes.channelsSelectContainer}>
<ChannelsSelect
channelChoice={channelChoice}
channelChoices={channelChoices}
setChannelChoice={setChannelChoice}
/>
</CardContent>
<CategoryProductList <CategoryProductList
channelsCount={channelsCount} channelsCount={channelsCount}
selectedChannel={channelChoice} selectedChannelId={selectedChannelId}
products={products} products={products}
disabled={disabled} disabled={disabled}
pageInfo={pageInfo} pageInfo={pageInfo}

View file

@ -18,7 +18,7 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { maybe } from "../../../misc"; import { maybe } from "../../../misc";
import { TabListActions } from "../../../types"; import { ChannelProps, TabListActions } from "../../../types";
import CategoryDetailsForm from "../../components/CategoryDetailsForm"; import CategoryDetailsForm from "../../components/CategoryDetailsForm";
import CategoryList from "../../components/CategoryList"; import CategoryList from "../../components/CategoryList";
import { import {
@ -36,7 +36,8 @@ export enum CategoryPageTab {
} }
export interface CategoryUpdatePageProps export interface CategoryUpdatePageProps
extends TabListActions<"productListToolbar" | "subcategoryListToolbar"> { extends TabListActions<"productListToolbar" | "subcategoryListToolbar">,
ChannelProps {
changeTab: (index: CategoryPageTab) => void; changeTab: (index: CategoryPageTab) => void;
currentTab: CategoryPageTab; currentTab: CategoryPageTab;
errors: ProductErrorFragment[]; errors: ProductErrorFragment[];
@ -93,6 +94,7 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
isChecked, isChecked,
productListToolbar, productListToolbar,
selected, selected,
selectedChannelId,
subcategoryListToolbar, subcategoryListToolbar,
toggle, toggle,
toggleAll toggleAll
@ -216,6 +218,7 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
toggle={toggle} toggle={toggle}
toggleAll={toggleAll} toggleAll={toggleAll}
selected={selected} selected={selected}
selectedChannelId={selectedChannelId}
isChecked={isChecked} isChecked={isChecked}
toolbar={productListToolbar} toolbar={productListToolbar}
/> />

View file

@ -1,8 +1,8 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import { useChannelsList } from "@saleor/channels/queries";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
@ -14,6 +14,7 @@ import usePaginator, {
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler"; import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
import { mapNodeToChoice } from "@saleor/utils/maps";
import { import {
useMetadataUpdate, useMetadataUpdate,
usePrivateMetadataUpdate usePrivateMetadataUpdate
@ -79,12 +80,9 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
variables: { ...paginationState, id } variables: { ...paginationState, id }
}); });
const { data: channelsData } = useChannelsList({}); const { availableChannels, channel } = useAppChannel();
const channelChoices = channelsData?.channels?.map(channel => ({ const channelChoices = mapNodeToChoice(availableChannels);
label: channel.name,
value: channel.id
}));
const category = data?.category; const category = data?.category;
@ -213,7 +211,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
<> <>
<WindowTitle title={maybe(() => data.category.name)} /> <WindowTitle title={maybe(() => data.category.name)} />
<CategoryUpdatePage <CategoryUpdatePage
channelsCount={channelsData?.channels?.length} channelsCount={availableChannels.length}
channelChoices={channelChoices} channelChoices={channelChoices}
changeTab={changeTab} changeTab={changeTab}
currentTab={params.activeTab} currentTab={params.activeTab}
@ -258,6 +256,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
data.category.products.edges.map(edge => edge.node) data.category.products.edges.map(edge => edge.node)
)} )}
saveButtonBarState={updateResult.status} saveButtonBarState={updateResult.status}
selectedChannelId={channel.id}
subcategories={maybe(() => subcategories={maybe(() =>
data.category.children.edges.map(edge => edge.node) data.category.children.edges.map(edge => edge.node)
)} )}

View file

@ -8,10 +8,10 @@
export interface Channel_channel { export interface Channel_channel {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -10,10 +10,10 @@ import { ChannelErrorCode } from "./../../types/globalTypes";
export interface ChannelActivate_channelActivate_channel { export interface ChannelActivate_channelActivate_channel {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -10,10 +10,10 @@ import { ChannelCreateInput, ChannelErrorCode } from "./../../types/globalTypes"
export interface ChannelCreate_channelCreate_channel { export interface ChannelCreate_channelCreate_channel {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -10,10 +10,10 @@ import { ChannelErrorCode } from "./../../types/globalTypes";
export interface ChannelDeactivate_channelDeactivate_channel { export interface ChannelDeactivate_channelDeactivate_channel {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -10,10 +10,10 @@ import { ChannelDeleteInput, ChannelErrorCode } from "./../../types/globalTypes"
export interface ChannelDelete_channelDelete_channel { export interface ChannelDelete_channelDelete_channel {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -10,10 +10,10 @@ import { ChannelUpdateInput, ChannelErrorCode } from "./../../types/globalTypes"
export interface ChannelUpdate_channelUpdate_channel { export interface ChannelUpdate_channelUpdate_channel {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -8,10 +8,10 @@
export interface Channels_channels { export interface Channels_channels {
__typename: "Channel"; __typename: "Channel";
id: string;
isActive: boolean;
name: string; name: string;
slug: string; slug: string;
id: string;
isActive: boolean;
currencyCode: string; currencyCode: string;
} }

View file

@ -6,7 +6,7 @@ import { RequireOnlyOne } from "@saleor/misc";
import { ProductDetails_product } from "@saleor/products/types/ProductDetails"; import { ProductDetails_product } from "@saleor/products/types/ProductDetails";
import { ProductVariantDetails_productVariant } from "@saleor/products/types/ProductVariantDetails"; import { ProductVariantDetails_productVariant } from "@saleor/products/types/ProductVariantDetails";
import { ShippingZone_shippingZone_shippingMethods_channelListings } from "@saleor/shipping/types/ShippingZone"; import { ShippingZone_shippingZone_shippingMethods_channelListings } from "@saleor/shipping/types/ShippingZone";
import { uniqBy } from "lodash"; import uniqBy from "lodash-es/uniqBy";
export interface Channel { export interface Channel {
id: string; id: string;

View file

@ -16,14 +16,17 @@ import { sectionNames } from "@saleor/intl";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { ListActions, PageListProps } from "../../../types"; import { ChannelProps, ListActions, PageListProps } from "../../../types";
import { CollectionDetails_collection } from "../../types/CollectionDetails"; import { CollectionDetails_collection } from "../../types/CollectionDetails";
import CollectionDetails from "../CollectionDetails/CollectionDetails"; import CollectionDetails from "../CollectionDetails/CollectionDetails";
import { CollectionImage } from "../CollectionImage/CollectionImage"; import { CollectionImage } from "../CollectionImage/CollectionImage";
import CollectionProducts from "../CollectionProducts/CollectionProducts"; import CollectionProducts from "../CollectionProducts/CollectionProducts";
import CollectionUpdateForm, { CollectionUpdateData } from "./form"; import CollectionUpdateForm, { CollectionUpdateData } from "./form";
export interface CollectionDetailsPageProps extends PageListProps, ListActions { export interface CollectionDetailsPageProps
extends PageListProps,
ListActions,
ChannelProps {
channelsCount: number; channelsCount: number;
channelsErrors: CollectionChannelListingErrorFragment[]; channelsErrors: CollectionChannelListingErrorFragment[];
collection: CollectionDetails_collection; collection: CollectionDetails_collection;
@ -31,7 +34,6 @@ export interface CollectionDetailsPageProps extends PageListProps, ListActions {
errors: CollectionErrorFragment[]; errors: CollectionErrorFragment[];
hasChannelChanged: boolean; hasChannelChanged: boolean;
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
selectedChannel: string;
onBack: () => void; onBack: () => void;
onCollectionRemove: () => void; onCollectionRemove: () => void;
onImageDelete: () => void; onImageDelete: () => void;
@ -51,7 +53,7 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
errors, errors,
hasChannelChanged, hasChannelChanged,
saveButtonBarState, saveButtonBarState,
selectedChannel, selectedChannelId,
onBack, onBack,
onCollectionRemove, onCollectionRemove,
onImageDelete, onImageDelete,
@ -99,7 +101,7 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
<CollectionProducts <CollectionProducts
disabled={disabled} disabled={disabled}
channelsCount={channelsCount} channelsCount={channelsCount}
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
collection={collection} collection={collection}
{...collectionProductsProps} {...collectionProductsProps}
/> />

View file

@ -12,7 +12,7 @@ import TableCellHeader from "@saleor/components/TableCellHeader";
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps, SortPage } from "@saleor/types"; import { ChannelProps, ListActions, ListProps, SortPage } from "@saleor/types";
import { getArrowDirection } from "@saleor/utils/sort"; import { getArrowDirection } from "@saleor/utils/sort";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@ -47,10 +47,10 @@ const useStyles = makeStyles(
interface CollectionListProps interface CollectionListProps
extends ListProps, extends ListProps,
ListActions, ListActions,
SortPage<CollectionListUrlSortField> { SortPage<CollectionListUrlSortField>,
ChannelProps {
collections: CollectionList_collections_edges_node[]; collections: CollectionList_collections_edges_node[];
channelsCount: number; channelsCount: number;
selectedChannel: string;
} }
const numberOfColumns = 4; const numberOfColumns = 4;
@ -70,7 +70,7 @@ const CollectionList: React.FC<CollectionListProps> = props => {
pageInfo, pageInfo,
isChecked, isChecked,
selected, selected,
selectedChannel, selectedChannelId,
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
@ -147,7 +147,7 @@ const CollectionList: React.FC<CollectionListProps> = props => {
collection => { collection => {
const isSelected = collection ? isChecked(collection.id) : false; const isSelected = collection ? isChecked(collection.id) : false;
const channel = collection?.channelListings.find( const channel = collection?.channelListings.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
return ( return (
<TableRow <TableRow

View file

@ -1,13 +1,12 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import makeStyles from "@material-ui/core/styles/makeStyles";
import { CollectionListUrlSortField } from "@saleor/collections/urls"; import { CollectionListUrlSortField } from "@saleor/collections/urls";
import CardMenu from "@saleor/components/CardMenu";
import { Container } from "@saleor/components/Container"; import { Container } from "@saleor/components/Container";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import SearchBar from "@saleor/components/SearchBar"; import SearchBar from "@saleor/components/SearchBar";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { import {
ChannelProps,
ListActions, ListActions,
PageListProps, PageListProps,
SearchPageProps, SearchPageProps,
@ -25,22 +24,12 @@ export interface CollectionListPageProps
ListActions, ListActions,
SearchPageProps, SearchPageProps,
SortPage<CollectionListUrlSortField>, SortPage<CollectionListUrlSortField>,
TabPageProps { TabPageProps,
ChannelProps {
collections: CollectionList_collections_edges_node[]; collections: CollectionList_collections_edges_node[];
channelsCount: number; channelsCount: number;
selectedChannel: string;
onSettingsOpen?: () => void;
} }
const useStyles = makeStyles(
theme => ({
settings: {
marginRight: theme.spacing(2)
}
}),
{ name: "CollectionListPage" }
);
const CollectionListPage: React.FC<CollectionListPageProps> = ({ const CollectionListPage: React.FC<CollectionListPageProps> = ({
channelsCount, channelsCount,
currentTab, currentTab,
@ -49,34 +38,18 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
onAdd, onAdd,
onAll, onAll,
onSearchChange, onSearchChange,
onSettingsOpen,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
onTabSave, onTabSave,
selectedChannel, selectedChannelId,
tabs, tabs,
...listProps ...listProps
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({});
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.collections)}> <PageHeader title={intl.formatMessage(sectionNames.collections)}>
{!!onSettingsOpen && (
<CardMenu
className={classes.settings}
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
}
]}
/>
)}
<Button <Button
color="primary" color="primary"
disabled={disabled} disabled={disabled}
@ -110,7 +83,7 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
<CollectionList <CollectionList
disabled={disabled} disabled={disabled}
channelsCount={channelsCount} channelsCount={channelsCount}
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
{...listProps} {...listProps}
/> />
</Card> </Card>

View file

@ -21,7 +21,7 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { maybe, renderCollection } from "../../../misc"; import { maybe, renderCollection } from "../../../misc";
import { ListActions, PageListProps } from "../../../types"; import { ChannelProps, ListActions, PageListProps } from "../../../types";
import { CollectionDetails_collection } from "../../types/CollectionDetails"; import { CollectionDetails_collection } from "../../types/CollectionDetails";
const useStyles = makeStyles( const useStyles = makeStyles(
@ -55,10 +55,12 @@ const useStyles = makeStyles(
{ name: "CollectionProducts" } { name: "CollectionProducts" }
); );
export interface CollectionProductsProps extends PageListProps, ListActions { export interface CollectionProductsProps
extends PageListProps,
ListActions,
ChannelProps {
collection: CollectionDetails_collection; collection: CollectionDetails_collection;
channelsCount: number; channelsCount: number;
selectedChannel: string;
onProductUnassign: (id: string, event: React.MouseEvent<any>) => void; onProductUnassign: (id: string, event: React.MouseEvent<any>) => void;
} }
@ -75,7 +77,7 @@ const CollectionProducts: React.FC<CollectionProductsProps> = props => {
onProductUnassign, onProductUnassign,
onRowClick, onRowClick,
pageInfo, pageInfo,
selectedChannel, selectedChannelId,
isChecked, isChecked,
selected, selected,
toggle, toggle,
@ -167,7 +169,7 @@ const CollectionProducts: React.FC<CollectionProductsProps> = props => {
const isSelected = product ? isChecked(product.id) : false; const isSelected = product ? isChecked(product.id) : false;
const channel = const channel =
product?.channelListings.find( product?.channelListings.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
) || product?.channelListings[0]; ) || product?.channelListings[0];
return ( return (

View file

@ -19,7 +19,7 @@ export enum CollectionListUrlFiltersEnum {
query = "query" query = "query"
} }
export type CollectionListUrlFilters = Filters<CollectionListUrlFiltersEnum>; export type CollectionListUrlFilters = Filters<CollectionListUrlFiltersEnum>;
export type CollectionListUrlDialog = "remove" | "settings" | TabActionDialog; export type CollectionListUrlDialog = "remove" | TabActionDialog;
export enum CollectionListUrlSortField { export enum CollectionListUrlSortField {
name = "name", name = "name",
available = "available", available = "available",

View file

@ -336,7 +336,7 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
collectionChannelsChoices?.length !== currentChannels?.length collectionChannelsChoices?.length !== currentChannels?.length
} }
channelsCount={channelsData?.channels?.length} channelsCount={channelsData?.channels?.length}
selectedChannel={selectedChannel} selectedChannelId={selectedChannel}
openChannelsModal={handleChannelsModalOpen} openChannelsModal={handleChannelsModalOpen}
onChannelsChange={setCurrentChannels} onChannelsChange={setCurrentChannels}
/> />

View file

@ -1,14 +1,13 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -90,6 +89,9 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
} }
} }
}); });
const { availableChannels, channel } = useAppChannel();
const tabs = getFilterTabs(); const tabs = getFilterTabs();
const currentTab = const currentTab =
@ -114,12 +116,6 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
CollectionListUrlQueryParams CollectionListUrlQueryParams
>(navigate, collectionListUrl, params); >(navigate, collectionListUrl, params);
const {
channelChoices,
handleChannelSelectConfirm,
selectedChannel
} = useChannelsSettings("collectionListChannel", { closeModal, openModal });
const handleTabChange = (tab: number) => { const handleTabChange = (tab: number) => {
reset(); reset();
navigate( navigate(
@ -151,16 +147,6 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
return ( return (
<> <>
{!!channelChoices?.length && (
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
)}
<CollectionListPage <CollectionListPage
currentTab={currentTab} currentTab={currentTab}
initialSearch={params.query || ""} initialSearch={params.query || ""}
@ -197,11 +183,8 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
selected={listElements.length} selected={listElements.length}
toggle={toggle} toggle={toggle}
toggleAll={toggleAll} toggleAll={toggleAll}
channelsCount={channelChoices?.length} channelsCount={availableChannels?.length}
selectedChannel={selectedChannel} selectedChannelId={channel.id}
onSettingsOpen={
!!channelChoices?.length ? () => openModal("settings") : undefined
}
/> />
<ActionDialog <ActionDialog
open={params.action === "remove" && maybe(() => params.ids.length > 0)} open={params.action === "remove" && maybe(() => params.ids.length > 0)}

View file

@ -0,0 +1,75 @@
import { useAuth } from "@saleor/auth/AuthProvider";
import { useChannelsList } from "@saleor/channels/queries";
import { ChannelDetailsFragment } from "@saleor/fragments/types/ChannelDetailsFragment";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import React from "react";
interface UseAppChannel {
availableChannels: ChannelDetailsFragment[];
channel: ChannelDetailsFragment;
isPickerActive: boolean;
refreshChannels: () => void;
setChannel: (id: string) => void;
}
export interface AppChannelContextData extends UseAppChannel {
setPickerActive: (isActive: boolean) => void;
}
const AppChannelContext = React.createContext<AppChannelContextData>({
availableChannels: [],
channel: undefined,
isPickerActive: false,
refreshChannels: () => undefined,
setChannel: () => undefined,
setPickerActive: () => undefined
});
export const AppChannelProvider: React.FC = ({ children }) => {
const { isAuthenticated } = useAuth();
const [selectedChannel, setSelectedChannel] = useLocalStorage("channel", "");
const { data: channelData, refetch } = useChannelsList({
skip: !isAuthenticated
});
const [isPickerActive, setPickerActive] = React.useState(false);
React.useEffect(() => {
if (!selectedChannel) {
setSelectedChannel(channelData?.channels[0].id);
}
}, [channelData]);
const availableChannels = channelData?.channels || [];
const channel = availableChannels.find(
channel => channel.id === selectedChannel
);
return (
<AppChannelContext.Provider
value={{
availableChannels,
channel,
isPickerActive,
refreshChannels: refetch,
setChannel: setSelectedChannel,
setPickerActive
}}
>
{children}
</AppChannelContext.Provider>
);
};
AppChannelProvider.displayName = "AppChannelProvider";
function useAppChannel(enablePicker = true): UseAppChannel {
const { setPickerActive, ...data } = React.useContext(AppChannelContext);
React.useEffect(() => {
if (enablePicker) {
setPickerActive(true);
}
return () => setPickerActive(false);
}, [enablePicker]);
return data;
}
export default useAppChannel;

View file

@ -0,0 +1,51 @@
import makeStyles from "@material-ui/core/styles/makeStyles";
import { ChannelDetailsFragment } from "@saleor/fragments/types/ChannelDetailsFragment";
import { ChannelProps } from "@saleor/types";
import { mapNodeToChoice } from "@saleor/utils/maps";
import React from "react";
import SingleSelectField from "../SingleSelectField";
const useStyles = makeStyles(
theme => ({
root: {
"&& fieldset": {
borderColor: theme.palette.divider
},
marginRight: theme.spacing(2),
width: 192
}
}),
{
name: "AppChannelSelect"
}
);
export interface AppChannelSelectProps extends ChannelProps {
channels: ChannelDetailsFragment[];
disabled: boolean;
onChannelSelect: (id: string) => void;
}
const AppChannelSelect: React.FC<AppChannelSelectProps> = ({
channels,
disabled,
onChannelSelect,
selectedChannelId
}) => {
const classes = useStyles({});
return (
<div className={classes.root}>
<SingleSelectField
choices={mapNodeToChoice(channels)}
disabled={disabled}
value={selectedChannelId}
onChange={event => onChannelSelect(event.target.value)}
/>
</div>
);
};
AppChannelSelect.displayName = "AppChannelSelect";
export default AppChannelSelect;

View file

@ -20,10 +20,11 @@ import SideBar from "../SideBar";
import SideBarDrawer from "../SideBarDrawer/SideBarDrawer"; import SideBarDrawer from "../SideBarDrawer/SideBarDrawer";
import UserChip from "../UserChip"; import UserChip from "../UserChip";
import AppActionContext from "./AppActionContext"; import AppActionContext from "./AppActionContext";
import useAppChannel from "./AppChannelContext";
import AppChannelSelect from "./AppChannelSelect";
import AppHeaderContext from "./AppHeaderContext"; import AppHeaderContext from "./AppHeaderContext";
import { appLoaderHeight } from "./consts"; import { appLoaderHeight } from "./consts";
import createMenuStructure from "./menuStructure"; import createMenuStructure from "./menuStructure";
import ThemeSwitch from "./ThemeSwitch";
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
@ -128,6 +129,12 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
const [isNavigatorVisible, setNavigatorVisibility] = React.useState(false); const [isNavigatorVisible, setNavigatorVisibility] = React.useState(false);
const isMdUp = useMediaQuery((theme: Theme) => theme.breakpoints.up("md")); const isMdUp = useMediaQuery((theme: Theme) => theme.breakpoints.up("md"));
const [docked, setDocked] = React.useState(true); const [docked, setDocked] = React.useState(true);
const {
availableChannels,
channel,
isPickerActive,
setChannel
} = useAppChannel(false);
const menuStructure = createMenuStructure(intl); const menuStructure = createMenuStructure(intl);
const configurationMenu = createConfigurationMenu(intl); const configurationMenu = createConfigurationMenu(intl);
@ -202,23 +209,26 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
)} )}
<div className={classes.spacer} /> <div className={classes.spacer} />
<div className={classes.userBar}> <div className={classes.userBar}>
<ThemeSwitch
className={classes.darkThemeSwitch}
checked={isDark}
onClick={toggleTheme}
/>
<NavigatorButton <NavigatorButton
isMac={navigator.platform isMac={navigator.platform
.toLowerCase() .toLowerCase()
.includes("mac")} .includes("mac")}
onClick={() => setNavigatorVisibility(true)} onClick={() => setNavigatorVisibility(true)}
/> />
<AppChannelSelect
channels={availableChannels}
disabled={!isPickerActive}
selectedChannelId={channel.id}
onChannelSelect={setChannel}
/>
<UserChip <UserChip
isDarkThemeEnabled={isDark}
user={user}
onLogout={logout} onLogout={logout}
onProfileClick={() => onProfileClick={() =>
navigate(staffMemberDetailsUrl(user.id)) navigate(staffMemberDetailsUrl(user.id))
} }
user={user} onThemeToggle={toggleTheme}
/> />
</div> </div>
</div> </div>

View file

@ -1,51 +0,0 @@
import { makeStyles } from "@material-ui/core/styles";
import Switch, { SwitchProps } from "@material-ui/core/Switch";
import React from "react";
import MoonIcon from "../../icons/Moon";
import SunIcon from "../../icons/Sun";
const useStyles = makeStyles(
theme => ({
checked: {
"& svg": {
background: theme.palette.primary.main,
color: theme.palette.background.paper
}
},
colorPrimary: {},
root: {
"& svg": {
background: theme.palette.primary.main,
borderRadius: "100%",
height: 20,
width: 20
}
},
track: {
"$colorPrimary$checked + &": {
backgroundColor: theme.palette.background.paper
},
background: theme.palette.background.paper
}
}),
{
name: "ThemeSwitch"
}
);
const ThemeSwitch: React.FC<SwitchProps> = props => {
const classes = useStyles(props);
return (
<Switch
{...props}
classes={classes}
color="primary"
icon={<SunIcon />}
checkedIcon={<MoonIcon />}
/>
);
};
ThemeSwitch.displayName = "ThemeSwitch";
export default ThemeSwitch;

View file

@ -1,22 +0,0 @@
import { product as productFixture } from "@saleor/products/fixtures";
import Decorator from "@saleor/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react";
import ChannelsSelect, { ChannelsSelectProps } from "./ChannelsSelect";
const product = productFixture("");
const channelChoices = product.channelListings.map(listing => ({
label: listing.channel.name,
value: listing.channel.id
}));
const props: ChannelsSelectProps = {
channelChoice: channelChoices[0].value,
channelChoices,
setChannelChoice: () => undefined
};
storiesOf("Generics / ChannelsSelect", module)
.addDecorator(Decorator)
.add("default", () => <ChannelsSelect {...props} />);

View file

@ -1,53 +0,0 @@
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import LinkChoice from "@saleor/components/LinkChoice";
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
import { FormChange } from "@saleor/hooks/useForm";
import React from "react";
import { FormattedMessage } from "react-intl";
export interface ChannelsSelectProps {
channelChoices: SingleAutocompleteChoiceType[];
channelChoice: string;
setChannelChoice: FormChange;
}
const useStyles = makeStyles(
theme => ({
label: {
display: "inline-block",
marginRight: theme.spacing(1)
},
select: {
display: "inline-block"
}
}),
{ name: "ChannelsSelect" }
);
export const ChannelsSelect: React.FC<ChannelsSelectProps> = ({
channelChoice,
channelChoices,
setChannelChoice
}) => {
const classes = useStyles({});
return channelChoices?.length ? (
<>
<Typography className={classes.label}>
<FormattedMessage
defaultMessage="Channel:"
description="channel select label"
/>
</Typography>
<LinkChoice
className={classes.select}
choices={channelChoices}
name="channels"
value={channelChoice}
onChange={event => setChannelChoice(event.target.value)}
/>
</>
) : null;
};
export default ChannelsSelect;

View file

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

View file

@ -1,6 +1,7 @@
import Avatar from "@material-ui/core/Avatar"; import Avatar from "@material-ui/core/Avatar";
import Chip from "@material-ui/core/Chip"; import Chip from "@material-ui/core/Chip";
import ClickAwayListener from "@material-ui/core/ClickAwayListener"; import ClickAwayListener from "@material-ui/core/ClickAwayListener";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Grow from "@material-ui/core/Grow"; import Grow from "@material-ui/core/Grow";
import Hidden from "@material-ui/core/Hidden"; import Hidden from "@material-ui/core/Hidden";
import MenuItem from "@material-ui/core/MenuItem"; import MenuItem from "@material-ui/core/MenuItem";
@ -8,12 +9,13 @@ import Menu from "@material-ui/core/MenuList";
import Paper from "@material-ui/core/Paper"; import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper"; import Popper from "@material-ui/core/Popper";
import makeStyles from "@material-ui/core/styles/makeStyles"; import makeStyles from "@material-ui/core/styles/makeStyles";
import Switch from "@material-ui/core/Switch";
import { User } from "@saleor/fragments/types/User"; import { User } from "@saleor/fragments/types/User";
import ArrowDropdown from "@saleor/icons/ArrowDropdown"; import ArrowDropdown from "@saleor/icons/ArrowDropdown";
import { getUserInitials, getUserName } from "@saleor/misc"; import { getUserInitials, getUserName } from "@saleor/misc";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
@ -46,11 +48,16 @@ const useStyles = makeStyles(
}, },
popover: { popover: {
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
zIndex: 1 zIndex: 10
}, },
rotate: { rotate: {
transform: "rotate(180deg)" transform: "rotate(180deg)"
}, },
switch: {
"&&:hover": {
background: "transparent"
}
},
userChip: { userChip: {
[theme.breakpoints.down("sm")]: { [theme.breakpoints.down("sm")]: {
height: 48 height: 48
@ -74,19 +81,24 @@ const useStyles = makeStyles(
); );
export interface UserChipProps { export interface UserChipProps {
isDarkThemeEnabled: boolean;
user: User; user: User;
onLogout: () => void; onLogout: () => void;
onProfileClick: () => void; onProfileClick: () => void;
onThemeToggle: () => void;
} }
const UserChip: React.FC<UserChipProps> = ({ const UserChip: React.FC<UserChipProps> = ({
isDarkThemeEnabled,
user, user,
onLogout, onLogout,
onProfileClick onProfileClick,
onThemeToggle
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const [isMenuOpened, setMenuState] = React.useState(false); const [isMenuOpened, setMenuState] = React.useState(false);
const anchor = React.useRef<HTMLDivElement>(); const anchor = React.useRef<HTMLDivElement>();
const intl = useIntl();
const handleLogout = () => { const handleLogout = () => {
setMenuState(false); setMenuState(false);
@ -170,6 +182,29 @@ const UserChip: React.FC<UserChipProps> = ({
description="button" description="button"
/> />
</MenuItem> </MenuItem>
<MenuItem
className={classes.userMenuItem}
data-test="themeSwitch"
data-test-is-dark={isDarkThemeEnabled}
>
<FormControlLabel
control={
<Switch
classes={{
switchBase: classes.switch
}}
checked={isDarkThemeEnabled}
color="primary"
disableRipple
/>
}
label={intl.formatMessage({
defaultMessage: "Enable Dark Mode",
description: "button"
})}
onChange={onThemeToggle}
/>
</MenuItem>
</Menu> </Menu>
</ClickAwayListener> </ClickAwayListener>
</Paper> </Paper>

View file

@ -21,14 +21,16 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { maybe, renderCollection } from "../../../misc"; import { maybe, renderCollection } from "../../../misc";
import { ListActions, ListProps } from "../../../types"; import { ChannelProps, ListActions, ListProps } from "../../../types";
import { SaleDetails_sale } from "../../types/SaleDetails"; import { SaleDetails_sale } from "../../types/SaleDetails";
import { VoucherDetails_voucher } from "../../types/VoucherDetails"; import { VoucherDetails_voucher } from "../../types/VoucherDetails";
export interface SaleProductsProps extends ListProps, ListActions { export interface SaleProductsProps
extends ListProps,
ListActions,
ChannelProps {
discount: SaleDetails_sale | VoucherDetails_voucher; discount: SaleDetails_sale | VoucherDetails_voucher;
channelsCount: number; channelsCount: number;
selectedChannel: string;
onProductAssign: () => void; onProductAssign: () => void;
onProductUnassign: (id: string) => void; onProductUnassign: (id: string) => void;
} }
@ -79,7 +81,7 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
onNextPage, onNextPage,
isChecked, isChecked,
selected, selected,
selectedChannel, selectedChannelId,
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
@ -156,7 +158,7 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
const isSelected = product ? isChecked(product.id) : false; const isSelected = product ? isChecked(product.id) : false;
const channel = const channel =
product?.channelListings.find( product?.channelListings.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
) || product?.channelListings[0]; ) || product?.channelListings[0];
return ( return (
<TableRow <TableRow

View file

@ -17,7 +17,7 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { maybe, splitDateTime } from "../../../misc"; import { maybe, splitDateTime } from "../../../misc";
import { ListProps, TabListActions } from "../../../types"; import { ChannelProps, ListProps, TabListActions } from "../../../types";
import { SaleType as SaleTypeEnum } from "../../../types/globalTypes"; import { SaleType as SaleTypeEnum } from "../../../types/globalTypes";
import { SaleDetails_sale } from "../../types/SaleDetails"; import { SaleDetails_sale } from "../../types/SaleDetails";
import DiscountCategories from "../DiscountCategories"; import DiscountCategories from "../DiscountCategories";
@ -57,11 +57,11 @@ export interface SaleDetailsPageProps
extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>, extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>,
TabListActions< TabListActions<
"categoryListToolbar" | "collectionListToolbar" | "productListToolbar" "categoryListToolbar" | "collectionListToolbar" | "productListToolbar"
> { >,
ChannelProps {
activeTab: SaleDetailsPageTab; activeTab: SaleDetailsPageTab;
errors: DiscountErrorFragment[]; errors: DiscountErrorFragment[];
sale: SaleDetails_sale; sale: SaleDetails_sale;
selectedChannel: string;
allChannelsCount: number; allChannelsCount: number;
channelListings: ChannelSaleData[]; channelListings: ChannelSaleData[];
hasChannelChanged: boolean; hasChannelChanged: boolean;
@ -119,7 +119,7 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
productListToolbar, productListToolbar,
isChecked, isChecked,
selected, selected,
selectedChannel, selectedChannelId,
toggle, toggle,
toggleAll toggleAll
}) => { }) => {
@ -270,7 +270,7 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
pageInfo={pageInfo} pageInfo={pageInfo}
discount={sale} discount={sale}
channelsCount={allChannelsCount} channelsCount={allChannelsCount}
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
isChecked={isChecked} isChecked={isChecked}
selected={selected} selected={selected}
toggle={toggle} toggle={toggle}
@ -287,7 +287,10 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
/> />
</div> </div>
<div> <div>
<SaleSummary selectedChannel={selectedChannel} sale={sale} /> <SaleSummary
selectedChannelId={selectedChannelId}
sale={sale}
/>
<CardSpacer /> <CardSpacer />
<ChannelsAvailability <ChannelsAvailability
selectedChannelsCount={data.channelListings.length} selectedChannelsCount={data.channelListings.length}

View file

@ -14,7 +14,7 @@ import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import { SaleListUrlSortField } from "@saleor/discounts/urls"; import { SaleListUrlSortField } from "@saleor/discounts/urls";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps, SortPage } from "@saleor/types"; import { ChannelProps, ListActions, ListProps, SortPage } from "@saleor/types";
import { SaleType } from "@saleor/types/globalTypes"; import { SaleType } from "@saleor/types/globalTypes";
import { getArrowDirection } from "@saleor/utils/sort"; import { getArrowDirection } from "@saleor/utils/sort";
import React from "react"; import React from "react";
@ -25,9 +25,9 @@ import { SaleList_sales_edges_node } from "../../types/SaleList";
export interface SaleListProps export interface SaleListProps
extends ListProps, extends ListProps,
ListActions, ListActions,
SortPage<SaleListUrlSortField> { SortPage<SaleListUrlSortField>,
ChannelProps {
sales: SaleList_sales_edges_node[]; sales: SaleList_sales_edges_node[];
selectedChannel: string;
} }
const useStyles = makeStyles( const useStyles = makeStyles(
@ -76,7 +76,7 @@ const SaleList: React.FC<SaleListProps> = props => {
onSort, onSort,
pageInfo, pageInfo,
sales, sales,
selectedChannel, selectedChannelId,
isChecked, isChecked,
selected, selected,
sort, sort,
@ -170,7 +170,7 @@ const SaleList: React.FC<SaleListProps> = props => {
sale => { sale => {
const isSelected = sale ? isChecked(sale.id) : false; const isSelected = sale ? isChecked(sale.id) : false;
const channel = sale?.channelListings?.find( const channel = sale?.channelListings?.find(
lisiting => lisiting.channel.id === selectedChannel lisiting => lisiting.channel.id === selectedChannelId
); );
return ( return (
<TableRow <TableRow

View file

@ -1,13 +1,12 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import makeStyles from "@material-ui/core/styles/makeStyles";
import CardMenu from "@saleor/components/CardMenu";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import FilterBar from "@saleor/components/FilterBar"; import FilterBar from "@saleor/components/FilterBar";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import { SaleListUrlSortField } from "@saleor/discounts/urls"; import { SaleListUrlSortField } from "@saleor/discounts/urls";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { import {
ChannelProps,
FilterPageProps, FilterPageProps,
ListActions, ListActions,
PageListProps, PageListProps,
@ -30,19 +29,10 @@ export interface SaleListPageProps
ListActions, ListActions,
FilterPageProps<SaleFilterKeys, SaleListFilterOpts>, FilterPageProps<SaleFilterKeys, SaleListFilterOpts>,
SortPage<SaleListUrlSortField>, SortPage<SaleListUrlSortField>,
TabPageProps { TabPageProps,
ChannelProps {
sales: SaleList_sales_edges_node[]; sales: SaleList_sales_edges_node[];
selectedChannel: string;
onSettingsOpen?: () => void;
} }
const useStyles = makeStyles(
theme => ({
settings: {
marginRight: theme.spacing(2)
}
}),
{ name: "SaleListPage" }
);
const SaleListPage: React.FC<SaleListPageProps> = ({ const SaleListPage: React.FC<SaleListPageProps> = ({
currentTab, currentTab,
@ -52,7 +42,6 @@ const SaleListPage: React.FC<SaleListPageProps> = ({
onAll, onAll,
onFilterChange, onFilterChange,
onSearchChange, onSearchChange,
onSettingsOpen,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
onTabSave, onTabSave,
@ -60,26 +49,11 @@ const SaleListPage: React.FC<SaleListPageProps> = ({
...listProps ...listProps
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({});
const structure = createFilterStructure(intl, filterOpts); const structure = createFilterStructure(intl, filterOpts);
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.sales)}> <PageHeader title={intl.formatMessage(sectionNames.sales)}>
{!!onSettingsOpen && (
<CardMenu
className={classes.settings}
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
}
]}
/>
)}
<Button onClick={onAdd} variant="contained" color="primary"> <Button onClick={onAdd} variant="contained" color="primary">
<FormattedMessage defaultMessage="Create Sale" description="button" /> <FormattedMessage defaultMessage="Create Sale" description="button" />
</Button> </Button>

View file

@ -10,6 +10,7 @@ import Money from "@saleor/components/Money";
import Percent from "@saleor/components/Percent"; import Percent from "@saleor/components/Percent";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { ChannelProps } from "@saleor/types";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -17,16 +18,18 @@ import { maybe } from "../../../misc";
import { SaleType } from "../../../types/globalTypes"; import { SaleType } from "../../../types/globalTypes";
import { SaleDetails_sale } from "../../types/SaleDetails"; import { SaleDetails_sale } from "../../types/SaleDetails";
export interface SaleSummaryProps { export interface SaleSummaryProps extends ChannelProps {
selectedChannel: string;
sale: SaleDetails_sale; sale: SaleDetails_sale;
} }
const SaleSummary: React.FC<SaleSummaryProps> = ({ selectedChannel, sale }) => { const SaleSummary: React.FC<SaleSummaryProps> = ({
selectedChannelId,
sale
}) => {
const intl = useIntl(); const intl = useIntl();
const channel = sale?.channelListings?.find( const channel = sale?.channelListings?.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
return ( return (
<Card> <Card>

View file

@ -20,7 +20,7 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { maybe, splitDateTime } from "../../../misc"; import { maybe, splitDateTime } from "../../../misc";
import { ListProps, TabListActions } from "../../../types"; import { ChannelProps, ListProps, TabListActions } from "../../../types";
import { import {
DiscountValueTypeEnum, DiscountValueTypeEnum,
VoucherTypeEnum VoucherTypeEnum
@ -73,12 +73,12 @@ export interface VoucherDetailsPageProps
extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>, extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>,
TabListActions< TabListActions<
"categoryListToolbar" | "collectionListToolbar" | "productListToolbar" "categoryListToolbar" | "collectionListToolbar" | "productListToolbar"
> { >,
ChannelProps {
activeTab: VoucherDetailsPageTab; activeTab: VoucherDetailsPageTab;
errors: DiscountErrorFragment[]; errors: DiscountErrorFragment[];
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
voucher: VoucherDetails_voucher; voucher: VoucherDetails_voucher;
selectedChannel: string;
allChannelsCount: number; allChannelsCount: number;
channelListings: ChannelVoucherData[]; channelListings: ChannelVoucherData[];
hasChannelChanged: boolean; hasChannelChanged: boolean;
@ -137,7 +137,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
toggle, toggle,
toggleAll, toggleAll,
selected, selected,
selectedChannel, selectedChannelId,
isChecked, isChecked,
categoryListToolbar, categoryListToolbar,
collectionListToolbar, collectionListToolbar,
@ -145,7 +145,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const channel = voucher?.channelListings?.find( const channel = voucher?.channelListings?.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
let requirementsPickerInitValue; let requirementsPickerInitValue;
if (voucher?.minCheckoutItemsQuantity > 0) { if (voucher?.minCheckoutItemsQuantity > 0) {
@ -331,7 +331,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
onRowClick={onProductClick} onRowClick={onProductClick}
pageInfo={pageInfo} pageInfo={pageInfo}
discount={voucher} discount={voucher}
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
channelsCount={allChannelsCount} channelsCount={allChannelsCount}
isChecked={isChecked} isChecked={isChecked}
selected={selected} selected={selected}
@ -391,7 +391,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
<div> <div>
<VoucherSummary <VoucherSummary
voucher={voucher} voucher={voucher}
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
/> />
<CardSpacer /> <CardSpacer />
<ChannelsAvailability <ChannelsAvailability

View file

@ -14,7 +14,7 @@ import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import { VoucherListUrlSortField } from "@saleor/discounts/urls"; import { VoucherListUrlSortField } from "@saleor/discounts/urls";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps, SortPage } from "@saleor/types"; import { ChannelProps, ListActions, ListProps, SortPage } from "@saleor/types";
import { DiscountValueTypeEnum } from "@saleor/types/globalTypes"; import { DiscountValueTypeEnum } from "@saleor/types/globalTypes";
import { getArrowDirection } from "@saleor/utils/sort"; import { getArrowDirection } from "@saleor/utils/sort";
import { getFooterColSpanWithBulkActions } from "@saleor/utils/tables"; import { getFooterColSpanWithBulkActions } from "@saleor/utils/tables";
@ -26,9 +26,9 @@ import { VoucherList_vouchers_edges_node } from "../../types/VoucherList";
export interface VoucherListProps export interface VoucherListProps
extends ListProps, extends ListProps,
ListActions, ListActions,
SortPage<VoucherListUrlSortField> { SortPage<VoucherListUrlSortField>,
ChannelProps {
vouchers: VoucherList_vouchers_edges_node[]; vouchers: VoucherList_vouchers_edges_node[];
selectedChannel: string;
} }
const useStyles = makeStyles( const useStyles = makeStyles(
@ -94,7 +94,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
vouchers, vouchers,
isChecked, isChecked,
selected, selected,
selectedChannel, selectedChannelId,
sort, sort,
toggle, toggle,
toggleAll, toggleAll,
@ -219,7 +219,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
voucher => { voucher => {
const isSelected = voucher ? isChecked(voucher.id) : false; const isSelected = voucher ? isChecked(voucher.id) : false;
const channel = voucher?.channelListings?.find( const channel = voucher?.channelListings?.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
const hasChannelsLoaded = voucher?.channelListings?.length; const hasChannelsLoaded = voucher?.channelListings?.length;

View file

@ -1,13 +1,12 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import makeStyles from "@material-ui/core/styles/makeStyles";
import CardMenu from "@saleor/components/CardMenu";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import FilterBar from "@saleor/components/FilterBar"; import FilterBar from "@saleor/components/FilterBar";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import { VoucherListUrlSortField } from "@saleor/discounts/urls"; import { VoucherListUrlSortField } from "@saleor/discounts/urls";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { import {
ChannelProps,
FilterPageProps, FilterPageProps,
ListActions, ListActions,
PageListProps, PageListProps,
@ -30,20 +29,10 @@ export interface VoucherListPageProps
ListActions, ListActions,
FilterPageProps<VoucherFilterKeys, VoucherListFilterOpts>, FilterPageProps<VoucherFilterKeys, VoucherListFilterOpts>,
SortPage<VoucherListUrlSortField>, SortPage<VoucherListUrlSortField>,
TabPageProps { TabPageProps,
ChannelProps {
vouchers: VoucherList_vouchers_edges_node[]; vouchers: VoucherList_vouchers_edges_node[];
selectedChannel: string;
onSettingsOpen?: () => void;
} }
const useStyles = makeStyles(
theme => ({
settings: {
marginRight: theme.spacing(2)
}
}),
{ name: "VoucherListPage" }
);
const VoucherListPage: React.FC<VoucherListPageProps> = ({ const VoucherListPage: React.FC<VoucherListPageProps> = ({
currentTab, currentTab,
filterOpts, filterOpts,
@ -52,7 +41,6 @@ const VoucherListPage: React.FC<VoucherListPageProps> = ({
onAll, onAll,
onFilterChange, onFilterChange,
onSearchChange, onSearchChange,
onSettingsOpen,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
onTabSave, onTabSave,
@ -60,26 +48,11 @@ const VoucherListPage: React.FC<VoucherListPageProps> = ({
...listProps ...listProps
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({});
const structure = createFilterStructure(intl, filterOpts); const structure = createFilterStructure(intl, filterOpts);
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.vouchers)}> <PageHeader title={intl.formatMessage(sectionNames.vouchers)}>
{onSettingsOpen && (
<CardMenu
className={classes.settings}
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
}
]}
/>
)}
<Button onClick={onAdd} variant="contained" color="primary"> <Button onClick={onAdd} variant="contained" color="primary">
<FormattedMessage <FormattedMessage
defaultMessage="Create voucher" defaultMessage="Create voucher"

View file

@ -10,6 +10,7 @@ import Money from "@saleor/components/Money";
import Percent from "@saleor/components/Percent"; import Percent from "@saleor/components/Percent";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { ChannelProps } from "@saleor/types";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -18,20 +19,19 @@ import { DiscountValueTypeEnum } from "../../../types/globalTypes";
import { translateVoucherTypes } from "../../translations"; import { translateVoucherTypes } from "../../translations";
import { VoucherDetails_voucher } from "../../types/VoucherDetails"; import { VoucherDetails_voucher } from "../../types/VoucherDetails";
export interface VoucherSummaryProps { export interface VoucherSummaryProps extends ChannelProps {
voucher: VoucherDetails_voucher; voucher: VoucherDetails_voucher;
selectedChannel: string;
} }
const VoucherSummary: React.FC<VoucherSummaryProps> = ({ const VoucherSummary: React.FC<VoucherSummaryProps> = ({
selectedChannel, selectedChannelId,
voucher voucher
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const translatedVoucherTypes = translateVoucherTypes(intl); const translatedVoucherTypes = translateVoucherTypes(intl);
const channel = voucher?.channelListings?.find( const channel = voucher?.channelListings?.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
return ( return (

View file

@ -29,7 +29,7 @@ export enum SaleListUrlFiltersWithMultipleValues {
} }
export type SaleListUrlFilters = Filters<SaleListUrlFiltersEnum> & export type SaleListUrlFilters = Filters<SaleListUrlFiltersEnum> &
FiltersWithMultipleValues<SaleListUrlFiltersWithMultipleValues>; FiltersWithMultipleValues<SaleListUrlFiltersWithMultipleValues>;
export type SaleListUrlDialog = "remove" | "settings" | TabActionDialog; export type SaleListUrlDialog = "remove" | TabActionDialog;
export enum SaleListUrlSortField { export enum SaleListUrlSortField {
name = "name", name = "name",
endDate = "end-date", endDate = "end-date",
@ -79,7 +79,7 @@ export enum VoucherListUrlFiltersWithMultipleValues {
} }
export type VoucherListUrlFilters = Filters<VoucherListUrlFiltersEnum> & export type VoucherListUrlFilters = Filters<VoucherListUrlFiltersEnum> &
FiltersWithMultipleValues<VoucherListUrlFiltersWithMultipleValues>; FiltersWithMultipleValues<VoucherListUrlFiltersWithMultipleValues>;
export type VoucherListUrlDialog = "remove" | "settings" | TabActionDialog; export type VoucherListUrlDialog = "remove" | TabActionDialog;
export enum VoucherListUrlSortField { export enum VoucherListUrlSortField {
code = "code", code = "code",
endDate = "end-date", endDate = "end-date",

View file

@ -279,7 +279,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
...(updateChannelsOpts.data ...(updateChannelsOpts.data
?.saleChannelListingUpdate.errors || []) ?.saleChannelListingUpdate.errors || [])
]} ]}
selectedChannel={selectedChannel} selectedChannelId={selectedChannel}
pageInfo={pageInfo} pageInfo={pageInfo}
openChannelsModal={handleChannelsModalOpen} openChannelsModal={handleChannelsModalOpen}
onChannelsChange={setCurrentChannels} onChannelsChange={setCurrentChannels}

View file

@ -1,15 +1,14 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -64,18 +63,13 @@ export const SaleList: React.FC<SaleListProps> = ({ params }) => {
ListViews.SALES_LIST ListViews.SALES_LIST
); );
const intl = useIntl(); const intl = useIntl();
const { channel } = useAppChannel();
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
SaleListUrlDialog, SaleListUrlDialog,
SaleListUrlQueryParams SaleListUrlQueryParams
>(navigate, saleListUrl, params); >(navigate, saleListUrl, params);
const {
channelChoices,
handleChannelSelectConfirm,
selectedChannel
} = useChannelsSettings("salesListChannel", { closeModal, openModal });
const paginationState = createPaginationState(settings.rowNumber, params); const paginationState = createPaginationState(settings.rowNumber, params);
const queryVariables = React.useMemo( const queryVariables = React.useMemo(
() => ({ () => ({
@ -167,16 +161,6 @@ export const SaleList: React.FC<SaleListProps> = ({ params }) => {
return ( return (
<> <>
<WindowTitle title={intl.formatMessage(sectionNames.sales)} /> <WindowTitle title={intl.formatMessage(sectionNames.sales)} />
{!!channelChoices?.length && (
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
)}
<SaleListPage <SaleListPage
currentTab={currentTab} currentTab={currentTab}
filterOpts={getFilterOpts(params)} filterOpts={getFilterOpts(params)}
@ -215,12 +199,7 @@ export const SaleList: React.FC<SaleListProps> = ({ params }) => {
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
} }
selectedChannel={selectedChannel} selectedChannelId={channel.id}
onSettingsOpen={
!!channelChoices?.length
? () => openModal("settings")
: undefined
}
/> />
<ActionDialog <ActionDialog
confirmButtonState={saleBulkDeleteOpts.status} confirmButtonState={saleBulkDeleteOpts.status}

View file

@ -7,6 +7,7 @@ import {
createSortedChannelsDataFromVoucher createSortedChannelsDataFromVoucher
} from "@saleor/channels/utils"; } from "@saleor/channels/utils";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog"; import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog";
import AssignCollectionDialog from "@saleor/components/AssignCollectionDialog"; import AssignCollectionDialog from "@saleor/components/AssignCollectionDialog";
import AssignProductDialog from "@saleor/components/AssignProductDialog"; import AssignProductDialog from "@saleor/components/AssignProductDialog";
@ -37,7 +38,6 @@ import {
} from "@saleor/discounts/urls"; } from "@saleor/discounts/urls";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannels from "@saleor/hooks/useChannels"; import useChannels from "@saleor/hooks/useChannels";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import usePaginator, { import usePaginator, {
@ -145,8 +145,7 @@ export const VoucherDetails: React.FC<VoucherDetailsProps> = ({
const [updateChannels, updateChannelsOpts] = useVoucherChannelListingUpdate( const [updateChannels, updateChannelsOpts] = useVoucherChannelListingUpdate(
{} {}
); );
const { channel } = useAppChannel();
const [selectedChannel] = useLocalStorage("vouchersListChannel", "");
const handleVoucherDelete = (data: VoucherDelete) => { const handleVoucherDelete = (data: VoucherDelete) => {
if (data.voucherDelete.errors.length === 0) { if (data.voucherDelete.errors.length === 0) {
@ -295,7 +294,7 @@ export const VoucherDetails: React.FC<VoucherDetailsProps> = ({
...(updateChannelsOpts.data ...(updateChannelsOpts.data
?.voucherChannelListingUpdate.errors || []) ?.voucherChannelListingUpdate.errors || [])
]} ]}
selectedChannel={selectedChannel} selectedChannelId={channel.id}
pageInfo={pageInfo} pageInfo={pageInfo}
onNextPage={loadNextPage} onNextPage={loadNextPage}
onPreviousPage={loadPreviousPage} onPreviousPage={loadPreviousPage}

View file

@ -1,15 +1,14 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -65,17 +64,13 @@ export const VoucherList: React.FC<VoucherListProps> = ({ params }) => {
); );
const intl = useIntl(); const intl = useIntl();
const { channel } = useAppChannel();
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
VoucherListUrlDialog, VoucherListUrlDialog,
VoucherListUrlQueryParams VoucherListUrlQueryParams
>(navigate, voucherListUrl, params); >(navigate, voucherListUrl, params);
const {
channelChoices,
handleChannelSelectConfirm,
selectedChannel
} = useChannelsSettings("vouchersListChannel", { closeModal, openModal });
const paginationState = createPaginationState(settings.rowNumber, params); const paginationState = createPaginationState(settings.rowNumber, params);
const queryVariables = React.useMemo( const queryVariables = React.useMemo(
() => ({ () => ({
@ -167,16 +162,6 @@ export const VoucherList: React.FC<VoucherListProps> = ({ params }) => {
return ( return (
<> <>
<WindowTitle title={intl.formatMessage(sectionNames.vouchers)} /> <WindowTitle title={intl.formatMessage(sectionNames.vouchers)} />
{!!channelChoices?.length && (
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
)}
<VoucherListPage <VoucherListPage
currentTab={currentTab} currentTab={currentTab}
filterOpts={getFilterOpts(params)} filterOpts={getFilterOpts(params)}
@ -215,12 +200,7 @@ export const VoucherList: React.FC<VoucherListProps> = ({ params }) => {
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
} }
selectedChannel={selectedChannel} selectedChannelId={channel.id}
onSettingsOpen={
!!channelChoices?.length
? () => openModal("settings")
: undefined
}
/> />
<ActionDialog <ActionDialog
confirmButtonState={voucherBulkDeleteOpts.status} confirmButtonState={voucherBulkDeleteOpts.status}

View file

@ -1,11 +1,8 @@
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";
import SingleSelectField, {
Choices
} from "@saleor/components/SingleSelectField";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage } from "react-intl";
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
@ -27,16 +24,12 @@ const useStyles = makeStyles(
interface HomeOrdersCardProps { interface HomeOrdersCardProps {
userName: string; userName: string;
channelChoices: Choices;
channelValue: string;
onChannelChange: (value: string) => void;
} }
const HomeOrdersCard: React.FC<HomeOrdersCardProps> = props => { const HomeOrdersCard: React.FC<HomeOrdersCardProps> = props => {
const { userName, channelChoices, channelValue, onChannelChange } = props; const { userName } = props;
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl();
return ( return (
<div className={classes.headerContainer} data-test="home-header"> <div className={classes.headerContainer} data-test="home-header">
@ -71,20 +64,6 @@ const HomeOrdersCard: React.FC<HomeOrdersCardProps> = props => {
)} )}
</Typography> </Typography>
</div> </div>
<div>
{!!channelChoices?.length && (
<SingleSelectField
name="channel"
label={intl.formatMessage({
defaultMessage: "Channel"
})}
choices={channelChoices}
value={channelValue}
onChange={e => onChannelChange(e.target.value)}
data-test="channel-select"
/>
)}
</div>
</div> </div>
); );
}; };

View file

@ -4,7 +4,6 @@ import Container from "@saleor/components/Container";
import Grid from "@saleor/components/Grid"; import Grid from "@saleor/components/Grid";
import Money from "@saleor/components/Money"; import Money from "@saleor/components/Money";
import RequirePermissions from "@saleor/components/RequirePermissions"; import RequirePermissions from "@saleor/components/RequirePermissions";
import { Choices } from "@saleor/components/SingleSelectField";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import { UserPermissionProps } from "@saleor/types"; import { UserPermissionProps } from "@saleor/types";
import { PermissionEnum } from "@saleor/types/globalTypes"; import { PermissionEnum } from "@saleor/types/globalTypes";
@ -54,9 +53,6 @@ export interface HomePageProps extends UserPermissionProps {
sales: Home_salesToday_gross; sales: Home_salesToday_gross;
topProducts: Home_productTopToday_edges_node[]; topProducts: Home_productTopToday_edges_node[];
userName: string; userName: string;
channelChoices: Choices;
channelValue: string;
onChannelChange: (value: string) => void;
onOrdersToCaptureClick: () => void; onOrdersToCaptureClick: () => void;
onOrdersToFulfillClick: () => void; onOrdersToFulfillClick: () => void;
onProductClick: (productId: string, variantId: string) => void; onProductClick: (productId: string, variantId: string) => void;
@ -65,8 +61,6 @@ export interface HomePageProps extends UserPermissionProps {
const HomePage: React.FC<HomePageProps> = props => { const HomePage: React.FC<HomePageProps> = props => {
const { const {
channelChoices,
channelValue,
userName, userName,
orders, orders,
sales, sales,
@ -78,7 +72,6 @@ const HomePage: React.FC<HomePageProps> = props => {
onProductsOutOfStockClick, onProductsOutOfStockClick,
ordersToCapture, ordersToCapture,
ordersToFulfill, ordersToFulfill,
onChannelChange,
productsOutOfStock, productsOutOfStock,
userPermissions userPermissions
} = props; } = props;
@ -87,12 +80,7 @@ const HomePage: React.FC<HomePageProps> = props => {
return ( return (
<Container> <Container>
<HomeHeader <HomeHeader userName={userName} />
userName={userName}
channelValue={channelValue}
channelChoices={channelChoices}
onChannelChange={onChannelChange}
/>
<CardSpacer /> <CardSpacer />
<Grid> <Grid>
<div> <div>

View file

@ -1,8 +1,7 @@
import { useChannelsList } from "@saleor/channels/queries"; import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useUser from "@saleor/hooks/useUser"; import useUser from "@saleor/hooks/useUser";
import React, { useCallback, useEffect } from "react"; import React from "react";
import { getUserName, maybe } from "../../misc"; import { getUserName, maybe } from "../../misc";
import { orderListUrl } from "../../orders/urls"; import { orderListUrl } from "../../orders/urls";
@ -14,29 +13,10 @@ import { HomePageQuery } from "../queries";
const HomeSection = () => { const HomeSection = () => {
const navigate = useNavigator(); const navigate = useNavigator();
const { user } = useUser(); const { user } = useUser();
const { data: channelsData } = useChannelsList({}); const { channel } = useAppChannel();
const channelChoices =
channelsData?.channels?.map(channel => ({
label: channel.name,
value: channel.slug
})) || [];
const [channelChoice, setChannelChoice] = useLocalStorage(
"homepageChannelChoice",
channelChoices?.length ? channelChoices[0]?.value : ""
);
useEffect(() => {
if (!channelChoice && channelChoices[0]) {
setChannelChoice(channelChoices[0].value);
}
}, [channelChoices]);
const handleChannelChange = useCallback(value => setChannelChoice(value), []);
return ( return (
<HomePageQuery displayLoader variables={{ channel: channelChoice }}> <HomePageQuery displayLoader variables={{ channel: channel.slug }}>
{({ data }) => ( {({ data }) => (
<HomePage <HomePage
activities={maybe(() => activities={maybe(() =>
@ -47,9 +27,6 @@ const HomeSection = () => {
topProducts={maybe(() => topProducts={maybe(() =>
data.productTopToday.edges.map(edge => edge.node) data.productTopToday.edges.map(edge => edge.node)
)} )}
channelChoices={channelChoices}
channelValue={channelChoice}
onChannelChange={handleChannelChange}
onProductClick={(productId, variantId) => onProductClick={(productId, variantId) =>
navigate(productVariantEditUrl(productId, variantId)) navigate(productVariantEditUrl(productId, variantId))
} }

View file

@ -1,44 +0,0 @@
import { useChannelsList } from "@saleor/channels/queries";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import { useEffect } from "react";
interface Actions {
openModal: (value: string) => void;
closeModal: () => void;
}
function useChannelsSettings(key: string, { openModal, closeModal }: Actions) {
const { data: channelsData } = useChannelsList({});
const channelChoices = channelsData?.channels?.map(channel => ({
label: channel.name,
value: channel.id
}));
const [selectedChannel, setSelectedChannel] = useLocalStorage(key, "");
const handleChannelSelectConfirm = (channel: string) => {
setSelectedChannel(channel);
closeModal();
};
useEffect(() => {
if (!selectedChannel) {
openModal("settings");
}
}, [selectedChannel]);
const channel = channelsData?.channels?.find(
channel => channel.id === selectedChannel
);
return {
channel,
channelChoices,
channels: channelsData?.channels,
handleChannelSelectConfirm,
selectedChannel,
slug: channel?.slug
};
}
export default useChannelsSettings;

View file

@ -7,14 +7,26 @@ export default function useLocalStorage<T>(
initialValue: T initialValue: T
): [T, SetLocalStorage<T>] { ): [T, SetLocalStorage<T>] {
const [storedValue, setStoredValue] = useState<T>(() => { const [storedValue, setStoredValue] = useState<T>(() => {
const item = window.localStorage.getItem(key); let result: T;
return item ? JSON.parse(item) : initialValue; try {
const item = window.localStorage.getItem(key);
result = item ? JSON.parse(item) : initialValue;
} catch {
result = initialValue;
}
return result;
}); });
const setValue = (value: SetLocalStorageValue<T>) => { const setValue = (value: SetLocalStorageValue<T>) => {
const valueToStore = value instanceof Function ? value(storedValue) : value; const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore); setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
try {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch {
console.warn(`Could not save ${key} to localStorage`);
}
}; };
return [storedValue, setValue]; return [storedValue, setValue];

View file

@ -27,6 +27,9 @@ import ChannelsSection from "./channels";
import { channelsSection } from "./channels/urls"; import { channelsSection } from "./channels/urls";
import CollectionSection from "./collections"; import CollectionSection from "./collections";
import AppLayout from "./components/AppLayout"; import AppLayout from "./components/AppLayout";
import useAppChannel, {
AppChannelProvider
} from "./components/AppLayout/AppChannelContext";
import { DateProvider } from "./components/Date"; import { DateProvider } from "./components/Date";
import { LocaleProvider } from "./components/Locale"; import { LocaleProvider } from "./components/Locale";
import MessageManagerProvider from "./components/messages"; import MessageManagerProvider from "./components/messages";
@ -60,7 +63,7 @@ import { PermissionEnum } from "./types/globalTypes";
import WarehouseSection from "./warehouses"; import WarehouseSection from "./warehouses";
import { warehouseSection } from "./warehouses/urls"; import { warehouseSection } from "./warehouses/urls";
if (process.env.GTM_ID !== undefined) { if (process.env.GTM_ID) {
TagManager.initialize({ gtmId: GTM_ID }); TagManager.initialize({ gtmId: GTM_ID });
} }
@ -111,7 +114,9 @@ const App: React.FC = () => {
<AppStateProvider> <AppStateProvider>
<ShopProvider> <ShopProvider>
<AuthProvider> <AuthProvider>
<Routes /> <AppChannelProvider>
<Routes />
</AppChannelProvider>
</AuthProvider> </AuthProvider>
</ShopProvider> </ShopProvider>
</AppStateProvider> </AppStateProvider>
@ -135,11 +140,15 @@ const Routes: React.FC = () => {
tokenVerifyLoading, tokenVerifyLoading,
user user
} = useAuth(); } = useAuth();
const { channel } = useAppChannel(false);
return ( return (
<> <>
<WindowTitle title={intl.formatMessage(commonMessages.dashboard)} /> <WindowTitle title={intl.formatMessage(commonMessages.dashboard)} />
{isAuthenticated && !tokenAuthLoading && !tokenVerifyLoading ? ( {channel &&
isAuthenticated &&
!tokenAuthLoading &&
!tokenVerifyLoading ? (
<AppLayout> <AppLayout>
<ErrorBoundary <ErrorBoundary
onError={() => onError={() =>
@ -271,7 +280,7 @@ const Routes: React.FC = () => {
</Switch> </Switch>
</ErrorBoundary> </ErrorBoundary>
</AppLayout> </AppLayout>
) : hasToken && tokenVerifyLoading ? ( ) : (isAuthenticated && !channel) || (hasToken && tokenVerifyLoading) ? (
<LoginLoading /> <LoginLoading />
) : ( ) : (
<Auth /> <Auth />

View file

@ -1,7 +1,5 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import makeStyles from "@material-ui/core/styles/makeStyles";
import CardMenu from "@saleor/components/CardMenu";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import FilterBar from "@saleor/components/FilterBar"; import FilterBar from "@saleor/components/FilterBar";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
@ -32,18 +30,8 @@ export interface OrderDraftListPageProps
SortPage<OrderDraftListUrlSortField>, SortPage<OrderDraftListUrlSortField>,
TabPageProps { TabPageProps {
orders: OrderDraftList_draftOrders_edges_node[]; orders: OrderDraftList_draftOrders_edges_node[];
onSettingsOpen?: () => void;
} }
const useStyles = makeStyles(
theme => ({
settings: {
marginRight: theme.spacing(2)
}
}),
{ name: "OrderDraftListPage" }
);
const OrderDraftListPage: React.FC<OrderDraftListPageProps> = ({ const OrderDraftListPage: React.FC<OrderDraftListPageProps> = ({
currentTab, currentTab,
disabled, disabled,
@ -53,7 +41,6 @@ const OrderDraftListPage: React.FC<OrderDraftListPageProps> = ({
onAll, onAll,
onFilterChange, onFilterChange,
onSearchChange, onSearchChange,
onSettingsOpen,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
onTabSave, onTabSave,
@ -61,26 +48,11 @@ const OrderDraftListPage: React.FC<OrderDraftListPageProps> = ({
...listProps ...listProps
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({});
const structure = createFilterStructure(intl, filterOpts); const structure = createFilterStructure(intl, filterOpts);
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.draftOrders)}> <PageHeader title={intl.formatMessage(sectionNames.draftOrders)}>
{!!onSettingsOpen && (
<CardMenu
className={classes.settings}
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
}
]}
/>
)}
<Button <Button
color="primary" color="primary"
variant="contained" variant="contained"

View file

@ -1,7 +1,5 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import makeStyles from "@material-ui/core/styles/makeStyles";
import CardMenu from "@saleor/components/CardMenu";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import FilterBar from "@saleor/components/FilterBar"; import FilterBar from "@saleor/components/FilterBar";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
@ -24,18 +22,8 @@ export interface OrderListPageProps
FilterPageProps<OrderFilterKeys, OrderListFilterOpts>, FilterPageProps<OrderFilterKeys, OrderListFilterOpts>,
SortPage<OrderListUrlSortField> { SortPage<OrderListUrlSortField> {
orders: OrderList_orders_edges_node[]; orders: OrderList_orders_edges_node[];
onSettingsOpen?: () => void;
} }
const useStyles = makeStyles(
theme => ({
settings: {
marginRight: theme.spacing(2)
}
}),
{ name: "OrderListPage" }
);
const OrderListPage: React.FC<OrderListPageProps> = ({ const OrderListPage: React.FC<OrderListPageProps> = ({
currentTab, currentTab,
initialSearch, initialSearch,
@ -44,7 +32,6 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
onAdd, onAdd,
onAll, onAll,
onSearchChange, onSearchChange,
onSettingsOpen,
onFilterChange, onFilterChange,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
@ -52,26 +39,11 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
...listProps ...listProps
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({});
const filterStructure = createFilterStructure(intl, filterOpts); const filterStructure = createFilterStructure(intl, filterOpts);
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.orders)}> <PageHeader title={intl.formatMessage(sectionNames.orders)}>
{!!onSettingsOpen && (
<CardMenu
className={classes.settings}
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
}
]}
/>
)}
<Button color="primary" variant="contained" onClick={onAdd}> <Button color="primary" variant="contained" onClick={onAdd}>
<FormattedMessage <FormattedMessage
defaultMessage="Create order" defaultMessage="Create order"

View file

@ -24,7 +24,7 @@ import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen";
import useSearchQuery from "@saleor/hooks/useSearchQuery"; import useSearchQuery from "@saleor/hooks/useSearchQuery";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { FetchMoreProps } from "@saleor/types"; import { ChannelProps, FetchMoreProps } from "@saleor/types";
import getOrderErrorMessage from "@saleor/utils/errors/order"; import getOrderErrorMessage from "@saleor/utils/errors/order";
import React from "react"; import React from "react";
import InfiniteScroll from "react-infinite-scroller"; import InfiniteScroll from "react-infinite-scroller";
@ -87,12 +87,13 @@ type SetVariantsAction = (
data: SearchOrderVariant_search_edges_node_variants[] data: SearchOrderVariant_search_edges_node_variants[]
) => void; ) => void;
export interface OrderProductAddDialogProps extends FetchMoreProps { export interface OrderProductAddDialogProps
extends FetchMoreProps,
ChannelProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[]; errors: OrderErrorFragment[];
open: boolean; open: boolean;
products: SearchOrderVariant_search_edges_node[]; products: SearchOrderVariant_search_edges_node[];
selectedChannel: string;
onClose: () => void; onClose: () => void;
onFetch: (query: string) => void; onFetch: (query: string) => void;
onSubmit: (data: SearchOrderVariant_search_edges_node_variants[]) => void; onSubmit: (data: SearchOrderVariant_search_edges_node_variants[]) => void;
@ -169,7 +170,7 @@ const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
loading, loading,
hasMore, hasMore,
products, products,
selectedChannel, selectedChannelId,
onFetch, onFetch,
onFetchMore, onFetchMore,
onClose, onClose,
@ -257,7 +258,7 @@ const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
(product, productIndex) => (product, productIndex) =>
product.variants.some(variant => product.variants.some(variant =>
variant.channelListings.some( variant.channelListings.some(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
) )
) ? ( ) ? (
<React.Fragment key={product ? product.id : "skeleton"}> <React.Fragment key={product ? product.id : "skeleton"}>
@ -293,7 +294,7 @@ const OrderProductAddDialog: React.FC<OrderProductAddDialogProps> = props => {
{maybe(() => product.variants, []).map( {maybe(() => product.variants, []).map(
(variant, variantIndex) => (variant, variantIndex) =>
variant.channelListings.some( variant.channelListings.some(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
) ? ( ) ? (
<TableRow key={variant.id}> <TableRow key={variant.id}>
<TableCell /> <TableCell />

View file

@ -31,7 +31,10 @@ import {
OrderDraftCancel, OrderDraftCancel,
OrderDraftCancelVariables OrderDraftCancelVariables
} from "./types/OrderDraftCancel"; } from "./types/OrderDraftCancel";
import { OrderDraftCreate } from "./types/OrderDraftCreate"; import {
OrderDraftCreate,
OrderDraftCreateVariables
} from "./types/OrderDraftCreate";
import { import {
OrderDraftFinalize, OrderDraftFinalize,
OrderDraftFinalizeVariables OrderDraftFinalizeVariables
@ -371,9 +374,10 @@ const orderDraftCreateMutation = gql`
} }
} }
`; `;
export const useOrderDraftCreateMutation = makeMutation<OrderDraftCreate, {}>( export const useOrderDraftCreateMutation = makeMutation<
orderDraftCreateMutation OrderDraftCreate,
); OrderDraftCreateVariables
>(orderDraftCreateMutation);
const orderLineDeleteMutation = gql` const orderLineDeleteMutation = gql`
${fragmentOrderDetails} ${fragmentOrderDetails}

View file

@ -28,7 +28,7 @@ export enum OrderListUrlFiltersWithMultipleValuesEnum {
} }
export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> & export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> &
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>; FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>;
export type OrderListUrlDialog = "cancel" | "settings" | TabActionDialog; export type OrderListUrlDialog = "cancel" | TabActionDialog;
export enum OrderListUrlSortField { export enum OrderListUrlSortField {
number = "number", number = "number",
customer = "customer", customer = "customer",
@ -61,7 +61,7 @@ export enum OrderDraftListUrlFiltersEnum {
query = "query" query = "query"
} }
export type OrderDraftListUrlFilters = Filters<OrderDraftListUrlFiltersEnum>; export type OrderDraftListUrlFilters = Filters<OrderDraftListUrlFiltersEnum>;
export type OrderDraftListUrlDialog = "remove" | "settings" | TabActionDialog; export type OrderDraftListUrlDialog = "remove" | TabActionDialog;
export enum OrderDraftListUrlSortField { export enum OrderDraftListUrlSortField {
number = "number", number = "number",
customer = "customer", customer = "customer",

View file

@ -561,7 +561,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
products={variantSearchOpts.data?.search.edges.map( products={variantSearchOpts.data?.search.edges.map(
edge => edge.node edge => edge.node
)} )}
selectedChannel={order?.channel?.id} selectedChannelId={order?.channel?.id}
onClose={closeModal} onClose={closeModal}
onFetch={variantSearch} onFetch={variantSearch}
onFetchMore={loadMore} onFetchMore={loadMore}

View file

@ -1,14 +1,13 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -80,6 +79,8 @@ export const OrderDraftList: React.FC<OrderDraftListProps> = ({ params }) => {
onCompleted: handleCreateOrderCreateSuccess onCompleted: handleCreateOrderCreateSuccess
}); });
const { channel } = useAppChannel();
const tabs = getFilterTabs(); const tabs = getFilterTabs();
const currentTab = const currentTab =
@ -106,12 +107,6 @@ export const OrderDraftList: React.FC<OrderDraftListProps> = ({ params }) => {
OrderDraftListUrlQueryParams OrderDraftListUrlQueryParams
>(navigate, orderDraftListUrl, params); >(navigate, orderDraftListUrl, params);
const {
channelChoices,
handleChannelSelectConfirm,
selectedChannel
} = useChannelsSettings("ordersDraftListChannel", { closeModal, openModal });
const handleTabChange = (tab: number) => { const handleTabChange = (tab: number) => {
reset(); reset();
navigate( navigate(
@ -171,16 +166,6 @@ export const OrderDraftList: React.FC<OrderDraftListProps> = ({ params }) => {
return ( return (
<> <>
{!!channelChoices?.length && (
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
)}
<TypedOrderDraftBulkCancelMutation <TypedOrderDraftBulkCancelMutation
onCompleted={handleOrderDraftBulkCancel} onCompleted={handleOrderDraftBulkCancel}
> >
@ -214,7 +199,7 @@ export const OrderDraftList: React.FC<OrderDraftListProps> = ({ params }) => {
onAdd={() => onAdd={() =>
createOrder({ createOrder({
variables: { variables: {
input: { channel: selectedChannel } input: { channel: channel.id }
} }
}) })
} }
@ -240,11 +225,6 @@ export const OrderDraftList: React.FC<OrderDraftListProps> = ({ params }) => {
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
} }
onSettingsOpen={
!!channelChoices?.length
? () => openModal("settings")
: undefined
}
/> />
<ActionDialog <ActionDialog
confirmButtonState={orderDraftBulkDeleteOpts.status} confirmButtonState={orderDraftBulkDeleteOpts.status}

View file

@ -1,9 +1,8 @@
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog"; import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -68,6 +67,8 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
onCompleted: handleCreateOrderCreateSuccess onCompleted: handleCreateOrderCreateSuccess
}); });
const { channel } = useAppChannel();
const tabs = getFilterTabs(); const tabs = getFilterTabs();
const currentTab = const currentTab =
@ -93,12 +94,6 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
OrderListUrlQueryParams OrderListUrlQueryParams
>(navigate, orderListUrl, params); >(navigate, orderListUrl, params);
const {
channelChoices,
handleChannelSelectConfirm,
selectedChannel
} = useChannelsSettings("ordersListChannel", { closeModal, openModal });
const handleTabChange = (tab: number) => const handleTabChange = (tab: number) =>
navigate( navigate(
orderListUrl({ orderListUrl({
@ -142,16 +137,6 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
return ( return (
<> <>
{!!channelChoices?.length && (
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
)}
<OrderListPage <OrderListPage
settings={settings} settings={settings}
currentTab={currentTab} currentTab={currentTab}
@ -163,7 +148,7 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
onAdd={() => onAdd={() =>
createOrder({ createOrder({
variables: { variables: {
input: { channel: selectedChannel } input: { channel: channel.id }
} }
}) })
} }
@ -180,9 +165,6 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
initialSearch={params.query || ""} initialSearch={params.query || ""}
tabs={getFilterTabs().map(tab => tab.name)} tabs={getFilterTabs().map(tab => tab.name)}
onAll={resetFilters} onAll={resetFilters}
onSettingsOpen={
!!channelChoices?.length ? () => openModal("settings") : undefined
}
/> />
<SaveFilterTabDialog <SaveFilterTabDialog
open={params.action === "save-search"} open={params.action === "save-search"}

View file

@ -24,7 +24,7 @@ import {
import { GridAttributes_grid_edges_node } from "@saleor/products/types/GridAttributes"; import { GridAttributes_grid_edges_node } from "@saleor/products/types/GridAttributes";
import { ProductList_products_edges_node } from "@saleor/products/types/ProductList"; import { ProductList_products_edges_node } from "@saleor/products/types/ProductList";
import { ProductListUrlSortField } from "@saleor/products/urls"; import { ProductListUrlSortField } from "@saleor/products/urls";
import { ListActions, ListProps, SortPage } from "@saleor/types"; import { ChannelProps, ListActions, ListProps, SortPage } from "@saleor/types";
import TDisplayColumn, { import TDisplayColumn, {
DisplayColumnProps DisplayColumnProps
} from "@saleor/utils/columns/DisplayColumn"; } from "@saleor/utils/columns/DisplayColumn";
@ -99,12 +99,12 @@ const DisplayColumn = TDisplayColumn as React.FunctionComponent<
interface ProductListProps interface ProductListProps
extends ListProps<ProductListColumns>, extends ListProps<ProductListColumns>,
ListActions, ListActions,
SortPage<ProductListUrlSortField> { SortPage<ProductListUrlSortField>,
ChannelProps {
activeAttributeSortId: string; activeAttributeSortId: string;
gridAttributes: GridAttributes_grid_edges_node[]; gridAttributes: GridAttributes_grid_edges_node[];
products: ProductList_products_edges_node[]; products: ProductList_products_edges_node[];
loading: boolean; loading: boolean;
selectedChannel: string;
channelsCount: number; channelsCount: number;
} }
@ -128,7 +128,7 @@ export const ProductList: React.FC<ProductListProps> = props => {
onUpdateListSettings, onUpdateListSettings,
onRowClick, onRowClick,
onSort, onSort,
selectedChannel selectedChannelId
} = props; } = props;
const classes = useStyles(props); const classes = useStyles(props);
@ -286,7 +286,7 @@ export const ProductList: React.FC<ProductListProps> = props => {
product => { product => {
const isSelected = product ? isChecked(product.id) : false; const isSelected = product ? isChecked(product.id) : false;
const channel = product?.channelListings.find( const channel = product?.channelListings.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
return ( return (
@ -362,9 +362,7 @@ export const ProductList: React.FC<ProductListProps> = props => {
) : product?.channelListings !== undefined ? ( ) : product?.channelListings !== undefined ? (
<ChannelsAvailabilityDropdown <ChannelsAvailabilityDropdown
allChannelsCount={channelsCount} allChannelsCount={channelsCount}
currentChannel={ currentChannel={channel}
channel || product?.channelListings[0]
}
channels={product?.channelListings} channels={product?.channelListings}
/> />
) : ( ) : (

View file

@ -16,6 +16,7 @@ import {
} from "@saleor/products/types/GridAttributes"; } from "@saleor/products/types/GridAttributes";
import { ProductList_products_edges_node } from "@saleor/products/types/ProductList"; import { ProductList_products_edges_node } from "@saleor/products/types/ProductList";
import { import {
ChannelProps,
FetchMoreProps, FetchMoreProps,
FilterPageProps, FilterPageProps,
ListActions, ListActions,
@ -38,7 +39,8 @@ export interface ProductListPageProps
ListActions, ListActions,
FilterPageProps<ProductFilterKeys, ProductListFilterOpts>, FilterPageProps<ProductFilterKeys, ProductListFilterOpts>,
FetchMoreProps, FetchMoreProps,
SortPage<ProductListUrlSortField> { SortPage<ProductListUrlSortField>,
ChannelProps {
activeAttributeSortId: string; activeAttributeSortId: string;
availableInGridAttributes: GridAttributes_availableInGrid_edges_node[]; availableInGridAttributes: GridAttributes_availableInGrid_edges_node[];
channelsCount: number; channelsCount: number;
@ -47,8 +49,6 @@ export interface ProductListPageProps
totalGridAttributes: number; totalGridAttributes: number;
products: ProductList_products_edges_node[]; products: ProductList_products_edges_node[];
onExport: () => void; onExport: () => void;
selectedChannel: string;
onSettingsOpen?: () => void;
} }
const useStyles = makeStyles( const useStyles = makeStyles(
@ -84,12 +84,11 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
onFetchMore, onFetchMore,
onFilterChange, onFilterChange,
onSearchChange, onSearchChange,
onSettingsOpen,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
onTabSave, onTabSave,
onUpdateListSettings, onUpdateListSettings,
selectedChannel, selectedChannelId,
...listProps ...listProps
} = props; } = props;
const intl = useIntl(); const intl = useIntl();
@ -134,13 +133,6 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
}), }),
onSelect: onExport, onSelect: onExport,
testId: "export" testId: "export"
},
onSettingsOpen && {
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
} }
]} ]}
data-test="menu" data-test="menu"
@ -199,7 +191,7 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
gridAttributes={gridAttributes} gridAttributes={gridAttributes}
settings={settings} settings={settings}
channelsCount={channelsCount} channelsCount={channelsCount}
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
onUpdateListSettings={onUpdateListSettings} onUpdateListSettings={onUpdateListSettings}
/> />
</Card> </Card>

View file

@ -58,6 +58,7 @@ const props: ProductUpdatePageProps = {
placeholderImage, placeholderImage,
product, product,
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannelId: "123",
taxTypes, taxTypes,
variants: product.variants, variants: product.variants,
warehouses: warehouseList warehouses: warehouseList

View file

@ -22,7 +22,12 @@ import { maybe } from "@saleor/misc";
import ProductVariantPrice from "@saleor/products/components/ProductVariantPrice"; import ProductVariantPrice from "@saleor/products/components/ProductVariantPrice";
import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories"; import { SearchCategories_search_edges_node } from "@saleor/searches/types/SearchCategories";
import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections"; import { SearchCollections_search_edges_node } from "@saleor/searches/types/SearchCollections";
import { FetchMoreProps, ListActions, ReorderAction } from "@saleor/types"; import {
ChannelProps,
FetchMoreProps,
ListActions,
ReorderAction
} from "@saleor/types";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -42,7 +47,7 @@ import ProductTaxes from "../ProductTaxes";
import ProductVariants from "../ProductVariants"; import ProductVariants from "../ProductVariants";
import ProductUpdateForm from "./form"; import ProductUpdateForm from "./form";
export interface ProductUpdatePageProps extends ListActions { export interface ProductUpdatePageProps extends ListActions, ChannelProps {
defaultWeightUnit: string; defaultWeightUnit: string;
errors: ProductErrorWithAttributesFragment[]; errors: ProductErrorWithAttributesFragment[];
channelsErrors: ProductChannelListingErrorFragment[]; channelsErrors: ProductChannelListingErrorFragment[];
@ -83,7 +88,9 @@ export interface ProductUpdatePageProps extends ListActions {
onWarehouseConfigure(); onWarehouseConfigure();
} }
export interface ProductUpdatePageSubmitData extends ProductUpdatePageFormData { export interface ProductUpdatePageSubmitData
extends ProductUpdatePageFormData,
ChannelProps {
addStocks: ProductStockInput[]; addStocks: ProductStockInput[];
attributes: ProductAttributeInput[]; attributes: ProductAttributeInput[];
collections: string[]; collections: string[];
@ -96,7 +103,6 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
defaultWeightUnit, defaultWeightUnit,
disabled, disabled,
categories: categoryChoiceList, categories: categoryChoiceList,
channelChoices,
channelsErrors, channelsErrors,
allChannelsCount, allChannelsCount,
currentChannels = [], currentChannels = [],
@ -133,6 +139,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
onWarehouseConfigure, onWarehouseConfigure,
isChecked, isChecked,
selected, selected,
selectedChannelId,
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
@ -235,7 +242,6 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
disabled={disabled} disabled={disabled}
variants={variants} variants={variants}
product={product} product={product}
channelChoices={channelChoices}
onRowClick={onVariantShow} onRowClick={onVariantShow}
onVariantAdd={onVariantAdd} onVariantAdd={onVariantAdd}
onVariantsAdd={onVariantsAdd} onVariantsAdd={onVariantsAdd}
@ -244,6 +250,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
toolbar={toolbar} toolbar={toolbar}
isChecked={isChecked} isChecked={isChecked}
selected={selected} selected={selected}
selectedChannelId={selectedChannelId}
toggle={toggle} toggle={toggle}
toggleAll={toggleAll} toggleAll={toggleAll}
/> />

View file

@ -7,7 +7,6 @@ import { fade } from "@material-ui/core/styles/colorManipulator";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import { ChannelsSelect } from "@saleor/components/ChannelsSelect";
import Checkbox from "@saleor/components/Checkbox"; import Checkbox from "@saleor/components/Checkbox";
import LinkChoice from "@saleor/components/LinkChoice"; import LinkChoice from "@saleor/components/LinkChoice";
import Money from "@saleor/components/Money"; import Money from "@saleor/components/Money";
@ -19,12 +18,11 @@ import {
SortableTableRow SortableTableRow
} from "@saleor/components/SortableTable"; } from "@saleor/components/SortableTable";
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import useStateFromProps from "@saleor/hooks/useStateFromProps";
import React from "react"; import React from "react";
import { FormattedMessage, IntlShape, useIntl } from "react-intl"; import { FormattedMessage, IntlShape, useIntl } from "react-intl";
import { maybe, renderCollection } from "../../../misc"; import { maybe, renderCollection } from "../../../misc";
import { ListActions, ReorderAction } from "../../../types"; import { ChannelProps, ListActions, ReorderAction } from "../../../types";
import { import {
ProductDetails_product, ProductDetails_product,
ProductDetails_product_variants, ProductDetails_product_variants,
@ -84,9 +82,6 @@ const useStyles = makeStyles(
width: 200 width: 200
} }
}, },
channelSelect: {
marginRight: theme.spacing(1)
},
colGrab: { colGrab: {
width: 60 width: 60
}, },
@ -183,12 +178,11 @@ function getAvailabilityLabel(
} }
} }
interface ProductVariantsProps extends ListActions { interface ProductVariantsProps extends ListActions, ChannelProps {
disabled: boolean; disabled: boolean;
product: ProductDetails_product; product: ProductDetails_product;
variants: ProductDetails_product_variants[]; variants: ProductDetails_product_variants[];
onVariantReorder: ReorderAction; onVariantReorder: ReorderAction;
channelChoices: SingleAutocompleteChoiceType[];
onRowClick: (id: string) => () => void; onRowClick: (id: string) => () => void;
onSetDefaultVariant(variant: ProductDetails_product_variants); onSetDefaultVariant(variant: ProductDetails_product_variants);
onVariantAdd?(); onVariantAdd?();
@ -199,7 +193,6 @@ const numberOfColumns = 7;
export const ProductVariants: React.FC<ProductVariantsProps> = props => { export const ProductVariants: React.FC<ProductVariantsProps> = props => {
const { const {
channelChoices,
disabled, disabled,
variants, variants,
product, product,
@ -210,6 +203,7 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
onSetDefaultVariant, onSetDefaultVariant,
isChecked, isChecked,
selected, selected,
selectedChannelId,
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
@ -218,9 +212,6 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
const intl = useIntl(); const intl = useIntl();
const [warehouse, setWarehouse] = React.useState<string>(null); const [warehouse, setWarehouse] = React.useState<string>(null);
const [channelChoice, setChannelChoice] = useStateFromProps(
channelChoices[0]?.value
);
const hasVariants = maybe(() => variants.length > 0, true); const hasVariants = maybe(() => variants.length > 0, true);
return ( return (
@ -261,11 +252,6 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
{variants.length > 0 ? ( {variants.length > 0 ? (
<CardContent className={classes.warehouseSelectContainer}> <CardContent className={classes.warehouseSelectContainer}>
<ChannelsSelect
channelChoice={channelChoice}
channelChoices={channelChoices}
setChannelChoice={setChannelChoice}
/>
<Typography className={classes.warehouseLabel}> <Typography className={classes.warehouseLabel}>
<FormattedMessage <FormattedMessage
defaultMessage="Available inventory at:" defaultMessage="Available inventory at:"
@ -345,7 +331,7 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
) )
: null; : null;
const channel = variant.channelListings.find( const channel = variant.channelListings.find(
listing => listing.channel.id === channelChoice listing => listing.channel.id === selectedChannelId
); );
return ( return (

View file

@ -19,11 +19,7 @@ export const productAddPath = urlJoin(productSection, "add");
export const productAddUrl = productAddPath; export const productAddUrl = productAddPath;
export const productListPath = productSection; export const productListPath = productSection;
export type ProductListUrlDialog = export type ProductListUrlDialog = "delete" | "export" | TabActionDialog;
| "settings"
| "delete"
| "export"
| TabActionDialog;
export enum ProductListUrlFiltersEnum { export enum ProductListUrlFiltersEnum {
priceFrom = "priceFrom", priceFrom = "priceFrom",
priceTo = "priceTo", priceTo = "priceTo",

View file

@ -1,8 +1,8 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
@ -16,7 +16,6 @@ import {
import { Task } from "@saleor/containers/BackgroundTasks/types"; import { Task } from "@saleor/containers/BackgroundTasks/types";
import useBackgroundTask from "@saleor/hooks/useBackgroundTask"; import useBackgroundTask from "@saleor/hooks/useBackgroundTask";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -126,33 +125,25 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
first: 100 first: 100
} }
}); });
const { availableChannels, channel } = useAppChannel();
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
ProductListUrlDialog, ProductListUrlDialog,
ProductListUrlQueryParams ProductListUrlQueryParams
>(navigate, productListUrl, params); >(navigate, productListUrl, params);
const { // Reset pagination
channel, React.useEffect(
channels, () =>
channelChoices, navigate(
handleChannelSelectConfirm, productListUrl({
selectedChannel, ...params,
slug ...DEFAULT_INITIAL_PAGINATION_DATA
} = useChannelsSettings("productsListChannel", { closeModal, openModal }); }),
true
React.useEffect(() => { ),
const action = selectedChannel [settings.rowNumber]
? {} );
: { action: "settings" as ProductListUrlDialog };
navigate(
productListUrl({
...{ ...params, ...action },
...DEFAULT_INITIAL_PAGINATION_DATA
}),
true
);
}, [settings.rowNumber]);
const tabs = getFilterTabs(); const tabs = getFilterTabs();
@ -231,13 +222,13 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
); );
const paginationState = createPaginationState(settings.rowNumber, params); const paginationState = createPaginationState(settings.rowNumber, params);
const filter = getFilterVariables(params, slug); const filter = getFilterVariables(params, channel.slug);
const sort = getSortQueryVariables(params, slug); const sort = getSortQueryVariables(params, channel.slug);
const queryVariables = React.useMemo<ProductListVariables>( const queryVariables = React.useMemo<ProductListVariables>(
() => ({ () => ({
...paginationState, ...paginationState,
filter, filter,
...(slug ? { sort } : {}) sort
}), }),
[params, settings.rowNumber] [params, settings.rowNumber]
); );
@ -388,22 +379,9 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
initialSearch={params.query || ""} initialSearch={params.query || ""}
tabs={getFilterTabs().map(tab => tab.name)} tabs={getFilterTabs().map(tab => tab.name)}
onExport={() => openModal("export")} onExport={() => openModal("export")}
channelsCount={channelChoices?.length} channelsCount={availableChannels?.length}
selectedChannel={selectedChannel} selectedChannelId={channel.id}
onSettingsOpen={
!!channelChoices?.length ? () => openModal("settings") : undefined
}
/> />
{!!channelChoices?.length && (
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
)}
<ActionDialog <ActionDialog
open={params.action === "delete"} open={params.action === "delete"}
confirmButtonState={productBulkDeleteOpts.status} confirmButtonState={productBulkDeleteOpts.status}
@ -449,7 +427,7 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
warehouses={ warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || [] warehouses.data?.warehouses.edges.map(edge => edge.node) || []
} }
channels={channels} channels={availableChannels}
onClose={closeModal} onClose={closeModal}
onSubmit={data => onSubmit={data =>
exportProducts({ exportProducts({

View file

@ -9,6 +9,7 @@ import {
createSortedChannelsDataFromProduct createSortedChannelsDataFromProduct
} from "@saleor/channels/utils"; } from "@saleor/channels/utils";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog"; import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog";
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
@ -114,6 +115,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
displayLoader: true, displayLoader: true,
variables: { id } variables: { id }
}); });
const { channel } = useAppChannel();
const handleUpdate = (data: ProductUpdateMutationResult) => { const handleUpdate = (data: ProductUpdateMutationResult) => {
if (data.productUpdate.errors.length === 0) { if (data.productUpdate.errors.length === 0) {
@ -404,6 +406,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
loading: searchCollectionsOpts.loading, loading: searchCollectionsOpts.loading,
onFetchMore: loadMoreCollections onFetchMore: loadMoreCollections
}} }}
selectedChannelId={channel.id}
openChannelsModal={handleChannelsModalOpen} openChannelsModal={handleChannelsModalOpen}
onChannelsChange={setCurrentChannels} onChannelsChange={setCurrentChannels}
/> />

View file

@ -21,7 +21,7 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { getStringOrPlaceholder } from "../../../misc"; import { getStringOrPlaceholder } from "../../../misc";
import { FetchMoreProps, SearchProps } from "../../../types"; import { ChannelProps, FetchMoreProps, SearchProps } from "../../../types";
import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes";
import ShippingZoneInfo from "../ShippingZoneInfo"; import ShippingZoneInfo from "../ShippingZoneInfo";
import ShippingZoneRates from "../ShippingZoneRates"; import ShippingZoneRates from "../ShippingZoneRates";
@ -34,11 +34,11 @@ export interface FormData {
export interface ShippingZoneDetailsPageProps export interface ShippingZoneDetailsPageProps
extends FetchMoreProps, extends FetchMoreProps,
SearchProps { SearchProps,
ChannelProps {
disabled: boolean; disabled: boolean;
errors: ShippingErrorFragment[]; errors: ShippingErrorFragment[];
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
selectedChannel: string;
shippingZone: ShippingZoneDetailsFragment; shippingZone: ShippingZoneDetailsFragment;
warehouses: ShippingZoneDetailsFragment_warehouses[]; warehouses: ShippingZoneDetailsFragment_warehouses[];
onBack: () => void; onBack: () => void;
@ -82,7 +82,7 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
onWeightRateAdd, onWeightRateAdd,
onWeightRateEdit, onWeightRateEdit,
saveButtonBarState, saveButtonBarState,
selectedChannel, selectedChannelId,
shippingZone, shippingZone,
warehouses warehouses
}) => { }) => {
@ -160,7 +160,7 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
method => method.type === ShippingMethodTypeEnum.PRICE method => method.type === ShippingMethodTypeEnum.PRICE
)} )}
variant="price" variant="price"
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
/> />
<CardSpacer /> <CardSpacer />
<ShippingZoneRates <ShippingZoneRates
@ -172,7 +172,7 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
method => method.type === ShippingMethodTypeEnum.WEIGHT method => method.type === ShippingMethodTypeEnum.WEIGHT
)} )}
variant="weight" variant="weight"
selectedChannel={selectedChannel} selectedChannelId={selectedChannelId}
/> />
</div> </div>
<div> <div>

View file

@ -15,16 +15,16 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import WeightRange from "@saleor/components/WeightRange"; import WeightRange from "@saleor/components/WeightRange";
import { ShippingZoneDetailsFragment_shippingMethods } from "@saleor/fragments/types/ShippingZoneDetailsFragment"; import { ShippingZoneDetailsFragment_shippingMethods } from "@saleor/fragments/types/ShippingZoneDetailsFragment";
import { ChannelProps } from "@saleor/types";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { maybe, renderCollection } from "../../../misc"; import { maybe, renderCollection } from "../../../misc";
import { ICONBUTTON_SIZE } from "../../../theme"; import { ICONBUTTON_SIZE } from "../../../theme";
export interface ShippingZoneRatesProps { export interface ShippingZoneRatesProps extends ChannelProps {
disabled: boolean; disabled: boolean;
rates: ShippingZoneDetailsFragment_shippingMethods[]; rates: ShippingZoneDetailsFragment_shippingMethods[];
selectedChannel: string;
variant: "price" | "weight"; variant: "price" | "weight";
onRateAdd: () => void; onRateAdd: () => void;
onRateEdit: (id: string) => void; onRateEdit: (id: string) => void;
@ -56,7 +56,7 @@ const ShippingZoneRates: React.FC<ShippingZoneRatesProps> = props => {
onRateEdit, onRateEdit,
onRateRemove, onRateRemove,
rates, rates,
selectedChannel, selectedChannelId,
variant variant
} = props; } = props;
@ -122,7 +122,7 @@ const ShippingZoneRates: React.FC<ShippingZoneRatesProps> = props => {
rates, rates,
rate => { rate => {
const channel = rate?.channelListings?.find( const channel = rate?.channelListings?.find(
listing => listing.channel.id === selectedChannel listing => listing.channel.id === selectedChannelId
); );
return ( return (
<TableRow <TableRow

View file

@ -1,5 +1,4 @@
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import CardMenu from "@saleor/components/CardMenu";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import Grid from "@saleor/components/Grid"; import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
@ -23,8 +22,6 @@ export interface ShippingZonesListPageProps
onBack: () => void; onBack: () => void;
onRemove: (id: string) => void; onRemove: (id: string) => void;
onSubmit: (unit: WeightUnitsEnum) => void; onSubmit: (unit: WeightUnitsEnum) => void;
selectedChannel: string;
onSettingsOpen: () => void;
} }
const ShippingZonesListPage: React.FC<ShippingZonesListPageProps> = ({ const ShippingZonesListPage: React.FC<ShippingZonesListPageProps> = ({
@ -32,7 +29,6 @@ const ShippingZonesListPage: React.FC<ShippingZonesListPageProps> = ({
disabled, disabled,
userPermissions, userPermissions,
onBack, onBack,
onSettingsOpen,
onSubmit, onSubmit,
...listProps ...listProps
}) => { }) => {
@ -48,19 +44,7 @@ const ShippingZonesListPage: React.FC<ShippingZonesListPageProps> = ({
defaultMessage: "Shipping", defaultMessage: "Shipping",
description: "header" description: "header"
})} })}
> />
<CardMenu
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Settings",
description: "button"
}),
onSelect: onSettingsOpen
}
]}
/>
</PageHeader>
<Grid> <Grid>
<div> <div>
<ShippingZonesList disabled={disabled} {...listProps} /> <ShippingZonesList disabled={disabled} {...listProps} />

View file

@ -7,7 +7,7 @@ import { ShippingMethodTypeEnum } from "../types/globalTypes";
export const shippingSection = "/shipping/"; export const shippingSection = "/shipping/";
export const shippingZonesListPath = shippingSection; export const shippingZonesListPath = shippingSection;
export type ShippingZonesListUrlDialog = "remove" | "remove-many" | "settings"; export type ShippingZonesListUrlDialog = "remove" | "remove-many";
export type ShippingZonesListUrlQueryParams = BulkAction & export type ShippingZonesListUrlQueryParams = BulkAction &
Dialog<ShippingZonesListUrlDialog> & Dialog<ShippingZonesListUrlDialog> &
Pagination & Pagination &

View file

@ -1,8 +1,8 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import useShop from "@saleor/hooks/useShop"; import useShop from "@saleor/hooks/useShop";
@ -63,8 +63,7 @@ const ShippingZoneDetails: React.FC<ShippingZoneDetailsProps> = ({
displayLoader: true, displayLoader: true,
variables: { id } variables: { id }
}); });
const { channel } = useAppChannel();
const [selectedChannel] = useLocalStorage("shippingListChannel", "");
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
ShippingZoneUrlDialog, ShippingZoneUrlDialog,
@ -183,7 +182,7 @@ const ShippingZoneDetails: React.FC<ShippingZoneDetailsProps> = ({
loading={searchWarehousesOpts.loading} loading={searchWarehousesOpts.loading}
onFetchMore={loadMore} onFetchMore={loadMore}
onSearchChange={search} onSearchChange={search}
selectedChannel={selectedChannel} selectedChannelId={channel.id}
/> />
<DeleteShippingRateDialog <DeleteShippingRateDialog
confirmButtonState={deleteShippingRateOpts.status} confirmButtonState={deleteShippingRateOpts.status}

View file

@ -1,11 +1,9 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import ChannelSettingsDialog from "@saleor/channels/components/ChannelSettingsDialog";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { configurationMenuUrl } from "@saleor/configuration"; import { configurationMenuUrl } from "@saleor/configuration";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useChannelsSettings from "@saleor/hooks/useChannelsSettings";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -63,12 +61,6 @@ export const ShippingZonesList: React.FC<ShippingZonesListProps> = ({
ShippingZonesListUrlQueryParams ShippingZonesListUrlQueryParams
>(navigate, shippingZonesListUrl, params); >(navigate, shippingZonesListUrl, params);
const {
channelChoices,
handleChannelSelectConfirm,
selectedChannel
} = useChannelsSettings("shippingListChannel", { closeModal, openModal });
const { data, loading, refetch } = useShippingZoneList({ const { data, loading, refetch } = useShippingZoneList({
displayLoader: true, displayLoader: true,
variables: paginationState variables: paginationState
@ -125,14 +117,6 @@ export const ShippingZonesList: React.FC<ShippingZonesListProps> = ({
); );
return ( return (
<> <>
<ChannelSettingsDialog
channelsChoices={channelChoices}
defaultChoice={selectedChannel}
open={params.action === "settings"}
confirmButtonState="default"
onClose={closeModal}
onConfirm={handleChannelSelectConfirm}
/>
<ShippingZonesListPage <ShippingZonesListPage
defaultWeightUnit={shop?.defaultWeightUnit} defaultWeightUnit={shop?.defaultWeightUnit}
settings={settings} settings={settings}
@ -178,8 +162,6 @@ export const ShippingZonesList: React.FC<ShippingZonesListProps> = ({
</IconButton> </IconButton>
} }
userPermissions={user?.userPermissions || []} userPermissions={user?.userPermissions || []}
selectedChannel={selectedChannel}
onSettingsOpen={() => openModal("settings")}
/> />
<ActionDialog <ActionDialog

File diff suppressed because it is too large Load diff

View file

@ -47,6 +47,7 @@ const updateProps: Omit<CategoryUpdatePageProps, "classes"> = {
productListToolbar: null, productListToolbar: null,
products: category.products.edges.map(edge => edge.node), products: category.products.edges.map(edge => edge.node),
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannelId: "123",
subcategories: category.children.edges.map(edge => edge.node), subcategories: category.children.edges.map(edge => edge.node),
subcategoryListToolbar: null, subcategoryListToolbar: null,
...listActionsProps ...listActionsProps

View file

@ -38,7 +38,7 @@ const props: Omit<CollectionDetailsPageProps, "classes"> = {
onSubmit: () => undefined, onSubmit: () => undefined,
openChannelsModal: () => undefined, openChannelsModal: () => undefined,
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannel: "123" selectedChannelId: "123"
}; };
storiesOf("Views / Collections / Collection details", module) storiesOf("Views / Collections / Collection details", module)

View file

@ -27,7 +27,7 @@ const props: CollectionListPageProps = {
}, },
...tabPageProps, ...tabPageProps,
collections, collections,
selectedChannel: "123" selectedChannelId: "123"
}; };
storiesOf("Views / Collections / Collection list", module) storiesOf("Views / Collections / Collection list", module)

View file

@ -47,7 +47,7 @@ const props: SaleDetailsPageProps = {
productListToolbar: null, productListToolbar: null,
sale, sale,
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannel: "123", selectedChannelId: "123",
...listActionsProps ...listActionsProps
}; };

View file

@ -42,9 +42,8 @@ const props: SaleListPageProps = {
value: [DiscountStatusEnum.ACTIVE] value: [DiscountStatusEnum.ACTIVE]
} }
}, },
onSettingsOpen: () => undefined,
sales: saleList, sales: saleList,
selectedChannel: "123", selectedChannelId: "123",
sort: { sort: {
...sortPageProps.sort, ...sortPageProps.sort,
sort: SaleListUrlSortField.name sort: SaleListUrlSortField.name
@ -60,7 +59,6 @@ storiesOf("Views / Discounts / Sale list", module)
<SaleListPage <SaleListPage
{...props} {...props}
sales={saleList.map(sale => ({ ...sale, channelListings: [] }))} sales={saleList.map(sale => ({ ...sale, channelListings: [] }))}
selectedChannel="" selectedChannelId=""
onSettingsOpen={undefined}
/> />
)); ));

View file

@ -47,7 +47,7 @@ const props: VoucherDetailsPageProps = {
openChannelsModal: () => undefined, openChannelsModal: () => undefined,
productListToolbar: null, productListToolbar: null,
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannel: "123", selectedChannelId: "123",
voucher: voucherDetails voucher: voucherDetails
}; };

View file

@ -51,8 +51,7 @@ const props: VoucherListPageProps = {
} }
} }
}, },
onSettingsOpen: () => undefined, selectedChannelId: "123",
selectedChannel: "123",
sort: { sort: {
...sortPageProps.sort, ...sortPageProps.sort,
sort: VoucherListUrlSortField.code sort: VoucherListUrlSortField.code
@ -68,8 +67,7 @@ storiesOf("Views / Discounts / Voucher list", module)
.add("no channels", () => ( .add("no channels", () => (
<VoucherListPage <VoucherListPage
{...props} {...props}
selectedChannel="" selectedChannelId=""
onSettingsOpen={undefined}
vouchers={voucherList.map(voucher => ({ vouchers={voucherList.map(voucher => ({
...voucher, ...voucher,
channelListings: [] channelListings: []

View file

@ -1,6 +1,5 @@
import placeholderImage from "@assets/images/placeholder60x60.png"; import placeholderImage from "@assets/images/placeholder60x60.png";
import { Omit } from "@material-ui/core"; import { Omit } from "@material-ui/core";
import { channelsList } from "@saleor/channels/fixtures";
import { adminUserPermissions } from "@saleor/fixtures"; import { adminUserPermissions } from "@saleor/fixtures";
import { PermissionEnum } from "@saleor/types/globalTypes"; import { PermissionEnum } from "@saleor/types/globalTypes";
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
@ -11,16 +10,9 @@ import { shop as shopFixture } from "../../../home/fixtures";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
const shop = shopFixture(placeholderImage); const shop = shopFixture(placeholderImage);
const channelChoices = channelsList.map(channel => ({
label: channel.name,
value: channel.slug
}));
const homePageProps: Omit<HomePageProps, "classes"> = { const homePageProps: Omit<HomePageProps, "classes"> = {
activities: shop.activities.edges.map(edge => edge.node), activities: shop.activities.edges.map(edge => edge.node),
channelChoices,
channelValue: channelChoices[0].value,
onChannelChange: () => undefined,
onOrdersToCaptureClick: () => undefined, onOrdersToCaptureClick: () => undefined,
onOrdersToFulfillClick: () => undefined, onOrdersToFulfillClick: () => undefined,
onProductClick: () => undefined, onProductClick: () => undefined,

View file

@ -37,7 +37,6 @@ const props: OrderDraftListPageProps = {
} }
}, },
onAdd: () => undefined, onAdd: () => undefined,
onSettingsOpen: () => undefined,
orders, orders,
sort: { sort: {
...sortPageProps.sort, ...sortPageProps.sort,

View file

@ -21,7 +21,7 @@ const props: OrderProductAddDialogProps = {
onSubmit: () => undefined, onSubmit: () => undefined,
open: true, open: true,
products, products,
selectedChannel: products[0].variants[0].channelListings[0].channel.id selectedChannelId: products[0].variants[0].channelListings[0].channel.id
}; };
storiesOf("Orders / OrderProductAddDialog", module) storiesOf("Orders / OrderProductAddDialog", module)

View file

@ -42,9 +42,8 @@ const props: ProductListPageProps = {
filterOpts: productListFilterOpts, filterOpts: productListFilterOpts,
gridAttributes: attributes, gridAttributes: attributes,
onExport: () => undefined, onExport: () => undefined,
onSettingsOpen: () => undefined,
products, products,
selectedChannel: "123", selectedChannelId: "123",
settings: { settings: {
...pageListProps.default.settings, ...pageListProps.default.settings,
columns: ["availability", "productType", "price"] columns: ["availability", "productType", "price"]
@ -69,8 +68,7 @@ storiesOf("Views / Products / Product list", module)
<ProductListPage <ProductListPage
{...props} {...props}
channelsCount={0} channelsCount={0}
onSettingsOpen={undefined} selectedChannelId={""}
selectedChannel={""}
products={products.map(product => ({ ...product, channelListings: [] }))} products={products.map(product => ({ ...product, channelListings: [] }))}
/> />
)); ));

View file

@ -58,6 +58,7 @@ const props: ProductUpdatePageProps = {
placeholderImage, placeholderImage,
product, product,
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannelId: "123",
taxTypes, taxTypes,
variants: product.variants, variants: product.variants,
warehouses: warehouseList warehouses: warehouseList

View file

@ -27,7 +27,7 @@ const props: ShippingZoneDetailsPageProps = {
onWeightRateAdd: () => undefined, onWeightRateAdd: () => undefined,
onWeightRateEdit: () => undefined, onWeightRateEdit: () => undefined,
saveButtonBarState: "default", saveButtonBarState: "default",
selectedChannel: "12345", selectedChannelId: "12345",
shippingZone, shippingZone,
warehouses: warehouseList warehouses: warehouseList
}; };

View file

@ -20,9 +20,7 @@ const props: ShippingZonesListPageProps = {
onAdd: () => undefined, onAdd: () => undefined,
onBack: () => undefined, onBack: () => undefined,
onRemove: () => undefined, onRemove: () => undefined,
onSettingsOpen: () => undefined,
onSubmit: () => undefined, onSubmit: () => undefined,
selectedChannel: "123",
shippingZones, shippingZones,
userPermissions: adminUserPermissions userPermissions: adminUserPermissions
}; };

View file

@ -117,6 +117,10 @@ export interface TabPageProps {
onTabSave: () => void; onTabSave: () => void;
} }
export interface ChannelProps {
selectedChannelId: string;
}
export interface PartialMutationProviderOutput< export interface PartialMutationProviderOutput<
TData extends {} = {}, TData extends {} = {},
TVariables extends {} = {} TVariables extends {} = {}

View file

@ -1,21 +1,32 @@
import { User } from "@saleor/fragments/types/User"; import { User } from "@saleor/fragments/types/User";
export const isSupported = export const isSupported = !!(
navigator.credentials && navigator.credentials.preventSilentAccess; navigator?.credentials?.preventSilentAccess && PasswordCredential
);
export function login<T>(loginFn: (id: string, password: string) => T): T { export async function login<T>(
if (isSupported) { loginFn: (id: string, password: string) => T
navigator.credentials.get({ password: true }).then(credential => { ): Promise<T | null> {
if (credential instanceof PasswordCredential) { let result: T;
return loginFn(credential.id, credential.password);
} try {
}); const credential = await navigator.credentials.get({ password: true });
if (credential instanceof PasswordCredential) {
result = loginFn(credential.id, credential.password);
}
} catch {
result = null;
} }
return null; return result;
} }
export function saveCredentials(user: User, password: string) { export function saveCredentials(
user: User,
password: string
): Promise<CredentialType | null> {
let result: Promise<CredentialType | null>;
if (isSupported) { if (isSupported) {
const cred = new PasswordCredential({ const cred = new PasswordCredential({
iconURL: user.avatar ? user.avatar.url : undefined, iconURL: user.avatar ? user.avatar.url : undefined,
@ -23,6 +34,14 @@ export function saveCredentials(user: User, password: string) {
name: user.firstName ? `${user.firstName} ${user.lastName}` : undefined, name: user.firstName ? `${user.firstName} ${user.lastName}` : undefined,
password password
}); });
navigator.credentials.store(cred); try {
result = navigator.credentials.store(cred);
} catch {
result = null;
}
} else {
result = null;
} }
return result;
} }