Refactor discount section translations (#114)
* Refactor discount sectionts translations Fix bulk action dialogs Fix id collision Update pot file wip * Fix id collision
This commit is contained in:
parent
a2efcde035
commit
2d0a33fc0d
32 changed files with 2142 additions and 823 deletions
File diff suppressed because it is too large
Load diff
1
react-intl.d.ts
vendored
1
react-intl.d.ts
vendored
|
@ -5,6 +5,7 @@ declare module "react-intl" {
|
|||
export interface MessageDescriptor {
|
||||
description?: string;
|
||||
defaultMessage: string;
|
||||
id?: string;
|
||||
}
|
||||
type Messages<Names extends keyof any = string> = Record<
|
||||
Names,
|
||||
|
|
|
@ -14,13 +14,13 @@ import TableFooter from "@material-ui/core/TableFooter";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import TableHead from "@saleor/components/TableHead";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import i18n from "../../../i18n";
|
||||
import { maybe, renderCollection } from "../../../misc";
|
||||
import { ListActions, ListProps } from "../../../types";
|
||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
||||
|
@ -71,13 +71,22 @@ const DiscountCategories = withStyles(styles, {
|
|||
toggleAll,
|
||||
selected,
|
||||
isChecked
|
||||
}: DiscountCategoriesProps & WithStyles<typeof styles>) => (
|
||||
}: DiscountCategoriesProps & WithStyles<typeof styles>) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Eligible Categories")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Eligible Categories",
|
||||
description: "section header"
|
||||
})}
|
||||
toolbar={
|
||||
<Button color="primary" onClick={onCategoryAssign}>
|
||||
{i18n.t("Assign categories")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Assign categories"
|
||||
description="button"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
@ -92,10 +101,13 @@ const DiscountCategories = withStyles(styles, {
|
|||
>
|
||||
<>
|
||||
<TableCell className={classes.wideColumn}>
|
||||
{i18n.t("Category name")}
|
||||
<FormattedMessage defaultMessage="Category name" />
|
||||
</TableCell>
|
||||
<TableCell className={classes.textRight}>
|
||||
{i18n.t("Products")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Products"
|
||||
description="number of products"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell />
|
||||
</>
|
||||
|
@ -104,7 +116,9 @@ const DiscountCategories = withStyles(styles, {
|
|||
<TableRow>
|
||||
<TablePagination
|
||||
colSpan={numberOfColumns}
|
||||
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||
hasNextPage={
|
||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
||||
}
|
||||
onNextPage={onNextPage}
|
||||
hasPreviousPage={
|
||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||
|
@ -136,7 +150,10 @@ const DiscountCategories = withStyles(styles, {
|
|||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{maybe<React.ReactNode>(() => category.name, <Skeleton />)}
|
||||
{maybe<React.ReactNode>(
|
||||
() => category.name,
|
||||
<Skeleton />
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className={classes.textRight}>
|
||||
{maybe<React.ReactNode>(
|
||||
|
@ -161,7 +178,7 @@ const DiscountCategories = withStyles(styles, {
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{i18n.t("No categories found")}
|
||||
<FormattedMessage defaultMessage="No categories found" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
@ -169,7 +186,8 @@ const DiscountCategories = withStyles(styles, {
|
|||
</TableBody>
|
||||
</Table>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
DiscountCategories.displayName = "DiscountCategories";
|
||||
export default DiscountCategories;
|
||||
|
|
|
@ -14,13 +14,13 @@ import TableFooter from "@material-ui/core/TableFooter";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import TableHead from "@saleor/components/TableHead";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import i18n from "../../../i18n";
|
||||
import { maybe, renderCollection } from "../../../misc";
|
||||
import { ListActions, ListProps } from "../../../types";
|
||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
||||
|
@ -71,13 +71,22 @@ const DiscountCollections = withStyles(styles, {
|
|||
toggle,
|
||||
toggleAll,
|
||||
toolbar
|
||||
}: DiscountCollectionsProps & WithStyles<typeof styles>) => (
|
||||
}: DiscountCollectionsProps & WithStyles<typeof styles>) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Eligible Collections")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Eligible Collections",
|
||||
description: "section header"
|
||||
})}
|
||||
toolbar={
|
||||
<Button color="primary" onClick={onCollectionAssign}>
|
||||
{i18n.t("Assign collections")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Assign collections"
|
||||
description="button"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
@ -91,10 +100,13 @@ const DiscountCollections = withStyles(styles, {
|
|||
toolbar={toolbar}
|
||||
>
|
||||
<TableCell className={classes.wideColumn}>
|
||||
{i18n.t("Collection name")}
|
||||
<FormattedMessage defaultMessage="Collection name" />
|
||||
</TableCell>
|
||||
<TableCell className={classes.textRight}>
|
||||
{i18n.t("Products")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Products"
|
||||
description="number of products"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell />
|
||||
</TableHead>
|
||||
|
@ -102,7 +114,9 @@ const DiscountCollections = withStyles(styles, {
|
|||
<TableRow>
|
||||
<TablePagination
|
||||
colSpan={numberOfColumns}
|
||||
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||
hasNextPage={
|
||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
||||
}
|
||||
onNextPage={onNextPage}
|
||||
hasPreviousPage={
|
||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||
|
@ -115,7 +129,9 @@ const DiscountCollections = withStyles(styles, {
|
|||
{renderCollection(
|
||||
maybe(() => sale.collections.edges.map(edge => edge.node)),
|
||||
collection => {
|
||||
const isSelected = collection ? isChecked(collection.id) : false;
|
||||
const isSelected = collection
|
||||
? isChecked(collection.id)
|
||||
: false;
|
||||
return (
|
||||
<TableRow
|
||||
selected={isSelected}
|
||||
|
@ -161,7 +177,7 @@ const DiscountCollections = withStyles(styles, {
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{i18n.t("No collections found")}
|
||||
<FormattedMessage defaultMessage="No collections found" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
@ -169,7 +185,8 @@ const DiscountCollections = withStyles(styles, {
|
|||
</TableBody>
|
||||
</Table>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
DiscountCollections.displayName = "DiscountCollections";
|
||||
export default DiscountCollections;
|
||||
|
|
|
@ -17,6 +17,7 @@ import TextField from "@material-ui/core/TextField";
|
|||
import Typography from "@material-ui/core/Typography";
|
||||
import { filter } from "fuzzaldrin";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import ConfirmButton, {
|
||||
|
@ -27,7 +28,7 @@ import FormSpacer from "@saleor/components/FormSpacer";
|
|||
import Hr from "@saleor/components/Hr";
|
||||
// tslint:disable no-submodule-imports
|
||||
import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo";
|
||||
import i18n from "../../../i18n";
|
||||
import { buttonMessages } from "@saleor/intl";
|
||||
|
||||
interface FormData {
|
||||
allCountries: boolean;
|
||||
|
@ -72,6 +73,8 @@ const DiscountCountrySelectDialog = withStyles(styles, {
|
|||
initial,
|
||||
onConfirm
|
||||
}: DiscountCountrySelectDialogProps & WithStyles<typeof styles>) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const initialForm: FormData = {
|
||||
allCountries: true,
|
||||
countries: initial,
|
||||
|
@ -90,23 +93,28 @@ const DiscountCountrySelectDialog = withStyles(styles, {
|
|||
|
||||
return (
|
||||
<>
|
||||
<DialogTitle>{i18n.t("Assign Countries")}</DialogTitle>
|
||||
<DialogTitle>
|
||||
<FormattedMessage
|
||||
defaultMessage="Assign Countries"
|
||||
description="dialog header"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>
|
||||
{i18n.t(
|
||||
"Choose countries, you want voucher to be limited to, from the list below"
|
||||
)}
|
||||
<FormattedMessage defaultMessage="Choose countries, you want voucher to be limited to, from the list below" />
|
||||
</Typography>
|
||||
<FormSpacer />
|
||||
<TextField
|
||||
name="query"
|
||||
value={data.query}
|
||||
onChange={event => change(event, () => fetch(data.query))}
|
||||
label={i18n.t("Search Countries", {
|
||||
context: "country search input label"
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Filter Countries",
|
||||
description: "search box label"
|
||||
})}
|
||||
placeholder={i18n.t("Search by country name", {
|
||||
context: "country search input placeholder"
|
||||
placeholder={intl.formatMessage({
|
||||
defaultMessage: "Search by country name",
|
||||
description: "search box placeholder"
|
||||
})}
|
||||
fullWidth
|
||||
/>
|
||||
|
@ -114,9 +122,10 @@ const DiscountCountrySelectDialog = withStyles(styles, {
|
|||
<Hr />
|
||||
<DialogContent className={classes.container}>
|
||||
<Typography className={classes.heading} variant="subtitle1">
|
||||
{i18n.t("Countries A to Z", {
|
||||
context: "country selection"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Countries A to Z"
|
||||
description="country selection"
|
||||
/>
|
||||
</Typography>
|
||||
<Table>
|
||||
<TableBody>
|
||||
|
@ -167,7 +176,7 @@ const DiscountCountrySelectDialog = withStyles(styles, {
|
|||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose}>
|
||||
{i18n.t("Cancel", { context: "button" })}
|
||||
<FormattedMessage {...buttonMessages.cancel} />
|
||||
</Button>
|
||||
<ConfirmButton
|
||||
transitionState={confirmButtonState}
|
||||
|
@ -175,7 +184,10 @@ const DiscountCountrySelectDialog = withStyles(styles, {
|
|||
variant="contained"
|
||||
type="submit"
|
||||
>
|
||||
{i18n.t("Assign countries", { context: "button" })}
|
||||
<FormattedMessage
|
||||
defaultMessage="Assign countries"
|
||||
description="button"
|
||||
/>
|
||||
</ConfirmButton>
|
||||
</DialogActions>
|
||||
</>
|
||||
|
|
|
@ -14,6 +14,7 @@ import TableFooter from "@material-ui/core/TableFooter";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
|
@ -24,7 +25,6 @@ import TableCellAvatar, {
|
|||
} from "@saleor/components/TableCellAvatar";
|
||||
import TableHead from "@saleor/components/TableHead";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import i18n from "../../../i18n";
|
||||
import { maybe, renderCollection } from "../../../misc";
|
||||
import { ListActions, ListProps } from "../../../types";
|
||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
||||
|
@ -84,13 +84,22 @@ const DiscountProducts = withStyles(styles, {
|
|||
toggle,
|
||||
toggleAll,
|
||||
toolbar
|
||||
}: SaleProductsProps & WithStyles<typeof styles>) => (
|
||||
}: SaleProductsProps & WithStyles<typeof styles>) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Eligible Products")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Eligible Products",
|
||||
description: "section header"
|
||||
})}
|
||||
toolbar={
|
||||
<Button color="primary" onClick={onProductAssign}>
|
||||
{i18n.t("Assign products")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Assign products"
|
||||
description="button"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
@ -105,14 +114,17 @@ const DiscountProducts = withStyles(styles, {
|
|||
>
|
||||
<TableCell className={classes.colName}>
|
||||
<span className={classes.colNameLabel}>
|
||||
{i18n.t("Product name")}
|
||||
<FormattedMessage defaultMessage="Product Name" />
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colType}>
|
||||
{i18n.t("Product Type")}
|
||||
<FormattedMessage defaultMessage="Product Type" />
|
||||
</TableCell>
|
||||
<TableCell className={classes.colPublished}>
|
||||
{i18n.t("Published")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Published"
|
||||
description="product is published"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell />
|
||||
</TableHead>
|
||||
|
@ -120,7 +132,9 @@ const DiscountProducts = withStyles(styles, {
|
|||
<TableRow>
|
||||
<TablePagination
|
||||
colSpan={numberOfColumns}
|
||||
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||
hasNextPage={
|
||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
||||
}
|
||||
onNextPage={onNextPage}
|
||||
hasPreviousPage={
|
||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||
|
@ -167,9 +181,13 @@ const DiscountProducts = withStyles(styles, {
|
|||
<StatusLabel
|
||||
label={
|
||||
product.isPublished
|
||||
? i18n.t("Published", { context: "product status" })
|
||||
: i18n.t("Not published", {
|
||||
context: "product status"
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Published",
|
||||
description: "product is published"
|
||||
})
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Not published",
|
||||
description: "product is not published"
|
||||
})
|
||||
}
|
||||
status={product.isPublished ? "success" : "error"}
|
||||
|
@ -195,7 +213,7 @@ const DiscountProducts = withStyles(styles, {
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{i18n.t("No products found")}
|
||||
<FormattedMessage defaultMessage="No products found" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
@ -203,7 +221,8 @@ const DiscountProducts = withStyles(styles, {
|
|||
</TableBody>
|
||||
</Table>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
DiscountProducts.displayName = "DiscountProducts";
|
||||
export default DiscountProducts;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
|
@ -8,7 +9,7 @@ import Form from "@saleor/components/Form";
|
|||
import Grid from "@saleor/components/Grid";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import i18n from "../../../i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { UserError } from "../../../types";
|
||||
import { SaleType } from "../../../types/globalTypes";
|
||||
import SaleInfo from "../SaleInfo";
|
||||
|
@ -39,6 +40,8 @@ const SaleCreatePage: React.StatelessComponent<SaleCreatePageProps> = ({
|
|||
saveButtonBarState,
|
||||
onBack
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const initialForm: FormData = {
|
||||
endDate: "",
|
||||
name: "",
|
||||
|
@ -50,8 +53,15 @@ const SaleCreatePage: React.StatelessComponent<SaleCreatePageProps> = ({
|
|||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({ change, data, errors: formErrors, hasChanged, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Sales")}</AppHeader>
|
||||
<PageHeader title={i18n.t("Create Sale")} />
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.sales)}
|
||||
</AppHeader>
|
||||
<PageHeader
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Create Sale",
|
||||
description: "page header"
|
||||
})}
|
||||
/>
|
||||
<Grid>
|
||||
<div>
|
||||
<SaleInfo
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
|
@ -9,7 +10,7 @@ import Grid from "@saleor/components/Grid";
|
|||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import { Tab, TabContainer } from "@saleor/components/Tab";
|
||||
import i18n from "../../../i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { maybe } from "../../../misc";
|
||||
import { ListProps, TabListActions, UserError } from "../../../types";
|
||||
import { SaleType } from "../../../types/globalTypes";
|
||||
|
@ -102,6 +103,8 @@ const SaleDetailsPage: React.StatelessComponent<SaleDetailsPageProps> = ({
|
|||
toggle,
|
||||
toggleAll
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const initialForm: FormData = {
|
||||
endDate: maybe(() => (sale.endDate ? sale.endDate : ""), ""),
|
||||
name: maybe(() => sale.name, ""),
|
||||
|
@ -113,7 +116,9 @@ const SaleDetailsPage: React.StatelessComponent<SaleDetailsPageProps> = ({
|
|||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({ change, data, errors: formErrors, hasChanged, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Sales")}</AppHeader>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.sales)}
|
||||
</AppHeader>
|
||||
<PageHeader title={maybe(() => sale.name)} />
|
||||
<Grid>
|
||||
<div>
|
||||
|
@ -137,34 +142,55 @@ const SaleDetailsPage: React.StatelessComponent<SaleDetailsPageProps> = ({
|
|||
isActive={activeTab === SaleDetailsPageTab.categories}
|
||||
changeTab={onTabClick}
|
||||
>
|
||||
{i18n.t("Categories ({{ number }})", {
|
||||
number: maybe(
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Categories ({quantity})",
|
||||
description: "number of categories",
|
||||
id: "saleDetailsPageCategoriesQuantity"
|
||||
},
|
||||
{
|
||||
quantity: maybe(
|
||||
() => sale.categories.totalCount.toString(),
|
||||
"…"
|
||||
)
|
||||
})}
|
||||
}
|
||||
)}
|
||||
</CategoriesTab>
|
||||
<CollectionsTab
|
||||
isActive={activeTab === SaleDetailsPageTab.collections}
|
||||
changeTab={onTabClick}
|
||||
>
|
||||
{i18n.t("Collections ({{ number }})", {
|
||||
number: maybe(
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Collections ({quantity})",
|
||||
description: "number of collections",
|
||||
id: "saleDetailsPageCollectionsQuantity"
|
||||
},
|
||||
{
|
||||
quantity: maybe(
|
||||
() => sale.collections.totalCount.toString(),
|
||||
"…"
|
||||
)
|
||||
})}
|
||||
}
|
||||
)}
|
||||
</CollectionsTab>
|
||||
<ProductsTab
|
||||
isActive={activeTab === SaleDetailsPageTab.products}
|
||||
changeTab={onTabClick}
|
||||
>
|
||||
{i18n.t("Products ({{ number }})", {
|
||||
number: maybe(
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Products ({quantity})",
|
||||
description: "number of products",
|
||||
id: "saleDetailsPageProductsQuantity"
|
||||
},
|
||||
{
|
||||
quantity: maybe(
|
||||
() => sale.products.totalCount.toString(),
|
||||
"…"
|
||||
)
|
||||
})}
|
||||
}
|
||||
)}
|
||||
</ProductsTab>
|
||||
</TabContainer>
|
||||
<CardSpacer />
|
||||
|
|
|
@ -8,9 +8,10 @@ import {
|
|||
} from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { FormData } from "../SaleDetailsPage";
|
||||
|
||||
export interface SaleInfoProps {
|
||||
|
@ -40,9 +41,14 @@ const SaleInfo = withStyles(styles, {
|
|||
disabled,
|
||||
errors,
|
||||
onChange
|
||||
}: SaleInfoProps & WithStyles<typeof styles>) => (
|
||||
}: SaleInfoProps & WithStyles<typeof styles>) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("General Information")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage(commonMessages.generalInformations)}
|
||||
/>
|
||||
<CardContent className={classes.root}>
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
|
@ -50,13 +56,17 @@ const SaleInfo = withStyles(styles, {
|
|||
helperText={errors.name}
|
||||
name={"name" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("Name")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Name",
|
||||
description: "sale name"
|
||||
})}
|
||||
value={data.name}
|
||||
fullWidth
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
SaleInfo.displayName = "SaleInfo";
|
||||
export default SaleInfo;
|
||||
|
|
|
@ -11,6 +11,7 @@ import TableCell from "@material-ui/core/TableCell";
|
|||
import TableFooter from "@material-ui/core/TableFooter";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import Date from "@saleor/components/Date";
|
||||
|
@ -19,7 +20,6 @@ import Percent from "@saleor/components/Percent";
|
|||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import TableHead from "@saleor/components/TableHead";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { maybe, renderCollection } from "@saleor/misc";
|
||||
import { ListActions, ListProps } from "@saleor/types";
|
||||
import { SaleType } from "@saleor/types/globalTypes";
|
||||
|
@ -92,24 +92,22 @@ const SaleList = withStyles(styles, {
|
|||
toolbar={toolbar}
|
||||
>
|
||||
<TableCell className={classes.colName}>
|
||||
{i18n.t("Name", {
|
||||
context: "sale list table header"
|
||||
})}
|
||||
<FormattedMessage defaultMessage="Name" description="sale name" />
|
||||
</TableCell>
|
||||
<TableCell className={classes.colStart}>
|
||||
{i18n.t("Starts", {
|
||||
context: "sale list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Starts"
|
||||
description="sale start date"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colEnd}>
|
||||
{i18n.t("Ends", {
|
||||
context: "sale list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Ends"
|
||||
description="sale end date"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colValue}>
|
||||
{i18n.t("Value", {
|
||||
context: "sale list table header"
|
||||
})}
|
||||
<FormattedMessage defaultMessage="Value" description="sale value" />
|
||||
</TableCell>
|
||||
</TableHead>
|
||||
<TableFooter>
|
||||
|
@ -193,7 +191,7 @@ const SaleList = withStyles(styles, {
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{i18n.t("No sales found")}
|
||||
<FormattedMessage defaultMessage="No sales found" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import Container from "@saleor/components/Container";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { ListActions, PageListProps } from "@saleor/types";
|
||||
import { SaleList_sales_edges_node } from "../../types/SaleList";
|
||||
import SaleList from "../SaleList";
|
||||
|
@ -17,16 +18,22 @@ export interface SaleListPageProps extends PageListProps, ListActions {
|
|||
const SaleListPage: React.StatelessComponent<SaleListPageProps> = ({
|
||||
onAdd,
|
||||
...listProps
|
||||
}) => (
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<PageHeader title={i18n.t("Sales")}>
|
||||
<PageHeader title={intl.formatMessage(sectionNames.sales)}>
|
||||
<Button onClick={onAdd} variant="contained" color="primary">
|
||||
{i18n.t("Add sale")}
|
||||
<FormattedMessage defaultMessage="Add Sale"
|
||||
description="button"
|
||||
/>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
</PageHeader>
|
||||
<SaleList {...listProps} />
|
||||
</Container>
|
||||
);
|
||||
);
|
||||
};
|
||||
SaleListPage.displayName = "SaleListPage";
|
||||
export default SaleListPage;
|
||||
|
|
|
@ -9,11 +9,12 @@ import {
|
|||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import TextFieldWithChoice from "@saleor/components/TextFieldWithChoice";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { FormErrors } from "../../../types";
|
||||
import { SaleType } from "../../../types/globalTypes";
|
||||
import { FormData } from "../SaleDetailsPage";
|
||||
|
@ -49,9 +50,17 @@ const SalePricing = withStyles(styles, {
|
|||
disabled,
|
||||
errors,
|
||||
onChange
|
||||
}: SalePricingProps & WithStyles<typeof styles>) => (
|
||||
}: SalePricingProps & WithStyles<typeof styles>) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Pricing")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Pricing",
|
||||
description: "sale pricing, header"
|
||||
})}
|
||||
/>
|
||||
<CardContent className={classes.root}>
|
||||
<TextFieldWithChoice
|
||||
disabled={disabled}
|
||||
|
@ -73,7 +82,9 @@ const SalePricing = withStyles(styles, {
|
|||
helperText={errors.value}
|
||||
name={"value" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("Discount Value")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Discount Value"
|
||||
})}
|
||||
value={data.value}
|
||||
type="number"
|
||||
fullWidth
|
||||
|
@ -85,7 +96,10 @@ const SalePricing = withStyles(styles, {
|
|||
<Hr />
|
||||
<CardContent className={classes.root}>
|
||||
<Typography className={classes.subheading} variant="subtitle1">
|
||||
{i18n.t("Time Frame")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Time Frame"
|
||||
description="time during which sale is active"
|
||||
/>
|
||||
</Typography>
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
|
@ -93,7 +107,7 @@ const SalePricing = withStyles(styles, {
|
|||
helperText={errors.startDate}
|
||||
name={"startDate" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("Start Date")}
|
||||
label={intl.formatMessage(commonMessages.startDate)}
|
||||
value={data.startDate}
|
||||
type="date"
|
||||
InputLabelProps={{
|
||||
|
@ -107,7 +121,7 @@ const SalePricing = withStyles(styles, {
|
|||
helperText={errors.endDate}
|
||||
name={"endDate" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("End Date")}
|
||||
label={intl.formatMessage(commonMessages.endDate)}
|
||||
value={data.endDate}
|
||||
type="date"
|
||||
InputLabelProps={{
|
||||
|
@ -117,7 +131,8 @@ const SalePricing = withStyles(styles, {
|
|||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
SalePricing.displayName = "SalePricing";
|
||||
export default SalePricing;
|
||||
|
|
|
@ -2,6 +2,7 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
|
@ -11,7 +12,7 @@ import Hr from "@saleor/components/Hr";
|
|||
import Money from "@saleor/components/Money";
|
||||
import Percent from "@saleor/components/Percent";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { maybe } from "../../../misc";
|
||||
import { SaleType } from "../../../types/globalTypes";
|
||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
||||
|
@ -24,17 +25,24 @@ export interface SaleSummaryProps {
|
|||
const SaleSummary: React.StatelessComponent<SaleSummaryProps> = ({
|
||||
defaultCurrency,
|
||||
sale
|
||||
}) => (
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Summary")} />
|
||||
<CardTitle title={intl.formatMessage(commonMessages.summary)} />
|
||||
<CardContent>
|
||||
<Typography variant="caption">{i18n.t("Name")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage defaultMessage="Name" description="sale name" />
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(() => sale.name, <Skeleton />)}
|
||||
</Typography>
|
||||
<FormSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Value")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage defaultMessage="Value" description="sale value" />
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
|
@ -56,7 +64,9 @@ const SaleSummary: React.StatelessComponent<SaleSummaryProps> = ({
|
|||
<Hr />
|
||||
<CardSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Start Date")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage {...commonMessages.startDate} />
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() => (
|
||||
|
@ -67,7 +77,9 @@ const SaleSummary: React.StatelessComponent<SaleSummaryProps> = ({
|
|||
</Typography>
|
||||
<FormSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("End Date")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage {...commonMessages.endDate} />
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
|
@ -77,6 +89,7 @@ const SaleSummary: React.StatelessComponent<SaleSummaryProps> = ({
|
|||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
);
|
||||
};
|
||||
SaleSummary.displayName = "SaleSummary";
|
||||
export default SaleSummary;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
|
@ -8,7 +9,6 @@ import Form from "@saleor/components/Form";
|
|||
import Grid from "@saleor/components/Grid";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import i18n from "../../../i18n";
|
||||
import { UserError } from "../../../types";
|
||||
import {
|
||||
DiscountValueTypeEnum,
|
||||
|
@ -21,6 +21,7 @@ import VoucherLimits from "../VoucherLimits";
|
|||
import VoucherRequirements from "../VoucherRequirements";
|
||||
import VoucherTypes from "../VoucherTypes";
|
||||
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import VoucherValue from "../VoucherValue";
|
||||
export interface FormData {
|
||||
applyOncePerCustomer: boolean;
|
||||
|
@ -58,6 +59,8 @@ const VoucherCreatePage: React.StatelessComponent<VoucherCreatePageProps> = ({
|
|||
onBack,
|
||||
onSubmit
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const initialForm: FormData = {
|
||||
applyOncePerCustomer: false,
|
||||
applyOncePerOrder: false,
|
||||
|
@ -81,8 +84,15 @@ const VoucherCreatePage: React.StatelessComponent<VoucherCreatePageProps> = ({
|
|||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({ change, data, errors: formErrors, hasChanged, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Vouchers")}</AppHeader>
|
||||
<PageHeader title={i18n.t("Create Voucher")} />
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.vouchers)}
|
||||
</AppHeader>
|
||||
<PageHeader
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Create Voucher",
|
||||
description: "page header"
|
||||
})}
|
||||
/>
|
||||
<Grid>
|
||||
<div>
|
||||
<VoucherInfo
|
||||
|
|
|
@ -2,11 +2,12 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
|
||||
import Grid from "@saleor/components/Grid";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { FormErrors } from "../../../types";
|
||||
import { FormData } from "../VoucherDetailsPage";
|
||||
|
||||
|
@ -24,9 +25,16 @@ const VoucherDates = ({
|
|||
errors,
|
||||
onChange
|
||||
}: VoucherDatesProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Active Dates")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Active Dates",
|
||||
description: "time during voucher is active, header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
<Grid variant="uniform">
|
||||
<TextField
|
||||
|
@ -35,7 +43,7 @@ const VoucherDates = ({
|
|||
helperText={errors.startDate}
|
||||
name={"startDate" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("Start Date")}
|
||||
label={intl.formatMessage(commonMessages.startDate)}
|
||||
value={data.startDate}
|
||||
type="date"
|
||||
InputLabelProps={{
|
||||
|
@ -49,7 +57,7 @@ const VoucherDates = ({
|
|||
helperText={errors.startDate}
|
||||
name={"startTime" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("Start Hour")}
|
||||
label={intl.formatMessage(commonMessages.startHour)}
|
||||
value={data.startTime}
|
||||
type="time"
|
||||
InputLabelProps={{
|
||||
|
@ -60,7 +68,10 @@ const VoucherDates = ({
|
|||
</Grid>
|
||||
<ControlledCheckbox
|
||||
checked={data.hasEndDate}
|
||||
label={i18n.t("Set end date")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Set end date",
|
||||
description: "voucher end date, switch button"
|
||||
})}
|
||||
name={"hasEndDate" as keyof FormData}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
@ -72,7 +83,7 @@ const VoucherDates = ({
|
|||
helperText={errors.endDate}
|
||||
name={"endDate" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("End Date")}
|
||||
label={intl.formatMessage(commonMessages.endDate)}
|
||||
value={data.endDate}
|
||||
type="date"
|
||||
InputLabelProps={{
|
||||
|
@ -86,7 +97,7 @@ const VoucherDates = ({
|
|||
helperText={errors.endDate}
|
||||
name={"endTime" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("End Hour")}
|
||||
label={intl.formatMessage(commonMessages.endHour)}
|
||||
value={data.endTime}
|
||||
type="time"
|
||||
InputLabelProps={{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
|
@ -12,7 +13,7 @@ import PageHeader from "@saleor/components/PageHeader";
|
|||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import { Tab, TabContainer } from "@saleor/components/Tab";
|
||||
import { RequirementsPicker } from "@saleor/discounts/types";
|
||||
import i18n from "../../../i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { maybe, splitDateTime } from "../../../misc";
|
||||
import { ListProps, TabListActions, UserError } from "../../../types";
|
||||
import {
|
||||
|
@ -128,6 +129,8 @@ const VoucherDetailsPage: React.StatelessComponent<VoucherDetailsPageProps> = ({
|
|||
collectionListToolbar,
|
||||
productListToolbar
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
let requirementsPickerInitValue;
|
||||
if (maybe(() => voucher.minAmountSpent.amount) > 0) {
|
||||
requirementsPickerInitValue = RequirementsPicker.ORDER;
|
||||
|
@ -166,7 +169,9 @@ const VoucherDetailsPage: React.StatelessComponent<VoucherDetailsPageProps> = ({
|
|||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({ change, data, errors: formErrors, hasChanged, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Vouchers")}</AppHeader>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.vouchers)}
|
||||
</AppHeader>
|
||||
<PageHeader title={maybe(() => voucher.code)} />
|
||||
<Grid>
|
||||
<div>
|
||||
|
@ -204,34 +209,52 @@ const VoucherDetailsPage: React.StatelessComponent<VoucherDetailsPageProps> = ({
|
|||
isActive={activeTab === VoucherDetailsPageTab.categories}
|
||||
changeTab={onTabClick}
|
||||
>
|
||||
{i18n.t("Categories ({{ number }})", {
|
||||
number: maybe(
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Categories ({quantity})",
|
||||
description: "number of categories"
|
||||
},
|
||||
{
|
||||
quantity: maybe(
|
||||
() => voucher.categories.totalCount.toString(),
|
||||
"…"
|
||||
)
|
||||
})}
|
||||
}
|
||||
)}
|
||||
</CategoriesTab>
|
||||
<CollectionsTab
|
||||
isActive={activeTab === VoucherDetailsPageTab.collections}
|
||||
changeTab={onTabClick}
|
||||
>
|
||||
{i18n.t("Collections ({{ number }})", {
|
||||
number: maybe(
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Collections ({quantity})",
|
||||
description: "number of collections"
|
||||
},
|
||||
{
|
||||
quantity: maybe(
|
||||
() => voucher.collections.totalCount.toString(),
|
||||
"…"
|
||||
)
|
||||
})}
|
||||
}
|
||||
)}
|
||||
</CollectionsTab>
|
||||
<ProductsTab
|
||||
isActive={activeTab === VoucherDetailsPageTab.products}
|
||||
changeTab={onTabClick}
|
||||
>
|
||||
{i18n.t("Products ({{ number }})", {
|
||||
number: maybe(
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Products ({quantity})",
|
||||
description: "number of products"
|
||||
},
|
||||
{
|
||||
quantity: maybe(
|
||||
() => voucher.products.totalCount.toString(),
|
||||
"…"
|
||||
)
|
||||
})}
|
||||
}
|
||||
)}
|
||||
</ProductsTab>
|
||||
</TabContainer>
|
||||
<CardSpacer />
|
||||
|
@ -291,12 +314,17 @@ const VoucherDetailsPage: React.StatelessComponent<VoucherDetailsPageProps> = ({
|
|||
<CountryList
|
||||
countries={maybe(() => voucher.countries)}
|
||||
disabled={disabled}
|
||||
emptyText={i18n.t("Voucher applies to all countries")}
|
||||
emptyText={intl.formatMessage({
|
||||
defaultMessage: "Voucher applies to all countries"
|
||||
})}
|
||||
title={
|
||||
<>
|
||||
{i18n.t("Countries")}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Countries",
|
||||
description: "voucher country range"
|
||||
})}
|
||||
<Typography variant="caption">
|
||||
{i18n.t("Vouchers limited to these countries")}
|
||||
<FormattedMessage defaultMessage="Voucher is limited to these countries" />
|
||||
</Typography>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { generateCode } from "../../../misc";
|
||||
import { FormErrors } from "../../../types";
|
||||
import { FormData } from "../VoucherDetailsPage";
|
||||
|
@ -25,6 +26,8 @@ const VoucherInfo = ({
|
|||
variant,
|
||||
onChange
|
||||
}: VoucherInfoProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const onGenerateCode = () =>
|
||||
onChange({
|
||||
target: {
|
||||
|
@ -36,11 +39,14 @@ const VoucherInfo = ({
|
|||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("General Information")}
|
||||
title={intl.formatMessage(commonMessages.generalInformations)}
|
||||
toolbar={
|
||||
variant === "create" && (
|
||||
<Button color="primary" onClick={onGenerateCode}>
|
||||
{i18n.t("Generate Code")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Generate Code"
|
||||
description="voucher code, button"
|
||||
/>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
@ -52,7 +58,9 @@ const VoucherInfo = ({
|
|||
fullWidth
|
||||
helperText={errors.code}
|
||||
name={"code" as keyof FormData}
|
||||
label={i18n.t("Discount Code")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Discount Code"
|
||||
})}
|
||||
value={data.code}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
|
|
@ -2,10 +2,10 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
|
||||
import i18n from "../../../i18n";
|
||||
import { FormErrors } from "../../../types";
|
||||
import { FormData } from "../VoucherDetailsPage";
|
||||
|
||||
|
@ -23,15 +23,23 @@ const VoucherLimits = ({
|
|||
errors,
|
||||
onChange
|
||||
}: VoucherLimitsProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Usage Limit ")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Usage Limit",
|
||||
description: "voucher usage limit, header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
<ControlledCheckbox
|
||||
checked={data.hasUsageLimit}
|
||||
label={i18n.t(
|
||||
label={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Limit number of times this discount can be used in total"
|
||||
)}
|
||||
})}
|
||||
name={"hasUsageLimit" as keyof FormData}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
@ -40,7 +48,10 @@ const VoucherLimits = ({
|
|||
disabled={disabled}
|
||||
error={!!errors.usageLimit}
|
||||
helperText={errors.usageLimit}
|
||||
label={i18n.t("Limit of Uses")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Limit of Uses",
|
||||
description: "voucher"
|
||||
})}
|
||||
name={"usageLimit" as keyof FormData}
|
||||
value={data.usageLimit}
|
||||
onChange={onChange}
|
||||
|
@ -53,7 +64,10 @@ const VoucherLimits = ({
|
|||
)}
|
||||
<ControlledCheckbox
|
||||
checked={data.applyOncePerCustomer}
|
||||
label={i18n.t("Limit to one use per customer")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Limit to one use per customer",
|
||||
description: "limit voucher"
|
||||
})}
|
||||
name={"applyOncePerCustomer" as keyof FormData}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
|
|
@ -11,6 +11,7 @@ import TableCell from "@material-ui/core/TableCell";
|
|||
import TableFooter from "@material-ui/core/TableFooter";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import Checkbox from "@saleor/components/Checkbox";
|
||||
import Date from "@saleor/components/Date";
|
||||
|
@ -19,7 +20,6 @@ import Percent from "@saleor/components/Percent";
|
|||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import TableHead from "@saleor/components/TableHead";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { maybe, renderCollection } from "@saleor/misc";
|
||||
import { ListActions, ListProps } from "@saleor/types";
|
||||
import { DiscountValueTypeEnum } from "@saleor/types/globalTypes";
|
||||
|
@ -107,34 +107,40 @@ const VoucherList = withStyles(styles, {
|
|||
toolbar={toolbar}
|
||||
>
|
||||
<TableCell className={classes.colName}>
|
||||
{i18n.t("Code", {
|
||||
context: "voucher list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Code"
|
||||
description="voucher code"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colMinSpent}>
|
||||
{i18n.t("Min. Spent", {
|
||||
context: "voucher list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Min. Spent"
|
||||
description="minimum amount of spent money to activate voucher"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colStart}>
|
||||
{i18n.t("Starts", {
|
||||
context: "voucher list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Starts"
|
||||
description="voucher is active from date"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colEnd}>
|
||||
{i18n.t("Ends", {
|
||||
context: "voucher list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Ends"
|
||||
description="voucher is active until date"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colValue}>
|
||||
{i18n.t("Value", {
|
||||
context: "voucher list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Value"
|
||||
description="voucher value"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colUses}>
|
||||
{i18n.t("Uses", {
|
||||
context: "voucher list table header"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Uses"
|
||||
description="voucher uses"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableHead>
|
||||
<TableFooter>
|
||||
|
@ -239,7 +245,7 @@ const VoucherList = withStyles(styles, {
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{i18n.t("No vouchers found")}
|
||||
<FormattedMessage defaultMessage="No vouchers found" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import Container from "@saleor/components/Container";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { ListActions, PageListProps } from "@saleor/types";
|
||||
import { VoucherList_vouchers_edges_node } from "../../types/VoucherList";
|
||||
import VoucherList from "../VoucherList";
|
||||
|
@ -30,11 +31,14 @@ const VoucherListPage: React.StatelessComponent<VoucherListPageProps> = ({
|
|||
toggle,
|
||||
toggleAll,
|
||||
toolbar
|
||||
}) => (
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<PageHeader title={i18n.t("Vouchers")}>
|
||||
<PageHeader title={intl.formatMessage(sectionNames.vouchers)}>
|
||||
<Button onClick={onAdd} variant="contained" color="primary">
|
||||
{i18n.t("Add voucher")}
|
||||
<FormattedMessage defaultMessage="Add voucher" description="button" />
|
||||
<AddIcon />
|
||||
</Button>
|
||||
</PageHeader>
|
||||
|
@ -55,6 +59,7 @@ const VoucherListPage: React.StatelessComponent<VoucherListPageProps> = ({
|
|||
toolbar={toolbar}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
);
|
||||
};
|
||||
VoucherListPage.displayName = "VoucherListPage";
|
||||
export default VoucherListPage;
|
||||
|
|
|
@ -2,12 +2,12 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import { FormSpacer } from "@saleor/components/FormSpacer";
|
||||
import RadioGroupField from "@saleor/components/RadioGroupField";
|
||||
import { RequirementsPicker } from "@saleor/discounts/types";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { FormErrors } from "@saleor/types";
|
||||
import { FormData } from "../VoucherDetailsPage";
|
||||
|
||||
|
@ -25,24 +25,43 @@ const VoucherRequirements = ({
|
|||
errors,
|
||||
onChange
|
||||
}: VoucherRequirementsProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const minimalOrderValueText = intl.formatMessage({
|
||||
defaultMessage: "Minimal order value",
|
||||
description: "voucher requirement"
|
||||
});
|
||||
const minimalQuantityText = intl.formatMessage({
|
||||
defaultMessage: "Minimum quantity of items",
|
||||
description: "voucher requirement"
|
||||
});
|
||||
|
||||
const requirementsPickerChoices = [
|
||||
{
|
||||
label: i18n.t("None"),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "None",
|
||||
description: "voucher has no requirements"
|
||||
}),
|
||||
value: RequirementsPicker.NONE
|
||||
},
|
||||
{
|
||||
label: i18n.t("Minimal order value"),
|
||||
label: minimalOrderValueText,
|
||||
value: RequirementsPicker.ORDER
|
||||
},
|
||||
{
|
||||
label: i18n.t("Minimum quantity of items"),
|
||||
label: minimalQuantityText,
|
||||
value: RequirementsPicker.ITEM
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Minimum Requirements")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Minimum Requirements",
|
||||
description: "voucher requirements, header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
<RadioGroupField
|
||||
choices={requirementsPickerChoices}
|
||||
|
@ -57,7 +76,7 @@ const VoucherRequirements = ({
|
|||
disabled={disabled}
|
||||
error={!!errors.minAmountSpent}
|
||||
helperText={errors.minAmountSpent}
|
||||
label={i18n.t("Minimal order value")}
|
||||
label={minimalOrderValueText}
|
||||
name={"minAmountSpent" as keyof FormData}
|
||||
value={data.minAmountSpent}
|
||||
onChange={onChange}
|
||||
|
@ -68,7 +87,7 @@ const VoucherRequirements = ({
|
|||
disabled={disabled}
|
||||
error={!!errors.minCheckoutItemsQuantity}
|
||||
helperText={errors.minCheckoutItemsQuantity}
|
||||
label={i18n.t("Minimum quantity of items")}
|
||||
label={minimalQuantityText}
|
||||
name={"minCheckoutItemsQuantity" as keyof FormData}
|
||||
value={data.minCheckoutItemsQuantity}
|
||||
onChange={onChange}
|
||||
|
|
|
@ -2,6 +2,7 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
|
@ -11,7 +12,7 @@ import Hr from "@saleor/components/Hr";
|
|||
import Money from "@saleor/components/Money";
|
||||
import Percent from "@saleor/components/Percent";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { maybe } from "../../../misc";
|
||||
import { DiscountValueTypeEnum } from "../../../types/globalTypes";
|
||||
import { translateVoucherTypes } from "../../translations";
|
||||
|
@ -26,19 +27,25 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
|
|||
defaultCurrency,
|
||||
voucher
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const translatedVoucherTypes = translateVoucherTypes();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Summary")} />
|
||||
<CardTitle title={intl.formatMessage(commonMessages.summary)} />
|
||||
<CardContent>
|
||||
<Typography variant="caption">{i18n.t("Code")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage defaultMessage="Code" description="voucher code" />
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(() => voucher.code, <Skeleton />)}
|
||||
</Typography>
|
||||
<FormSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Applies to")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage defaultMessage="Applies to" description="voucher" />
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() => translatedVoucherTypes[voucher.type],
|
||||
|
@ -47,7 +54,12 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
|
|||
</Typography>
|
||||
<FormSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Value")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage
|
||||
defaultMessage="Value"
|
||||
description="voucher value"
|
||||
/>
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
|
@ -69,7 +81,9 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
|
|||
<Hr />
|
||||
<CardSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Start Date")}</Typography>
|
||||
<Typography variant="caption">
|
||||
{intl.formatMessage(commonMessages.startDate)}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() => (
|
||||
|
@ -80,7 +94,9 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
|
|||
</Typography>
|
||||
<FormSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("End Date")}</Typography>
|
||||
<Typography variant="caption">
|
||||
{intl.formatMessage(commonMessages.endDate)}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
|
@ -97,7 +113,12 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
|
|||
<Hr />
|
||||
<CardSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Min. Order Value")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage
|
||||
defaultMessage="Min. Order Value"
|
||||
description="voucher value requirement"
|
||||
/>
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
|
@ -111,7 +132,12 @@ const VoucherSummary: React.StatelessComponent<VoucherSummaryProps> = ({
|
|||
</Typography>
|
||||
<FormSpacer />
|
||||
|
||||
<Typography variant="caption">{i18n.t("Usage Limit")}</Typography>
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage
|
||||
defaultMessage="Usage Limit"
|
||||
description="voucher value requirement"
|
||||
/>
|
||||
</Typography>
|
||||
<Typography>
|
||||
{maybe<React.ReactNode>(
|
||||
() => (voucher.usageLimit === null ? "-" : voucher.usageLimit),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Grid from "@saleor/components/Grid";
|
||||
import RadioGroupField from "@saleor/components/RadioGroupField";
|
||||
import i18n from "../../../i18n";
|
||||
import { FormErrors } from "../../../types";
|
||||
import { DiscountValueTypeEnum } from "../../../types/globalTypes";
|
||||
import { FormData } from "../VoucherDetailsPage";
|
||||
|
@ -23,24 +23,40 @@ const VoucherTypes = ({
|
|||
errors,
|
||||
onChange
|
||||
}: VoucherTypesProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const voucherTypeChoices = [
|
||||
{
|
||||
label: i18n.t("Fixed Amount"),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Fixed Amount",
|
||||
description: "voucher discount type"
|
||||
}),
|
||||
value: DiscountValueTypeEnum.FIXED
|
||||
},
|
||||
{
|
||||
label: i18n.t("Percentage"),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Percentage",
|
||||
description: "voucher discount type"
|
||||
}),
|
||||
value: DiscountValueTypeEnum.PERCENTAGE
|
||||
},
|
||||
{
|
||||
label: i18n.t("Free Shipping"),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Free Shipping",
|
||||
description: "voucher discount type"
|
||||
}),
|
||||
value: "SHIPPING"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Discount Type")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Discount Type",
|
||||
description: "header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
<Grid variant="uniform">
|
||||
<RadioGroupField
|
||||
|
|
|
@ -2,6 +2,7 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import ControlledSwitch from "@saleor/components/ControlledSwitch";
|
||||
|
@ -9,7 +10,6 @@ import { FormSpacer } from "@saleor/components/FormSpacer";
|
|||
import Hr from "@saleor/components/Hr";
|
||||
import RadioGroupField from "@saleor/components/RadioGroupField";
|
||||
import TextFieldWithChoice from "@saleor/components/TextFieldWithChoice";
|
||||
import i18n from "../../../i18n";
|
||||
import { FormErrors } from "../../../types";
|
||||
import { DiscountValueTypeEnum } from "../../../types/globalTypes";
|
||||
import { translateVoucherTypes } from "../../translations";
|
||||
|
@ -37,6 +37,8 @@ const VoucherValue = ({
|
|||
variant,
|
||||
onChange
|
||||
}: VoucherValueProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const translatedVoucherTypes = translateVoucherTypes();
|
||||
const voucherTypeChoices = Object.values(VoucherType).map(type => ({
|
||||
label: translatedVoucherTypes[type],
|
||||
|
@ -45,7 +47,12 @@ const VoucherValue = ({
|
|||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("Value")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Value",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
<TextFieldWithChoice
|
||||
disabled={disabled}
|
||||
|
@ -61,7 +68,9 @@ const VoucherValue = ({
|
|||
helperText={errors.discountValue}
|
||||
name={"value" as keyof FormData}
|
||||
onChange={onChange}
|
||||
label={i18n.t("Discount Value")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Discount Value"
|
||||
})}
|
||||
value={data.value}
|
||||
type="number"
|
||||
fullWidth
|
||||
|
@ -77,7 +86,9 @@ const VoucherValue = ({
|
|||
disabled={disabled}
|
||||
error={!!errors.type}
|
||||
hint={errors.type}
|
||||
label={i18n.t("Discount Specific Information")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Discount Specific Information"
|
||||
})}
|
||||
name={"type" as keyof FormData}
|
||||
value={data.type}
|
||||
onChange={onChange}
|
||||
|
@ -91,13 +102,12 @@ const VoucherValue = ({
|
|||
checked={data.applyOncePerOrder}
|
||||
label={
|
||||
<>
|
||||
{i18n.t("Only once per order", {
|
||||
context: "voucher application"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Only once per order"
|
||||
description="voucher application, switch button"
|
||||
/>
|
||||
<Typography variant="caption">
|
||||
{i18n.t(
|
||||
"If this option is disabled, discount will be counted for every eligible product"
|
||||
)}
|
||||
<FormattedMessage defaultMessage="If this option is disabled, discount will be counted for every eligible product" />
|
||||
</Typography>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { parse as parseQs } from "qs";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import { Route, RouteComponentProps, Switch } from "react-router-dom";
|
||||
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { WindowTitle } from "../components/WindowTitle";
|
||||
import i18n from "../i18n";
|
||||
import { saleDetailsPageTab } from "./components/SaleDetailsPage";
|
||||
import { voucherDetailsPageTab } from "./components/VoucherDetailsPage";
|
||||
import {
|
||||
|
@ -73,9 +74,12 @@ const VoucherDetailsView: React.StatelessComponent<
|
|||
);
|
||||
};
|
||||
|
||||
export const DiscountSection: React.StatelessComponent<{}> = () => (
|
||||
export const DiscountSection: React.StatelessComponent<{}> = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Discounts")} />
|
||||
<WindowTitle title={intl.formatMessage(sectionNames.vouchers)} />
|
||||
<Switch>
|
||||
<Route exact path={saleListPath} component={SaleListView} />
|
||||
<Route exact path={saleAddPath} component={SaleCreateView} />
|
||||
|
@ -85,5 +89,6 @@ export const DiscountSection: React.StatelessComponent<{}> = () => (
|
|||
<Route path={voucherPath(":id")} component={VoucherDetailsView} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
);
|
||||
};
|
||||
export default DiscountSection;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import i18n from "../../i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { decimal, getMutationState, maybe } from "../../misc";
|
||||
import { DiscountValueTypeEnum, SaleType } from "../../types/globalTypes";
|
||||
import SaleCreatePage from "../components/SaleCreatePage";
|
||||
|
@ -22,12 +23,13 @@ export const SaleDetails: React.StatelessComponent = () => {
|
|||
const navigate = useNavigator();
|
||||
const pushMessage = useNotifier();
|
||||
const shop = useShop();
|
||||
const intl = useIntl();
|
||||
|
||||
const handleSaleCreate = (data: SaleCreate) => {
|
||||
if (data.saleCreate.errors.length === 0) {
|
||||
pushMessage({
|
||||
text: i18n.t("Successfully created sale", {
|
||||
context: "notification"
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Successfully created sale"
|
||||
})
|
||||
});
|
||||
navigate(saleUrl(data.saleCreate.sale.id), true);
|
||||
|
@ -45,7 +47,7 @@ export const SaleDetails: React.StatelessComponent = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Sales")} />
|
||||
<WindowTitle title={intl.formatMessage(sectionNames.sales)} />
|
||||
<SaleCreatePage
|
||||
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
||||
disabled={saleCreateOpts.loading}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog";
|
||||
|
@ -14,13 +15,13 @@ import usePaginator, {
|
|||
createPaginationState
|
||||
} from "@saleor/hooks/usePaginator";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { categoryUrl } from "../../categories/urls";
|
||||
import { collectionUrl } from "../../collections/urls";
|
||||
import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config";
|
||||
import SearchCategories from "../../containers/SearchCategories";
|
||||
import SearchCollections from "../../containers/SearchCollections";
|
||||
import SearchProducts from "../../containers/SearchProducts";
|
||||
import i18n from "../../i18n";
|
||||
import { decimal, getMutationState, maybe } from "../../misc";
|
||||
import { productUrl } from "../../products/urls";
|
||||
import { DiscountValueTypeEnum, SaleType } from "../../types/globalTypes";
|
||||
|
@ -67,6 +68,7 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
||||
params.ids
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const paginationState = createPaginationState(PAGINATE_BY, params);
|
||||
const changeTab = (tab: SaleDetailsPageTab) => {
|
||||
|
@ -81,8 +83,8 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
const handleSaleDelete = (data: SaleDelete) => {
|
||||
if (data.saleDelete.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Removed sale", {
|
||||
context: "notification"
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Removed sale"
|
||||
})
|
||||
});
|
||||
navigate(saleListUrl(), true);
|
||||
|
@ -92,9 +94,7 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
const handleSaleUpdate = (data: SaleUpdate) => {
|
||||
if (data.saleUpdate.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Updated sale", {
|
||||
context: "notification"
|
||||
})
|
||||
text: intl.formatMessage(commonMessages.savedChanges)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -131,6 +131,8 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
||||
|
||||
return (
|
||||
<TypedSaleCataloguesRemove onCompleted={handleCatalogueRemove}>
|
||||
{(saleCataloguesRemove, saleCataloguesRemoveOpts) => (
|
||||
|
@ -222,7 +224,9 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Sales")} />
|
||||
<WindowTitle
|
||||
title={intl.formatMessage(sectionNames.sales)}
|
||||
/>
|
||||
<SaleDetailsPage
|
||||
defaultCurrency={maybe(
|
||||
() => shop.defaultCurrency
|
||||
|
@ -295,7 +299,11 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
openModal("unassign-category", listElements)
|
||||
}
|
||||
>
|
||||
{i18n.t("Unassign")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Unassign"
|
||||
description="unassign category from sale, button"
|
||||
id="saleDetailsUnassignCategory"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
collectionListToolbar={
|
||||
|
@ -308,7 +316,11 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
)
|
||||
}
|
||||
>
|
||||
{i18n.t("Unassign")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Unassign"
|
||||
description="unassign collection from sale, button"
|
||||
id="saleDetailsUnassignCollection"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
productListToolbar={
|
||||
|
@ -318,7 +330,11 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
openModal("unassign-product", listElements)
|
||||
}
|
||||
>
|
||||
{i18n.t("Unassign")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Unassign"
|
||||
description="unassign product from sale, button"
|
||||
id="saleDetailsUnassignProduct"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
isChecked={isSelected}
|
||||
|
@ -437,77 +453,111 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
)}
|
||||
</SearchCollections>
|
||||
<ActionDialog
|
||||
open={params.action === "unassign-category"}
|
||||
title={i18n.t("Unassign Categories From Sale")}
|
||||
open={
|
||||
params.action === "unassign-category" &&
|
||||
canOpenBulkActionDialog
|
||||
}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Unassign Categories From Sale",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={unassignTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={() =>
|
||||
handleCategoriesUnassign(params.ids)
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to unassign <strong>{{ saleName }}</strong> categories?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to unassign {counter, plural,
|
||||
one {this category}
|
||||
other {{displayQuantity} categories}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "unassign-collection"}
|
||||
title={i18n.t("Unassign Collections From Sale")}
|
||||
open={
|
||||
params.action === "unassign-collection" &&
|
||||
canOpenBulkActionDialog
|
||||
}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Unassign Collections From Sale",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={unassignTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={() =>
|
||||
handleCollectionsUnassign(params.ids)
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to unassign <strong>{{ saleName }}</strong> collections?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to unassign {counter, plural,
|
||||
one {this collection}
|
||||
other {{displayQuantity} collections}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "unassign-product"}
|
||||
title={i18n.t("Unassign Products From Sale")}
|
||||
open={
|
||||
params.action === "unassign-product" &&
|
||||
canOpenBulkActionDialog
|
||||
}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Unassign Products From Sale",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={unassignTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={() =>
|
||||
handleProductsUnassign(params.ids)
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to unassign <strong>{{ saleName }}</strong> products?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to unassign {counter, plural,
|
||||
one {this product}
|
||||
other {{displayQuantity} products}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "remove"}
|
||||
title={i18n.t("Remove Sale")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete Sale",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={removeTransitionState}
|
||||
onClose={closeModal}
|
||||
variant="delete"
|
||||
|
@ -517,19 +567,19 @@ export const SaleDetails: React.StatelessComponent<SaleDetailsProps> = ({
|
|||
})
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ saleName }}</strong>?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => data.sale.name,
|
||||
"..."
|
||||
)
|
||||
}
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete {saleName}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
saleName: (
|
||||
<strong>
|
||||
{maybe(() => data.sale.name, "...")}
|
||||
</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText";
|
|||
import IconButton from "@material-ui/core/IconButton";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||
|
@ -13,7 +14,7 @@ import usePaginator, {
|
|||
createPaginationState
|
||||
} from "@saleor/hooks/usePaginator";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { getMutationState, maybe } from "@saleor/misc";
|
||||
import { ListViews } from "@saleor/types";
|
||||
import SaleListPage from "../components/SaleListPage";
|
||||
|
@ -44,10 +45,12 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
|||
const { updateListSettings, settings } = useListSettings(
|
||||
ListViews.SALES_LIST
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const closeModal = () => navigate(saleListUrl(), true);
|
||||
|
||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
||||
|
||||
return (
|
||||
<TypedSaleList displayLoader variables={paginationState}>
|
||||
|
@ -61,7 +64,7 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
|||
const handleSaleBulkDelete = (data: SaleBulkDelete) => {
|
||||
if (data.saleBulkDelete.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Removed sales")
|
||||
text: intl.formatMessage(commonMessages.savedChanges)
|
||||
});
|
||||
reset();
|
||||
closeModal();
|
||||
|
@ -86,7 +89,7 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Sales")} />
|
||||
<WindowTitle title={intl.formatMessage(sectionNames.sales)} />
|
||||
<SaleListPage
|
||||
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
||||
sales={maybe(() => data.sales.edges.map(edge => edge.node))}
|
||||
|
@ -122,23 +125,30 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
|||
confirmButtonState={bulkRemoveTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={onSaleBulkDelete}
|
||||
open={params.action === "remove"}
|
||||
title={i18n.t("Remove Sales")}
|
||||
open={params.action === "remove" && canOpenBulkActionDialog}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete Sales",
|
||||
description: "dialog header"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ number }}</strong> sales?",
|
||||
{
|
||||
number: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete {counter, plural,
|
||||
one {this sale}
|
||||
other {{displayQuantity} sales}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import i18n from "../../i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { decimal, getMutationState, joinDateTime, maybe } from "../../misc";
|
||||
import {
|
||||
DiscountValueTypeEnum,
|
||||
|
@ -20,12 +21,13 @@ export const VoucherDetails: React.StatelessComponent = () => {
|
|||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const shop = useShop();
|
||||
const intl = useIntl();
|
||||
|
||||
const handleVoucherCreate = (data: VoucherCreate) => {
|
||||
if (data.voucherCreate.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Successfully created voucher", {
|
||||
context: "notification"
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Successfully created voucher"
|
||||
})
|
||||
});
|
||||
navigate(voucherUrl(data.voucherCreate.voucher.id), true);
|
||||
|
@ -43,7 +45,7 @@ export const VoucherDetails: React.StatelessComponent = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Vouchers")} />
|
||||
<WindowTitle title={intl.formatMessage(sectionNames.vouchers)} />
|
||||
<VoucherCreatePage
|
||||
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
||||
disabled={voucherCreateOpts.loading}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog";
|
||||
|
@ -14,13 +15,13 @@ import usePaginator, {
|
|||
createPaginationState
|
||||
} from "@saleor/hooks/usePaginator";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { categoryUrl } from "../../categories/urls";
|
||||
import { collectionUrl } from "../../collections/urls";
|
||||
import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "../../config";
|
||||
import SearchCategories from "../../containers/SearchCategories";
|
||||
import SearchCollections from "../../containers/SearchCollections";
|
||||
import SearchProducts from "../../containers/SearchProducts";
|
||||
import i18n from "../../i18n";
|
||||
import { decimal, getMutationState, joinDateTime, maybe } from "../../misc";
|
||||
import { productUrl } from "../../products/urls";
|
||||
import {
|
||||
|
@ -66,6 +67,7 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
||||
params.ids
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const paginationState = createPaginationState(PAGINATE_BY, params);
|
||||
const changeTab = (tab: VoucherDetailsPageTab) => {
|
||||
|
@ -80,8 +82,8 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
const handleVoucherDelete = (data: VoucherDelete) => {
|
||||
if (data.voucherDelete.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Removed voucher", {
|
||||
context: "notification"
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Deleted voucher"
|
||||
})
|
||||
});
|
||||
navigate(voucherListUrl(), true);
|
||||
|
@ -92,9 +94,7 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
if (data.voucherUpdate.errors.length === 0) {
|
||||
closeModal();
|
||||
notify({
|
||||
text: i18n.t("Updated voucher", {
|
||||
context: "notification"
|
||||
})
|
||||
text: intl.formatMessage(commonMessages.savedChanges)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -130,6 +130,8 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
||||
|
||||
return (
|
||||
<TypedVoucherCataloguesRemove onCompleted={handleCatalogueRemove}>
|
||||
{(voucherCataloguesRemove, voucherCataloguesRemoveOpts) => (
|
||||
|
@ -225,7 +227,9 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Vouchers")} />
|
||||
<WindowTitle
|
||||
title={intl.formatMessage(sectionNames.vouchers)}
|
||||
/>
|
||||
<VoucherDetailsPage
|
||||
defaultCurrency={maybe(
|
||||
() => shop.defaultCurrency
|
||||
|
@ -374,7 +378,11 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
openModal("unassign-category", listElements)
|
||||
}
|
||||
>
|
||||
{i18n.t("Unassign")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Unassign"
|
||||
description="unassign category from voucher, button"
|
||||
id="voucherDetailsUnassignCategory"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
collectionListToolbar={
|
||||
|
@ -387,7 +395,11 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
)
|
||||
}
|
||||
>
|
||||
{i18n.t("Unassign")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Unassign"
|
||||
description="unassign collection from voucher, button"
|
||||
id="voucherDetailsUnassignCollection"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
productListToolbar={
|
||||
|
@ -397,7 +409,11 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
openModal("unassign-product", listElements)
|
||||
}
|
||||
>
|
||||
{i18n.t("Unassign")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Unassign"
|
||||
description="unassign product from voucher, button"
|
||||
id="voucherDetailsUnassignProduct"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
isChecked={isSelected}
|
||||
|
@ -539,77 +555,113 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
)}
|
||||
</SearchProducts>
|
||||
<ActionDialog
|
||||
open={params.action === "unassign-category"}
|
||||
title={i18n.t("Unassign Categories From Sale")}
|
||||
open={
|
||||
params.action === "unassign-category" &&
|
||||
canOpenBulkActionDialog
|
||||
}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Unassign Categories From Voucher",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={unassignTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={() =>
|
||||
handleCategoriesUnassign(params.ids)
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to unassign <strong>{{ saleName }}</strong> categories?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to unassign {counter, plural,
|
||||
one {this category}
|
||||
other {{displayQuantity} categories}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "unassign-collection"}
|
||||
title={i18n.t("Unassign Collections From Sale")}
|
||||
open={
|
||||
params.action === "unassign-collection" &&
|
||||
canOpenBulkActionDialog
|
||||
}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Unassign Collections From Voucher",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={unassignTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={() =>
|
||||
handleCollectionsUnassign(params.ids)
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to unassign <strong>{{ saleName }}</strong> collections?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to unassign {counter, plural,
|
||||
one {this collection}
|
||||
other {{displayQuantity} collections}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "unassign-product"}
|
||||
title={i18n.t("Unassign Products From Sale")}
|
||||
open={
|
||||
params.action === "unassign-product" &&
|
||||
canOpenBulkActionDialog
|
||||
}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Unassign Products From Voucher",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={unassignTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={() =>
|
||||
handleProductsUnassign(params.ids)
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to unassign <strong>{{ saleName }}</strong> products?",
|
||||
{
|
||||
saleName: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to unassign {counter, plural,
|
||||
one {this product}
|
||||
other {{displayQuantity} products}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "remove"}
|
||||
title={i18n.t("Remove Voucher")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete Voucher",
|
||||
description: "dialog header"
|
||||
})}
|
||||
confirmButtonState={removeTransitionState}
|
||||
onClose={closeModal}
|
||||
variant="delete"
|
||||
|
@ -619,19 +671,19 @@ export const VoucherDetails: React.StatelessComponent<VoucherDetailsProps> = ({
|
|||
})
|
||||
}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ voucherCode }}</strong>?",
|
||||
{
|
||||
voucherCode: maybe(
|
||||
() => data.voucher.code,
|
||||
"..."
|
||||
)
|
||||
}
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete {voucherCode}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
voucherCode: (
|
||||
<strong>
|
||||
{maybe(() => data.voucher.code, "...")}
|
||||
</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@ import DialogContentText from "@material-ui/core/DialogContentText";
|
|||
import IconButton from "@material-ui/core/IconButton";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||
|
@ -13,7 +14,7 @@ import usePaginator, {
|
|||
createPaginationState
|
||||
} from "@saleor/hooks/usePaginator";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { getMutationState, maybe } from "@saleor/misc";
|
||||
import { ListViews } from "@saleor/types";
|
||||
import VoucherListPage from "../components/VoucherListPage";
|
||||
|
@ -44,10 +45,12 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
|||
const { updateListSettings, settings } = useListSettings(
|
||||
ListViews.VOUCHER_LIST
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const closeModal = () => navigate(voucherListUrl(), true);
|
||||
|
||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
||||
|
||||
return (
|
||||
<TypedVoucherList displayLoader variables={paginationState}>
|
||||
|
@ -61,7 +64,7 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
|||
const handleVoucherBulkDelete = (data: VoucherBulkDelete) => {
|
||||
if (data.voucherBulkDelete.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Removed vouchers")
|
||||
text: intl.formatMessage(commonMessages.savedChanges)
|
||||
});
|
||||
reset();
|
||||
closeModal();
|
||||
|
@ -85,7 +88,9 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
|||
});
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Vouchers")} />
|
||||
<WindowTitle
|
||||
title={intl.formatMessage(sectionNames.vouchers)}
|
||||
/>
|
||||
<VoucherListPage
|
||||
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
||||
settings={settings}
|
||||
|
@ -123,23 +128,30 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
|||
confirmButtonState={bulkRemoveTransitionState}
|
||||
onClose={closeModal}
|
||||
onConfirm={onVoucherBulkDelete}
|
||||
open={params.action === "remove"}
|
||||
title={i18n.t("Remove Vouchers")}
|
||||
open={params.action === "remove" && canOpenBulkActionDialog}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete Vouchers",
|
||||
description: "dialog header"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ number }}</strong> vouchers?",
|
||||
{
|
||||
number: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{canOpenBulkActionDialog && (
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete {counter, plural,
|
||||
one {this voucher}
|
||||
other {{displayQuantity} vouchers}
|
||||
}?"
|
||||
description="dialog content"
|
||||
values={{
|
||||
counter: params.ids.length,
|
||||
displayQuantity: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
)}
|
||||
</ActionDialog>
|
||||
</>
|
||||
);
|
||||
|
|
23
src/intl.ts
23
src/intl.ts
|
@ -13,6 +13,12 @@ export const commonMessages = defineMessages({
|
|||
email: {
|
||||
defaultMessage: "E-mail Address"
|
||||
},
|
||||
endDate: {
|
||||
defaultMessage: "End Date"
|
||||
},
|
||||
endHour: {
|
||||
defaultMessage: "End Hour"
|
||||
},
|
||||
firstName: {
|
||||
defaultMessage: "First Name"
|
||||
},
|
||||
|
@ -28,6 +34,15 @@ export const commonMessages = defineMessages({
|
|||
savedChanges: {
|
||||
defaultMessage: "Saved changes"
|
||||
},
|
||||
startDate: {
|
||||
defaultMessage: "Start Date"
|
||||
},
|
||||
startHour: {
|
||||
defaultMessage: "Start Hour"
|
||||
},
|
||||
summary: {
|
||||
defaultMessage: "Summary"
|
||||
},
|
||||
uploadImage: {
|
||||
defaultMessage: "Upload image",
|
||||
description: "button"
|
||||
|
@ -94,6 +109,10 @@ export const sectionNames = defineMessages({
|
|||
defaultMessage: "Product Types",
|
||||
description: "product types section name"
|
||||
},
|
||||
sales: {
|
||||
defaultMessage: "Sales",
|
||||
description: "sales section name"
|
||||
},
|
||||
shipping: {
|
||||
defaultMessage: "Shipping Methods",
|
||||
description: "shipping section name"
|
||||
|
@ -109,5 +128,9 @@ export const sectionNames = defineMessages({
|
|||
taxes: {
|
||||
defaultMessage: "Taxes",
|
||||
description: "taxes section name"
|
||||
},
|
||||
vouchers: {
|
||||
defaultMessage: "Vouchers",
|
||||
description: "vouchers section name"
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue