Saleor 1680 add shipping methods to translation section (#864)

* Add update shipping method translations query

* Added queries and types for shipping method translation tab

* Fix tab view for shipping method

* Fix query and view for shipping method

* Revert password credentials type any

* Update storybook

* Update locale

* Update CHANGELOG.md
This commit is contained in:
Marek Choiński 2020-11-27 16:53:48 +01:00 committed by GitHub
parent 44bbe5842c
commit 9069b6bc80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 606 additions and 2 deletions

View file

@ -5,6 +5,7 @@ All notable, unreleased changes to this project will be documented in this file.
## [Unreleased]
- Add Page Types - #807 by @orzechdev
- Add shipping methods to translation section - #864 by @marekchoinski
# 2.11.1

View file

@ -5828,6 +5828,9 @@
"src_dot_translations_dot_components_dot_TranslationsEntitiesListPage_dot_3583204912": {
"string": "Categories"
},
"src_dot_translations_dot_components_dot_TranslationsEntitiesListPage_dot_3731925413": {
"string": "Shipping methods"
},
"src_dot_translations_dot_components_dot_TranslationsEntitiesListPage_dot_4153345096": {
"string": "Attributes"
},
@ -5917,6 +5920,13 @@
"src_dot_translations_dot_components_dot_TranslationsSalesPage_dot_898281424": {
"string": "Sale Name"
},
"src_dot_translations_dot_components_dot_TranslationsShippingMethodPage_dot_3498202636": {
"context": "header",
"string": "Translation ShippingMethod \"{shippingMethodName}\" - {languageCode}"
},
"src_dot_translations_dot_components_dot_TranslationsShippingMethodPage_dot_99732714": {
"string": "ShippingMethod Name"
},
"src_dot_translations_dot_components_dot_TranslationsVouchersPage_dot_2447510181": {
"context": "header",
"string": "Translation Voucher \"{voucherName}\" - {languageCode}"

View file

@ -98,6 +98,9 @@ export const voucherTranslationFragment = gql`
`;
export const shippingMethodTranslationFragment = gql`
fragment ShippingMethodTranslationFragment on ShippingMethodTranslatableContent {
shippingMethod {
id
}
id
name
translation(languageCode: $language) {

View file

@ -8,6 +8,11 @@ import { LanguageCodeEnum } from "./../../types/globalTypes";
// GraphQL fragment: ShippingMethodTranslationFragment
// ====================================================
export interface ShippingMethodTranslationFragment_shippingMethod {
__typename: "ShippingMethod";
id: string;
}
export interface ShippingMethodTranslationFragment_translation_language {
__typename: "LanguageDisplay";
code: LanguageCodeEnum;
@ -23,6 +28,7 @@ export interface ShippingMethodTranslationFragment_translation {
export interface ShippingMethodTranslationFragment {
__typename: "ShippingMethodTranslatableContent";
shippingMethod: ShippingMethodTranslationFragment_shippingMethod | null;
id: string;
name: string;
translation: ShippingMethodTranslationFragment_translation | null;

View file

@ -204764,6 +204764,18 @@ exports[`Storyshots Views / Translations / Entity list default 1`] = `
Attributes
</span>
</button>
<button
class="MuiButtonBase-root-id MuiTab-root-id FilterTab-tabRoot-id MuiTab-textColorInherit-id"
role="tab"
tabindex="0"
type="button"
>
<span
class="MuiTab-wrapper-id FilterTab-tabLabel-id"
>
Shipping methods
</span>
</button>
</div>
</div>
</div>

View file

@ -21,6 +21,7 @@ const props: TranslationsEntitiesListPageProps = {
onProductTypesTabClick: () => undefined,
onProductsTabClick: () => undefined,
onSalesTabClick: () => undefined,
onShippingMethodsTabClick: () => undefined,
onVouchersTabClick: () => undefined
},
language: {

View file

@ -26,6 +26,7 @@ export interface TranslationsEntitiesFilters {
onVouchersTabClick: () => void;
onPagesTabClick: () => void;
onProductTypesTabClick: () => void;
onShippingMethodsTabClick: () => void;
}
export type TranslationsEntitiesListFilterTab = keyof typeof TranslatableEntities;
@ -37,7 +38,8 @@ const tabs: TranslationsEntitiesListFilterTab[] = [
"sales",
"vouchers",
"pages",
"productTypes"
"productTypes",
"shippingMethods"
];
const TranslationsEntitiesListPage: React.FC<TranslationsEntitiesListPageProps> = props => {
@ -108,6 +110,12 @@ const TranslationsEntitiesListPage: React.FC<TranslationsEntitiesListPageProps>
})}
onClick={filters.onProductTypesTabClick}
/>
<FilterTab
label={intl.formatMessage({
defaultMessage: "Shipping methods"
})}
onClick={filters.onShippingMethodsTabClick}
/>
</FilterTabs>
{children}
</Card>

View file

@ -0,0 +1,87 @@
import AppHeader from "@saleor/components/AppHeader";
import Container from "@saleor/components/Container";
import LanguageSwitch from "@saleor/components/LanguageSwitch";
import PageHeader from "@saleor/components/PageHeader";
import { ShippingMethodTranslationFragment } from "@saleor/fragments/types/ShippingMethodTranslationFragment";
import { commonMessages, sectionNames } from "@saleor/intl";
import { TranslationsEntitiesPageProps } from "@saleor/translations/types";
import React from "react";
import { useIntl } from "react-intl";
import { LanguageCodeEnum } from "../../../types/globalTypes";
import TranslationFields from "../TranslationFields";
export interface TranslationsShippingMethodPageProps
extends TranslationsEntitiesPageProps {
data: ShippingMethodTranslationFragment;
}
export const fieldNames = {
name: "name"
};
const TranslationsShippingMethodPage: React.FC<TranslationsShippingMethodPageProps> = ({
activeField,
disabled,
languageCode,
languages,
data,
saveButtonState,
onBack,
onDiscard,
onEdit,
onLanguageChange,
onSubmit
}) => {
const intl = useIntl();
return (
<Container>
<AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.translations)}
</AppHeader>
<PageHeader
title={intl.formatMessage(
{
defaultMessage:
'Translation ShippingMethod "{shippingMethodName}" - {languageCode}',
description: "header"
},
{
languageCode,
shippingMethodName: data?.name || "..."
}
)}
>
<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: "ShippingMethod Name"
}),
name: fieldNames.name,
translation: data?.translation?.name || null,
type: "short" as "short",
value: data?.name
}
]}
saveButtonState={saveButtonState}
onEdit={onEdit}
onDiscard={onDiscard}
onSubmit={onSubmit}
/>
</Container>
);
};
TranslationsShippingMethodPage.displayName = "TranslationsShippingMethodPage";
export default TranslationsShippingMethodPage;

View file

@ -0,0 +1,2 @@
export { default } from "./TranslationsShippingMethodPage";
export * from "./TranslationsShippingMethodPage";

View file

@ -32,6 +32,9 @@ import TranslationsProductTypesComponent, {
import TranslationsSaleComponent, {
TranslationsSalesQueryParams
} from "./views/TranslationsSales";
import TranslationsShippingMethodComponent, {
TranslationsShippingMethodQueryParams
} from "./views/TranslationsShippingMethod";
import TranslationsVouchersComponent, {
TranslationsVouchersQueryParams
} from "./views/TranslationsVouchers";
@ -168,6 +171,22 @@ const TranslationsProductTypes: React.FC<TranslationsEntityRouteProps> = ({
/>
);
};
const TranslationsShippingMethod: React.FC<TranslationsEntityRouteProps> = ({
location,
match
}) => {
const qs = parseQs(location.search.substr(1));
const params: TranslationsShippingMethodQueryParams = {
activeField: qs.activeField
};
return (
<TranslationsShippingMethodComponent
id={decodeURIComponent(match.params.id)}
languageCode={LanguageCodeEnum[match.params.languageCode]}
params={params}
/>
);
};
const TranslationsRouter: React.FC = () => {
const intl = useIntl();
@ -249,6 +268,15 @@ const TranslationsRouter: React.FC = () => {
)}
component={TranslationsProductTypes}
/>
<Route
exact
path={languageEntityPath(
":languageCode",
TranslatableEntities.shippingMethods,
":id"
)}
component={TranslationsShippingMethod}
/>
</Switch>
</>
);

View file

@ -30,6 +30,10 @@ import {
UpdateSaleTranslations,
UpdateSaleTranslationsVariables
} from "./types/UpdateSaleTranslations";
import {
UpdateShippingMethodTranslations,
UpdateShippingMethodTranslationsVariables
} from "./types/UpdateShippingMethodTranslations";
import {
UpdateVoucherTranslations,
UpdateVoucherTranslationsVariables
@ -282,3 +286,34 @@ export const TypedUpdateAttributeValueTranslations = TypedMutation<
UpdateAttributeValueTranslations,
UpdateAttributeValueTranslationsVariables
>(updateAttributeValueTranslations);
const updateShippingMethodTranslations = gql`
mutation UpdateShippingMethodTranslations(
$id: ID!
$input: NameTranslationInput!
$language: LanguageCodeEnum!
) {
shippingPriceTranslate(id: $id, input: $input, languageCode: $language) {
errors {
field
message
}
shippingMethod {
id
name
translation(languageCode: $language) {
id
language {
language
}
name
}
}
}
}
`;
export const TypedUpdateShippingMethodTranslations = TypedMutation<
UpdateShippingMethodTranslations,
UpdateShippingMethodTranslationsVariables
>(updateShippingMethodTranslations);

View file

@ -6,6 +6,7 @@ import {
pageTranslationFragment,
productTranslationFragment,
saleTranslationFragment,
shippingMethodTranslationFragment,
voucherTranslationFragment
} from "@saleor/fragments/translations";
import makeQuery from "@saleor/hooks/makeQuery";
@ -60,6 +61,14 @@ import {
SaleTranslations,
SaleTranslationsVariables
} from "./types/SaleTranslations";
import {
ShippingMethodTranslationDetails,
ShippingMethodTranslationDetailsVariables
} from "./types/ShippingMethodTranslationDetails";
import {
ShippingMethodTranslations,
ShippingMethodTranslationsVariables
} from "./types/ShippingMethodTranslations";
import {
VoucherTranslationDetails,
VoucherTranslationDetailsVariables
@ -300,6 +309,39 @@ export const TypedAttributeTranslations = TypedQuery<
AttributeTranslationsVariables
>(attributeTranslations);
const shippingMethodTranslations = gql`
${pageInfoFragment}
${shippingMethodTranslationFragment}
query ShippingMethodTranslations(
$language: LanguageCodeEnum!
$first: Int
$after: String
$last: Int
$before: String
) {
translations(
kind: SHIPPING_METHOD
before: $before
after: $after
first: $first
last: $last
) {
edges {
node {
...ShippingMethodTranslationFragment
}
}
pageInfo {
...PageInfoFragment
}
}
}
`;
export const TypedShippingMethodTranslations = TypedQuery<
ShippingMethodTranslations,
ShippingMethodTranslationsVariables
>(shippingMethodTranslations);
const productTranslationDetails = gql`
${productTranslationFragment}
query ProductTranslationDetails($id: ID!, $language: LanguageCodeEnum!) {
@ -390,3 +432,19 @@ export const useAttributeTranslationDetails = makeQuery<
AttributeTranslationDetails,
AttributeTranslationDetailsVariables
>(attributeTranslationDetails);
const shippingMethodTranslationDetails = gql`
${shippingMethodTranslationFragment}
query ShippingMethodTranslationDetails(
$id: ID!
$language: LanguageCodeEnum!
) {
translation(kind: SHIPPING_METHOD, id: $id) {
...ShippingMethodTranslationFragment
}
}
`;
export const useShippingMethodTranslationDetails = makeQuery<
ShippingMethodTranslationDetails,
ShippingMethodTranslationDetailsVariables
>(shippingMethodTranslationDetails);

View file

@ -0,0 +1,50 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { LanguageCodeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL query operation: ShippingMethodTranslationDetails
// ====================================================
export interface ShippingMethodTranslationDetails_translation_ProductTranslatableContent {
__typename: "ProductTranslatableContent" | "CollectionTranslatableContent" | "CategoryTranslatableContent" | "AttributeTranslatableContent" | "AttributeValueTranslatableContent" | "ProductVariantTranslatableContent" | "PageTranslatableContent" | "SaleTranslatableContent" | "VoucherTranslatableContent" | "MenuItemTranslatableContent";
}
export interface ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent_shippingMethod {
__typename: "ShippingMethod";
id: string;
}
export interface ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent_translation_language {
__typename: "LanguageDisplay";
code: LanguageCodeEnum;
language: string;
}
export interface ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent_translation {
__typename: "ShippingMethodTranslation";
id: string;
language: ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent_translation_language;
name: string | null;
}
export interface ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent {
__typename: "ShippingMethodTranslatableContent";
shippingMethod: ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent_shippingMethod | null;
id: string;
name: string;
translation: ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent_translation | null;
}
export type ShippingMethodTranslationDetails_translation = ShippingMethodTranslationDetails_translation_ProductTranslatableContent | ShippingMethodTranslationDetails_translation_ShippingMethodTranslatableContent;
export interface ShippingMethodTranslationDetails {
translation: ShippingMethodTranslationDetails_translation | null;
}
export interface ShippingMethodTranslationDetailsVariables {
id: string;
language: LanguageCodeEnum;
}

View file

@ -0,0 +1,72 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { LanguageCodeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL query operation: ShippingMethodTranslations
// ====================================================
export interface ShippingMethodTranslations_translations_edges_node_ProductTranslatableContent {
__typename: "ProductTranslatableContent" | "CollectionTranslatableContent" | "CategoryTranslatableContent" | "AttributeTranslatableContent" | "AttributeValueTranslatableContent" | "ProductVariantTranslatableContent" | "PageTranslatableContent" | "SaleTranslatableContent" | "VoucherTranslatableContent" | "MenuItemTranslatableContent";
}
export interface ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent_shippingMethod {
__typename: "ShippingMethod";
id: string;
}
export interface ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent_translation_language {
__typename: "LanguageDisplay";
code: LanguageCodeEnum;
language: string;
}
export interface ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent_translation {
__typename: "ShippingMethodTranslation";
id: string;
language: ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent_translation_language;
name: string | null;
}
export interface ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent {
__typename: "ShippingMethodTranslatableContent";
shippingMethod: ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent_shippingMethod | null;
id: string;
name: string;
translation: ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent_translation | null;
}
export type ShippingMethodTranslations_translations_edges_node = ShippingMethodTranslations_translations_edges_node_ProductTranslatableContent | ShippingMethodTranslations_translations_edges_node_ShippingMethodTranslatableContent;
export interface ShippingMethodTranslations_translations_edges {
__typename: "TranslatableItemEdge";
node: ShippingMethodTranslations_translations_edges_node;
}
export interface ShippingMethodTranslations_translations_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
hasPreviousPage: boolean;
startCursor: string | null;
}
export interface ShippingMethodTranslations_translations {
__typename: "TranslatableItemConnection";
edges: ShippingMethodTranslations_translations_edges[];
pageInfo: ShippingMethodTranslations_translations_pageInfo;
}
export interface ShippingMethodTranslations {
translations: ShippingMethodTranslations_translations | null;
}
export interface ShippingMethodTranslationsVariables {
language: LanguageCodeEnum;
first?: number | null;
after?: string | null;
last?: number | null;
before?: string | null;
}

View file

@ -0,0 +1,50 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { NameTranslationInput, LanguageCodeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: UpdateShippingMethodTranslations
// ====================================================
export interface UpdateShippingMethodTranslations_shippingPriceTranslate_errors {
__typename: "Error";
field: string | null;
message: string | null;
}
export interface UpdateShippingMethodTranslations_shippingPriceTranslate_shippingMethod_translation_language {
__typename: "LanguageDisplay";
language: string;
}
export interface UpdateShippingMethodTranslations_shippingPriceTranslate_shippingMethod_translation {
__typename: "ShippingMethodTranslation";
id: string;
language: UpdateShippingMethodTranslations_shippingPriceTranslate_shippingMethod_translation_language;
name: string | null;
}
export interface UpdateShippingMethodTranslations_shippingPriceTranslate_shippingMethod {
__typename: "ShippingMethod";
id: string;
name: string;
translation: UpdateShippingMethodTranslations_shippingPriceTranslate_shippingMethod_translation | null;
}
export interface UpdateShippingMethodTranslations_shippingPriceTranslate {
__typename: "ShippingPriceTranslate";
errors: UpdateShippingMethodTranslations_shippingPriceTranslate_errors[];
shippingMethod: UpdateShippingMethodTranslations_shippingPriceTranslate_shippingMethod | null;
}
export interface UpdateShippingMethodTranslations {
shippingPriceTranslate: UpdateShippingMethodTranslations_shippingPriceTranslate | null;
}
export interface UpdateShippingMethodTranslationsVariables {
id: string;
input: NameTranslationInput;
language: LanguageCodeEnum;
}

View file

@ -11,7 +11,8 @@ export enum TranslatableEntities {
sales = "sales",
vouchers = "vouchers",
pages = "pages",
productTypes = "productTypes"
productTypes = "productTypes",
shippingMethods = "shippingMethods"
}
const translationsSection = "/translations/";

View file

@ -17,6 +17,7 @@ import {
TypedPageTranslations,
TypedProductTranslations,
TypedSaleTranslations,
TypedShippingMethodTranslations,
TypedVoucherTranslations
} from "../queries";
import {
@ -92,6 +93,13 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
tab: TranslatableEntities.sales
})
),
onShippingMethodsTabClick: () =>
navigate(
"?" +
stringifyQs({
tab: TranslatableEntities.shippingMethods
})
),
onVouchersTabClick: () =>
navigate(
"?" +
@ -453,6 +461,49 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
);
}}
</TypedAttributeTranslations>
) : params.tab === "shippingMethods" ? (
<TypedShippingMethodTranslations variables={queryVariables}>
{({ data, loading }) => {
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
data?.translations?.pageInfo,
paginationState,
params
);
return (
<TranslationsEntitiesList
disabled={loading}
entities={data?.translations?.edges
.map(edge => edge.node)
.map(
node =>
node.__typename ===
"ShippingMethodTranslatableContent" && {
completion: {
current: node.translation
? +!!node.translation.name
: 0,
max: 1
},
id: node?.shippingMethod.id,
name: node?.name
}
)}
onRowClick={id =>
navigate(
languageEntityUrl(
language,
TranslatableEntities.shippingMethods,
id
)
)
}
onNextPage={loadNextPage}
onPreviousPage={loadPreviousPage}
pageInfo={pageInfo}
/>
);
}}
</TypedShippingMethodTranslations>
) : null}
</TranslationsEntitiesListPage>
);

View file

@ -0,0 +1,129 @@
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 {
LanguageCodeEnum,
NameTranslationInput
} from "../../types/globalTypes";
import TranslationsShippingMethodPage, {
fieldNames
} from "../components/TranslationsShippingMethodPage";
import { TypedUpdateShippingMethodTranslations } from "../mutations";
import { useShippingMethodTranslationDetails } from "../queries";
import { UpdateShippingMethodTranslations } from "../types/UpdateShippingMethodTranslations";
import {
languageEntitiesUrl,
languageEntityUrl,
TranslatableEntities
} from "../urls";
export interface TranslationsShippingMethodQueryParams {
activeField: string;
}
export interface TranslationsShippingMethodProps {
id: string;
languageCode: LanguageCodeEnum;
params: TranslationsShippingMethodQueryParams;
}
const TranslationsShippingMethod: React.FC<TranslationsShippingMethodProps> = ({
id,
languageCode,
params
}) => {
const navigate = useNavigator();
const notify = useNotifier();
const shop = useShop();
const intl = useIntl();
const shippingMethodTranslations = useShippingMethodTranslationDetails({
variables: { id, language: languageCode }
});
const onEdit = (field: string) =>
navigate(
"?" +
stringifyQs({
activeField: field
}),
true
);
const onUpdate = (data: UpdateShippingMethodTranslations) => {
if (data.shippingPriceTranslate.errors.length === 0) {
shippingMethodTranslations.refetch();
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
});
navigate("?", true);
}
};
const onDiscard = () => {
navigate("?", true);
};
return (
<TypedUpdateShippingMethodTranslations onCompleted={onUpdate}>
{(updateTranslations, updateTranslationsOpts) => {
const handleSubmit = (field: string, data: string) => {
const input: NameTranslationInput = {};
if (field === fieldNames.name) {
input.name = data;
}
updateTranslations({
variables: {
id,
input,
language: languageCode
}
});
};
const translation = shippingMethodTranslations?.data?.translation;
return (
<TranslationsShippingMethodPage
activeField={params.activeField}
disabled={
shippingMethodTranslations.loading ||
updateTranslationsOpts.loading
}
languages={shop?.languages || []}
languageCode={languageCode}
saveButtonState={updateTranslationsOpts.status}
onBack={() =>
navigate(
languageEntitiesUrl(languageCode, {
tab: TranslatableEntities.shippingMethods
})
)
}
onEdit={onEdit}
onDiscard={onDiscard}
onSubmit={handleSubmit}
onLanguageChange={lang =>
navigate(
languageEntityUrl(
lang,
TranslatableEntities.shippingMethods,
id
)
)
}
data={
translation?.__typename === "ShippingMethodTranslatableContent"
? translation
: null
}
/>
);
}}
</TypedUpdateShippingMethodTranslations>
);
};
TranslationsShippingMethod.displayName = "TranslationsShippingMethod";
export default TranslationsShippingMethod;