Refactor attribute section translations

This commit is contained in:
Dominik Żegleń 2019-08-16 13:47:30 +02:00 committed by dominik-zeglen
parent e574945972
commit a573f5e139
15 changed files with 559 additions and 320 deletions

41
package-lock.json generated
View file

@ -9397,7 +9397,8 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true "bundled": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -9415,11 +9416,13 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true "bundled": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -9432,15 +9435,18 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -9543,7 +9549,8 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true "bundled": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -9553,6 +9560,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -9565,17 +9573,20 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true "bundled": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -9592,6 +9603,7 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -9664,7 +9676,8 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -9674,6 +9687,7 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -9749,7 +9763,8 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true "bundled": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -9779,6 +9794,7 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -9796,6 +9812,7 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -9834,11 +9851,13 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true "bundled": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true "bundled": true,
"optional": true
} }
} }
}, },

View file

@ -1,13 +1,13 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import i18n from "../../../i18n";
export interface AttributeBulkDeleteDialogProps { export interface AttributeBulkDeleteDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
quantity: string; quantity: number;
open: boolean; open: boolean;
onConfirm: () => void; onConfirm: () => void;
onClose: () => void; onClose: () => void;
@ -15,26 +15,38 @@ export interface AttributeBulkDeleteDialogProps {
const AttributeBulkDeleteDialog: React.StatelessComponent< const AttributeBulkDeleteDialog: React.StatelessComponent<
AttributeBulkDeleteDialogProps AttributeBulkDeleteDialogProps
> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => ( > = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => {
<ActionDialog const intl = useIntl();
open={open}
confirmButtonState={confirmButtonState} return (
onClose={onClose} <ActionDialog
onConfirm={onConfirm} open={open}
title={i18n.t("Remove attributes")} confirmButtonState={confirmButtonState}
variant="delete" onClose={onClose}
> onConfirm={onConfirm}
<DialogContentText title={intl.formatMessage({
dangerouslySetInnerHTML={{ defaultMessage: "Remove attributes",
__html: i18n.t( description: "dialog title",
"Are you sure you want to remove <strong>{{ quantity }}</strong> attributes?", id: "attributeBulkDeleteDialogTitle"
{ })}
quantity variant="delete"
} >
) <DialogContentText>
}} <FormattedMessage
/> defaultMessage="Are you sure you want to remove {counter, plural,
</ActionDialog> one {this attribute}
); other {{displayQuantity} attributes}
}?"
description="dialog content"
id="attributeBulkDeleteDialogContent"
values={{
counter: quantity,
displayQuantity: <strong>{quantity}</strong>
}}
/>
</DialogContentText>
</ActionDialog>
);
};
AttributeBulkDeleteDialog.displayName = "AttributeBulkDeleteDialog"; AttributeBulkDeleteDialog.displayName = "AttributeBulkDeleteDialog";
export default AttributeBulkDeleteDialog; export default AttributeBulkDeleteDialog;

View file

@ -1,9 +1,9 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import i18n from "@saleor/i18n";
export interface AttributeDeleteDialogProps { export interface AttributeDeleteDialogProps {
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
@ -19,27 +19,35 @@ const AttributeDeleteDialog: React.FC<AttributeDeleteDialogProps> = ({
onClose, onClose,
onConfirm, onConfirm,
open open
}) => ( }) => {
<ActionDialog const intl = useIntl();
open={open}
onClose={onClose} return (
confirmButtonState={confirmButtonState} <ActionDialog
onConfirm={onConfirm} open={open}
variant="delete" onClose={onClose}
title={i18n.t("Remove attribute")} confirmButtonState={confirmButtonState}
> onConfirm={onConfirm}
<DialogContentText variant="delete"
dangerouslySetInnerHTML={{ title={intl.formatMessage({
__html: i18n.t( defaultMessage: "Remove attribute",
"Are you sure you want to remove <strong>{{ name }}</strong>?", description: "dialog title",
{ id: "attributeDeleteDialogTitle"
name })}
} >
) <DialogContentText>
}} <FormattedMessage
/> defaultMessage="Are you sure you want to remove {name}?"
</ActionDialog> description="dialog content"
); id="attributeDeleteDialogContent"
values={{
name: <strong>{name}</strong>
}}
/>
</DialogContentText>
</ActionDialog>
);
};
AttributeDeleteDialog.displayName = "AttributeDeleteDialog"; AttributeDeleteDialog.displayName = "AttributeDeleteDialog";
export default AttributeDeleteDialog; export default AttributeDeleteDialog;

View file

@ -2,13 +2,14 @@ import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import slugify from "slugify"; import slugify from "slugify";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import ControlledSwitch from "@saleor/components/ControlledSwitch"; import ControlledSwitch from "@saleor/components/ControlledSwitch";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
import SingleSelectField from "@saleor/components/SingleSelectField"; import SingleSelectField from "@saleor/components/SingleSelectField";
import i18n from "@saleor/i18n"; import { commonMessages } from "@saleor/intl";
import { FormErrors } from "@saleor/types"; import { FormErrors } from "@saleor/types";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { AttributePageFormData } from "../AttributePage"; import { AttributePageFormData } from "../AttributePage";
@ -21,78 +22,108 @@ export interface AttributeDetailsProps {
onChange: (event: React.ChangeEvent<any>) => void; onChange: (event: React.ChangeEvent<any>) => void;
} }
const inputTypeChoices = [
{
label: i18n.t("Dropdown"),
value: AttributeInputTypeEnum.DROPDOWN
},
{
label: i18n.t("Multiple Select"),
value: AttributeInputTypeEnum.MULTISELECT
}
];
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
canChangeType, canChangeType,
data, data,
disabled, disabled,
errors, errors,
onChange onChange
}) => ( }) => {
<Card> const intl = useIntl();
<CardTitle title={i18n.t("General Information")} /> const inputTypeChoices = [
<CardContent> {
<TextField label: intl.formatMessage({
disabled={disabled} defaultMessage: "Dropdown",
error={!!errors.name} description: "attribute editor component type",
label={i18n.t("Default Label")} id: "attributeDetailsInputTypeDropdown"
name={"name" as keyof AttributePageFormData} }),
fullWidth value: AttributeInputTypeEnum.DROPDOWN
helperText={errors.name} },
value={data.name} {
onChange={onChange} label: intl.formatMessage({
/> defaultMessage: "Multiple Select",
<FormSpacer /> description: "attribute editor component type",
<TextField id: "attributeDetailsInputTypeMultiselect"
disabled={disabled} }),
error={!!errors.slug} value: AttributeInputTypeEnum.MULTISELECT
label={i18n.t("Attribute Code")} }
name={"slug" as keyof AttributePageFormData} ];
placeholder={slugify(data.name).toLowerCase()}
fullWidth return (
helperText={ <Card>
errors.slug || <CardTitle
i18n.t("This is used internally. Make sure you dont use spaces", { title={
context: "slug input" intl.formatMessage(commonMessages.generalInformations)
})
} }
value={data.slug}
onChange={onChange}
/> />
<FormSpacer /> <CardContent>
<SingleSelectField <TextField
choices={inputTypeChoices} disabled={disabled}
disabled={disabled || !canChangeType} error={!!errors.name}
error={!!errors.inputType} label={intl.formatMessage({
hint={errors.inputType} defaultMessage: "Default Label",
label={i18n.t("Catalog Input type for Store Owner", { description: "attribute label input field",
context: "attribute input type" id: "attributeDetailsNameInputLabel"
})} })}
name="inputType" name={"name" as keyof AttributePageFormData}
onChange={onChange} fullWidth
value={data.inputType} helperText={errors.name}
/> value={data.name}
<FormSpacer /> onChange={onChange}
<ControlledSwitch />
checked={data.valueRequired} <FormSpacer />
label={i18n.t("Value Required", { <TextField
context: "attribute must have value" disabled={disabled}
})} error={!!errors.slug}
name={"valueRequired" as keyof AttributePageFormData} label={intl.formatMessage({
onChange={onChange} defaultMessage: "Attribute Code",
/> description: "attribute slug input field",
</CardContent> id: "attributeDetailsSlugInputLabel"
</Card> })}
); name={"slug" as keyof AttributePageFormData}
placeholder={slugify(data.name).toLowerCase()}
fullWidth
helperText={
errors.slug ||
intl.formatMessage({
defaultMessage:
"This is used internally. Make sure you dont use spaces",
description: "attribute slug input field helper text",
id: "attributeDetailsNameInputHelperText"
})
}
value={data.slug}
onChange={onChange}
/>
<FormSpacer />
<SingleSelectField
choices={inputTypeChoices}
disabled={disabled || !canChangeType}
error={!!errors.inputType}
hint={errors.inputType}
label={intl.formatMessage({
defaultMessage: "Catalog Input type for Store Owner",
description: "attribute editor component type select field label",
id: "attributeDetailsInputTypeField"
})}
name="inputType"
onChange={onChange}
value={data.inputType}
/>
<FormSpacer />
<ControlledSwitch
checked={data.valueRequired}
label={intl.formatMessage({
defaultMessage: "Value Required",
description: "check to require attribute to have value",
id: "attributeDetailsValueRequiredInputLabel"
})}
name={"valueRequired" as keyof AttributePageFormData}
onChange={onChange}
/>
</CardContent>
</Card>
);
};
AttributeDetails.displayName = "AttributeDetails"; AttributeDetails.displayName = "AttributeDetails";
export default AttributeDetails; export default AttributeDetails;

View file

@ -6,12 +6,12 @@ import TableFooter from "@material-ui/core/TableFooter";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import makeStyles from "@material-ui/styles/makeStyles"; import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl";
import Checkbox from "@saleor/components/Checkbox"; import Checkbox from "@saleor/components/Checkbox";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import i18n from "@saleor/i18n";
import { renderCollection } from "@saleor/misc"; import { renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types"; import { ListActions, ListProps } from "@saleor/types";
import { translateBoolean } from "@saleor/utils/i18n"; import { translateBoolean } from "@saleor/utils/i18n";
@ -83,23 +83,39 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
toolbar={toolbar} toolbar={toolbar}
> >
<TableCell className={classes.colSlug}> <TableCell className={classes.colSlug}>
{i18n.t("Attribute Code", { context: "attribute slug" })} <FormattedMessage
defaultMessage="Attribute Code"
description="attribute list: slug column header"
id="attributeListSlugColumnHeader"
/>
</TableCell> </TableCell>
<TableCell className={classes.colName}> <TableCell className={classes.colName}>
{i18n.t("Default Label", { context: "attribute name" })} <FormattedMessage
defaultMessage="Default Label"
description="attribute list: name column header"
id="attributeListNameColumnHeader"
/>
</TableCell> </TableCell>
<TableCell className={classes.colVisible}> <TableCell className={classes.colVisible}>
{i18n.t("Visible", { context: "attribute visibility" })} <FormattedMessage
defaultMessage="Visible"
description="attribute list: visibility column header"
id="attributeListVisibilityColumnHeader"
/>
</TableCell> </TableCell>
<TableCell className={classes.colSearchable}> <TableCell className={classes.colSearchable}>
{i18n.t("Searchable", { <FormattedMessage
context: "attribute can be searched in dashboard" defaultMessage="Searchable"
})} description="attribute list: attribute can be searched in dashboard column header"
id="attributeListSearchableColumnHeader"
/>
</TableCell> </TableCell>
<TableCell className={classes.colFaceted}> <TableCell className={classes.colFaceted}>
{i18n.t("Use in faceted search", { <FormattedMessage
context: "attribute can be searched in storefront" defaultMessage="Use in faceted search"
})} description="attribute list: attribute can be searched in storefront column header"
id="attributeListFacetedColumnHeader"
/>
</TableCell> </TableCell>
</TableHead> </TableHead>
<TableFooter> <TableFooter>
@ -170,7 +186,11 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
() => ( () => (
<TableRow> <TableRow>
<TableCell colSpan={numberOfColumns}> <TableCell colSpan={numberOfColumns}>
{i18n.t("No attributes found")} <FormattedMessage
defaultMessage="No attributes found"
description="no attributes found with present filters"
id="AttributeListNoAttributes"
/>
</TableCell> </TableCell>
</TableRow> </TableRow>
) )

View file

@ -2,10 +2,11 @@ import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import AddIcon from "@material-ui/icons/Add"; import AddIcon from "@material-ui/icons/Add";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { sectionNames } from "@saleor/intl";
import Container from "../../../components/Container"; import Container from "../../../components/Container";
import PageHeader from "../../../components/PageHeader"; import PageHeader from "../../../components/PageHeader";
import i18n from "../../../i18n";
import { ListActions, PageListProps } from "../../../types"; import { ListActions, PageListProps } from "../../../types";
import { AttributeList_attributes_edges_node } from "../../types/AttributeList"; import { AttributeList_attributes_edges_node } from "../../types/AttributeList";
import AttributeList from "../AttributeList/AttributeList"; import AttributeList from "../AttributeList/AttributeList";
@ -17,17 +18,28 @@ export interface AttributeListPageProps extends PageListProps, ListActions {
const AttributeListPage: React.FC<AttributeListPageProps> = ({ const AttributeListPage: React.FC<AttributeListPageProps> = ({
onAdd, onAdd,
...listProps ...listProps
}) => ( }) => {
<Container> const intl = useIntl();
<PageHeader title={i18n.t("Attributes")}>
<Button onClick={onAdd} color="primary" variant="contained"> return (
{i18n.t("Add attribute")} <AddIcon /> <Container>
</Button> <PageHeader
</PageHeader> title={intl.formatMessage(sectionNames.attributes)}
<Card> >
<AttributeList {...listProps} /> <Button onClick={onAdd} color="primary" variant="contained">
</Card> <FormattedMessage
</Container> defaultMessage="New attribute"
); description="button"
id="attributeListPageNewAttribute"
/>
<AddIcon />
</Button>
</PageHeader>
<Card>
<AttributeList {...listProps} />
</Card>
</Container>
);
};
AttributeListPage.displayName = "AttributeListPage"; AttributeListPage.displayName = "AttributeListPage";
export default AttributeListPage; export default AttributeListPage;

View file

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import slugify from "slugify"; import slugify from "slugify";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
@ -9,7 +10,7 @@ import Form from "@saleor/components/Form";
import Grid from "@saleor/components/Grid"; import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SaveButtonBar from "@saleor/components/SaveButtonBar";
import i18n from "@saleor/i18n"; import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { ReorderAction, UserError } from "@saleor/types"; import { ReorderAction, UserError } from "@saleor/types";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
@ -62,6 +63,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
onValueReorder, onValueReorder,
onValueUpdate onValueUpdate
}) => { }) => {
const intl = useIntl();
const initialForm: AttributePageFormData = const initialForm: AttributePageFormData =
attribute === null attribute === null
? { ? {
@ -109,12 +111,16 @@ const AttributePage: React.FC<AttributePageProps> = ({
<Form errors={errors} initial={initialForm} onSubmit={handleSubmit}> <Form errors={errors} initial={initialForm} onSubmit={handleSubmit}>
{({ change, errors: formErrors, data, submit }) => ( {({ change, errors: formErrors, data, submit }) => (
<Container> <Container>
<AppHeader onBack={onBack}>{i18n.t("Attributes")}</AppHeader> <AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.attributes)}
</AppHeader>
<PageHeader <PageHeader
title={ title={
attribute === null attribute === null
? i18n.t("Create New Attribute", { ? intl.formatMessage({
context: "page title" defaultMessage: "Create New Attribute",
description: "page title",
id: "attributePageTitle"
}) })
: maybe(() => attribute.name) : maybe(() => attribute.name)
} }

View file

@ -3,13 +3,14 @@ import CardContent from "@material-ui/core/CardContent";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import ControlledSwitch from "@saleor/components/ControlledSwitch"; import ControlledSwitch from "@saleor/components/ControlledSwitch";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import i18n from "@saleor/i18n"; import { commonMessages } from "@saleor/intl";
import { FormErrors } from "@saleor/types"; import { FormErrors } from "@saleor/types";
import { AttributePageFormData } from "../AttributePage"; import { AttributePageFormData } from "../AttributePage";
@ -25,103 +26,136 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
errors, errors,
disabled, disabled,
onChange onChange
}) => ( }) => {
<Card> const intl = useIntl();
<CardTitle title={i18n.t("Properties")} />
<CardContent>
{/* <Typography variant="subtitle1">
{i18n.t("General Properties")}
</Typography>
<Hr />
<CardSpacer />
<ControlledSwitch
name={"" as keyof AttributePageFormData}
checked={false}
disabled={disabled}
label={
<>
<span>{i18n.t("Variant Attribute")}</span>
<Typography variant="caption">
{i18n.t(
"If enabled, you'll be able to use this attribute to create product variants"
)}
</Typography>
</>
}
onChange={onChange}
/> */}
<Typography variant="subtitle1"> return (
{i18n.t("Storefront Properties")} <Card>
</Typography> <CardTitle title={intl.formatMessage(commonMessages.properties)} />
<Hr /> <CardContent>
<ControlledSwitch {/* <Typography variant="subtitle1">
name={"filterableInStorefront" as keyof AttributePageFormData} <FormattedMessage
checked={data.filterableInStorefront} defaultMessage="General Properties"
disabled={disabled} description="attribute general properties section"
label={i18n.t("Use in faceted navigation")} id="attributePropertiesGeneralSectionTitle"
onChange={onChange} />
/> </Typography>
{data.filterableInStorefront && ( <Hr />
<TextField <CardSpacer />
<ControlledSwitch
name={"" as keyof AttributePageFormData}
checked={false}
disabled={disabled} disabled={disabled}
error={!!errors.storefrontSearchPosition} label={
fullWidth <>
helperText={errors.storefrontSearchPosition} <FormattedMessage
name={"storefrontSearchPosition" as keyof AttributePageFormData} defaultMessage="Variant Attribute"
label={i18n.t("Position in faceted navigation")} description="attribute is variant-only"
value={data.storefrontSearchPosition} id="attributePropertiesVariantOnly"
/>
<Typography variant="caption">
<FormattedMessage
defaultMessage="If enabled, you'll be able to use this attribute to create product variants"
id="attributePropertiesVariantOnlyHelperText"
/>
</Typography>
</>
}
onChange={onChange}
/> */}
<Typography variant="subtitle1">
<FormattedMessage
defaultMessage="Storefront Properties"
description="attribute properties regarding storefront"
id="attributePropertiesStorefront"
/>
</Typography>
<Hr />
<ControlledSwitch
name={"filterableInStorefront" as keyof AttributePageFormData}
checked={data.filterableInStorefront}
disabled={disabled}
label={intl.formatMessage({
defaultMessage: "Use in faceted navigation",
description: "attribute is filterable in storefront",
id: "attributePropertiesUseInFacetedNavigation"
})}
onChange={onChange} onChange={onChange}
/> />
)} {data.filterableInStorefront && (
<FormSpacer /> <TextField
<ControlledSwitch disabled={disabled}
name={"visibleInStorefront" as keyof AttributePageFormData} error={!!errors.storefrontSearchPosition}
checked={data.visibleInStorefront} fullWidth
disabled={disabled} helperText={errors.storefrontSearchPosition}
label={i18n.t("Visible on Product Page in Storefront", { name={"storefrontSearchPosition" as keyof AttributePageFormData}
context: "attribute" label={intl.formatMessage({
})} defaultMessage: "Position in faceted navigation",
onChange={onChange} description: "attribute position in storefront filters",
/> id: "attributePropertiesFacetedNavigationPosition"
<CardSpacer /> })}
value={data.storefrontSearchPosition}
<Typography variant="subtitle1"> onChange={onChange}
{i18n.t("Dashboard Properties")} />
</Typography> )}
<Hr /> <FormSpacer />
<CardSpacer /> <ControlledSwitch
<ControlledSwitch name={"visibleInStorefront" as keyof AttributePageFormData}
name={"filterableInDashboard" as keyof AttributePageFormData} checked={data.visibleInStorefront}
checked={data.filterableInDashboard} disabled={disabled}
disabled={disabled} label={intl.formatMessage({
label={i18n.t("Use in Filtering")} defaultMessage: "Visible on Product Page in Storefront",
secondLabel={ description: "attribute",
<Typography variant="caption"> id: "attributePropertiesVisibility"
{i18n.t( })}
"If enabled, youll be able to use this attribute to filter products in product list." onChange={onChange}
)} />
</Typography> <CardSpacer />
} <Typography variant="subtitle1">
onChange={onChange} <FormattedMessage
/> defaultMessage="Dashboard Properties"
<FormSpacer /> description="attribute properties regarding dashboard"
<ControlledSwitch id="attributePropertiesDashboard"
name={"availableInGrid" as keyof AttributePageFormData} />
checked={data.availableInGrid} </Typography>
disabled={disabled} <Hr />
label={i18n.t("Add to Column Options")} <CardSpacer />
secondLabel={ <ControlledSwitch
<Typography variant="caption"> name={"filterableInDashboard" as keyof AttributePageFormData}
{i18n.t( checked={data.filterableInDashboard}
"If enable this attribute can be used as a column in product table." disabled={disabled}
)} label={intl.formatMessage({
</Typography> defaultMessage: "Use in Filtering",
} description: "use attribute in filtering",
onChange={onChange} id: "attributePropertiesDashboardFiltering"
/> })}
</CardContent> secondLabel={
</Card> <Typography variant="caption">
); <FormattedMessage defaultMessage="If enabled, youll be able to use this attribute to filter products in product list." />
</Typography>
}
onChange={onChange}
/>
<FormSpacer />
<ControlledSwitch
name={"availableInGrid" as keyof AttributePageFormData}
checked={data.availableInGrid}
disabled={disabled}
label={intl.formatMessage({
defaultMessage: "Add to Column Options",
description: "add attribute as column in product list table"
})}
secondLabel={
<Typography variant="caption">
<FormattedMessage defaultMessage="If enable this attribute can be used as a column in product table." />
</Typography>
}
onChange={onChange}
/>
</CardContent>
</Card>
);
};
AttributeProperties.displayName = "AttributeProperties"; AttributeProperties.displayName = "AttributeProperties";
export default AttributeProperties; export default AttributeProperties;

View file

@ -1,9 +1,9 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import i18n from "@saleor/i18n";
export interface AttributeValueDeleteDialogProps { export interface AttributeValueDeleteDialogProps {
attributeName: string; attributeName: string;
@ -23,30 +23,46 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
onClose, onClose,
onConfirm, onConfirm,
open open
}) => ( }) => {
<ActionDialog const intl = useIntl();
open={open}
onClose={onClose} return (
confirmButtonState={confirmButtonState} <ActionDialog
onConfirm={onConfirm} open={open}
variant="delete" onClose={onClose}
title={i18n.t("Remove attribute value")} confirmButtonState={confirmButtonState}
> onConfirm={onConfirm}
<DialogContentText> variant="delete"
{useName title={intl.formatMessage({
? i18n.t( defaultMessage: "Remove attribute value",
'Are you sure you want to remove "{{ name }}" value? If you remove it you wont be able to assign it to any of the products with "{{ attributeName }}" attribute.', description: "dialog title",
{ id: "attributeValueDeleteDialogTitle"
})}
>
<DialogContentText>
{useName ? (
<FormattedMessage
defaultMessage='Are you sure you want to remove "{ name }" value? If you remove it you wont be able to assign it to any of the products with "{ attributeName }" attribute.'
id="attributeValueDeleteDialogContentWithAttributeName"
values={{
attributeName, attributeName,
name name
} }}
) />
: i18n.t('Are you sure you want to remove "{{ name }}" value?', { ) : (
name <FormattedMessage
})} defaultMessage='Are you sure you want to remove "{ name }" value?'
</DialogContentText> description="remove attribute value"
</ActionDialog> id="attributeValueDeleteDialogContentWithoutAttributeName"
); values={{
name
}}
/>
)}
</DialogContentText>
</ActionDialog>
);
};
AttributeValueDeleteDialog.displayName = "AttributeValueDeleteDialog"; AttributeValueDeleteDialog.displayName = "AttributeValueDeleteDialog";
export default AttributeValueDeleteDialog; export default AttributeValueDeleteDialog;

View file

@ -5,13 +5,14 @@ import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import ConfirmButton, { import ConfirmButton, {
ConfirmButtonTransitionState ConfirmButtonTransitionState
} from "@saleor/components/ConfirmButton"; } from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import i18n from "@saleor/i18n"; import { commonMessages } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { UserError } from "@saleor/types"; import { UserError } from "@saleor/types";
import { AttributeDetails_attribute_values } from "../../types/AttributeDetails"; import { AttributeDetails_attribute_values } from "../../types/AttributeDetails";
@ -40,6 +41,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
onSubmit, onSubmit,
open open
}) => { }) => {
const intl = useIntl();
const initialForm: AttributeValueEditDialogFormData = { const initialForm: AttributeValueEditDialogFormData = {
name: maybe(() => attributeValue.name, "") name: maybe(() => attributeValue.name, "")
}; };
@ -48,13 +50,19 @@ const AttributeValueEditDialog: React.StatelessComponent<
return ( return (
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm"> <Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
<DialogTitle> <DialogTitle>
{attributeValue === null {attributeValue === null ? (
? i18n.t("Add Value", { <FormattedMessage
context: "add attribute value" defaultMessage="Add Value"
}) description="add attribute value"
: i18n.t("Edit Value", { id="attributeValueEditDialogTitleNewValue"
context: "edit attribute value" />
})} ) : (
<FormattedMessage
defaultMessage="Edit Value"
description="edit attribute value"
id="attributeValueEditDialogTitle"
/>
)}
</DialogTitle> </DialogTitle>
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}> <Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
{({ change, data, errors: formErrors, submit }) => ( {({ change, data, errors: formErrors, submit }) => (
@ -67,8 +75,10 @@ const AttributeValueEditDialog: React.StatelessComponent<
fullWidth fullWidth
helperText={formErrors.name} helperText={formErrors.name}
name={"name" as keyof AttributeValueEditDialogFormData} name={"name" as keyof AttributeValueEditDialogFormData}
label={i18n.t("Name", { label={intl.formatMessage({
context: "attribute name" defaultMessage: "Name",
description: "attribute name",
id: "attributeValueEditDialogNameField"
})} })}
value={data.name} value={data.name}
onChange={change} onChange={change}
@ -76,7 +86,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}> <Button onClick={onClose}>
{i18n.t("Cancel", { context: "button" })} <FormattedMessage {...commonMessages.cancel} />
</Button> </Button>
<ConfirmButton <ConfirmButton
transitionState={confirmButtonState} transitionState={confirmButtonState}
@ -84,7 +94,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
variant="contained" variant="contained"
onClick={submit} onClick={submit}
> >
{i18n.t("Save")} <FormattedMessage {...commonMessages.save} />
</ConfirmButton> </ConfirmButton>
</DialogActions> </DialogActions>
</> </>

View file

@ -9,6 +9,7 @@ import TableRow from "@material-ui/core/TableRow";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import makeStyles from "@material-ui/styles/makeStyles"; import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
@ -16,7 +17,6 @@ import {
SortableTableBody, SortableTableBody,
SortableTableRow SortableTableRow
} from "@saleor/components/SortableTable"; } from "@saleor/components/SortableTable";
import i18n from "@saleor/i18n";
import { maybe, renderCollection, stopPropagation } from "@saleor/misc"; import { maybe, renderCollection, stopPropagation } from "@saleor/misc";
import { ReorderAction } from "@saleor/types"; import { ReorderAction } from "@saleor/types";
import { AttributeDetailsFragment_values } from "../../types/AttributeDetailsFragment"; import { AttributeDetailsFragment_values } from "../../types/AttributeDetailsFragment";
@ -63,14 +63,23 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
values values
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl();
return ( return (
<Card> <Card>
<CardTitle <CardTitle
title={i18n.t("Attribute Values")} title={intl.formatMessage({
defaultMessage: "Attribute Values",
description: "section header",
id: "attributeValuesHeader"
})}
toolbar={ toolbar={
<Button color="primary" variant="text" onClick={onValueAdd}> <Button color="primary" variant="text" onClick={onValueAdd}>
{i18n.t("Add value", { context: "button" })} <FormattedMessage
defaultMessage="Add value"
description="add attribute value button"
id="attributeValuesAddButton"
/>
</Button> </Button>
} }
/> />
@ -79,10 +88,18 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
<TableRow> <TableRow>
<TableCell className={classes.columnDrag} /> <TableCell className={classes.columnDrag} />
<TableCell className={classes.columnAdmin}> <TableCell className={classes.columnAdmin}>
{i18n.t("Admin")} <FormattedMessage
defaultMessage="Admin"
description="attribute values list: slug column header"
id="attributeValuesSlugColumnHeader"
/>
</TableCell> </TableCell>
<TableCell className={classes.columnStore}> <TableCell className={classes.columnStore}>
{i18n.t("Default Store View")} <FormattedMessage
defaultMessage="Default Store View"
description="attribute values list: name column header"
id="attributeValuesNameColumnHeader"
/>
</TableCell> </TableCell>
<TableCell /> <TableCell />
</TableRow> </TableRow>
@ -116,7 +133,13 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
), ),
() => ( () => (
<TableRow> <TableRow>
<TableCell colSpan={2}>{i18n.t("No values found")}</TableCell> <TableCell colSpan={2}>
<FormattedMessage
defaultMessage="No values found"
description="No attribute values found"
id="attributeValuesNotFound"
/>
</TableCell>
</TableRow> </TableRow>
) )
)} )}

View file

@ -2,8 +2,9 @@ import { parse as parseQs } from "qs";
import React from "react"; import React from "react";
import { Route, RouteComponentProps, Switch } from "react-router-dom"; import { Route, RouteComponentProps, Switch } from "react-router-dom";
import { sectionNames } from "@saleor/intl";
import { useIntl } from "react-intl";
import { WindowTitle } from "../components/WindowTitle"; import { WindowTitle } from "../components/WindowTitle";
import i18n from "../i18n";
import { import {
attributeAddPath, attributeAddPath,
AttributeAddUrlQueryParams, AttributeAddUrlQueryParams,
@ -42,14 +43,18 @@ const AttributeDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
); );
}; };
export const AttributeSection: React.FC = () => ( export const AttributeSection: React.FC = () => {
<> const intl = useIntl();
<WindowTitle title={i18n.t("Attributes")} />
<Switch> return (
<Route exact path={attributeListPath} component={AttributeList} /> <>
<Route exact path={attributeAddPath} component={AttributeCreate} /> <WindowTitle title={intl.formatMessage(sectionNames.attributes)} />
<Route path={attributePath(":id")} component={AttributeDetails} /> <Switch>
</Switch> <Route exact path={attributeListPath} component={AttributeList} />
</> <Route exact path={attributeAddPath} component={AttributeCreate} />
); <Route path={attributePath(":id")} component={AttributeDetails} />
</Switch>
</>
);
};
export default AttributeSection; export default AttributeSection;

