Use react-intl
This commit is contained in:
parent
fe57528820
commit
77da4694ac
13 changed files with 655 additions and 486 deletions
|
@ -1,10 +1,6 @@
|
|||
import {
|
||||
createStyles,
|
||||
Theme,
|
||||
withStyles,
|
||||
WithStyles
|
||||
} from "@material-ui/core/styles";
|
||||
import { Theme } from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import makeStyles from "@material-ui/styles/makeStyles";
|
||||
import React from "react";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
|
@ -15,12 +11,12 @@ import Hr from "@saleor/components/Hr";
|
|||
import ImageTile from "@saleor/components/ImageTile";
|
||||
import ImageUpload from "@saleor/components/ImageUpload";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { CategoryDetails_category_backgroundImage } from "../../types/CategoryDetails";
|
||||
import { FormData } from "../CategoryUpdatePage";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
fileField: {
|
||||
display: "none"
|
||||
},
|
||||
|
@ -41,9 +37,9 @@ const styles = (theme: Theme) =>
|
|||
position: "relative",
|
||||
width: 148
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
export interface CategoryBackgroundProps extends WithStyles<typeof styles> {
|
||||
export interface CategoryBackgroundProps {
|
||||
data: FormData;
|
||||
image: CategoryDetails_category_backgroundImage;
|
||||
onChange: (event: React.ChangeEvent<any>) => void;
|
||||
|
@ -51,43 +47,38 @@ export interface CategoryBackgroundProps extends WithStyles<typeof styles> {
|
|||
onImageUpload: (file: File) => void;
|
||||
}
|
||||
|
||||
export const CategoryBackground = withStyles(styles)(
|
||||
class CategoryBackgroundComponent extends React.Component<
|
||||
CategoryBackgroundProps,
|
||||
{}
|
||||
> {
|
||||
imgInputAnchor = React.createRef<HTMLInputElement>();
|
||||
const CategoryBackground: React.FC<CategoryBackgroundProps> = props => {
|
||||
const classes = useStyles(props);
|
||||
const intl = useIntl();
|
||||
const anchor = React.useRef<HTMLInputElement>();
|
||||
|
||||
clickImgInput = () => this.imgInputAnchor.current.click();
|
||||
const { data, onImageUpload, image, onChange, onImageDelete } = props;
|
||||
|
||||
const handleImageUploadButtonClick = () => anchor.current.click();
|
||||
|
||||
render() {
|
||||
const {
|
||||
classes,
|
||||
data,
|
||||
onImageUpload,
|
||||
image,
|
||||
onChange,
|
||||
onImageDelete
|
||||
} = this.props;
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Background image (optional)")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Background image (optional)",
|
||||
description: "section header",
|
||||
id: "categoryBackgroundHeader"
|
||||
})}
|
||||
toolbar={
|
||||
<>
|
||||
<Button
|
||||
variant="text"
|
||||
color="primary"
|
||||
onClick={this.clickImgInput}
|
||||
onClick={handleImageUploadButtonClick}
|
||||
>
|
||||
{i18n.t("Upload image")}
|
||||
<FormattedMessage {...commonMessages.uploadImage} />
|
||||
</Button>
|
||||
<input
|
||||
className={classes.fileField}
|
||||
id="fileUpload"
|
||||
onChange={event => onImageUpload(event.target.files[0])}
|
||||
type="file"
|
||||
ref={this.imgInputAnchor}
|
||||
ref={anchor}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
|
@ -114,8 +105,8 @@ export const CategoryBackground = withStyles(styles)(
|
|||
<CardContent>
|
||||
<TextField
|
||||
name="backgroundImageAlt"
|
||||
label={i18n.t("Description")}
|
||||
helperText={i18n.t("Optional")}
|
||||
label={intl.formatMessage(commonMessages.description)}
|
||||
helperText={intl.formatMessage(commonMessages.optionalField)}
|
||||
value={data.backgroundImageAlt}
|
||||
onChange={onChange}
|
||||
fullWidth
|
||||
|
@ -126,8 +117,6 @@ export const CategoryBackground = withStyles(styles)(
|
|||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
CategoryBackground.displayName = "CategoryBackground";
|
||||
export default CategoryBackground;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ContentState, convertToRaw, RawDraftContentState } from "draft-js";
|
||||
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 Form from "@saleor/components/Form";
|
|||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import SeoForm from "@saleor/components/SeoForm";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { UserError } from "../../../types";
|
||||
import CategoryDetailsForm from "../../components/CategoryDetailsForm";
|
||||
|
||||
|
@ -43,7 +44,9 @@ export const CategoryCreatePage: React.StatelessComponent<
|
|||
onBack,
|
||||
errors: userErrors,
|
||||
saveButtonBarState
|
||||
}) => (
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Form
|
||||
onSubmit={onSubmit}
|
||||
initial={initialData}
|
||||
|
@ -52,8 +55,16 @@ export const CategoryCreatePage: React.StatelessComponent<
|
|||
>
|
||||
{({ data, change, errors, submit, hasChanged }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Categories")}</AppHeader>
|
||||
<PageHeader title={i18n.t("Add Category")} />
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.categories)}
|
||||
</AppHeader>
|
||||
<PageHeader
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Create New Category",
|
||||
description: "page header",
|
||||
id: "categoryCreatePageHeader"
|
||||
})}
|
||||
/>
|
||||
<div>
|
||||
<CategoryDetailsForm
|
||||
disabled={disabled}
|
||||
|
@ -63,9 +74,11 @@ export const CategoryCreatePage: React.StatelessComponent<
|
|||
/>
|
||||
<CardSpacer />
|
||||
<SeoForm
|
||||
helperText={i18n.t(
|
||||
"Add search engine title and description to make this product easier to find"
|
||||
)}
|
||||
helperText={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Add search engine title and description to make this category easier to find",
|
||||
id: "categoryCreatePageSeo"
|
||||
})}
|
||||
title={data.seoTitle}
|
||||
titlePlaceholder={data.name}
|
||||
description={data.seoDescription}
|
||||
|
@ -77,9 +90,6 @@ export const CategoryCreatePage: React.StatelessComponent<
|
|||
<SaveButtonBar
|
||||
onCancel={onBack}
|
||||
onSave={submit}
|
||||
labels={{
|
||||
save: i18n.t("Save category")
|
||||
}}
|
||||
state={saveButtonBarState}
|
||||
disabled={disabled || !hasChanged}
|
||||
/>
|
||||
|
@ -88,5 +98,6 @@ export const CategoryCreatePage: React.StatelessComponent<
|
|||
)}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
CategoryCreatePage.displayName = "CategoryCreatePage";
|
||||
export default CategoryCreatePage;
|
||||
|
|
|
@ -11,8 +11,9 @@ import {
|
|||
WithStyles
|
||||
} from "@material-ui/core/styles";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
|
@ -36,27 +37,35 @@ const CategoryDeleteDialog = withStyles(styles, {
|
|||
name: "CategoryDeleteDialog"
|
||||
})(({ classes, name, open, onConfirm, onClose }: CategoryDeleteDialogProps) => (
|
||||
<Dialog onClose={onClose} open={open}>
|
||||
<DialogTitle>{i18n.t("Delete category", { context: "title" })}</DialogTitle>
|
||||
<DialogTitle>
|
||||
<FormattedMessage
|
||||
defaultMessage="Delete category"
|
||||
description="dialog title"
|
||||
id="categoryDeleteDialogTitle"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{name}}</strong>?",
|
||||
{ name }
|
||||
)
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {name}?"
|
||||
description="delete category"
|
||||
id="<categoryDeleteDialogContent<"
|
||||
values={{
|
||||
name: <strong>{name}</strong>
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose}>
|
||||
{i18n.t("Cancel", { context: "button" })}
|
||||
<FormattedMessage {...commonMessages.cancel} />
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.deleteButton}
|
||||
variant="contained"
|
||||
onClick={onConfirm}
|
||||
>
|
||||
{i18n.t("Delete category", { context: "button" })}
|
||||
<FormattedMessage {...commonMessages.save} />
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
|
|
@ -4,11 +4,12 @@ import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
|||
import TextField from "@material-ui/core/TextField";
|
||||
import { RawDraftContentState } from "draft-js";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import RichTextEditor from "@saleor/components/RichTextEditor";
|
||||
import i18n from "../../../i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { maybe } from "../../../misc";
|
||||
import { CategoryDetails_category } from "../../types/CategoryDetails";
|
||||
|
||||
|
@ -40,15 +41,23 @@ export const CategoryDetailsForm = withStyles(styles, {
|
|||
onChange,
|
||||
errors
|
||||
}: CategoryDetailsFormProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("General information")} />
|
||||
<CardTitle
|
||||
title={intl.formatMessage(commonMessages.generalInformations)}
|
||||
/>
|
||||
<CardContent>
|
||||
<>
|
||||
<div>
|
||||
<TextField
|
||||
classes={{ root: classes.root }}
|
||||
label={i18n.t("Name")}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Name",
|
||||
description: "category name",
|
||||
id: "categoryDetailsFormNameInputLabel"
|
||||
})}
|
||||
name="name"
|
||||
disabled={disabled}
|
||||
value={data && data.name}
|
||||
|
@ -62,7 +71,7 @@ export const CategoryDetailsForm = withStyles(styles, {
|
|||
disabled={disabled}
|
||||
error={!!errors.descriptionJson}
|
||||
helperText={errors.descriptionJson}
|
||||
label={i18n.t("Description")}
|
||||
label={intl.formatMessage(commonMessages.description)}
|
||||
initial={maybe(() => JSON.parse(category.descriptionJson))}
|
||||
name="description"
|
||||
onChange={onChange}
|
||||
|
|
|
@ -12,13 +12,13 @@ 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, 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 "@saleor/i18n";
|
||||
import { renderCollection } from "@saleor/misc";
|
||||
import { ListActions, ListProps } from "@saleor/types";
|
||||
|
||||
|
@ -87,14 +87,25 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
|||
onPreviousPage,
|
||||
onUpdateListSettings,
|
||||
onRowClick
|
||||
}: CategoryListProps) => (
|
||||
}: CategoryListProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{!isRoot && (
|
||||
<CardTitle
|
||||
title={i18n.t("All Subcategories")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "All Subcategories",
|
||||
description: "section header",
|
||||
id: "categoryListSubcategoriesSectionHeader"
|
||||
})}
|
||||
toolbar={
|
||||
<Button color="primary" variant="text" onClick={onAdd}>
|
||||
{i18n.t("Add subcategory")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Add subcategory"
|
||||
description="button"
|
||||
id="categoryListAddSubcategoryButton"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
@ -109,13 +120,25 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
|||
toolbar={toolbar}
|
||||
>
|
||||
<TableCell className={classes.colName}>
|
||||
{i18n.t("Category Name", { context: "object" })}
|
||||
<FormattedMessage
|
||||
defaultMessage="Category Name"
|
||||
description="category list: name column header"
|
||||
id="categoryListNameColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colSubcategories}>
|
||||
{i18n.t("Subcategories", { context: "object" })}
|
||||
<FormattedMessage
|
||||
defaultMessage="Subcategories"
|
||||
description="category list: subcategories column header"
|
||||
id="categoryListSubcategoriesColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colProducts}>
|
||||
{i18n.t("No. Products", { context: "object" }).replace(" ", "\xa0")}
|
||||
<FormattedMessage
|
||||
defaultMessage="No. Products"
|
||||
description="category list: number of products column header"
|
||||
id="categoryListNumberOfProductsColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableHead>
|
||||
<TableFooter>
|
||||
|
@ -123,7 +146,9 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
|||
<TablePagination
|
||||
colSpan={numberOfColumns}
|
||||
settings={settings}
|
||||
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||
hasNextPage={
|
||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
||||
}
|
||||
onNextPage={onNextPage}
|
||||
onUpdateListSettings={onUpdateListSettings}
|
||||
hasPreviousPage={
|
||||
|
@ -182,9 +207,17 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{isRoot
|
||||
? i18n.t("No categories found")
|
||||
: i18n.t("No subcategories found")}
|
||||
{isRoot ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="No categories found"
|
||||
id="categoryListNoCategories"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="No subcategories found"
|
||||
id="categoryListNoSubcategories"
|
||||
/>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
@ -192,7 +225,8 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
|||
</TableBody>
|
||||
</Table>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
CategoryList.displayName = "CategoryList";
|
||||
export default CategoryList;
|
||||
|
|
|
@ -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 CategoryList from "../CategoryList";
|
||||
|
||||
|
@ -36,11 +37,18 @@ export const CategoryListPage: React.StatelessComponent<CategoryTableProps> = ({
|
|||
toggle,
|
||||
toggleAll,
|
||||
toolbar
|
||||
}) => (
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Container>
|
||||
<PageHeader title={i18n.t("Categories")}>
|
||||
<PageHeader title={intl.formatMessage(sectionNames.categories)}>
|
||||
<Button color="primary" variant="contained" onClick={onAdd}>
|
||||
{i18n.t("Add category")} <AddIcon />
|
||||
<FormattedMessage
|
||||
defaultMessage="Add category"
|
||||
description="button"
|
||||
id="categoryListPageAddCategoryButton"
|
||||
/>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
</PageHeader>
|
||||
<CategoryList
|
||||
|
@ -62,5 +70,6 @@ export const CategoryListPage: React.StatelessComponent<CategoryTableProps> = ({
|
|||
/>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
CategoryListPage.displayName = "CategoryListPage";
|
||||
export default CategoryListPage;
|
||||
|
|
|
@ -13,13 +13,13 @@ import TableFooter from "@material-ui/core/TableFooter";
|
|||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import i18n from "../../../i18n";
|
||||
import { maybe, renderCollection } from "../../../misc";
|
||||
import { maybe, renderCollection } from "@saleor/misc";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
|
@ -61,13 +61,24 @@ export const ProductList = withStyles(styles, { name: "ProductList" })(
|
|||
onNextPage,
|
||||
onPreviousPage,
|
||||
onRowClick
|
||||
}: ProductListProps) => (
|
||||
}: ProductListProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Products")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Products",
|
||||
description: "section header",
|
||||
id: "categoryProductsHeader"
|
||||
})}
|
||||
toolbar={
|
||||
<Button variant="text" color="primary" onClick={onAddProduct}>
|
||||
{i18n.t("Add product")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Add product"
|
||||
description="button"
|
||||
id="categoryProductsAddProductButton"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
@ -76,9 +87,19 @@ export const ProductList = withStyles(styles, { name: "ProductList" })(
|
|||
<TableRow>
|
||||
{(products === undefined || products.length > 0) && <TableCell />}
|
||||
<TableCell className={classes.textLeft}>
|
||||
{i18n.t("Name", { context: "object" })}
|
||||
<FormattedMessage
|
||||
defaultMessage="Name"
|
||||
description="product list: product name column header"
|
||||
id="categoryProductsNameHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage
|
||||
defaultMessage="Type"
|
||||
description="product list: product type column header"
|
||||
id="categoryProductsTypeHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{i18n.t("Type", { context: "object" })}</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableFooter>
|
||||
|
@ -123,14 +144,20 @@ export const ProductList = withStyles(styles, { name: "ProductList" })(
|
|||
),
|
||||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={3}>{i18n.t("No products found")}</TableCell>
|
||||
<TableCell colSpan={3}>
|
||||
<FormattedMessage
|
||||
defaultMessage="No products found"
|
||||
id="categoryProductsNoProducts"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
ProductList.displayName = "CategoryProductList";
|
||||
export default ProductList;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import ProductList from "@saleor/components/ProductList";
|
||||
import i18n from "../../../i18n";
|
||||
import { ListActions, PageListProps } from "../../../types";
|
||||
import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails";
|
||||
|
||||
|
@ -29,13 +29,28 @@ export const CategoryProductsCard: React.StatelessComponent<
|
|||
toggle,
|
||||
toggleAll,
|
||||
toolbar
|
||||
}) => (
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Products in {{ categoryName }}", { categoryName })}
|
||||
title={intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Products in {name}",
|
||||
description: "products in category section header",
|
||||
id: "categoryProductsCardHeader"
|
||||
},
|
||||
{
|
||||
name: categoryName
|
||||
}
|
||||
)}
|
||||
toolbar={
|
||||
<Button color="primary" variant="text" onClick={onAdd}>
|
||||
{i18n.t("Add product")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Add product"
|
||||
description="button"
|
||||
id="categoryProductsCardAddProductButton"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
@ -58,6 +73,7 @@ export const CategoryProductsCard: React.StatelessComponent<
|
|||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
CategoryProductsCard.displayName = "CategoryProductsCard";
|
||||
export default CategoryProductsCard;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { RawDraftContentState } from "draft-js";
|
||||
import React from "react";
|
||||
import { useIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import { CardSpacer } from "@saleor/components/CardSpacer";
|
||||
|
@ -10,7 +11,6 @@ import PageHeader from "@saleor/components/PageHeader";
|
|||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import SeoForm from "@saleor/components/SeoForm";
|
||||
import { Tab, TabContainer } from "@saleor/components/Tab";
|
||||
import i18n from "../../../i18n";
|
||||
import { maybe } from "../../../misc";
|
||||
import { TabListActions, UserError } from "../../../types";
|
||||
import CategoryDetailsForm from "../../components/CategoryDetailsForm";
|
||||
|
@ -96,6 +96,7 @@ export const CategoryUpdatePage: React.StatelessComponent<
|
|||
toggle,
|
||||
toggleAll
|
||||
}: CategoryUpdatePageProps) => {
|
||||
const intl = useIntl();
|
||||
const initialData: FormData = category
|
||||
? {
|
||||
backgroundImageAlt: maybe(() => category.backgroundImage.alt, ""),
|
||||
|
@ -139,9 +140,11 @@ export const CategoryUpdatePage: React.StatelessComponent<
|
|||
/>
|
||||
<CardSpacer />
|
||||
<SeoForm
|
||||
helperText={i18n.t(
|
||||
"Add search engine title and description to make this category easier to find"
|
||||
)}
|
||||
helperText={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Add search engine title and description to make this category easier to find",
|
||||
id: "categoryUpdatePageSeo"
|
||||
})}
|
||||
title={data.seoTitle}
|
||||
titlePlaceholder={data.name}
|
||||
description={data.seoDescription}
|
||||
|
@ -156,13 +159,21 @@ export const CategoryUpdatePage: React.StatelessComponent<
|
|||
isActive={currentTab === CategoryPageTab.categories}
|
||||
changeTab={changeTab}
|
||||
>
|
||||
{i18n.t("Subcategories")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Subcategories"
|
||||
description="category list: number of subcategories column header"
|
||||
id="categoryUpdatePageSubcategoriesColumnHeader"
|
||||
/>
|
||||
</CategoriesTab>
|
||||
<ProductsTab
|
||||
isActive={currentTab === CategoryPageTab.products}
|
||||
changeTab={changeTab}
|
||||
>
|
||||
{i18n.t("Products")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Products"
|
||||
description="category list: number of products column header"
|
||||
id="categoryUpdatePageProductsColumnHeader"
|
||||
/>
|
||||
</ProductsTab>
|
||||
</TabContainer>
|
||||
<CardSpacer />
|
||||
|
@ -204,9 +215,6 @@ export const CategoryUpdatePage: React.StatelessComponent<
|
|||
onCancel={onBack}
|
||||
onDelete={onDelete}
|
||||
onSave={submit}
|
||||
labels={{
|
||||
delete: i18n.t("Delete category")
|
||||
}}
|
||||
state={saveButtonBarState}
|
||||
disabled={disabled || !hasChanged}
|
||||
/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 i18n from "../../i18n";
|
||||
import { getMutationState, maybe } from "../../misc";
|
||||
import CategoryCreatePage from "../components/CategoryCreatePage";
|
||||
import { TypedCategoryCreateMutation } from "../mutations";
|
||||
|
@ -19,10 +19,16 @@ export const CategoryCreateView: React.StatelessComponent<
|
|||
> = ({ parentId }) => {
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
const handleSuccess = (data: CategoryCreate) => {
|
||||
if (data.categoryCreate.errors.length === 0) {
|
||||
notify({ text: i18n.t("Category created") });
|
||||
notify({
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Category created",
|
||||
id: "categoryCreateCategoryCreated"
|
||||
})
|
||||
});
|
||||
navigate(categoryUrl(data.categoryCreate.category.id));
|
||||
}
|
||||
};
|
||||
|
@ -42,7 +48,13 @@ export const CategoryCreateView: React.StatelessComponent<
|
|||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Create category")} />
|
||||
<WindowTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Create category",
|
||||
description: "window title",
|
||||
id: "categoryCreateWindowTitle"
|
||||
})}
|
||||
/>
|
||||
<CategoryCreatePage
|
||||
saveButtonBarState={formTransitionState}
|
||||
errors={errors}
|
||||
|
|
|
@ -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";
|
||||
|
@ -12,7 +13,6 @@ import usePaginator, {
|
|||
createPaginationState
|
||||
} from "@saleor/hooks/usePaginator";
|
||||
import { PAGINATE_BY } from "../../config";
|
||||
import i18n from "../../i18n";
|
||||
import { getMutationState, maybe } from "../../misc";
|
||||
import { TypedProductBulkDeleteMutation } from "../../products/mutations";
|
||||
import { productBulkDelete } from "../../products/types/productBulkDelete";
|
||||
|
@ -59,12 +59,14 @@ export const CategoryDetails: React.StatelessComponent<
|
|||
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
||||
params.ids
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const handleCategoryDelete = (data: CategoryDelete) => {
|
||||
if (data.categoryDelete.errors.length === 0) {
|
||||
notify({
|
||||
text: i18n.t("Category deleted", {
|
||||
context: "notification"
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Category deleted",
|
||||
id: "categoryDetailsCategoryDeleted"
|
||||
})
|
||||
});
|
||||
navigate(categoryListUrl());
|
||||
|
@ -140,7 +142,10 @@ export const CategoryDetails: React.StatelessComponent<
|
|||
if (data.categoryBulkDelete.errors.length === 0) {
|
||||
closeModal();
|
||||
notify({
|
||||
text: i18n.t("Categories removed")
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Categories removed",
|
||||
id: "categoryDetailsCategoriesRemoved"
|
||||
})
|
||||
});
|
||||
refetch();
|
||||
reset();
|
||||
|
@ -151,7 +156,10 @@ export const CategoryDetails: React.StatelessComponent<
|
|||
if (data.productBulkDelete.errors.length === 0) {
|
||||
closeModal();
|
||||
notify({
|
||||
text: i18n.t("Products removed")
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Products removed",
|
||||
id: "categoryDetailsProductsRemoved"
|
||||
})
|
||||
});
|
||||
refetch();
|
||||
reset();
|
||||
|
@ -319,32 +327,43 @@ export const CategoryDetails: React.StatelessComponent<
|
|||
deleteCategory({ variables: { id } })
|
||||
}
|
||||
open={params.action === "delete"}
|
||||
title={i18n.t("Delete category", {
|
||||
context: "modal title"
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete category",
|
||||
description: "dialog title",
|
||||
id:
|
||||
"categoryDetailsDeleteCategoryDialogTitle"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ categoryName }}</strong>? <br /> ",
|
||||
{
|
||||
categoryName: maybe(
|
||||
() => data.category.name
|
||||
),
|
||||
context: "modal message"
|
||||
}
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {name}?"
|
||||
description="remove category"
|
||||
id="categoryDetailsDeleteCategoryDialogContent"
|
||||
values={{
|
||||
name: (
|
||||
<strong>
|
||||
{maybe(
|
||||
() => data.category.name,
|
||||
"..."
|
||||
)}
|
||||
</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
<DialogContentText>
|
||||
{i18n.t(
|
||||
"Remember that this will also remove all products assigned to this category."
|
||||
)}
|
||||
<FormattedMessage
|
||||
defaultMessage="Remember that this will also remove all products assigned to this category."
|
||||
id="categoryDetailsDeleteCategoryDialogContentAdditionalText"
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
open={params.action === "delete-categories"}
|
||||
open={
|
||||
params.action === "delete-categories" &&
|
||||
maybe(() => params.ids.length > 0)
|
||||
}
|
||||
confirmButtonState={
|
||||
categoryBulkDeleteMutationState
|
||||
}
|
||||
|
@ -354,27 +373,30 @@ export const CategoryDetails: React.StatelessComponent<
|
|||
variables: { ids: params.ids }
|
||||
})
|
||||
}
|
||||
title={i18n.t("Remove categories")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Remove categories",
|
||||
description: "dialog title",
|
||||
id:
|
||||
"categoryDetailsDeleteSubcategoriesDialogTitle"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ number }}</strong> categories?",
|
||||
{
|
||||
number: maybe(
|
||||
() =>
|
||||
params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {number} categories?"
|
||||
id="categoryDetailsDeleteCategoriesDialogContent"
|
||||
values={{
|
||||
number: (
|
||||
<strong>{params.ids.length}</strong>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
<DialogContentText>
|
||||
{i18n.t(
|
||||
"Remember that this will also remove all products assigned to this category."
|
||||
)}
|
||||
<FormattedMessage
|
||||
defaultMessage="Remember that this will also remove all products assigned to this category."
|
||||
id="categoryDetailsDeleteCategoriesDialogContentAdditionalText"
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
<ActionDialog
|
||||
|
@ -388,23 +410,26 @@ export const CategoryDetails: React.StatelessComponent<
|
|||
variables: { ids: params.ids }
|
||||
})
|
||||
}
|
||||
title={i18n.t("Remove products")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Remove products",
|
||||
description: "dialog title",
|
||||
id:
|
||||
"categoryDetailsDeleteProductsDialogTitle"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ number }}</strong> products?",
|
||||
{
|
||||
number: maybe(
|
||||
() =>
|
||||
params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
{" "}
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {number} products?"
|
||||
id="categoryDetailsDeleteProductsDialogContent"
|
||||
values={{
|
||||
number: (
|
||||
<strong>{params.ids.length}</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 useBulkActions from "@saleor/hooks/useBulkActions";
|
||||
|
@ -10,7 +11,6 @@ import useNavigator from "@saleor/hooks/useNavigator";
|
|||
import usePaginator, {
|
||||
createPaginationState
|
||||
} from "@saleor/hooks/usePaginator";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { getMutationState, maybe } from "@saleor/misc";
|
||||
import { ListViews } from "@saleor/types";
|
||||
import { CategoryListPage } from "../components/CategoryListPage/CategoryListPage";
|
||||
|
@ -39,6 +39,8 @@ export const CategoryList: React.StatelessComponent<CategoryListProps> = ({
|
|||
const { updateListSettings, settings } = useListSettings(
|
||||
ListViews.CATEGORY_LIST
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||
return (
|
||||
<TypedRootCategoriesQuery displayLoader variables={paginationState}>
|
||||
|
@ -124,26 +126,25 @@ export const CategoryList: React.StatelessComponent<CategoryListProps> = ({
|
|||
})
|
||||
}
|
||||
open={params.action === "delete"}
|
||||
title={i18n.t("Remove categories")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Remove categories",
|
||||
description: "dialog title",
|
||||
id: "categoryListDeleteSubcategoriesDialogTitle"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ number }}</strong> categories?",
|
||||
{
|
||||
number: maybe(
|
||||
() => params.ids.length.toString(),
|
||||
"..."
|
||||
)
|
||||
}
|
||||
)
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {number} categories?"
|
||||
id="categoryListDeleteCategoriesDialogContent"
|
||||
values={{
|
||||
number: <strong>{params.ids.length}</strong>
|
||||
}}
|
||||
/>
|
||||
<DialogContentText>
|
||||
{i18n.t(
|
||||
"Remember that this will also remove all products assigned to this category."
|
||||
)}
|
||||
<FormattedMessage
|
||||
defaultMessage="Remember that this will also remove all products assigned to this category."
|
||||
id="categoryListDeleteCategoriesDialogContentAdditionalText"
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
</>
|
||||
|
|
19
src/intl.ts
19
src/intl.ts
|
@ -9,10 +9,19 @@ export const commonMessages = defineMessages({
|
|||
defaultMessage: "Confirm",
|
||||
id: "confirm"
|
||||
},
|
||||
description: {
|
||||
defaultMessage: "Description",
|
||||
id: "description"
|
||||
},
|
||||
generalInformations: {
|
||||
defaultMessage: "General Informations",
|
||||
id: "generalInformations"
|
||||
},
|
||||
optionalField: {
|
||||
defaultMessage: "Optional",
|
||||
description: "field is optional",
|
||||
id: "optionalField"
|
||||
},
|
||||
properties: {
|
||||
defaultMessage: "Properties",
|
||||
id: "properties"
|
||||
|
@ -24,6 +33,11 @@ export const commonMessages = defineMessages({
|
|||
savedChanges: {
|
||||
defaultMessage: "Saved changes",
|
||||
id: "savedChanges"
|
||||
},
|
||||
uploadImage: {
|
||||
defaultMessage: "Upload image",
|
||||
description: "button",
|
||||
id: "uploadImage"
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -32,5 +46,10 @@ export const sectionNames = defineMessages({
|
|||
defaultMessage: "Attributes",
|
||||
description: "attributes section name",
|
||||
id: "attributes"
|
||||
},
|
||||
categories: {
|
||||
defaultMessage: "Categories",
|
||||
description: "categories section name",
|
||||
id: "categories"
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue