Add product variant translation view (#1285)
* Add product variant translation view * Final adjustments
This commit is contained in:
parent
6d3e346a19
commit
b65a632e07
27 changed files with 940 additions and 13 deletions
|
@ -1583,6 +1583,10 @@
|
|||
"context": "alert",
|
||||
"string": "Channel limit reached"
|
||||
},
|
||||
"src_dot_channels_dot_pages_dot_ChannelsListPage_dot_3277722884": {
|
||||
"context": "created channels counter",
|
||||
"string": "{count}/{max} channels used"
|
||||
},
|
||||
"src_dot_channels_dot_pages_dot_ChannelsListPage_dot_3511613983": {
|
||||
"context": "channel name",
|
||||
"string": "Channel Name"
|
||||
|
@ -3445,6 +3449,13 @@
|
|||
"context": "orders section name",
|
||||
"string": "Orders"
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_2214147779": {
|
||||
"context": "alert",
|
||||
"string": "Order limit reached"
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_3769643084": {
|
||||
"string": "You have reached your order limit, you will be billed extra for orders above limit. If you would like to up your limit, contact your administration staff about raising your limits."
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_DraftOrderChannelSectionCard_dot_1243773440": {
|
||||
"context": "section header",
|
||||
"string": "Sales channel"
|
||||
|
@ -3670,6 +3681,10 @@
|
|||
"context": "button",
|
||||
"string": "Add products"
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_OrderDraftListPage_dot_1629108523": {
|
||||
"context": "placed orders counter",
|
||||
"string": "{count}/{max} orders"
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_OrderDraftListPage_dot_2826235371": {
|
||||
"context": "button",
|
||||
"string": "Create order"
|
||||
|
@ -4010,9 +4025,9 @@
|
|||
"context": "generate invoice button",
|
||||
"string": "Generate"
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_OrderListPage_dot_2214147779": {
|
||||
"context": "alert",
|
||||
"string": "Order limit reached"
|
||||
"src_dot_orders_dot_components_dot_OrderListPage_dot_1629108523": {
|
||||
"context": "placed order counter",
|
||||
"string": "{count}/{max} orders"
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_OrderListPage_dot_2225897825": {
|
||||
"context": "button",
|
||||
|
@ -4025,9 +4040,6 @@
|
|||
"src_dot_orders_dot_components_dot_OrderListPage_dot_355376157": {
|
||||
"string": "Search Orders..."
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_OrderListPage_dot_3769643084": {
|
||||
"string": "You have reached your order limit, you will be billed extra for orders above limit. If you would like to up your limit, contact your administration staff about raising your limits."
|
||||
},
|
||||
"src_dot_orders_dot_components_dot_OrderListPage_dot_875489544": {
|
||||
"context": "tab name",
|
||||
"string": "All Orders"
|
||||
|
@ -5382,6 +5394,10 @@
|
|||
"context": "alert",
|
||||
"string": "SKU limit reached"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductListPage_dot_3155791658": {
|
||||
"context": "created products counter",
|
||||
"string": "{count}/{max} SKUs used"
|
||||
},
|
||||
"src_dot_products_dot_components_dot_ProductListPage_dot_3550330425": {
|
||||
"string": "Search Products..."
|
||||
},
|
||||
|
@ -6508,6 +6524,10 @@
|
|||
"context": "button",
|
||||
"string": "Invite staff member"
|
||||
},
|
||||
"src_dot_staff_dot_components_dot_StaffListPage_dot_938945387": {
|
||||
"context": "used staff users counter",
|
||||
"string": "{count}/{max} members"
|
||||
},
|
||||
"src_dot_staff_dot_components_dot_StaffListPage_dot_active": {
|
||||
"context": "staff member's account",
|
||||
"string": "Active"
|
||||
|
@ -6675,6 +6695,12 @@
|
|||
"context": "translations section name",
|
||||
"string": "Translations"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_ProductContextSwitcher_dot_1932340772": {
|
||||
"string": "Translating"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_ProductContextSwitcher_dot_197468239": {
|
||||
"string": "Main Product"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_TranslationFields_dot_1308081812": {
|
||||
"string": "{numberOfFields} Translations, {numberOfTranslatedFields} Completed"
|
||||
},
|
||||
|
@ -6815,6 +6841,17 @@
|
|||
"src_dot_translations_dot_components_dot_TranslationsPagesPage_dot_432157284": {
|
||||
"string": "Page Title"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_TranslationsProductVariantsPage_dot_4165966072": {
|
||||
"context": "attribute list",
|
||||
"string": "Attribute {number}"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_TranslationsProductVariantsPage_dot_847507870": {
|
||||
"context": "header",
|
||||
"string": "Translation Product Variant \"{productName}\" - {languageCode}"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_TranslationsProductVariantsPage_dot_953327101": {
|
||||
"string": "Variant Name"
|
||||
},
|
||||
"src_dot_translations_dot_components_dot_TranslationsProductsPage_dot_1406947243": {
|
||||
"string": "Search Engine Description"
|
||||
},
|
||||
|
@ -7118,6 +7155,10 @@
|
|||
"src_dot_warehouses_dot_components_dot_WarehouseInfo_dot_2622674857": {
|
||||
"string": "Warehouse Name"
|
||||
},
|
||||
"src_dot_warehouses_dot_components_dot_WarehouseListPage_dot_1082745946": {
|
||||
"context": "used warehouses counter",
|
||||
"string": "{count}/{max} warehouses used"
|
||||
},
|
||||
"src_dot_warehouses_dot_components_dot_WarehouseListPage_dot_2304765290": {
|
||||
"string": "Search Warehouse"
|
||||
},
|
||||
|
|
|
@ -84,6 +84,41 @@ export const productTranslationFragment = gql`
|
|||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const productVariantTranslationFragment = gql`
|
||||
fragment ProductVariantTranslationFragment on ProductVariantTranslatableContent {
|
||||
productVariant {
|
||||
id
|
||||
}
|
||||
name
|
||||
translation(languageCode: $language) {
|
||||
id
|
||||
name
|
||||
language {
|
||||
code
|
||||
language
|
||||
}
|
||||
}
|
||||
attributeValues {
|
||||
id
|
||||
name
|
||||
richText
|
||||
attributeValue {
|
||||
id
|
||||
}
|
||||
translation(languageCode: $language) {
|
||||
id
|
||||
name
|
||||
richText
|
||||
language {
|
||||
code
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const saleTranslationFragment = gql`
|
||||
fragment SaleTranslationFragment on SaleTranslatableContent {
|
||||
sale {
|
||||
|
|
64
src/fragments/types/ProductVariantTranslationFragment.ts
Normal file
64
src/fragments/types/ProductVariantTranslationFragment.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: ProductVariantTranslationFragment
|
||||
// ====================================================
|
||||
|
||||
export interface ProductVariantTranslationFragment_productVariant {
|
||||
__typename: "ProductVariant";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment_translation_language {
|
||||
__typename: "LanguageDisplay";
|
||||
code: LanguageCodeEnum;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment_translation {
|
||||
__typename: "ProductVariantTranslation";
|
||||
id: string;
|
||||
name: string;
|
||||
language: ProductVariantTranslationFragment_translation_language;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment_attributeValues_attributeValue {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment_attributeValues_translation_language {
|
||||
__typename: "LanguageDisplay";
|
||||
code: LanguageCodeEnum;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment_attributeValues_translation {
|
||||
__typename: "AttributeValueTranslation";
|
||||
id: string;
|
||||
name: string;
|
||||
richText: any | null;
|
||||
language: ProductVariantTranslationFragment_attributeValues_translation_language;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment_attributeValues {
|
||||
__typename: "AttributeValueTranslatableContent";
|
||||
id: string;
|
||||
name: string;
|
||||
richText: any | null;
|
||||
attributeValue: ProductVariantTranslationFragment_attributeValues_attributeValue | null;
|
||||
translation: ProductVariantTranslationFragment_attributeValues_translation | null;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationFragment {
|
||||
__typename: "ProductVariantTranslatableContent";
|
||||
productVariant: ProductVariantTranslationFragment_productVariant | null;
|
||||
name: string;
|
||||
translation: ProductVariantTranslationFragment_translation | null;
|
||||
attributeValues: ProductVariantTranslationFragment_attributeValues[];
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
import {
|
||||
Card,
|
||||
ClickAwayListener,
|
||||
Grow,
|
||||
MenuItem,
|
||||
MenuList as Menu,
|
||||
Paper,
|
||||
Popper,
|
||||
Typography
|
||||
} from "@material-ui/core";
|
||||
import ArrowDropDown from "@material-ui/icons/ArrowDropDown";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import { makeStyles } from "@saleor/macaw-ui";
|
||||
import {
|
||||
languageEntityUrl,
|
||||
productVariantUrl,
|
||||
TranslatableEntities
|
||||
} from "@saleor/translations/urls";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { useProductVariantList } from "../../queries";
|
||||
|
||||
export interface ProductContextSwitcherProps {
|
||||
productId: string;
|
||||
selectedId: string;
|
||||
languageCode: string;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
arrow: {
|
||||
color: theme.palette.primary.main,
|
||||
transition: theme.transitions.duration.standard + "ms"
|
||||
},
|
||||
container: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
paddingBottom: theme.spacing(1),
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
label: {
|
||||
paddingRight: theme.spacing(1)
|
||||
},
|
||||
menuContainer: {
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
minWidth: 90,
|
||||
padding: theme.spacing(),
|
||||
position: "relative"
|
||||
},
|
||||
menuItem: {
|
||||
textAlign: "justify"
|
||||
},
|
||||
menuPaper: {
|
||||
maxHeight: `calc(100vh - ${theme.spacing(2)}px)`,
|
||||
overflow: "scroll"
|
||||
},
|
||||
popover: {
|
||||
zIndex: 1
|
||||
},
|
||||
rotate: {
|
||||
transform: "rotate(180deg)"
|
||||
}
|
||||
}),
|
||||
{ name: "ProductContextSwitcher" }
|
||||
);
|
||||
const ProductContextSwitcher: React.FC<ProductContextSwitcherProps> = ({
|
||||
languageCode,
|
||||
productId,
|
||||
selectedId
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const navigate = useNavigator();
|
||||
const intl = useIntl();
|
||||
const { data } = useProductVariantList({
|
||||
variables: { id: productId }
|
||||
});
|
||||
|
||||
const [isExpanded, setExpandedState] = React.useState(false);
|
||||
const anchor = React.useRef();
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: intl.formatMessage({ defaultMessage: "Main Product" }),
|
||||
value: productId,
|
||||
onClick: () =>
|
||||
navigate(
|
||||
languageEntityUrl(
|
||||
languageCode,
|
||||
TranslatableEntities.products,
|
||||
productId
|
||||
)
|
||||
)
|
||||
},
|
||||
...(data?.product?.variants?.map(({ name, sku, id }) => ({
|
||||
label: name || sku,
|
||||
value: id,
|
||||
onClick: () => navigate(productVariantUrl(languageCode, productId, id))
|
||||
})) || [])
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<Typography className={classes.label}>
|
||||
<FormattedMessage defaultMessage="Translating" />:
|
||||
</Typography>
|
||||
<div ref={anchor}>
|
||||
<Card
|
||||
className={classes.menuContainer}
|
||||
onClick={() => setExpandedState(!isExpanded)}
|
||||
>
|
||||
<Typography>
|
||||
{items.find(({ value }) => value === selectedId)?.label || "-"}
|
||||
</Typography>
|
||||
<ArrowDropDown
|
||||
className={classNames(classes.arrow, {
|
||||
[classes.rotate]: isExpanded
|
||||
})}
|
||||
/>
|
||||
</Card>
|
||||
<Popper
|
||||
className={classes.popover}
|
||||
open={isExpanded}
|
||||
anchorEl={anchor.current}
|
||||
transition
|
||||
disablePortal
|
||||
placement="bottom-end"
|
||||
>
|
||||
{({ TransitionProps, placement }) => (
|
||||
<Grow
|
||||
{...TransitionProps}
|
||||
style={{
|
||||
transformOrigin:
|
||||
placement === "bottom" ? "right top" : "right bottom"
|
||||
}}
|
||||
>
|
||||
<Paper className={classes.menuPaper}>
|
||||
<ClickAwayListener
|
||||
onClickAway={() => setExpandedState(false)}
|
||||
mouseEvent="onClick"
|
||||
>
|
||||
<Menu>
|
||||
{items.map(({ label, value, onClick }) => (
|
||||
<MenuItem
|
||||
key={value}
|
||||
className={classes.menuItem}
|
||||
onClick={() => {
|
||||
setExpandedState(false);
|
||||
onClick();
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Grow>
|
||||
)}
|
||||
</Popper>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
ProductContextSwitcher.displayName = "ProductContextSwitcher";
|
||||
export default ProductContextSwitcher;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./ProductContextSwitcher";
|
||||
export { default } from "./ProductContextSwitcher";
|
|
@ -38,6 +38,7 @@ export interface TranslationFieldsProps {
|
|||
initialState: boolean;
|
||||
saveButtonState: ConfirmButtonTransitionState;
|
||||
pagination?: Pagination;
|
||||
richTextResetKey: string; // temporary workaround TODO: fix rich text editor
|
||||
onEdit: (field: string) => void;
|
||||
onDiscard: () => void;
|
||||
onSubmit: (field: TranslationField, data: string | OutputData) => void;
|
||||
|
@ -120,6 +121,7 @@ const TranslationFields: React.FC<TranslationFieldsProps> = props => {
|
|||
title,
|
||||
saveButtonState,
|
||||
pagination,
|
||||
richTextResetKey,
|
||||
onEdit,
|
||||
onDiscard,
|
||||
onSubmit
|
||||
|
@ -187,6 +189,7 @@ const TranslationFields: React.FC<TranslationFieldsProps> = props => {
|
|||
/>
|
||||
) : (
|
||||
<TranslationFieldsRich
|
||||
resetKey={richTextResetKey}
|
||||
disabled={disabled}
|
||||
edit={false}
|
||||
initial={field.value}
|
||||
|
@ -221,6 +224,7 @@ const TranslationFields: React.FC<TranslationFieldsProps> = props => {
|
|||
/>
|
||||
) : (
|
||||
<TranslationFieldsRich
|
||||
resetKey={richTextResetKey}
|
||||
disabled={disabled}
|
||||
edit={activeField === field.name}
|
||||
initial={field.translation}
|
||||
|
|
|
@ -14,6 +14,7 @@ interface TranslationFieldsRichProps {
|
|||
edit: boolean;
|
||||
initial: string;
|
||||
saveButtonState: ConfirmButtonTransitionState;
|
||||
resetKey: string;
|
||||
onDiscard: () => void;
|
||||
onSubmit: (data: OutputData) => void;
|
||||
}
|
||||
|
@ -23,6 +24,7 @@ const TranslationFieldsRich: React.FC<TranslationFieldsRichProps> = ({
|
|||
edit,
|
||||
initial,
|
||||
saveButtonState,
|
||||
resetKey,
|
||||
onDiscard,
|
||||
onSubmit
|
||||
}) => {
|
||||
|
@ -59,7 +61,7 @@ const TranslationFieldsRich: React.FC<TranslationFieldsRichProps> = ({
|
|||
</Typography>
|
||||
) : (
|
||||
<Typography>
|
||||
<RichTextEditorContent data={JSON.parse(initial)} />
|
||||
<RichTextEditorContent key={resetKey} data={JSON.parse(initial)} />
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -107,6 +107,7 @@ const TranslationsAttributesPage: React.FC<TranslationsAttributesPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -142,6 +143,7 @@ const TranslationsAttributesPage: React.FC<TranslationsAttributesPageProps> = ({
|
|||
) || []
|
||||
}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
pagination={{
|
||||
settings,
|
||||
onUpdateListSettings,
|
||||
|
|
|
@ -83,6 +83,7 @@ const TranslationsCategoriesPage: React.FC<TranslationsCategoriesPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -116,6 +117,7 @@ const TranslationsCategoriesPage: React.FC<TranslationsCategoriesPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
|
|
@ -84,6 +84,7 @@ const TranslationsCollectionsPage: React.FC<TranslationsCollectionsPageProps> =
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -117,6 +118,7 @@ const TranslationsCollectionsPage: React.FC<TranslationsCollectionsPageProps> =
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
|
|
@ -88,6 +88,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -122,6 +123,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -153,6 +155,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
|
|||
})) || []
|
||||
}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onAttributeValueSubmit}
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Container from "@saleor/components/Container";
|
||||
import LanguageSwitch from "@saleor/components/LanguageSwitch";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import { ProductVariantTranslationFragment } from "@saleor/fragments/types/ProductVariantTranslationFragment";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { Backlink } from "@saleor/macaw-ui";
|
||||
import { getStringOrPlaceholder } from "@saleor/misc";
|
||||
import {
|
||||
TranslationInputFieldName,
|
||||
TranslationsEntitiesPageProps
|
||||
} from "@saleor/translations/types";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { LanguageCodeEnum } from "../../../types/globalTypes";
|
||||
import ProductContextSwitcher from "../ProductContextSwitcher";
|
||||
import TranslationFields from "../TranslationFields";
|
||||
|
||||
export interface TranslationsProductsPageProps
|
||||
extends TranslationsEntitiesPageProps {
|
||||
data: ProductVariantTranslationFragment;
|
||||
productId: string;
|
||||
variantId: string;
|
||||
onAttributeValueSubmit: TranslationsEntitiesPageProps["onSubmit"];
|
||||
}
|
||||
|
||||
const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
|
||||
activeField,
|
||||
disabled,
|
||||
languageCode,
|
||||
languages,
|
||||
data,
|
||||
saveButtonState,
|
||||
productId,
|
||||
variantId,
|
||||
onBack,
|
||||
onDiscard,
|
||||
onEdit,
|
||||
onLanguageChange,
|
||||
onSubmit,
|
||||
onAttributeValueSubmit
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Backlink onClick={onBack}>
|
||||
{intl.formatMessage(sectionNames.products)}
|
||||
</Backlink>
|
||||
<PageHeader
|
||||
title={intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
'Translation Product Variant "{productName}" - {languageCode}',
|
||||
description: "header"
|
||||
},
|
||||
{
|
||||
languageCode,
|
||||
productName: getStringOrPlaceholder(data?.name)
|
||||
}
|
||||
)}
|
||||
>
|
||||
<ProductContextSwitcher
|
||||
languageCode={languageCode}
|
||||
productId={productId}
|
||||
selectedId={variantId}
|
||||
/>
|
||||
<LanguageSwitch
|
||||
currentLanguage={LanguageCodeEnum[languageCode]}
|
||||
languages={languages}
|
||||
onLanguageChange={onLanguageChange}
|
||||
/>
|
||||
</PageHeader>
|
||||
<TranslationFields
|
||||
activeField={activeField}
|
||||
disabled={disabled}
|
||||
initialState={true}
|
||||
title={intl.formatMessage(commonMessages.generalInformations)}
|
||||
fields={[
|
||||
{
|
||||
displayName: intl.formatMessage({
|
||||
defaultMessage: "Variant Name"
|
||||
}),
|
||||
name: TranslationInputFieldName.name,
|
||||
translation: data?.translation?.name || null,
|
||||
type: "short" as "short",
|
||||
value: data?.name
|
||||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
<CardSpacer />
|
||||
{data?.attributeValues?.length > 0 && (
|
||||
<>
|
||||
<TranslationFields
|
||||
activeField={activeField}
|
||||
disabled={disabled}
|
||||
initialState={true}
|
||||
title={intl.formatMessage(commonMessages.translationAttributes)}
|
||||
fields={
|
||||
data.attributeValues.map((attrVal, i) => ({
|
||||
id: attrVal.attributeValue.id,
|
||||
displayName: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Attribute {number}",
|
||||
description: "attribute list"
|
||||
},
|
||||
{
|
||||
number: i + 1
|
||||
}
|
||||
),
|
||||
name: attrVal?.name,
|
||||
translation: attrVal?.translation?.richText || null,
|
||||
type: "rich" as "rich",
|
||||
value: attrVal?.richText
|
||||
})) || []
|
||||
}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onAttributeValueSubmit}
|
||||
/>
|
||||
<CardSpacer />
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
TranslationsProductsPage.displayName = "TranslationsProductsPage";
|
||||
export default TranslationsProductsPage;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./TranslationsProductVariantsPage";
|
||||
export * from "./TranslationsProductVariantsPage";
|
|
@ -14,15 +14,18 @@ import React from "react";
|
|||
import { useIntl } from "react-intl";
|
||||
|
||||
import { LanguageCodeEnum } from "../../../types/globalTypes";
|
||||
import ProductContextSwitcher from "../ProductContextSwitcher";
|
||||
import TranslationFields from "../TranslationFields";
|
||||
|
||||
export interface TranslationsProductsPageProps
|
||||
extends TranslationsEntitiesPageProps {
|
||||
data: ProductTranslationFragment;
|
||||
productId: string;
|
||||
onAttributeValueSubmit: TranslationsEntitiesPageProps["onSubmit"];
|
||||
}
|
||||
|
||||
const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
|
||||
productId,
|
||||
activeField,
|
||||
disabled,
|
||||
languageCode,
|
||||
|
@ -56,6 +59,11 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
|
|||
}
|
||||
)}
|
||||
>
|
||||
<ProductContextSwitcher
|
||||
languageCode={languageCode}
|
||||
productId={productId}
|
||||
selectedId={productId}
|
||||
/>
|
||||
<LanguageSwitch
|
||||
currentLanguage={LanguageCodeEnum[languageCode]}
|
||||
languages={languages}
|
||||
|
@ -88,6 +96,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -121,6 +130,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
@ -152,6 +162,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
|
|||
})) || []
|
||||
}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onAttributeValueSubmit}
|
||||
|
|
|
@ -76,6 +76,7 @@ const TranslationsSalesPage: React.FC<TranslationsSalesPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
|
|
@ -87,6 +87,7 @@ const TranslationsShippingMethodPage: React.FC<TranslationsShippingMethodPagePro
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
|
|
@ -77,6 +77,7 @@ const TranslationsVouchersPage: React.FC<TranslationsVouchersPageProps> = ({
|
|||
}
|
||||
]}
|
||||
saveButtonState={saveButtonState}
|
||||
richTextResetKey={languageCode}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onSubmit={onSubmit}
|
||||
|
|
|
@ -29,6 +29,9 @@ import TranslationsPagesComponent, {
|
|||
import TranslationsProductsComponent, {
|
||||
TranslationsProductsQueryParams
|
||||
} from "./views/TranslationsProducts";
|
||||
import TranslationsProductVariantsComponent, {
|
||||
TranslationsProductVariantsQueryParams
|
||||
} from "./views/TranslationsProductVariants";
|
||||
import TranslationsSaleComponent, {
|
||||
TranslationsSalesQueryParams
|
||||
} from "./views/TranslationsSales";
|
||||
|
@ -107,6 +110,28 @@ const TranslationsProducts: React.FC<TranslationsEntityRouteProps> = ({
|
|||
/>
|
||||
);
|
||||
};
|
||||
type TranslationsProductVariantProps = RouteComponentProps<{
|
||||
productId: string;
|
||||
id: string;
|
||||
languageCode: string;
|
||||
}>;
|
||||
const TranslationsProductVariants: React.FC<TranslationsProductVariantProps> = ({
|
||||
location,
|
||||
match
|
||||
}) => {
|
||||
const qs = parseQs(location.search.substr(1));
|
||||
const params: TranslationsProductVariantsQueryParams = {
|
||||
activeField: qs.activeField
|
||||
};
|
||||
return (
|
||||
<TranslationsProductVariantsComponent
|
||||
id={decodeURIComponent(match.params.id)}
|
||||
productId={decodeURIComponent(match.params.productId)}
|
||||
languageCode={LanguageCodeEnum[match.params.languageCode]}
|
||||
params={params}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const TranslationsSales: React.FC<TranslationsEntityRouteProps> = ({
|
||||
location,
|
||||
match
|
||||
|
@ -214,6 +239,17 @@ const TranslationsRouter: React.FC = () => {
|
|||
)}
|
||||
component={TranslationsProducts}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={languageEntityPath(
|
||||
":languageCode",
|
||||
TranslatableEntities.products,
|
||||
":productId",
|
||||
TranslatableEntities.productVariants,
|
||||
":id"
|
||||
)}
|
||||
component={TranslationsProductVariants}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={languageEntityPath(
|
||||
|
|
|
@ -26,6 +26,10 @@ import {
|
|||
UpdateProductTranslations,
|
||||
UpdateProductTranslationsVariables
|
||||
} from "./types/UpdateProductTranslations";
|
||||
import {
|
||||
UpdateProductVariantTranslations,
|
||||
UpdateProductVariantTranslationsVariables
|
||||
} from "./types/UpdateProductVariantTranslations";
|
||||
import {
|
||||
UpdateSaleTranslations,
|
||||
UpdateSaleTranslationsVariables
|
||||
|
@ -76,6 +80,37 @@ export const TypedUpdateProductTranslations = TypedMutation<
|
|||
UpdateProductTranslationsVariables
|
||||
>(updateProductTranslations);
|
||||
|
||||
const updateProductVariantTranslations = gql`
|
||||
mutation UpdateProductVariantTranslations(
|
||||
$id: ID!
|
||||
$input: NameTranslationInput!
|
||||
$language: LanguageCodeEnum!
|
||||
) {
|
||||
productVariantTranslate(id: $id, input: $input, languageCode: $language) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
productVariant {
|
||||
id
|
||||
name
|
||||
translation(languageCode: $language) {
|
||||
id
|
||||
name
|
||||
language {
|
||||
code
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const TypedUpdateProductVariantTranslations = TypedMutation<
|
||||
UpdateProductVariantTranslations,
|
||||
UpdateProductVariantTranslationsVariables
|
||||
>(updateProductVariantTranslations);
|
||||
|
||||
const updateCategoryTranslations = gql`
|
||||
mutation UpdateCategoryTranslations(
|
||||
$id: ID!
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
collectionTranslationFragment,
|
||||
pageTranslationFragment,
|
||||
productTranslationFragment,
|
||||
productVariantTranslationFragment,
|
||||
saleTranslationFragment,
|
||||
shippingMethodTranslationFragment,
|
||||
voucherTranslationFragment
|
||||
|
@ -54,6 +55,14 @@ import {
|
|||
ProductTranslations,
|
||||
ProductTranslationsVariables
|
||||
} from "./types/ProductTranslations";
|
||||
import {
|
||||
ProductVariantList,
|
||||
ProductVariantListVariables
|
||||
} from "./types/ProductVariantList";
|
||||
import {
|
||||
ProductVariantTranslationDetails,
|
||||
ProductVariantTranslationDetailsVariables
|
||||
} from "./types/ProductVariantTranslationDetails";
|
||||
import {
|
||||
SaleTranslationDetails,
|
||||
SaleTranslationDetailsVariables
|
||||
|
@ -356,6 +365,39 @@ export const useProductTranslationDetails = makeQuery<
|
|||
ProductTranslationDetailsVariables
|
||||
>(productTranslationDetails);
|
||||
|
||||
const productVariantList = gql`
|
||||
query ProductVariantList($id: ID!) {
|
||||
product(id: $id) {
|
||||
id
|
||||
variants {
|
||||
id
|
||||
name
|
||||
sku
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const useProductVariantList = makeQuery<
|
||||
ProductVariantList,
|
||||
ProductVariantListVariables
|
||||
>(productVariantList);
|
||||
|
||||
const productVariantTranslationDetails = gql`
|
||||
${productVariantTranslationFragment}
|
||||
query ProductVariantTranslationDetails(
|
||||
$id: ID!
|
||||
$language: LanguageCodeEnum!
|
||||
) {
|
||||
translation(kind: VARIANT, id: $id) {
|
||||
...ProductVariantTranslationFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const useProductVariantTranslationDetails = makeQuery<
|
||||
ProductVariantTranslationDetails,
|
||||
ProductVariantTranslationDetailsVariables
|
||||
>(productVariantTranslationDetails);
|
||||
|
||||
const categoryTranslationDetails = gql`
|
||||
${categoryTranslationFragment}
|
||||
query CategoryTranslationDetails($id: ID!, $language: LanguageCodeEnum!) {
|
||||
|
|
29
src/translations/types/ProductVariantList.ts
Normal file
29
src/translations/types/ProductVariantList.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: ProductVariantList
|
||||
// ====================================================
|
||||
|
||||
export interface ProductVariantList_product_variants {
|
||||
__typename: "ProductVariant";
|
||||
id: string;
|
||||
name: string;
|
||||
sku: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantList_product {
|
||||
__typename: "Product";
|
||||
id: string;
|
||||
variants: (ProductVariantList_product_variants | null)[] | null;
|
||||
}
|
||||
|
||||
export interface ProductVariantList {
|
||||
product: ProductVariantList_product | null;
|
||||
}
|
||||
|
||||
export interface ProductVariantListVariables {
|
||||
id: string;
|
||||
}
|
79
src/translations/types/ProductVariantTranslationDetails.ts
Normal file
79
src/translations/types/ProductVariantTranslationDetails.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: ProductVariantTranslationDetails
|
||||
// ====================================================
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductTranslatableContent {
|
||||
__typename: "ProductTranslatableContent" | "CollectionTranslatableContent" | "CategoryTranslatableContent" | "AttributeTranslatableContent" | "AttributeValueTranslatableContent" | "PageTranslatableContent" | "ShippingMethodTranslatableContent" | "SaleTranslatableContent" | "VoucherTranslatableContent" | "MenuItemTranslatableContent";
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_productVariant {
|
||||
__typename: "ProductVariant";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_translation_language {
|
||||
__typename: "LanguageDisplay";
|
||||
code: LanguageCodeEnum;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_translation {
|
||||
__typename: "ProductVariantTranslation";
|
||||
id: string;
|
||||
name: string;
|
||||
language: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_translation_language;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues_attributeValue {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues_translation_language {
|
||||
__typename: "LanguageDisplay";
|
||||
code: LanguageCodeEnum;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues_translation {
|
||||
__typename: "AttributeValueTranslation";
|
||||
id: string;
|
||||
name: string;
|
||||
richText: any | null;
|
||||
language: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues_translation_language;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues {
|
||||
__typename: "AttributeValueTranslatableContent";
|
||||
id: string;
|
||||
name: string;
|
||||
richText: any | null;
|
||||
attributeValue: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues_attributeValue | null;
|
||||
translation: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues_translation | null;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent {
|
||||
__typename: "ProductVariantTranslatableContent";
|
||||
productVariant: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_productVariant | null;
|
||||
name: string;
|
||||
translation: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_translation | null;
|
||||
attributeValues: ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent_attributeValues[];
|
||||
}
|
||||
|
||||
export type ProductVariantTranslationDetails_translation = ProductVariantTranslationDetails_translation_ProductTranslatableContent | ProductVariantTranslationDetails_translation_ProductVariantTranslatableContent;
|
||||
|
||||
export interface ProductVariantTranslationDetails {
|
||||
translation: ProductVariantTranslationDetails_translation | null;
|
||||
}
|
||||
|
||||
export interface ProductVariantTranslationDetailsVariables {
|
||||
id: string;
|
||||
language: LanguageCodeEnum;
|
||||
}
|
52
src/translations/types/UpdateProductVariantTranslations.ts
Normal file
52
src/translations/types/UpdateProductVariantTranslations.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { NameTranslationInput, LanguageCodeEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: UpdateProductVariantTranslations
|
||||
// ====================================================
|
||||
|
||||
export interface UpdateProductVariantTranslations_productVariantTranslate_errors {
|
||||
__typename: "TranslationError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface UpdateProductVariantTranslations_productVariantTranslate_productVariant_translation_language {
|
||||
__typename: "LanguageDisplay";
|
||||
code: LanguageCodeEnum;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export interface UpdateProductVariantTranslations_productVariantTranslate_productVariant_translation {
|
||||
__typename: "ProductVariantTranslation";
|
||||
id: string;
|
||||
name: string;
|
||||
language: UpdateProductVariantTranslations_productVariantTranslate_productVariant_translation_language;
|
||||
}
|
||||
|
||||
export interface UpdateProductVariantTranslations_productVariantTranslate_productVariant {
|
||||
__typename: "ProductVariant";
|
||||
id: string;
|
||||
name: string;
|
||||
translation: UpdateProductVariantTranslations_productVariantTranslate_productVariant_translation | null;
|
||||
}
|
||||
|
||||
export interface UpdateProductVariantTranslations_productVariantTranslate {
|
||||
__typename: "ProductVariantTranslate";
|
||||
errors: UpdateProductVariantTranslations_productVariantTranslate_errors[];
|
||||
productVariant: UpdateProductVariantTranslations_productVariantTranslate_productVariant | null;
|
||||
}
|
||||
|
||||
export interface UpdateProductVariantTranslations {
|
||||
productVariantTranslate: UpdateProductVariantTranslations_productVariantTranslate | null;
|
||||
}
|
||||
|
||||
export interface UpdateProductVariantTranslationsVariables {
|
||||
id: string;
|
||||
input: NameTranslationInput;
|
||||
language: LanguageCodeEnum;
|
||||
}
|
|
@ -7,6 +7,7 @@ import { TranslationsEntitiesListFilterTab } from "./components/TranslationsEnti
|
|||
export enum TranslatableEntities {
|
||||
categories = "categories",
|
||||
products = "products",
|
||||
productVariants = "variants",
|
||||
collections = "collections",
|
||||
sales = "sales",
|
||||
vouchers = "vouchers",
|
||||
|
@ -35,10 +36,25 @@ export const languageEntitiesUrl = (
|
|||
export const languageEntityPath = (
|
||||
code: string,
|
||||
entity: TranslatableEntities,
|
||||
id: string
|
||||
) => urlJoin(languageEntitiesPath(code), entity.toString(), id);
|
||||
id: string,
|
||||
...args: string[]
|
||||
) => urlJoin(languageEntitiesPath(code), entity.toString(), id, ...args);
|
||||
export const languageEntityUrl = (
|
||||
code: string,
|
||||
entity: TranslatableEntities,
|
||||
id: string
|
||||
) => languageEntityPath(code, entity, encodeURIComponent(id));
|
||||
id: string,
|
||||
...args: string[]
|
||||
) => languageEntityPath(code, entity, encodeURIComponent(id), ...args);
|
||||
|
||||
export const productVariantUrl = (
|
||||
code: string,
|
||||
productId: string,
|
||||
variantId: string
|
||||
) =>
|
||||
languageEntityUrl(
|
||||
code,
|
||||
TranslatableEntities.products,
|
||||
productId,
|
||||
TranslatableEntities.productVariants,
|
||||
variantId
|
||||
);
|
||||
|
|
|
@ -194,9 +194,12 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
|||
node.translation?.description,
|
||||
node.translation?.name,
|
||||
node.translation?.seoDescription,
|
||||
node.translation?.seoTitle
|
||||
node.translation?.seoTitle,
|
||||
...(node.attributeValues?.map(
|
||||
({ translation }) => translation?.richText
|
||||
) || [])
|
||||
]),
|
||||
max: 4
|
||||
max: 4 + (node.attributeValues?.length || 0)
|
||||
},
|
||||
id: node?.product?.id,
|
||||
name: node?.product?.name
|
||||
|
|
156
src/translations/views/TranslationsProductVariants.tsx
Normal file
156
src/translations/views/TranslationsProductVariants.tsx
Normal file
|
@ -0,0 +1,156 @@
|
|||
import { OutputData } from "@editorjs/editorjs";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { stringify as stringifyQs } from "qs";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { maybe } from "../../misc";
|
||||
import { LanguageCodeEnum } from "../../types/globalTypes";
|
||||
import TranslationsProductVariantsPage from "../components/TranslationsProductVariantsPage";
|
||||
import {
|
||||
TypedUpdateAttributeValueTranslations,
|
||||
TypedUpdateProductVariantTranslations
|
||||
} from "../mutations";
|
||||
import { useProductVariantTranslationDetails } from "../queries";
|
||||
import { TranslationField, TranslationInputFieldName } from "../types";
|
||||
import {
|
||||
languageEntitiesUrl,
|
||||
productVariantUrl,
|
||||
TranslatableEntities
|
||||
} from "../urls";
|
||||
import { getParsedTranslationInputData } from "../utils";
|
||||
|
||||
export interface TranslationsProductVariantsQueryParams {
|
||||
activeField: string;
|
||||
}
|
||||
export interface TranslationsProductVariantsProps {
|
||||
id: string;
|
||||
productId: string;
|
||||
languageCode: LanguageCodeEnum;
|
||||
params: TranslationsProductVariantsQueryParams;
|
||||
}
|
||||
|
||||
const TranslationsProductVariants: React.FC<TranslationsProductVariantsProps> = ({
|
||||
id,
|
||||
productId,
|
||||
languageCode,
|
||||
params
|
||||
}) => {
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const shop = useShop();
|
||||
const intl = useIntl();
|
||||
|
||||
const productVariantTranslations = useProductVariantTranslationDetails({
|
||||
variables: { id, language: languageCode }
|
||||
});
|
||||
|
||||
const onEdit = (field: string) =>
|
||||
navigate(
|
||||
"?" +
|
||||
stringifyQs({
|
||||
activeField: field
|
||||
}),
|
||||
true
|
||||
);
|
||||
|
||||
const onUpdate = (errors: unknown[]) => {
|
||||
if (errors.length === 0) {
|
||||
productVariantTranslations.refetch();
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage(commonMessages.savedChanges)
|
||||
});
|
||||
navigate("?", true);
|
||||
}
|
||||
};
|
||||
|
||||
const onDiscard = () => {
|
||||
navigate("?", true);
|
||||
};
|
||||
|
||||
return (
|
||||
<TypedUpdateProductVariantTranslations
|
||||
onCompleted={data => onUpdate(data.productVariantTranslate.errors)}
|
||||
>
|
||||
{(updateTranslations, updateTranslationsOpts) => (
|
||||
<TypedUpdateAttributeValueTranslations
|
||||
onCompleted={data => onUpdate(data.attributeValueTranslate.errors)}
|
||||
>
|
||||
{updateAttributeValueTranslations => {
|
||||
const handleSubmit = (
|
||||
{ name: fieldName }: TranslationField<TranslationInputFieldName>,
|
||||
data: string
|
||||
) => {
|
||||
updateTranslations({
|
||||
variables: {
|
||||
id,
|
||||
input: getParsedTranslationInputData({
|
||||
data,
|
||||
fieldName
|
||||
}),
|
||||
language: languageCode
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleAttributeValueSubmit = (
|
||||
{ id }: TranslationField<TranslationInputFieldName>,
|
||||
data: OutputData
|
||||
) => {
|
||||
updateAttributeValueTranslations({
|
||||
variables: {
|
||||
id,
|
||||
input: { richText: JSON.stringify(data) },
|
||||
language: languageCode
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const translation = productVariantTranslations?.data?.translation;
|
||||
|
||||
return (
|
||||
<TranslationsProductVariantsPage
|
||||
productId={productId}
|
||||
variantId={id}
|
||||
activeField={params.activeField}
|
||||
disabled={
|
||||
productVariantTranslations.loading ||
|
||||
updateTranslationsOpts.loading
|
||||
}
|
||||
languageCode={languageCode}
|
||||
languages={maybe(() => shop.languages, [])}
|
||||
saveButtonState={updateTranslationsOpts.status}
|
||||
onBack={() =>
|
||||
navigate(
|
||||
languageEntitiesUrl(languageCode, {
|
||||
tab: TranslatableEntities.products
|
||||
})
|
||||
)
|
||||
}
|
||||
onEdit={onEdit}
|
||||
onDiscard={onDiscard}
|
||||
onLanguageChange={lang =>
|
||||
navigate(productVariantUrl(lang, productId, id))
|
||||
}
|
||||
onSubmit={handleSubmit}
|
||||
onAttributeValueSubmit={handleAttributeValueSubmit}
|
||||
data={
|
||||
translation?.__typename ===
|
||||
"ProductVariantTranslatableContent"
|
||||
? translation
|
||||
: null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</TypedUpdateAttributeValueTranslations>
|
||||
)}
|
||||
</TypedUpdateProductVariantTranslations>
|
||||
);
|
||||
};
|
||||
TranslationsProductVariants.displayName = "TranslationsProductVariants";
|
||||
export default TranslationsProductVariants;
|
|
@ -112,6 +112,7 @@ const TranslationsProducts: React.FC<TranslationsProductsProps> = ({
|
|||
|
||||
return (
|
||||
<TranslationsProductsPage
|
||||
productId={id}
|
||||
activeField={params.activeField}
|
||||
disabled={
|
||||
productTranslations.loading || updateTranslationsOpts.loading
|
||||
|
|
Loading…
Reference in a new issue