View file

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import slugify from "slugify"; import slugify from "slugify";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import i18n from "@saleor/i18n";
import { getMutationState, maybe } from "@saleor/misc"; import { getMutationState, maybe } from "@saleor/misc";
import { ReorderEvent, UserError } from "@saleor/types"; import { ReorderEvent, UserError } from "@saleor/types";
import { import {
@ -42,6 +42,7 @@ function areValuesEqual(
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => { const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const intl = useIntl();
const [values, setValues] = React.useState< const [values, setValues] = React.useState<
AttributeValueEditDialogFormData[] AttributeValueEditDialogFormData[]
@ -75,7 +76,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
}; };
const handleCreate = (data: AttributeCreate) => { const handleCreate = (data: AttributeCreate) => {
if (data.attributeCreate.errors.length === 0) { if (data.attributeCreate.errors.length === 0) {
notify({ text: i18n.t("Successfully created attribute") }); notify({
text: intl.formatMessage({
defaultMessage: "Successfully created attribute",
id: "attributeCreateAttributeCreateSuccess"
})
});
navigate(attributeUrl(data.attributeCreate.attribute.id)); navigate(attributeUrl(data.attributeCreate.attribute.id));
} }
}; };
@ -84,10 +90,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
setValueErrors([ setValueErrors([
{ {
field: "name", field: "name",
message: i18n.t("A value named {{ name }} already exists", { message: intl.formatMessage(
context: "value edit error", {
name: input.name defaultMessage: "A value named { name } already exists",
}) description: "attribute value edit error",
id: "attributeCreateErrorExists"
},
{
name: input.name
}
)
} }
]); ]);
} else { } else {
@ -100,10 +112,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
setValueErrors([ setValueErrors([
{ {
field: "name", field: "name",
message: i18n.t("A value named {{ name }} already exists", { message: intl.formatMessage(
context: "value edit error", {
name: input.name defaultMessage: "A value named { name } already exists",
}) description: "attribute value edit error",
id: "attributeCreateErrorExists"
},
{
name: input.name
}
)
} }
]); ]);
} else { } else {

View file

@ -1,8 +1,9 @@
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import i18n from "@saleor/i18n"; import { commonMessages } from "@saleor/intl";
import { getMutationState, maybe } from "@saleor/misc"; import { getMutationState, maybe } from "@saleor/misc";
import { ReorderEvent } from "@saleor/types"; import { ReorderEvent } from "@saleor/types";
import { move } from "@saleor/utils/lists"; import { move } from "@saleor/utils/lists";
@ -40,6 +41,7 @@ interface AttributeDetailsProps {
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => { const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const intl = useIntl();
const closeModal = () => const closeModal = () =>
navigate( navigate(
@ -63,39 +65,54 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
const handleDelete = (data: AttributeDelete) => { const handleDelete = (data: AttributeDelete) => {
if (data.attributeDelete.errors.length === 0) { if (data.attributeDelete.errors.length === 0) {
notify({ text: i18n.t("Attribute removed") }); notify({
text: intl.formatMessage({
defaultMessage: "Attribute removed",
id: "attributeDetailsAttributeRemoveSuccess"
})
});
navigate(attributeListUrl()); navigate(attributeListUrl());
} }
}; };
const handleValueDelete = (data: AttributeValueDelete) => { const handleValueDelete = (data: AttributeValueDelete) => {
if (data.attributeValueDelete.errors.length === 0) { if (data.attributeValueDelete.errors.length === 0) {
notify({ text: i18n.t("Value removed") }); notify({
text: intl.formatMessage({
defaultMessage: "Value removed",
description: "attribute value removed",
id: "attributeDetailsAttributeValueRemoveSuccess"
})
});
closeModal(); closeModal();
} }
}; };
const handleUpdate = (data: AttributeUpdate) => { const handleUpdate = (data: AttributeUpdate) => {
if (data.attributeUpdate.errors.length === 0) { if (data.attributeUpdate.errors.length === 0) {
notify({ text: i18n.t("Saved changes") }); notify({ text: intl.formatMessage(commonMessages.savedChanges) });
} }
}; };
const handleValueUpdate = (data: AttributeValueUpdate) => { const handleValueUpdate = (data: AttributeValueUpdate) => {
if (data.attributeValueUpdate.errors.length === 0) { if (data.attributeValueUpdate.errors.length === 0) {
notify({ text: i18n.t("Saved changes") }); notify({ text: intl.formatMessage(commonMessages.savedChanges) });
closeModal(); closeModal();
} }
}; };
const handleValueCreate = (data: AttributeValueCreate) => { const handleValueCreate = (data: AttributeValueCreate) => {
if (data.attributeValueCreate.errors.length === 0) { if (data.attributeValueCreate.errors.length === 0) {
notify({ text: i18n.t("Added new value") }); notify({
text: intl.formatMessage({
defaultMessage: "Added new value",
description: "added new attribute value",
id: "attributeDetailsAttributeValueCreateSuccess"
})
});
closeModal(); closeModal();
} }
}; };
const handleValueReorderMutation = (data: AttributeValueReorder) => { const handleValueReorderMutation = (data: AttributeValueReorder) => {
if (data.attributeReorderValues.errors.length !== 0) { if (data.attributeReorderValues.errors.length !== 0) {
notify({ notify({
text: i18n.t("Error: {{ errorMessage }}", { text: data.attributeReorderValues.errors[0].message
errorMessage: data.attributeReorderValues.errors[0].message
})
}); });
} }
}; };

View file

@ -1,6 +1,7 @@
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -9,7 +10,6 @@ import usePaginator, {
} from "@saleor/hooks/usePaginator"; } from "@saleor/hooks/usePaginator";
import { PAGINATE_BY } from "../../../config"; import { PAGINATE_BY } from "../../../config";
import useBulkActions from "../../../hooks/useBulkActions"; import useBulkActions from "../../../hooks/useBulkActions";
import i18n from "../../../i18n";
import { getMutationState, maybe } from "../../../misc"; import { getMutationState, maybe } from "../../../misc";
import AttributeBulkDeleteDialog from "../../components/AttributeBulkDeleteDialog"; import AttributeBulkDeleteDialog from "../../components/AttributeBulkDeleteDialog";
import AttributeListPage from "../../components/AttributeListPage"; import AttributeListPage from "../../components/AttributeListPage";
@ -35,6 +35,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
params.ids params.ids
); );
const intl = useIntl();
const closeModal = () => const closeModal = () =>
navigate( navigate(
@ -71,7 +72,11 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
if (data.attributeBulkDelete.errors.length === 0) { if (data.attributeBulkDelete.errors.length === 0) {
closeModal(); closeModal();
notify({ notify({
text: i18n.t("Attributes removed") text: intl.formatMessage({
defaultMessage: "Attributes successfully removed",
description: "remove multiple attributes",
id: "attributeListAttributesRemoved"
})
}); });
reset(); reset();
refetch(); refetch();
@ -116,12 +121,15 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
/> />
<AttributeBulkDeleteDialog <AttributeBulkDeleteDialog
confirmButtonState={bulkDeleteMutationState} confirmButtonState={bulkDeleteMutationState}
open={params.action === "remove"} open={
params.action === "remove" &&
maybe(() => params.ids.length > 0)
}
onConfirm={() => onConfirm={() =>
attributeBulkDelete({ variables: { ids: params.ids } }) attributeBulkDelete({ variables: { ids: params.ids } })
} }
onClose={closeModal} onClose={closeModal}
quantity={maybe(() => params.ids.length.toString(), "...")} quantity={maybe(() => params.ids.length)}
/> />
</> </>
); );