Refactor attribute section translations
This commit is contained in:
parent
e574945972
commit
a573f5e139
15 changed files with 559 additions and 320 deletions
41
package-lock.json
generated
41
package-lock.json
generated
|
@ -9397,7 +9397,8 @@
|
|||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -9415,11 +9416,13 @@
|
|||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -9432,15 +9435,18 @@
|
|||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -9543,7 +9549,8 @@
|
|||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -9553,6 +9560,7 @@
|
|||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -9565,17 +9573,20 @@
|
|||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -9592,6 +9603,7 @@
|
|||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -9664,7 +9676,8 @@
|
|||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -9674,6 +9687,7 @@
|
|||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -9749,7 +9763,8 @@
|
|||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -9779,6 +9794,7 @@
|
|||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -9796,6 +9812,7 @@
|
|||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -9834,11 +9851,13 @@
|
|||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import i18n from "../../../i18n";
|
||||
|
||||
export interface AttributeBulkDeleteDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
quantity: string;
|
||||
quantity: number;
|
||||
open: boolean;
|
||||
onConfirm: () => void;
|
||||
onClose: () => void;
|
||||
|
@ -15,26 +15,38 @@ export interface AttributeBulkDeleteDialogProps {
|
|||
|
||||
const AttributeBulkDeleteDialog: React.StatelessComponent<
|
||||
AttributeBulkDeleteDialogProps
|
||||
> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => (
|
||||
<ActionDialog
|
||||
open={open}
|
||||
confirmButtonState={confirmButtonState}
|
||||
onClose={onClose}
|
||||
onConfirm={onConfirm}
|
||||
title={i18n.t("Remove attributes")}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ quantity }}</strong> attributes?",
|
||||
{
|
||||
quantity
|
||||
}
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ActionDialog>
|
||||
);
|
||||
> = ({ confirmButtonState, quantity, onClose, onConfirm, open }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
open={open}
|
||||
confirmButtonState={confirmButtonState}
|
||||
onClose={onClose}
|
||||
onConfirm={onConfirm}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Remove attributes",
|
||||
description: "dialog title",
|
||||
id: "attributeBulkDeleteDialogTitle"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {counter, plural,
|
||||
one {this attribute}
|
||||
other {{displayQuantity} attributes}
|
||||
}?"
|
||||
description="dialog content"
|
||||
id="attributeBulkDeleteDialogContent"
|
||||
values={{
|
||||
counter: quantity,
|
||||
displayQuantity: <strong>{quantity}</strong>
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
AttributeBulkDeleteDialog.displayName = "AttributeBulkDeleteDialog";
|
||||
export default AttributeBulkDeleteDialog;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import i18n from "@saleor/i18n";
|
||||
|
||||
export interface AttributeDeleteDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
|
@ -19,27 +19,35 @@ const AttributeDeleteDialog: React.FC<AttributeDeleteDialogProps> = ({
|
|||
onClose,
|
||||
onConfirm,
|
||||
open
|
||||
}) => (
|
||||
<ActionDialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
confirmButtonState={confirmButtonState}
|
||||
onConfirm={onConfirm}
|
||||
variant="delete"
|
||||
title={i18n.t("Remove attribute")}
|
||||
>
|
||||
<DialogContentText
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: i18n.t(
|
||||
"Are you sure you want to remove <strong>{{ name }}</strong>?",
|
||||
{
|
||||
name
|
||||
}
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ActionDialog>
|
||||
);
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
confirmButtonState={confirmButtonState}
|
||||
onConfirm={onConfirm}
|
||||
variant="delete"
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Remove attribute",
|
||||
description: "dialog title",
|
||||
id: "attributeDeleteDialogTitle"
|
||||
})}
|
||||
>
|
||||
<DialogContentText>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to remove {name}?"
|
||||
description="dialog content"
|
||||
id="attributeDeleteDialogContent"
|
||||
values={{
|
||||
name: <strong>{name}</strong>
|
||||
}}
|
||||
/>
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
|
||||
AttributeDeleteDialog.displayName = "AttributeDeleteDialog";
|
||||
export default AttributeDeleteDialog;
|
||||
|
|
|
@ -2,13 +2,14 @@ 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 slugify from "slugify";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import ControlledSwitch from "@saleor/components/ControlledSwitch";
|
||||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import SingleSelectField from "@saleor/components/SingleSelectField";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { FormErrors } from "@saleor/types";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
import { AttributePageFormData } from "../AttributePage";
|
||||
|
@ -21,78 +22,108 @@ export interface AttributeDetailsProps {
|
|||
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> = ({
|
||||
canChangeType,
|
||||
data,
|
||||
disabled,
|
||||
errors,
|
||||
onChange
|
||||
}) => (
|
||||
<Card>
|
||||
<CardTitle title={i18n.t("General Information")} />
|
||||
<CardContent>
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.name}
|
||||
label={i18n.t("Default Label")}
|
||||
name={"name" as keyof AttributePageFormData}
|
||||
fullWidth
|
||||
helperText={errors.name}
|
||||
value={data.name}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<FormSpacer />
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.slug}
|
||||
label={i18n.t("Attribute Code")}
|
||||
name={"slug" as keyof AttributePageFormData}
|
||||
placeholder={slugify(data.name).toLowerCase()}
|
||||
fullWidth
|
||||
helperText={
|
||||
errors.slug ||
|
||||
i18n.t("This is used internally. Make sure you don’t use spaces", {
|
||||
context: "slug input"
|
||||
})
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const inputTypeChoices = [
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Dropdown",
|
||||
description: "attribute editor component type",
|
||||
id: "attributeDetailsInputTypeDropdown"
|
||||
}),
|
||||
value: AttributeInputTypeEnum.DROPDOWN
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Multiple Select",
|
||||
description: "attribute editor component type",
|
||||
id: "attributeDetailsInputTypeMultiselect"
|
||||
}),
|
||||
value: AttributeInputTypeEnum.MULTISELECT
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={
|
||||
intl.formatMessage(commonMessages.generalInformations)
|
||||
}
|
||||
value={data.slug}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<FormSpacer />
|
||||
<SingleSelectField
|
||||
choices={inputTypeChoices}
|
||||
disabled={disabled || !canChangeType}
|
||||
error={!!errors.inputType}
|
||||
hint={errors.inputType}
|
||||
label={i18n.t("Catalog Input type for Store Owner", {
|
||||
context: "attribute input type"
|
||||
})}
|
||||
name="inputType"
|
||||
onChange={onChange}
|
||||
value={data.inputType}
|
||||
/>
|
||||
<FormSpacer />
|
||||
<ControlledSwitch
|
||||
checked={data.valueRequired}
|
||||
label={i18n.t("Value Required", {
|
||||
context: "attribute must have value"
|
||||
})}
|
||||
name={"valueRequired" as keyof AttributePageFormData}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
<CardContent>
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.name}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Default Label",
|
||||
description: "attribute label input field",
|
||||
id: "attributeDetailsNameInputLabel"
|
||||
})}
|
||||
name={"name" as keyof AttributePageFormData}
|
||||
fullWidth
|
||||
helperText={errors.name}
|
||||
value={data.name}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<FormSpacer />
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.slug}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Attribute Code",
|
||||
description: "attribute slug input field",
|
||||
id: "attributeDetailsSlugInputLabel"
|
||||
})}
|
||||
name={"slug" as keyof AttributePageFormData}
|
||||
placeholder={slugify(data.name).toLowerCase()}
|
||||
fullWidth
|
||||
helperText={
|
||||
errors.slug ||
|
||||
intl.formatMessage({
|
||||
defaultMessage:
|
||||
"This is used internally. Make sure you don’t 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";
|
||||
export default AttributeDetails;
|
||||
|
|
|
@ -6,12 +6,12 @@ import TableFooter from "@material-ui/core/TableFooter";
|
|||
import TableRow from "@material-ui/core/TableRow";
|
||||
import makeStyles from "@material-ui/styles/makeStyles";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
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";
|
||||
import { translateBoolean } from "@saleor/utils/i18n";
|
||||
|
@ -83,23 +83,39 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
|
|||
toolbar={toolbar}
|
||||
>
|
||||
<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 className={classes.colName}>
|
||||
{i18n.t("Default Label", { context: "attribute name" })}
|
||||
<FormattedMessage
|
||||
defaultMessage="Default Label"
|
||||
description="attribute list: name column header"
|
||||
id="attributeListNameColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colVisible}>
|
||||
{i18n.t("Visible", { context: "attribute visibility" })}
|
||||
<FormattedMessage
|
||||
defaultMessage="Visible"
|
||||
description="attribute list: visibility column header"
|
||||
id="attributeListVisibilityColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colSearchable}>
|
||||
{i18n.t("Searchable", {
|
||||
context: "attribute can be searched in dashboard"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Searchable"
|
||||
description="attribute list: attribute can be searched in dashboard column header"
|
||||
id="attributeListSearchableColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colFaceted}>
|
||||
{i18n.t("Use in faceted search", {
|
||||
context: "attribute can be searched in storefront"
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="Use in faceted search"
|
||||
description="attribute list: attribute can be searched in storefront column header"
|
||||
id="attributeListFacetedColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableHead>
|
||||
<TableFooter>
|
||||
|
@ -170,7 +186,11 @@ const AttributeList: React.StatelessComponent<AttributeListProps> = ({
|
|||
() => (
|
||||
<TableRow>
|
||||
<TableCell colSpan={numberOfColumns}>
|
||||
{i18n.t("No attributes found")}
|
||||
<FormattedMessage
|
||||
defaultMessage="No attributes found"
|
||||
description="no attributes found with present filters"
|
||||
id="AttributeListNoAttributes"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
|
|
@ -2,10 +2,11 @@ import Button from "@material-ui/core/Button";
|
|||
import Card from "@material-ui/core/Card";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import Container from "../../../components/Container";
|
||||
import PageHeader from "../../../components/PageHeader";
|
||||
import i18n from "../../../i18n";
|
||||
import { ListActions, PageListProps } from "../../../types";
|
||||
import { AttributeList_attributes_edges_node } from "../../types/AttributeList";
|
||||
import AttributeList from "../AttributeList/AttributeList";
|
||||
|
@ -17,17 +18,28 @@ export interface AttributeListPageProps extends PageListProps, ListActions {
|
|||
const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
||||
onAdd,
|
||||
...listProps
|
||||
}) => (
|
||||
<Container>
|
||||
<PageHeader title={i18n.t("Attributes")}>
|
||||
<Button onClick={onAdd} color="primary" variant="contained">
|
||||
{i18n.t("Add attribute")} <AddIcon />
|
||||
</Button>
|
||||
</PageHeader>
|
||||
<Card>
|
||||
<AttributeList {...listProps} />
|
||||
</Card>
|
||||
</Container>
|
||||
);
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<PageHeader
|
||||
title={intl.formatMessage(sectionNames.attributes)}
|
||||
>
|
||||
<Button onClick={onAdd} color="primary" variant="contained">
|
||||
<FormattedMessage
|
||||
defaultMessage="New attribute"
|
||||
description="button"
|
||||
id="attributeListPageNewAttribute"
|
||||
/>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
</PageHeader>
|
||||
<Card>
|
||||
<AttributeList {...listProps} />
|
||||
</Card>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
AttributeListPage.displayName = "AttributeListPage";
|
||||
export default AttributeListPage;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import slugify from "slugify";
|
||||
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
|
@ -9,7 +10,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 "@saleor/i18n";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import { ReorderAction, UserError } from "@saleor/types";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
|
@ -62,6 +63,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
|||
onValueReorder,
|
||||
onValueUpdate
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const initialForm: AttributePageFormData =
|
||||
attribute === null
|
||||
? {
|
||||
|
@ -109,12 +111,16 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
|||
<Form errors={errors} initial={initialForm} onSubmit={handleSubmit}>
|
||||
{({ change, errors: formErrors, data, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Attributes")}</AppHeader>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.attributes)}
|
||||
</AppHeader>
|
||||
<PageHeader
|
||||
title={
|
||||
attribute === null
|
||||
? i18n.t("Create New Attribute", {
|
||||
context: "page title"
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Create New Attribute",
|
||||
description: "page title",
|
||||
id: "attributePageTitle"
|
||||
})
|
||||
: maybe(() => attribute.name)
|
||||
}
|
||||
|
|
|
@ -3,13 +3,14 @@ import CardContent from "@material-ui/core/CardContent";
|
|||
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 CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import ControlledSwitch from "@saleor/components/ControlledSwitch";
|
||||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { FormErrors } from "@saleor/types";
|
||||
import { AttributePageFormData } from "../AttributePage";
|
||||
|
||||
|
@ -25,103 +26,136 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
|
|||
errors,
|
||||
disabled,
|
||||
onChange
|
||||
}) => (
|
||||
<Card>
|
||||
<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}
|
||||
/> */}
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
<Typography variant="subtitle1">
|
||||
{i18n.t("Storefront Properties")}
|
||||
</Typography>
|
||||
<Hr />
|
||||
<ControlledSwitch
|
||||
name={"filterableInStorefront" as keyof AttributePageFormData}
|
||||
checked={data.filterableInStorefront}
|
||||
disabled={disabled}
|
||||
label={i18n.t("Use in faceted navigation")}
|
||||
onChange={onChange}
|
||||
/>
|
||||
{data.filterableInStorefront && (
|
||||
<TextField
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={intl.formatMessage(commonMessages.properties)} />
|
||||
<CardContent>
|
||||
{/* <Typography variant="subtitle1">
|
||||
<FormattedMessage
|
||||
defaultMessage="General Properties"
|
||||
description="attribute general properties section"
|
||||
id="attributePropertiesGeneralSectionTitle"
|
||||
/>
|
||||
</Typography>
|
||||
<Hr />
|
||||
<CardSpacer />
|
||||
<ControlledSwitch
|
||||
name={"" as keyof AttributePageFormData}
|
||||
checked={false}
|
||||
disabled={disabled}
|
||||
error={!!errors.storefrontSearchPosition}
|
||||
fullWidth
|
||||
helperText={errors.storefrontSearchPosition}
|
||||
name={"storefrontSearchPosition" as keyof AttributePageFormData}
|
||||
label={i18n.t("Position in faceted navigation")}
|
||||
value={data.storefrontSearchPosition}
|
||||
label={
|
||||
<>
|
||||
<FormattedMessage
|
||||
defaultMessage="Variant Attribute"
|
||||
description="attribute is variant-only"
|
||||
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}
|
||||
/>
|
||||
)}
|
||||
<FormSpacer />
|
||||
<ControlledSwitch
|
||||
name={"visibleInStorefront" as keyof AttributePageFormData}
|
||||
checked={data.visibleInStorefront}
|
||||
disabled={disabled}
|
||||
label={i18n.t("Visible on Product Page in Storefront", {
|
||||
context: "attribute"
|
||||
})}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<CardSpacer />
|
||||
|
||||
<Typography variant="subtitle1">
|
||||
{i18n.t("Dashboard Properties")}
|
||||
</Typography>
|
||||
<Hr />
|
||||
<CardSpacer />
|
||||
<ControlledSwitch
|
||||
name={"filterableInDashboard" as keyof AttributePageFormData}
|
||||
checked={data.filterableInDashboard}
|
||||
disabled={disabled}
|
||||
label={i18n.t("Use in Filtering")}
|
||||
secondLabel={
|
||||
<Typography variant="caption">
|
||||
{i18n.t(
|
||||
"If enabled, you’ll 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={i18n.t("Add to Column Options")}
|
||||
secondLabel={
|
||||
<Typography variant="caption">
|
||||
{i18n.t(
|
||||
"If enable this attribute can be used as a column in product table."
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
{data.filterableInStorefront && (
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.storefrontSearchPosition}
|
||||
fullWidth
|
||||
helperText={errors.storefrontSearchPosition}
|
||||
name={"storefrontSearchPosition" as keyof AttributePageFormData}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Position in faceted navigation",
|
||||
description: "attribute position in storefront filters",
|
||||
id: "attributePropertiesFacetedNavigationPosition"
|
||||
})}
|
||||
value={data.storefrontSearchPosition}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
<FormSpacer />
|
||||
<ControlledSwitch
|
||||
name={"visibleInStorefront" as keyof AttributePageFormData}
|
||||
checked={data.visibleInStorefront}
|
||||
disabled={disabled}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Visible on Product Page in Storefront",
|
||||
description: "attribute",
|
||||
id: "attributePropertiesVisibility"
|
||||
})}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<Typography variant="subtitle1">
|
||||
<FormattedMessage
|
||||
defaultMessage="Dashboard Properties"
|
||||
description="attribute properties regarding dashboard"
|
||||
id="attributePropertiesDashboard"
|
||||
/>
|
||||
</Typography>
|
||||
<Hr />
|
||||
<CardSpacer />
|
||||
<ControlledSwitch
|
||||
name={"filterableInDashboard" as keyof AttributePageFormData}
|
||||
checked={data.filterableInDashboard}
|
||||
disabled={disabled}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Use in Filtering",
|
||||
description: "use attribute in filtering",
|
||||
id: "attributePropertiesDashboardFiltering"
|
||||
})}
|
||||
secondLabel={
|
||||
<Typography variant="caption">
|
||||
<FormattedMessage defaultMessage="If enabled, you’ll 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";
|
||||
export default AttributeProperties;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import i18n from "@saleor/i18n";
|
||||
|
||||
export interface AttributeValueDeleteDialogProps {
|
||||
attributeName: string;
|
||||
|
@ -23,30 +23,46 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
|
|||
onClose,
|
||||
onConfirm,
|
||||
open
|
||||
}) => (
|
||||
<ActionDialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
confirmButtonState={confirmButtonState}
|
||||
onConfirm={onConfirm}
|
||||
variant="delete"
|
||||
title={i18n.t("Remove attribute value")}
|
||||
>
|
||||
<DialogContentText>
|
||||
{useName
|
||||
? i18n.t(
|
||||
'Are you sure you want to remove "{{ name }}" value? If you remove it you won’t be able to assign it to any of the products with "{{ attributeName }}" attribute.',
|
||||
{
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
confirmButtonState={confirmButtonState}
|
||||
onConfirm={onConfirm}
|
||||
variant="delete"
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Remove attribute value",
|
||||
description: "dialog title",
|
||||
id: "attributeValueDeleteDialogTitle"
|
||||
})}
|
||||
>
|
||||
<DialogContentText>
|
||||
{useName ? (
|
||||
<FormattedMessage
|
||||
defaultMessage='Are you sure you want to remove "{ name }" value? If you remove it you won’t be able to assign it to any of the products with "{ attributeName }" attribute.'
|
||||
id="attributeValueDeleteDialogContentWithAttributeName"
|
||||
values={{
|
||||
attributeName,
|
||||
name
|
||||
}
|
||||
)
|
||||
: i18n.t('Are you sure you want to remove "{{ name }}" value?', {
|
||||
name
|
||||
})}
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage='Are you sure you want to remove "{ name }" value?'
|
||||
description="remove attribute value"
|
||||
id="attributeValueDeleteDialogContentWithoutAttributeName"
|
||||
values={{
|
||||
name
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
|
||||
AttributeValueDeleteDialog.displayName = "AttributeValueDeleteDialog";
|
||||
export default AttributeValueDeleteDialog;
|
||||
|
|
|
@ -5,13 +5,14 @@ import DialogContent from "@material-ui/core/DialogContent";
|
|||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import ConfirmButton, {
|
||||
ConfirmButtonTransitionState
|
||||
} from "@saleor/components/ConfirmButton";
|
||||
import Form from "@saleor/components/Form";
|
||||
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import { UserError } from "@saleor/types";
|
||||
import { AttributeDetails_attribute_values } from "../../types/AttributeDetails";
|
||||
|
@ -40,6 +41,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
|
|||
onSubmit,
|
||||
open
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const initialForm: AttributeValueEditDialogFormData = {
|
||||
name: maybe(() => attributeValue.name, "")
|
||||
};
|
||||
|
@ -48,13 +50,19 @@ const AttributeValueEditDialog: React.StatelessComponent<
|
|||
return (
|
||||
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
|
||||
<DialogTitle>
|
||||
{attributeValue === null
|
||||
? i18n.t("Add Value", {
|
||||
context: "add attribute value"
|
||||
})
|
||||
: i18n.t("Edit Value", {
|
||||
context: "edit attribute value"
|
||||
})}
|
||||
{attributeValue === null ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Add Value"
|
||||
description="add attribute value"
|
||||
id="attributeValueEditDialogTitleNewValue"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit Value"
|
||||
description="edit attribute value"
|
||||
id="attributeValueEditDialogTitle"
|
||||
/>
|
||||
)}
|
||||
</DialogTitle>
|
||||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({ change, data, errors: formErrors, submit }) => (
|
||||
|
@ -67,8 +75,10 @@ const AttributeValueEditDialog: React.StatelessComponent<
|
|||
fullWidth
|
||||
helperText={formErrors.name}
|
||||
name={"name" as keyof AttributeValueEditDialogFormData}
|
||||
label={i18n.t("Name", {
|
||||
context: "attribute name"
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Name",
|
||||
description: "attribute name",
|
||||
id: "attributeValueEditDialogNameField"
|
||||
})}
|
||||
value={data.name}
|
||||
onChange={change}
|
||||
|
@ -76,7 +86,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
|
|||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose}>
|
||||
{i18n.t("Cancel", { context: "button" })}
|
||||
<FormattedMessage {...commonMessages.cancel} />
|
||||
</Button>
|
||||
<ConfirmButton
|
||||
transitionState={confirmButtonState}
|
||||
|
@ -84,7 +94,7 @@ const AttributeValueEditDialog: React.StatelessComponent<
|
|||
variant="contained"
|
||||
onClick={submit}
|
||||
>
|
||||
{i18n.t("Save")}
|
||||
<FormattedMessage {...commonMessages.save} />
|
||||
</ConfirmButton>
|
||||
</DialogActions>
|
||||
</>
|
||||
|
|
|
@ -9,6 +9,7 @@ import TableRow from "@material-ui/core/TableRow";
|
|||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import makeStyles from "@material-ui/styles/makeStyles";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
|
@ -16,7 +17,6 @@ import {
|
|||
SortableTableBody,
|
||||
SortableTableRow
|
||||
} from "@saleor/components/SortableTable";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { maybe, renderCollection, stopPropagation } from "@saleor/misc";
|
||||
import { ReorderAction } from "@saleor/types";
|
||||
import { AttributeDetailsFragment_values } from "../../types/AttributeDetailsFragment";
|
||||
|
@ -63,14 +63,23 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
|
|||
values
|
||||
}) => {
|
||||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Attribute Values")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Attribute Values",
|
||||
description: "section header",
|
||||
id: "attributeValuesHeader"
|
||||
})}
|
||||
toolbar={
|
||||
<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>
|
||||
}
|
||||
/>
|
||||
|
@ -79,10 +88,18 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
|
|||
<TableRow>
|
||||
<TableCell className={classes.columnDrag} />
|
||||
<TableCell className={classes.columnAdmin}>
|
||||
{i18n.t("Admin")}
|
||||
<FormattedMessage
|
||||
defaultMessage="Admin"
|
||||
description="attribute values list: slug column header"
|
||||
id="attributeValuesSlugColumnHeader"
|
||||
/>
|
||||
</TableCell>
|
||||
<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 />
|
||||
</TableRow>
|
||||
|
@ -116,7 +133,13 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
|
|||
),
|
||||
() => (
|
||||
<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>
|
||||
)
|
||||
)}
|
||||
|
|
|
@ -2,8 +2,9 @@ import { parse as parseQs } from "qs";
|
|||
import React from "react";
|
||||
import { Route, RouteComponentProps, Switch } from "react-router-dom";
|
||||
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { useIntl } from "react-intl";
|
||||
import { WindowTitle } from "../components/WindowTitle";
|
||||
import i18n from "../i18n";
|
||||
import {
|
||||
attributeAddPath,
|
||||
AttributeAddUrlQueryParams,
|
||||
|
@ -42,14 +43,18 @@ const AttributeDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export const AttributeSection: React.FC = () => (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Attributes")} />
|
||||
<Switch>
|
||||
<Route exact path={attributeListPath} component={AttributeList} />
|
||||
<Route exact path={attributeAddPath} component={AttributeCreate} />
|
||||
<Route path={attributePath(":id")} component={AttributeDetails} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
export const AttributeSection: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={intl.formatMessage(sectionNames.attributes)} />
|
||||
<Switch>
|
||||
<Route exact path={attributeListPath} component={AttributeList} />
|
||||
<Route exact path={attributeAddPath} component={AttributeCreate} />
|
||||
<Route path={attributePath(":id")} component={AttributeDetails} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default AttributeSection;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import slugify from "slugify";
|
||||
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { getMutationState, maybe } from "@saleor/misc";
|
||||
import { ReorderEvent, UserError } from "@saleor/types";
|
||||
import {
|
||||
|
@ -42,6 +42,7 @@ function areValuesEqual(
|
|||
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
const [values, setValues] = React.useState<
|
||||
AttributeValueEditDialogFormData[]
|
||||
|
@ -75,7 +76,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
};
|
||||
const handleCreate = (data: AttributeCreate) => {
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
@ -84,10 +90,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
setValueErrors([
|
||||
{
|
||||
field: "name",
|
||||
message: i18n.t("A value named {{ name }} already exists", {
|
||||
context: "value edit error",
|
||||
name: input.name
|
||||
})
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "A value named { name } already exists",
|
||||
description: "attribute value edit error",
|
||||
id: "attributeCreateErrorExists"
|
||||
},
|
||||
{
|
||||
name: input.name
|
||||
}
|
||||
)
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
|
@ -100,10 +112,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
setValueErrors([
|
||||
{
|
||||
field: "name",
|
||||
message: i18n.t("A value named {{ name }} already exists", {
|
||||
context: "value edit error",
|
||||
name: input.name
|
||||
})
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "A value named { name } already exists",
|
||||
description: "attribute value edit error",
|
||||
id: "attributeCreateErrorExists"
|
||||
},
|
||||
{
|
||||
name: input.name
|
||||
}
|
||||
)
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import i18n from "@saleor/i18n";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { getMutationState, maybe } from "@saleor/misc";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import { move } from "@saleor/utils/lists";
|
||||
|
@ -40,6 +41,7 @@ interface AttributeDetailsProps {
|
|||
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
const closeModal = () =>
|
||||
navigate(
|
||||
|
@ -63,39 +65,54 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
|
||||
const handleDelete = (data: AttributeDelete) => {
|
||||
if (data.attributeDelete.errors.length === 0) {
|
||||
notify({ text: i18n.t("Attribute removed") });
|
||||
notify({
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Attribute removed",
|
||||
id: "attributeDetailsAttributeRemoveSuccess"
|
||||
})
|
||||
});
|
||||
navigate(attributeListUrl());
|
||||
}
|
||||
};
|
||||
const handleValueDelete = (data: AttributeValueDelete) => {
|
||||
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();
|
||||
}
|
||||
};
|
||||
const handleUpdate = (data: AttributeUpdate) => {
|
||||
if (data.attributeUpdate.errors.length === 0) {
|
||||
notify({ text: i18n.t("Saved changes") });
|
||||
notify({ text: intl.formatMessage(commonMessages.savedChanges) });
|
||||
}
|
||||
};
|
||||
const handleValueUpdate = (data: AttributeValueUpdate) => {
|
||||
if (data.attributeValueUpdate.errors.length === 0) {
|
||||
notify({ text: i18n.t("Saved changes") });
|
||||
notify({ text: intl.formatMessage(commonMessages.savedChanges) });
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
const handleValueCreate = (data: AttributeValueCreate) => {
|
||||
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();
|
||||
}
|
||||
};
|
||||
const handleValueReorderMutation = (data: AttributeValueReorder) => {
|
||||
if (data.attributeReorderValues.errors.length !== 0) {
|
||||
notify({
|
||||
text: i18n.t("Error: {{ errorMessage }}", {
|
||||
errorMessage: data.attributeReorderValues.errors[0].message
|
||||
})
|
||||
text: data.attributeReorderValues.errors[0].message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import IconButton from "@material-ui/core/IconButton";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
|
@ -9,7 +10,6 @@ import usePaginator, {
|
|||
} from "@saleor/hooks/usePaginator";
|
||||
import { PAGINATE_BY } from "../../../config";
|
||||
import useBulkActions from "../../../hooks/useBulkActions";
|
||||
import i18n from "../../../i18n";
|
||||
import { getMutationState, maybe } from "../../../misc";
|
||||
import AttributeBulkDeleteDialog from "../../components/AttributeBulkDeleteDialog";
|
||||
import AttributeListPage from "../../components/AttributeListPage";
|
||||
|
@ -35,6 +35,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
||||
params.ids
|
||||
);
|
||||
const intl = useIntl();
|
||||
|
||||
const closeModal = () =>
|
||||
navigate(
|
||||
|
@ -71,7 +72,11 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
if (data.attributeBulkDelete.errors.length === 0) {
|
||||
closeModal();
|
||||
notify({
|
||||
text: i18n.t("Attributes removed")
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Attributes successfully removed",
|
||||
description: "remove multiple attributes",
|
||||
id: "attributeListAttributesRemoved"
|
||||
})
|
||||
});
|
||||
reset();
|
||||
refetch();
|
||||
|
@ -116,12 +121,15 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
/>
|
||||
<AttributeBulkDeleteDialog
|
||||
confirmButtonState={bulkDeleteMutationState}
|
||||
open={params.action === "remove"}
|
||||
open={
|
||||
params.action === "remove" &&
|
||||
maybe(() => params.ids.length > 0)
|
||||
}
|
||||
onConfirm={() =>
|
||||
attributeBulkDelete({ variables: { ids: params.ids } })
|
||||
}
|
||||
onClose={closeModal}
|
||||
quantity={maybe(() => params.ids.length.toString(), "...")}
|
||||
quantity={maybe(() => params.ids.length)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue