Merge pull request #607 from mirumee/ref/add-2.10.1

Apply fixes from 2.10.1
This commit is contained in:
Dominik Żegleń 2020-07-17 12:16:21 +02:00 committed by GitHub
commit 38e790a4dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 2369 additions and 126 deletions

View file

@ -12,6 +12,11 @@ All notable, unreleased changes to this project will be documented in this file.
- Move fragments to separate directory to avoid circular imports - #592 by @dominik-zeglen - Move fragments to separate directory to avoid circular imports - #592 by @dominik-zeglen
- Add order invoices management - #570 by @orzechdev - Add order invoices management - #570 by @orzechdev
## 2.10.1
- Add weight field and fix warehouse country selection - #597 by @dominik-zeglen
- Fix weight based rate update - #604 by @dominik-zeglen
## 2.10.0 ## 2.10.0
- Fix minor bugs - #244 by @dominik-zeglen - Fix minor bugs - #244 by @dominik-zeglen

View file

@ -40,7 +40,7 @@ $ cd saleor-dashboard
To use the official stable release, checkout to a release tag: To use the official stable release, checkout to a release tag:
``` ```
$ git checkout 2.10.0 $ git checkout 2.10.1
``` ```
See the list of all releases here: https://github.com/mirumee/saleor-dashboard/releases/ See the list of all releases here: https://github.com/mirumee/saleor-dashboard/releases/

View file

@ -3704,6 +3704,14 @@
"src_dot_products_dot_components_dot_ProductPricing_dot_3015886868": { "src_dot_products_dot_components_dot_ProductPricing_dot_3015886868": {
"string": "Charge taxes for this item" "string": "Charge taxes for this item"
}, },
"src_dot_products_dot_components_dot_ProductShipping_dot_1325966144": {
"context": "product shipping",
"string": "Shipping"
},
"src_dot_products_dot_components_dot_ProductShipping_dot_746695941": {
"context": "product weight",
"string": "Weight"
},
"src_dot_products_dot_components_dot_ProductStocks_dot_2585918415": { "src_dot_products_dot_components_dot_ProductStocks_dot_2585918415": {
"string": "SKU (Stock Keeping Unit)" "string": "SKU (Stock Keeping Unit)"
}, },
@ -3741,14 +3749,6 @@
"src_dot_products_dot_components_dot_ProductUpdatePage_dot_2706108815": { "src_dot_products_dot_components_dot_ProductUpdatePage_dot_2706108815": {
"string": "Add search engine title and description to make this product easier to find" "string": "Add search engine title and description to make this product easier to find"
}, },
"src_dot_products_dot_components_dot_ProductVariantAttributes_dot_1536841622": {
"context": "product attribute error",
"string": "All attributes should have value"
},
"src_dot_products_dot_components_dot_ProductVariantAttributes_dot_258966189": {
"context": "product attribute error",
"string": "This variant already exists"
},
"src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_2853608829": { "src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_2853608829": {
"context": "button", "context": "button",
"string": "Save variant" "string": "Save variant"
@ -5134,6 +5134,10 @@
"src_dot_utils_dot_errors_dot_attributeCannotBeAssigned": { "src_dot_utils_dot_errors_dot_attributeCannotBeAssigned": {
"string": "This attribute cannot be assigned to this product type" "string": "This attribute cannot be assigned to this product type"
}, },
"src_dot_utils_dot_errors_dot_attributeRequired": {
"context": "product attribute error",
"string": "All attributes should have value"
},
"src_dot_utils_dot_errors_dot_attributeVariantsDisabled": { "src_dot_utils_dot_errors_dot_attributeVariantsDisabled": {
"string": "Variants are disabled in this product type" "string": "Variants are disabled in this product type"
}, },
@ -5262,6 +5266,10 @@
"src_dot_utils_dot_errors_dot_variantNoDigitalContent": { "src_dot_utils_dot_errors_dot_variantNoDigitalContent": {
"string": "This variant does not have any digital content" "string": "This variant does not have any digital content"
}, },
"src_dot_utils_dot_errors_dot_variantUnique": {
"context": "product attribute error",
"string": "This variant already exists"
},
"src_dot_vouchers": { "src_dot_vouchers": {
"context": "vouchers section name", "context": "vouchers section name",
"string": "Vouchers" "string": "Vouchers"

2
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "saleor-dashboard", "name": "saleor-dashboard",
"version": "2.10.0", "version": "2.10.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View file

@ -1,6 +1,6 @@
{ {
"name": "saleor-dashboard", "name": "saleor-dashboard",
"version": "2.10.0", "version": "2.10.1",
"main": "src/index.tsx", "main": "src/index.tsx",
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -79,14 +79,16 @@ export const TimelineNote: React.FC<TimelineNoteProps> = props => {
return ( return (
<div className={classes.root}> <div className={classes.root}>
{user && (
<Avatar <Avatar
className={classes.avatar} className={classes.avatar}
style={{ background: palette[CRC.str(user.email) % palette.length] }} style={{ background: palette[CRC.str(user.email) % palette.length] }}
> >
<PersonIcon /> <PersonIcon />
</Avatar> </Avatar>
)}
<div className={classes.title}> <div className={classes.title}>
<Typography>{user.email}</Typography> <Typography>{user?.email}</Typography>
<Typography> <Typography>
<DateTime date={date} /> <DateTime date={date} />
</Typography> </Typography>

View file

@ -1,5 +1,7 @@
import gql from "graphql-tag"; import gql from "graphql-tag";
import { weightFragment } from "./weight";
export const stockFragment = gql` export const stockFragment = gql`
fragment StockFragment on Stock { fragment StockFragment on Stock {
id id
@ -102,6 +104,7 @@ export const productFragmentDetails = gql`
${fragmentMoney} ${fragmentMoney}
${productVariantAttributesFragment} ${productVariantAttributesFragment}
${stockFragment} ${stockFragment}
${weightFragment}
fragment Product on Product { fragment Product on Product {
...ProductVariantAttributesFragment ...ProductVariantAttributesFragment
name name
@ -167,6 +170,9 @@ export const productFragmentDetails = gql`
name name
hasVariants hasVariants
} }
weight {
...WeightFragment
}
} }
`; `;
@ -174,6 +180,7 @@ export const fragmentVariant = gql`
${fragmentMoney} ${fragmentMoney}
${fragmentProductImage} ${fragmentProductImage}
${stockFragment} ${stockFragment}
${weightFragment}
fragment ProductVariant on ProductVariant { fragment ProductVariant on ProductVariant {
id id
attributes { attributes {
@ -229,5 +236,8 @@ export const fragmentVariant = gql`
...StockFragment ...StockFragment
} }
trackInventory trackInventory
weight {
...WeightFragment
}
} }
`; `;

View file

@ -168,6 +168,12 @@ export interface Product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface Product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface Product { export interface Product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -188,4 +194,5 @@ export interface Product {
publicationDate: any | null; publicationDate: any | null;
images: (Product_images | null)[] | null; images: (Product_images | null)[] | null;
variants: (Product_variants | null)[] | null; variants: (Product_variants | null)[] | null;
weight: Product_weight | null;
} }

View file

@ -103,6 +103,12 @@ export interface ProductVariant_stocks {
warehouse: ProductVariant_stocks_warehouse; warehouse: ProductVariant_stocks_warehouse;
} }
export interface ProductVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductVariant { export interface ProductVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -115,4 +121,5 @@ export interface ProductVariant {
sku: string; sku: string;
stocks: (ProductVariant_stocks | null)[] | null; stocks: (ProductVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: ProductVariant_weight | null;
} }

View file

@ -0,0 +1,13 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL fragment: WeightFragment
// ====================================================
export interface WeightFragment {
__typename: "Weight";
unit: string;
value: number;
}

8
src/fragments/weight.ts Normal file
View file

@ -0,0 +1,8 @@
import gql from "graphql-tag";
export const weightFragment = gql`
fragment WeightFragment on Weight {
unit
value
}
`;

View file

@ -59,6 +59,10 @@ export function decimal(value: string | number) {
return value; return value;
} }
export function weight(value: string) {
return value === "" ? null : parseFloat(value);
}
export const removeDoubleSlashes = (url: string) => export const removeDoubleSlashes = (url: string) =>
url.replace(/([^:]\/)\/+/g, "$1"); url.replace(/([^:]\/)\/+/g, "$1");

View file

@ -820,8 +820,8 @@ export const order = (placeholder: string): OrderDetails_order => ({
date: "2018-09-17T13:22:24.376193+00:00", date: "2018-09-17T13:22:24.376193+00:00",
email: null, email: null,
emailType: null, emailType: null,
invoiceNumber: "23/07/2020",
id: "T3JkZXJFdmVudDoyMQ==", id: "T3JkZXJFdmVudDoyMQ==",
invoiceNumber: "23/07/2020",
message: null, message: null,
quantity: 1, quantity: 1,
type: OrderEventsEnum.FULFILLMENT_FULFILLED_ITEMS, type: OrderEventsEnum.FULFILLMENT_FULFILLED_ITEMS,
@ -830,6 +830,32 @@ export const order = (placeholder: string): OrderDetails_order => ({
email: "admin@example.com", email: "admin@example.com",
id: "QWRkcmVzczoxNQ==" id: "QWRkcmVzczoxNQ=="
} }
},
{
__typename: "OrderEvent",
amount: null,
date: "2019-09-17T13:22:24.376193+00:00",
email: null,
emailType: null,
id: "T3JkZXJFdmVudDo0",
invoiceNumber: "23/07/2020",
message: "This is note",
quantity: null,
type: OrderEventsEnum.NOTE_ADDED,
user: null
},
{
__typename: "OrderEvent",
amount: null,
date: "2019-09-17T13:22:24.376193+00:00",
email: null,
emailType: null,
id: "T3JkZXJFdmVudDo1",
invoiceNumber: "24/07/2020",
message: "This is note",
quantity: null,
type: OrderEventsEnum.NOTE_ADDED,
user: null
} }
], ],
fulfillments: [ fulfillments: [

View file

@ -105,7 +105,7 @@ const ProductTypeCreatePage: React.FC<ProductTypeCreatePageProps> = ({
<ProductTypeShipping <ProductTypeShipping
disabled={disabled} disabled={disabled}
data={data} data={data}
defaultWeightUnit={defaultWeightUnit} weightUnit={defaultWeightUnit}
onChange={change} onChange={change}
/> />
</div> </div>

View file

@ -199,7 +199,7 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
<ProductTypeShipping <ProductTypeShipping
disabled={disabled} disabled={disabled}
data={data} data={data}
defaultWeightUnit={defaultWeightUnit} weightUnit={productType?.weight?.unit || defaultWeightUnit}
onChange={change} onChange={change}
/> />
</div> </div>

View file

@ -6,21 +6,19 @@ import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { WeightUnitsEnum } from "../../../types/globalTypes";
interface ProductTypeShippingProps { interface ProductTypeShippingProps {
data: { data: {
isShippingRequired: boolean; isShippingRequired: boolean;
weight: number | null; weight: number | null;
}; };
defaultWeightUnit: WeightUnitsEnum; weightUnit: string;
disabled: boolean; disabled: boolean;
onChange: (event: React.ChangeEvent<any>) => void; onChange: (event: React.ChangeEvent<any>) => void;
} }
const ProductTypeShipping: React.FC<ProductTypeShippingProps> = ({ const ProductTypeShipping: React.FC<ProductTypeShippingProps> = ({
data, data,
defaultWeightUnit, weightUnit,
disabled, disabled,
onChange onChange
}) => { }) => {
@ -48,7 +46,7 @@ const ProductTypeShipping: React.FC<ProductTypeShippingProps> = ({
{data.isShippingRequired && ( {data.isShippingRequired && (
<TextField <TextField
disabled={disabled} disabled={disabled}
InputProps={{ endAdornment: defaultWeightUnit }} InputProps={{ endAdornment: weightUnit }}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Weight" defaultMessage: "Weight"
})} })}

View file

@ -42,6 +42,7 @@ import ProductAttributes, {
import ProductDetailsForm from "../ProductDetailsForm"; import ProductDetailsForm from "../ProductDetailsForm";
import ProductOrganization from "../ProductOrganization"; import ProductOrganization from "../ProductOrganization";
import ProductPricing from "../ProductPricing"; import ProductPricing from "../ProductPricing";
import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks, { ProductStockInput } from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
interface FormData { interface FormData {
@ -59,6 +60,7 @@ interface FormData {
sku: string; sku: string;
stockQuantity: number; stockQuantity: number;
trackInventory: boolean; trackInventory: boolean;
weight: string;
} }
export interface ProductCreatePageSubmitData extends FormData { export interface ProductCreatePageSubmitData extends FormData {
attributes: ProductAttributeInput[]; attributes: ProductAttributeInput[];
@ -82,6 +84,7 @@ interface ProductCreatePageProps {
}>; }>;
header: string; header: string;
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
weightUnit: string;
warehouses: SearchWarehouses_search_edges_node[]; warehouses: SearchWarehouses_search_edges_node[];
fetchCategories: (data: string) => void; fetchCategories: (data: string) => void;
fetchCollections: (data: string) => void; fetchCollections: (data: string) => void;
@ -107,6 +110,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
warehouses, warehouses,
onBack, onBack,
fetchProductTypes, fetchProductTypes,
weightUnit,
onSubmit onSubmit
}: ProductCreatePageProps) => { }: ProductCreatePageProps) => {
const intl = useIntl(); const intl = useIntl();
@ -143,7 +147,8 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
seoTitle: "", seoTitle: "",
sku: null, sku: null,
stockQuantity: null, stockQuantity: null,
trackInventory: false trackInventory: false,
weight: ""
}; };
// Display values // Display values
@ -234,6 +239,13 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
<CardSpacer /> <CardSpacer />
{!!productType && !productType.hasVariants && ( {!!productType && !productType.hasVariants && (
<> <>
<ProductShipping
data={data}
disabled={disabled}
errors={errors}
weightUnit={weightUnit}
onChange={change}
/>
<ProductPricing <ProductPricing
currency={currency} currency={currency}
data={data} data={data}

View file

@ -0,0 +1,65 @@
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import InputAdornment from "@material-ui/core/InputAdornment";
import TextField from "@material-ui/core/TextField";
import CardTitle from "@saleor/components/CardTitle";
import Grid from "@saleor/components/Grid";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors";
import React from "react";
import { useIntl } from "react-intl";
interface ProductShippingProps {
data: {
weight: string;
};
disabled: boolean;
errors: ProductErrorFragment[];
weightUnit: string;
onChange: (event: React.ChangeEvent<any>) => void;
}
const ProductShipping: React.FC<ProductShippingProps> = props => {
const { data, disabled, errors, weightUnit, onChange } = props;
const intl = useIntl();
const formErrors = getFormErrors(["weight"], errors);
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Shipping",
description: "product shipping"
})}
/>
<CardContent>
<Grid variant="uniform">
<TextField
disabled={disabled}
label={intl.formatMessage({
defaultMessage: "Weight",
description: "product weight"
})}
error={!!formErrors.weight}
helperText={getProductErrorMessage(formErrors.weight, intl)}
name="weight"
value={data.weight}
onChange={onChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">{weightUnit}</InputAdornment>
),
inputProps: {
min: 0
}
}}
/>
</Grid>
</CardContent>
</Card>
);
};
ProductShipping.displayName = "ProductShipping";
export default ProductShipping;

View file

@ -48,10 +48,12 @@ import ProductDetailsForm from "../ProductDetailsForm";
import ProductImages from "../ProductImages"; import ProductImages from "../ProductImages";
import ProductOrganization from "../ProductOrganization"; import ProductOrganization from "../ProductOrganization";
import ProductPricing from "../ProductPricing"; import ProductPricing from "../ProductPricing";
import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks, { ProductStockInput } from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
import ProductVariants from "../ProductVariants"; import ProductVariants from "../ProductVariants";
export interface ProductUpdatePageProps extends ListActions { export interface ProductUpdatePageProps extends ListActions {
defaultWeightUnit: string;
errors: ProductErrorFragment[]; errors: ProductErrorFragment[];
placeholderImage: string; placeholderImage: string;
collections: SearchCollections_search_edges_node[]; collections: SearchCollections_search_edges_node[];
@ -89,6 +91,7 @@ export interface ProductUpdatePageSubmitData extends ProductUpdatePageFormData {
} }
export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
defaultWeightUnit,
disabled, disabled,
categories: categoryChoiceList, categories: categoryChoiceList,
collections: collectionChoiceList, collections: collectionChoiceList,
@ -278,6 +281,15 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
toggleAll={toggleAll} toggleAll={toggleAll}
/> />
) : ( ) : (
<>
<ProductShipping
data={data}
disabled={disabled}
errors={errors}
weightUnit={product?.weight?.unit || defaultWeightUnit}
onChange={change}
/>
<CardSpacer />
<ProductStocks <ProductStocks
data={data} data={data}
disabled={disabled} disabled={disabled}
@ -305,6 +317,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
removeStock(id); removeStock(id);
}} }}
/> />
</>
)} )}
<CardSpacer /> <CardSpacer />
<SeoForm <SeoForm

View file

@ -12,9 +12,9 @@ import { ProductVariant_attributes_attribute_values } from "@saleor/fragments/ty
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { VariantCreate_productVariantCreate_errors } from "@saleor/products/types/VariantCreate"; import { VariantCreate_productVariantCreate_errors } from "@saleor/products/types/VariantCreate";
import { ProductErrorCode } from "@saleor/types/globalTypes"; import { getProductVariantAttributeErrorMessage } from "@saleor/utils/errors/product";
import React from "react"; import React from "react";
import { IntlShape, useIntl } from "react-intl"; import { useIntl } from "react-intl";
export interface VariantAttributeInputData { export interface VariantAttributeInputData {
values: ProductVariant_attributes_attribute_values[]; values: ProductVariant_attributes_attribute_values[];
@ -66,19 +66,6 @@ function getAttributeValueChoices(
})); }));
} }
function translateErrors(intl: IntlShape) {
return {
[ProductErrorCode.REQUIRED]: intl.formatMessage({
defaultMessage: "All attributes should have value",
description: "product attribute error"
}),
[ProductErrorCode.UNIQUE]: intl.formatMessage({
defaultMessage: "This variant already exists",
description: "product attribute error"
})
};
}
const ProductVariantAttributes: React.FC<ProductVariantAttributesProps> = ({ const ProductVariantAttributes: React.FC<ProductVariantAttributesProps> = ({
attributes, attributes,
disabled, disabled,
@ -87,8 +74,6 @@ const ProductVariantAttributes: React.FC<ProductVariantAttributesProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const translatedErrors = translateErrors(intl);
return ( return (
<Card> <Card>
<CardTitle <CardTitle
@ -126,7 +111,7 @@ const ProductVariantAttributes: React.FC<ProductVariantAttributesProps> = ({
.filter(error => error.field === "attributes") .filter(error => error.field === "attributes")
.map(error => ( .map(error => (
<Typography color="error" key={error.code}> <Typography color="error" key={error.code}>
{translatedErrors[error.code]} {getProductVariantAttributeErrorMessage(error, intl)}
</Typography> </Typography>
))} ))}
</> </>

View file

@ -18,6 +18,7 @@ import { useIntl } from "react-intl";
import { maybe } from "../../../misc"; import { maybe } from "../../../misc";
import { ProductVariantCreateData_product } from "../../types/ProductVariantCreateData"; import { ProductVariantCreateData_product } from "../../types/ProductVariantCreateData";
import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks, { ProductStockInput } from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
import ProductVariantAttributes, { import ProductVariantAttributes, {
VariantAttributeInputData VariantAttributeInputData
@ -32,6 +33,7 @@ interface ProductVariantCreatePageFormData {
quantity: string; quantity: string;
sku: string; sku: string;
trackInventory: boolean; trackInventory: boolean;
weight: string;
} }
export interface ProductVariantCreatePageSubmitData export interface ProductVariantCreatePageSubmitData
@ -48,6 +50,7 @@ interface ProductVariantCreatePageProps {
product: ProductVariantCreateData_product; product: ProductVariantCreateData_product;
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
warehouses: SearchWarehouses_search_edges_node[]; warehouses: SearchWarehouses_search_edges_node[];
weightUnit: string;
onBack: () => void; onBack: () => void;
onSubmit: (data: ProductVariantCreatePageSubmitData) => void; onSubmit: (data: ProductVariantCreatePageSubmitData) => void;
onVariantClick: (variantId: string) => void; onVariantClick: (variantId: string) => void;
@ -61,6 +64,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
product, product,
saveButtonBarState, saveButtonBarState,
warehouses, warehouses,
weightUnit,
onBack, onBack,
onSubmit, onSubmit,
onVariantClick onVariantClick
@ -86,7 +90,8 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
price: "", price: "",
quantity: "0", quantity: "0",
sku: "", sku: "",
trackInventory: true trackInventory: true,
weight: ""
}; };
const handleSubmit = (data: ProductVariantCreatePageFormData) => const handleSubmit = (data: ProductVariantCreatePageFormData) =>
@ -137,6 +142,14 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
onChange={change} onChange={change}
/> />
<CardSpacer /> <CardSpacer />
<ProductShipping
data={data}
disabled={disabled}
errors={errors}
weightUnit={weightUnit}
onChange={change}
/>
<CardSpacer />
<ProductStocks <ProductStocks
data={data} data={data}
disabled={disabled} disabled={disabled}

View file

@ -21,6 +21,7 @@ import { diff } from "fast-array-diff";
import React from "react"; import React from "react";
import { maybe } from "../../../misc"; import { maybe } from "../../../misc";
import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks, { ProductStockInput } from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
import ProductVariantAttributes, { import ProductVariantAttributes, {
VariantAttributeInputData VariantAttributeInputData
@ -35,6 +36,7 @@ export interface ProductVariantPageFormData {
price: string; price: string;
sku: string; sku: string;
trackInventory: boolean; trackInventory: boolean;
weight: string;
} }
export interface ProductVariantPageSubmitData export interface ProductVariantPageSubmitData
@ -46,6 +48,7 @@ export interface ProductVariantPageSubmitData
} }
interface ProductVariantPageProps { interface ProductVariantPageProps {
defaultWeightUnit: string;
variant?: ProductVariant; variant?: ProductVariant;
errors: VariantUpdate_productVariantUpdate_errors[]; errors: VariantUpdate_productVariantUpdate_errors[];
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
@ -62,6 +65,7 @@ interface ProductVariantPageProps {
} }
const ProductVariantPage: React.FC<ProductVariantPageProps> = ({ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
defaultWeightUnit,
errors, errors,
loading, loading,
header, header,
@ -112,7 +116,8 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
costPrice: maybe(() => variant.costPrice.amount.toString(), ""), costPrice: maybe(() => variant.costPrice.amount.toString(), ""),
price: maybe(() => variant.price.amount.toString(), ""), price: maybe(() => variant.price.amount.toString(), ""),
sku: maybe(() => variant.sku, ""), sku: maybe(() => variant.sku, ""),
trackInventory: variant?.trackInventory trackInventory: variant?.trackInventory,
weight: variant?.weight?.value.toString() || ""
}; };
const handleSubmit = (data: ProductVariantPageFormData) => { const handleSubmit = (data: ProductVariantPageFormData) => {
@ -195,6 +200,14 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onChange={change} onChange={change}
/> />
<CardSpacer /> <CardSpacer />
<ProductShipping
data={data}
disabled={loading}
errors={errors}
weightUnit={variant?.weight?.unit || defaultWeightUnit}
onChange={change}
/>
<CardSpacer />
<ProductStocks <ProductStocks
data={data} data={data}
disabled={loading} disabled={loading}

View file

@ -278,7 +278,12 @@ export const product: (
warehouse: warehouseList[1] warehouse: warehouseList[1]
} }
], ],
trackInventory: true trackInventory: true,
weight: {
__typename: "Weight",
unit: "kg",
value: 3
}
}, },
{ {
__typename: "ProductVariant", __typename: "ProductVariant",
@ -308,9 +313,19 @@ export const product: (
warehouse: warehouseList[0] warehouse: warehouseList[0]
} }
], ],
trackInventory: false trackInventory: false,
weight: {
__typename: "Weight",
unit: "kg",
value: 4
}
}
],
weight: {
__typename: "Weight",
unit: "kg",
value: 5
} }
]
}); });
export const products = ( export const products = (
placeholderImage: string placeholderImage: string
@ -1654,7 +1669,12 @@ export const variant = (placeholderImage: string): ProductVariant => ({
} }
} }
], ],
trackInventory: true trackInventory: true,
weight: {
__typename: "Weight",
unit: "kg",
value: 6
}
}); });
export const variantImages = (placeholderImage: string) => export const variantImages = (placeholderImage: string) =>
variant(placeholderImage).images; variant(placeholderImage).images;

View file

@ -192,6 +192,7 @@ export const simpleProductUpdateMutation = gql`
$addStocks: [StockInput!]! $addStocks: [StockInput!]!
$deleteStocks: [ID!]! $deleteStocks: [ID!]!
$updateStocks: [StockInput!]! $updateStocks: [StockInput!]!
$weight: WeightScalar
) { ) {
productUpdate( productUpdate(
id: $id id: $id
@ -206,6 +207,7 @@ export const simpleProductUpdateMutation = gql`
name: $name name: $name
basePrice: $basePrice basePrice: $basePrice
seo: $seo seo: $seo
weight: $weight
} }
) { ) {
errors: productErrors { errors: productErrors {
@ -281,6 +283,7 @@ export const productCreateMutation = gql`
$seo: SeoInput $seo: SeoInput
$stocks: [StockInput!]! $stocks: [StockInput!]!
$trackInventory: Boolean! $trackInventory: Boolean!
$weight: WeightScalar
) { ) {
productCreate( productCreate(
input: { input: {
@ -298,6 +301,7 @@ export const productCreateMutation = gql`
seo: $seo seo: $seo
stocks: $stocks stocks: $stocks
trackInventory: $trackInventory trackInventory: $trackInventory
weight: $weight
} }
) { ) {
errors: productErrors { errors: productErrors {
@ -346,6 +350,7 @@ export const variantUpdateMutation = gql`
$sku: String $sku: String
$trackInventory: Boolean! $trackInventory: Boolean!
$stocks: [StockInput!]! $stocks: [StockInput!]!
$weight: WeightScalar
) { ) {
productVariantUpdate( productVariantUpdate(
id: $id id: $id
@ -355,6 +360,7 @@ export const variantUpdateMutation = gql`
price: $price price: $price
sku: $sku sku: $sku
trackInventory: $trackInventory trackInventory: $trackInventory
weight: $weight
} }
) { ) {
errors: productErrors { errors: productErrors {

View file

@ -174,6 +174,12 @@ export interface ProductCreate_productCreate_product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface ProductCreate_productCreate_product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductCreate_productCreate_product { export interface ProductCreate_productCreate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -194,6 +200,7 @@ export interface ProductCreate_productCreate_product {
publicationDate: any | null; publicationDate: any | null;
images: (ProductCreate_productCreate_product_images | null)[] | null; images: (ProductCreate_productCreate_product_images | null)[] | null;
variants: (ProductCreate_productCreate_product_variants | null)[] | null; variants: (ProductCreate_productCreate_product_variants | null)[] | null;
weight: ProductCreate_productCreate_product_weight | null;
} }
export interface ProductCreate_productCreate { export interface ProductCreate_productCreate {
@ -221,4 +228,5 @@ export interface ProductCreateVariables {
seo?: SeoInput | null; seo?: SeoInput | null;
stocks: StockInput[]; stocks: StockInput[];
trackInventory: boolean; trackInventory: boolean;
weight?: any | null;
} }

View file

@ -168,6 +168,12 @@ export interface ProductDetails_product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface ProductDetails_product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductDetails_product { export interface ProductDetails_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -188,6 +194,7 @@ export interface ProductDetails_product {
publicationDate: any | null; publicationDate: any | null;
images: (ProductDetails_product_images | null)[] | null; images: (ProductDetails_product_images | null)[] | null;
variants: (ProductDetails_product_variants | null)[] | null; variants: (ProductDetails_product_variants | null)[] | null;
weight: ProductDetails_product_weight | null;
} }
export interface ProductDetails { export interface ProductDetails {

View file

@ -174,6 +174,12 @@ export interface ProductImageCreate_productImageCreate_product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface ProductImageCreate_productImageCreate_product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductImageCreate_productImageCreate_product { export interface ProductImageCreate_productImageCreate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -194,6 +200,7 @@ export interface ProductImageCreate_productImageCreate_product {
publicationDate: any | null; publicationDate: any | null;
images: (ProductImageCreate_productImageCreate_product_images | null)[] | null; images: (ProductImageCreate_productImageCreate_product_images | null)[] | null;
variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null; variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null;
weight: ProductImageCreate_productImageCreate_product_weight | null;
} }
export interface ProductImageCreate_productImageCreate { export interface ProductImageCreate_productImageCreate {

View file

@ -174,6 +174,12 @@ export interface ProductImageUpdate_productImageUpdate_product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface ProductImageUpdate_productImageUpdate_product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductImageUpdate_productImageUpdate_product { export interface ProductImageUpdate_productImageUpdate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -194,6 +200,7 @@ export interface ProductImageUpdate_productImageUpdate_product {
publicationDate: any | null; publicationDate: any | null;
images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null; images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null;
variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null; variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null;
weight: ProductImageUpdate_productImageUpdate_product_weight | null;
} }
export interface ProductImageUpdate_productImageUpdate { export interface ProductImageUpdate_productImageUpdate {

View file

@ -174,6 +174,12 @@ export interface ProductUpdate_productUpdate_product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface ProductUpdate_productUpdate_product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductUpdate_productUpdate_product { export interface ProductUpdate_productUpdate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -194,6 +200,7 @@ export interface ProductUpdate_productUpdate_product {
publicationDate: any | null; publicationDate: any | null;
images: (ProductUpdate_productUpdate_product_images | null)[] | null; images: (ProductUpdate_productUpdate_product_images | null)[] | null;
variants: (ProductUpdate_productUpdate_product_variants | null)[] | null; variants: (ProductUpdate_productUpdate_product_variants | null)[] | null;
weight: ProductUpdate_productUpdate_product_weight | null;
} }
export interface ProductUpdate_productUpdate { export interface ProductUpdate_productUpdate {

View file

@ -103,6 +103,12 @@ export interface ProductVariantDetails_productVariant_stocks {
warehouse: ProductVariantDetails_productVariant_stocks_warehouse; warehouse: ProductVariantDetails_productVariant_stocks_warehouse;
} }
export interface ProductVariantDetails_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface ProductVariantDetails_productVariant { export interface ProductVariantDetails_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -115,6 +121,7 @@ export interface ProductVariantDetails_productVariant {
sku: string; sku: string;
stocks: (ProductVariantDetails_productVariant_stocks | null)[] | null; stocks: (ProductVariantDetails_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: ProductVariantDetails_productVariant_weight | null;
} }
export interface ProductVariantDetails { export interface ProductVariantDetails {

View file

@ -174,6 +174,12 @@ export interface SimpleProductUpdate_productUpdate_product_variants {
trackInventory: boolean; trackInventory: boolean;
} }
export interface SimpleProductUpdate_productUpdate_product_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface SimpleProductUpdate_productUpdate_product { export interface SimpleProductUpdate_productUpdate_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
@ -194,6 +200,7 @@ export interface SimpleProductUpdate_productUpdate_product {
publicationDate: any | null; publicationDate: any | null;
images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null; images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null;
variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null; variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null;
weight: SimpleProductUpdate_productUpdate_product_weight | null;
} }
export interface SimpleProductUpdate_productUpdate { export interface SimpleProductUpdate_productUpdate {
@ -305,6 +312,12 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant_stocks
warehouse: SimpleProductUpdate_productVariantUpdate_productVariant_stocks_warehouse; warehouse: SimpleProductUpdate_productVariantUpdate_productVariant_stocks_warehouse;
} }
export interface SimpleProductUpdate_productVariantUpdate_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant { export interface SimpleProductUpdate_productVariantUpdate_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -317,6 +330,7 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant {
sku: string; sku: string;
stocks: (SimpleProductUpdate_productVariantUpdate_productVariant_stocks | null)[] | null; stocks: (SimpleProductUpdate_productVariantUpdate_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: SimpleProductUpdate_productVariantUpdate_productVariant_weight | null;
} }
export interface SimpleProductUpdate_productVariantUpdate { export interface SimpleProductUpdate_productVariantUpdate {
@ -429,6 +443,12 @@ export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_s
warehouse: SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks_warehouse; warehouse: SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks_warehouse;
} }
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant { export interface SimpleProductUpdate_productVariantStocksCreate_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -441,6 +461,7 @@ export interface SimpleProductUpdate_productVariantStocksCreate_productVariant {
sku: string; sku: string;
stocks: (SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks | null)[] | null; stocks: (SimpleProductUpdate_productVariantStocksCreate_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: SimpleProductUpdate_productVariantStocksCreate_productVariant_weight | null;
} }
export interface SimpleProductUpdate_productVariantStocksCreate { export interface SimpleProductUpdate_productVariantStocksCreate {
@ -552,6 +573,12 @@ export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_s
warehouse: SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks_warehouse; warehouse: SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks_warehouse;
} }
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant { export interface SimpleProductUpdate_productVariantStocksDelete_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -564,6 +591,7 @@ export interface SimpleProductUpdate_productVariantStocksDelete_productVariant {
sku: string; sku: string;
stocks: (SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks | null)[] | null; stocks: (SimpleProductUpdate_productVariantStocksDelete_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: SimpleProductUpdate_productVariantStocksDelete_productVariant_weight | null;
} }
export interface SimpleProductUpdate_productVariantStocksDelete { export interface SimpleProductUpdate_productVariantStocksDelete {
@ -676,6 +704,12 @@ export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_s
warehouse: SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse; warehouse: SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse;
} }
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant { export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -688,6 +722,7 @@ export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant {
sku: string; sku: string;
stocks: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks | null)[] | null; stocks: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: SimpleProductUpdate_productVariantStocksUpdate_productVariant_weight | null;
} }
export interface SimpleProductUpdate_productVariantStocksUpdate { export interface SimpleProductUpdate_productVariantStocksUpdate {
@ -721,4 +756,5 @@ export interface SimpleProductUpdateVariables {
addStocks: StockInput[]; addStocks: StockInput[];
deleteStocks: string[]; deleteStocks: string[];
updateStocks: StockInput[]; updateStocks: StockInput[];
weight?: any | null;
} }

View file

@ -111,6 +111,12 @@ export interface VariantCreate_productVariantCreate_productVariant_stocks {
warehouse: VariantCreate_productVariantCreate_productVariant_stocks_warehouse; warehouse: VariantCreate_productVariantCreate_productVariant_stocks_warehouse;
} }
export interface VariantCreate_productVariantCreate_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface VariantCreate_productVariantCreate_productVariant { export interface VariantCreate_productVariantCreate_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -123,6 +129,7 @@ export interface VariantCreate_productVariantCreate_productVariant {
sku: string; sku: string;
stocks: (VariantCreate_productVariantCreate_productVariant_stocks | null)[] | null; stocks: (VariantCreate_productVariantCreate_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: VariantCreate_productVariantCreate_productVariant_weight | null;
} }
export interface VariantCreate_productVariantCreate { export interface VariantCreate_productVariantCreate {

View file

@ -111,6 +111,12 @@ export interface VariantImageAssign_variantImageAssign_productVariant_stocks {
warehouse: VariantImageAssign_variantImageAssign_productVariant_stocks_warehouse; warehouse: VariantImageAssign_variantImageAssign_productVariant_stocks_warehouse;
} }
export interface VariantImageAssign_variantImageAssign_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface VariantImageAssign_variantImageAssign_productVariant { export interface VariantImageAssign_variantImageAssign_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -123,6 +129,7 @@ export interface VariantImageAssign_variantImageAssign_productVariant {
sku: string; sku: string;
stocks: (VariantImageAssign_variantImageAssign_productVariant_stocks | null)[] | null; stocks: (VariantImageAssign_variantImageAssign_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: VariantImageAssign_variantImageAssign_productVariant_weight | null;
} }
export interface VariantImageAssign_variantImageAssign { export interface VariantImageAssign_variantImageAssign {

View file

@ -111,6 +111,12 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant_stocks
warehouse: VariantImageUnassign_variantImageUnassign_productVariant_stocks_warehouse; warehouse: VariantImageUnassign_variantImageUnassign_productVariant_stocks_warehouse;
} }
export interface VariantImageUnassign_variantImageUnassign_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant { export interface VariantImageUnassign_variantImageUnassign_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -123,6 +129,7 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant {
sku: string; sku: string;
stocks: (VariantImageUnassign_variantImageUnassign_productVariant_stocks | null)[] | null; stocks: (VariantImageUnassign_variantImageUnassign_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: VariantImageUnassign_variantImageUnassign_productVariant_weight | null;
} }
export interface VariantImageUnassign_variantImageUnassign { export interface VariantImageUnassign_variantImageUnassign {

View file

@ -111,6 +111,12 @@ export interface VariantUpdate_productVariantUpdate_productVariant_stocks {
warehouse: VariantUpdate_productVariantUpdate_productVariant_stocks_warehouse; warehouse: VariantUpdate_productVariantUpdate_productVariant_stocks_warehouse;
} }
export interface VariantUpdate_productVariantUpdate_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface VariantUpdate_productVariantUpdate_productVariant { export interface VariantUpdate_productVariantUpdate_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -123,6 +129,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant {
sku: string; sku: string;
stocks: (VariantUpdate_productVariantUpdate_productVariant_stocks | null)[] | null; stocks: (VariantUpdate_productVariantUpdate_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: VariantUpdate_productVariantUpdate_productVariant_weight | null;
} }
export interface VariantUpdate_productVariantUpdate { export interface VariantUpdate_productVariantUpdate {
@ -235,6 +242,12 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_stocks
warehouse: VariantUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse; warehouse: VariantUpdate_productVariantStocksUpdate_productVariant_stocks_warehouse;
} }
export interface VariantUpdate_productVariantStocksUpdate_productVariant_weight {
__typename: "Weight";
unit: string;
value: number;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant { export interface VariantUpdate_productVariantStocksUpdate_productVariant {
__typename: "ProductVariant"; __typename: "ProductVariant";
id: string; id: string;
@ -247,6 +260,7 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant {
sku: string; sku: string;
stocks: (VariantUpdate_productVariantStocksUpdate_productVariant_stocks | null)[] | null; stocks: (VariantUpdate_productVariantStocksUpdate_productVariant_stocks | null)[] | null;
trackInventory: boolean; trackInventory: boolean;
weight: VariantUpdate_productVariantStocksUpdate_productVariant_weight | null;
} }
export interface VariantUpdate_productVariantStocksUpdate { export interface VariantUpdate_productVariantStocksUpdate {
@ -337,4 +351,5 @@ export interface VariantUpdateVariables {
sku?: string | null; sku?: string | null;
trackInventory: boolean; trackInventory: boolean;
stocks: StockInput[]; stocks: StockInput[];
weight?: any | null;
} }

View file

@ -181,6 +181,7 @@ export interface ProductUpdatePageFormData {
seoTitle: string; seoTitle: string;
sku: string; sku: string;
trackInventory: boolean; trackInventory: boolean;
weight: string;
} }
export function getProductUpdatePageFormData( export function getProductUpdatePageFormData(
@ -210,7 +211,8 @@ export function getProductUpdatePageFormData(
: undefined, : undefined,
"" ""
), ),
trackInventory: !!product?.variants[0]?.trackInventory trackInventory: !!product?.variants[0]?.trackInventory,
weight: product?.weight?.value.toString() || ""
}; };
} }

View file

@ -10,7 +10,7 @@ import { useWarehouseList } from "@saleor/warehouses/queries";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { decimal, maybe } from "../../misc"; import { decimal, maybe, weight } from "../../misc";
import ProductCreatePage, { import ProductCreatePage, {
ProductCreatePageSubmitData ProductCreatePageSubmitData
} from "../components/ProductCreatePage"; } from "../components/ProductCreatePage";
@ -96,7 +96,8 @@ export const ProductCreateView: React.FC = () => {
quantity: parseInt(stock.value, 0), quantity: parseInt(stock.value, 0),
warehouse: stock.id warehouse: stock.id
})), })),
trackInventory: formData.trackInventory trackInventory: formData.trackInventory,
weight: weight(formData.weight)
} }
}); });
}; };
@ -158,6 +159,7 @@ export const ProductCreateView: React.FC = () => {
warehouses={ warehouses={
warehouses.data?.warehouses.edges.map(edge => edge.node) || [] warehouses.data?.warehouses.edges.map(edge => edge.node) || []
} }
weightUnit={shop?.defaultWeightUnit}
/> />
</> </>
); );

View file

@ -9,6 +9,7 @@ import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import useShop from "@saleor/hooks/useShop";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCategorySearch from "@saleor/searches/useCategorySearch";
import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch";
@ -75,6 +76,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
first: 50 first: 50
} }
}); });
const shop = useShop();
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
ProductUrlDialog, ProductUrlDialog,
@ -217,6 +219,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
<ProductUpdatePage <ProductUpdatePage
categories={categories} categories={categories}
collections={collections} collections={collections}
defaultWeightUnit={shop?.defaultWeightUnit}
disabled={disableFormSave} disabled={disableFormSave}
errors={errors} errors={errors}
fetchCategories={searchCategories} fetchCategories={searchCategories}

View file

@ -1,4 +1,4 @@
import { decimal } from "@saleor/misc"; import { decimal, weight } from "@saleor/misc";
import { ProductUpdatePageSubmitData } from "@saleor/products/components/ProductUpdatePage"; import { ProductUpdatePageSubmitData } from "@saleor/products/components/ProductUpdatePage";
import { ProductDetails_product } from "@saleor/products/types/ProductDetails"; import { ProductDetails_product } from "@saleor/products/types/ProductDetails";
import { ProductImageCreateVariables } from "@saleor/products/types/ProductImageCreate"; import { ProductImageCreateVariables } from "@saleor/products/types/ProductImageCreate";
@ -48,7 +48,8 @@ export function createUpdateHandler(
sku: data.sku, sku: data.sku,
trackInventory: data.trackInventory trackInventory: data.trackInventory
}, },
updateStocks: data.updateStocks.map(mapFormsetStockToStockInput) updateStocks: data.updateStocks.map(mapFormsetStockToStockInput),
weight: weight(data.weight)
}); });
} }
}; };

View file

@ -3,13 +3,14 @@ import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import useShop from "@saleor/hooks/useShop";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import { useWarehouseList } from "@saleor/warehouses/queries"; import { useWarehouseList } from "@saleor/warehouses/queries";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { decimal } from "../../misc"; import { decimal, weight } from "../../misc";
import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog"; import ProductVariantDeleteDialog from "../components/ProductVariantDeleteDialog";
import ProductVariantPage, { import ProductVariantPage, {
ProductVariantPageSubmitData ProductVariantPageSubmitData
@ -40,6 +41,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
productId, productId,
params params
}) => { }) => {
const shop = useShop();
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const intl = useIntl(); const intl = useIntl();
@ -133,6 +135,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
<> <>
<WindowTitle title={data?.productVariant?.name} /> <WindowTitle title={data?.productVariant?.name} />
<ProductVariantPage <ProductVariantPage
defaultWeightUnit={shop?.defaultWeightUnit}
errors={errors} errors={errors}
saveButtonBarState={updateVariant.opts.status} saveButtonBarState={updateVariant.opts.status}
loading={disableFormSave} loading={disableFormSave}
@ -165,7 +168,8 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
stocks: data.updateStocks.map( stocks: data.updateStocks.map(
mapFormsetStockToStockInput mapFormsetStockToStockInput
), ),
trackInventory: data.trackInventory trackInventory: data.trackInventory,
weight: weight(data.weight)
}) })
} }
onVariantClick={variantId => { onVariantClick={variantId => {

View file

@ -8,7 +8,7 @@ import { useWarehouseList } from "@saleor/warehouses/queries";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { decimal } from "../../misc"; import { decimal, weight } from "../../misc";
import ProductVariantCreatePage, { import ProductVariantCreatePage, {
ProductVariantCreatePageSubmitData ProductVariantCreatePageSubmitData
} from "../components/ProductVariantCreatePage"; } from "../components/ProductVariantCreatePage";
@ -83,7 +83,8 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
quantity: parseInt(stock.value, 0), quantity: parseInt(stock.value, 0),
warehouse: stock.id warehouse: stock.id
})), })),
trackInventory: true trackInventory: true,
weight: weight(formData.weight)
} }
} }
}); });
@ -121,6 +122,7 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
edge => edge.node edge => edge.node
) || [] ) || []
} }
weightUnit={shop?.defaultWeightUnit}
/> />
</> </>
); );

View file

@ -1,10 +1,15 @@
import { CreateShippingRateVariables } from "@saleor/shipping/types/CreateShippingRate"; import { CreateShippingRateVariables } from "@saleor/shipping/types/CreateShippingRate";
import { ShippingZone_shippingZone_shippingMethods } from "@saleor/shipping/types/ShippingZone";
import { UpdateShippingRateVariables } from "@saleor/shipping/types/UpdateShippingRate"; import { UpdateShippingRateVariables } from "@saleor/shipping/types/UpdateShippingRate";
import { ShippingZoneUrlQueryParams } from "@saleor/shipping/urls"; import { ShippingZoneUrlQueryParams } from "@saleor/shipping/urls";
import { ShippingMethodTypeEnum } from "@saleor/types/globalTypes"; import { ShippingMethodTypeEnum } from "@saleor/types/globalTypes";
import { FormData as ShippingZoneRateDialogFormData } from "../../components/ShippingZoneRateDialog"; import { FormData as ShippingZoneRateDialogFormData } from "../../components/ShippingZoneRateDialog";
function getValue(value: string, hasLimits: boolean): number | null {
return hasLimits ? null : parseFloat(value);
}
export function getCreateShippingRateVariables( export function getCreateShippingRateVariables(
data: ShippingZoneRateDialogFormData, data: ShippingZoneRateDialogFormData,
params: ShippingZoneUrlQueryParams, params: ShippingZoneUrlQueryParams,
@ -14,28 +19,20 @@ export function getCreateShippingRateVariables(
input: { input: {
maximumOrderPrice: maximumOrderPrice:
params.type === ShippingMethodTypeEnum.PRICE params.type === ShippingMethodTypeEnum.PRICE
? data.noLimits ? getValue(data.maxValue, data.noLimits)
? null
: parseFloat(data.maxValue)
: null, : null,
maximumOrderWeight: maximumOrderWeight:
params.type === ShippingMethodTypeEnum.WEIGHT params.type === ShippingMethodTypeEnum.WEIGHT
? data.noLimits ? getValue(data.maxValue, data.noLimits)
? null
: parseFloat(data.maxValue)
: null, : null,
minimumOrderPrice: minimumOrderPrice:
params.type === ShippingMethodTypeEnum.PRICE params.type === ShippingMethodTypeEnum.PRICE
? data.noLimits ? getValue(data.maxValue, data.noLimits)
? null
: parseFloat(data.minValue)
: null, : null,
minimumOrderWeight: minimumOrderWeight:
params.type === ShippingMethodTypeEnum.WEIGHT params.type === ShippingMethodTypeEnum.WEIGHT
? data.noLimits ? getValue(data.minValue, data.noLimits)
? null
: parseFloat(data.minValue)
: null, : null,
name: data.name, name: data.name,
price: data.isFree ? 0 : parseFloat(data.price), price: data.isFree ? 0 : parseFloat(data.price),
@ -47,25 +44,36 @@ export function getCreateShippingRateVariables(
export function getUpdateShippingRateVariables( export function getUpdateShippingRateVariables(
data: ShippingZoneRateDialogFormData, data: ShippingZoneRateDialogFormData,
params: ShippingZoneUrlQueryParams, shippingRate: ShippingZone_shippingZone_shippingMethods,
id: string shippingZoneId: string
): UpdateShippingRateVariables { ): UpdateShippingRateVariables {
const isPriceType = data.type === ShippingMethodTypeEnum.PRICE; const base: UpdateShippingRateVariables = {
const parsedMinValue = parseFloat(data.minValue); id: shippingRate.id,
const parsedMaxValue = parseFloat(data.maxValue);
const isPriceSet = !data.noLimits && isPriceType;
const isWeightSet = !data.noLimits && !isPriceType;
return {
id: params.id,
input: { input: {
maximumOrderPrice: isPriceSet ? parsedMaxValue : null,
maximumOrderWeight: isWeightSet ? parsedMaxValue : null,
minimumOrderPrice: isPriceSet ? parsedMinValue : null,
minimumOrderWeight: isWeightSet ? parsedMinValue : null,
name: data.name, name: data.name,
price: data.isFree ? 0 : parseFloat(data.price), price: data.isFree ? 0 : parseFloat(data.price),
shippingZone: id, shippingZone: shippingZoneId,
type: data.type type: shippingRate.type
}
};
if (shippingRate.type === ShippingMethodTypeEnum.PRICE) {
return {
...base,
input: {
...base.input,
maximumOrderPrice: getValue(data.maxValue, data.noLimits),
minimumOrderPrice: getValue(data.minValue, data.noLimits)
}
};
}
return {
...base,
input: {
...base.input,
maximumOrderWeight: getValue(data.maxValue, data.noLimits),
minimumOrderWeight: getValue(data.minValue, data.noLimits)
} }
}; };
} }

View file

@ -227,9 +227,15 @@ const ShippingZoneDetails: React.FC<ShippingZoneDetailsProps> = ({
disabled={updateShippingRateOpts.loading} disabled={updateShippingRateOpts.loading}
errors={updateShippingRateOpts.data?.shippingPriceUpdate.errors || []} errors={updateShippingRateOpts.data?.shippingPriceUpdate.errors || []}
onClose={closeModal} onClose={closeModal}
onSubmit={data => onSubmit={submitData =>
updateShippingRate({ updateShippingRate({
variables: getUpdateShippingRateVariables(data, params, id) variables: getUpdateShippingRateVariables(
submitData,
data?.shippingZone?.shippingMethods.find(
shippingMethod => shippingMethod.id === params.id
),
id
)
}) })
} }
open={params.action === "edit-rate"} open={params.action === "edit-rate"}

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined} onSubmit={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
weightUnit="kg"
/> />
)) ))
.add("When loading", () => ( .add("When loading", () => (
@ -55,6 +56,7 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined} onSubmit={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={undefined} warehouses={undefined}
weightUnit="kg"
/> />
)) ))
.add("form errors", () => ( .add("form errors", () => (
@ -82,5 +84,6 @@ storiesOf("Views / Products / Create product", module)
onSubmit={() => undefined} onSubmit={() => undefined}
saveButtonBarState="default" saveButtonBarState="default"
warehouses={warehouseList} warehouses={warehouseList}
weightUnit="kg"
/> />
)); ));

View file

@ -19,6 +19,7 @@ const props: ProductUpdatePageProps = {
...listActionsProps, ...listActionsProps,
categories: [product.category], categories: [product.category],
collections, collections,
defaultWeightUnit: "kg",
disabled: false, disabled: false,
errors: [], errors: [],
fetchCategories: () => undefined, fetchCategories: () => undefined,

View file

@ -15,6 +15,7 @@ storiesOf("Views / Products / Create product variant", module)
.add("default", () => ( .add("default", () => (
<ProductVariantCreatePage <ProductVariantCreatePage
currencySymbol="USD" currencySymbol="USD"
weightUnit="kg"
disabled={false} disabled={false}
errors={[]} errors={[]}
header="Add variant" header="Add variant"
@ -29,6 +30,7 @@ storiesOf("Views / Products / Create product variant", module)
.add("with errors", () => ( .add("with errors", () => (
<ProductVariantCreatePage <ProductVariantCreatePage
currencySymbol="USD" currencySymbol="USD"
weightUnit="kg"
disabled={false} disabled={false}
errors={[ errors={[
{ {
@ -59,6 +61,7 @@ storiesOf("Views / Products / Create product variant", module)
.add("when loading data", () => ( .add("when loading data", () => (
<ProductVariantCreatePage <ProductVariantCreatePage
currencySymbol="USD" currencySymbol="USD"
weightUnit="kg"
disabled={true} disabled={true}
errors={[]} errors={[]}
header="Add variant" header="Add variant"
@ -73,6 +76,7 @@ storiesOf("Views / Products / Create product variant", module)
.add("add first variant", () => ( .add("add first variant", () => (
<ProductVariantCreatePage <ProductVariantCreatePage
currencySymbol="USD" currencySymbol="USD"
weightUnit="kg"
disabled={false} disabled={false}
errors={[]} errors={[]}
header="Add variant" header="Add variant"

View file

@ -14,6 +14,7 @@ storiesOf("Views / Products / Product variant details", module)
.addDecorator(Decorator) .addDecorator(Decorator)
.add("when loaded data", () => ( .add("when loaded data", () => (
<ProductVariantPage <ProductVariantPage
defaultWeightUnit="kg"
header={variant.name || variant.sku} header={variant.name || variant.sku}
errors={[]} errors={[]}
variant={variant} variant={variant}
@ -29,6 +30,7 @@ storiesOf("Views / Products / Product variant details", module)
)) ))
.add("when loading data", () => ( .add("when loading data", () => (
<ProductVariantPage <ProductVariantPage
defaultWeightUnit="kg"
header={undefined} header={undefined}
errors={[]} errors={[]}
loading={true} loading={true}
@ -45,6 +47,7 @@ storiesOf("Views / Products / Product variant details", module)
)) ))
.add("attribute errors", () => ( .add("attribute errors", () => (
<ProductVariantPage <ProductVariantPage
defaultWeightUnit="kg"
header={variant.name || variant.sku} header={variant.name || variant.sku}
variant={variant} variant={variant}
onAdd={() => undefined} onAdd={() => undefined}

View file

@ -14,15 +14,26 @@ const messages = defineMessages({
attributeCannotBeAssigned: { attributeCannotBeAssigned: {
defaultMessage: "This attribute cannot be assigned to this product type" defaultMessage: "This attribute cannot be assigned to this product type"
}, },
attributeRequired: {
defaultMessage: "All attributes should have value",
description: "product attribute error"
},
attributeVariantsDisabled: { attributeVariantsDisabled: {
defaultMessage: "Variants are disabled in this product type" defaultMessage: "Variants are disabled in this product type"
}, },
duplicatedInputItem: {
defaultMessage: "Variant with these attributes already exists"
},
skuUnique: { skuUnique: {
defaultMessage: "SKUs must be unique", defaultMessage: "SKUs must be unique",
description: "bulk variant create error" description: "bulk variant create error"
}, },
variantNoDigitalContent: { variantNoDigitalContent: {
defaultMessage: "This variant does not have any digital content" defaultMessage: "This variant does not have any digital content"
},
variantUnique: {
defaultMessage: "This variant already exists",
description: "product attribute error"
} }
}); });
@ -38,6 +49,8 @@ function getProductErrorMessage(
return intl.formatMessage(messages.attributeCannotBeAssigned); return intl.formatMessage(messages.attributeCannotBeAssigned);
case ProductErrorCode.ATTRIBUTE_VARIANTS_DISABLED: case ProductErrorCode.ATTRIBUTE_VARIANTS_DISABLED:
return intl.formatMessage(messages.attributeVariantsDisabled); return intl.formatMessage(messages.attributeVariantsDisabled);
case ProductErrorCode.DUPLICATED_INPUT_ITEM:
return intl.formatMessage(messages.duplicatedInputItem);
case ProductErrorCode.GRAPHQL_ERROR: case ProductErrorCode.GRAPHQL_ERROR:
return intl.formatMessage(commonErrorMessages.graphqlError); return intl.formatMessage(commonErrorMessages.graphqlError);
case ProductErrorCode.REQUIRED: case ProductErrorCode.REQUIRED:
@ -54,6 +67,24 @@ function getProductErrorMessage(
return undefined; return undefined;
} }
export function getProductVariantAttributeErrorMessage(
err: Omit<ProductErrorFragment, "__typename"> | undefined,
intl: IntlShape
): string {
if (err) {
switch (err.code) {
case ProductErrorCode.REQUIRED:
return intl.formatMessage(messages.attributeRequired);
case ProductErrorCode.UNIQUE:
return intl.formatMessage(messages.variantUnique);
default:
return getProductErrorMessage(err, intl);
}
}
return undefined;
}
export function getBulkProductErrorMessage( export function getBulkProductErrorMessage(
err: BulkProductErrorFragment | undefined, err: BulkProductErrorFragment | undefined,
intl: IntlShape intl: IntlShape

View file

@ -51,7 +51,9 @@ const WarehouseDetailsPage: React.FC<WarehouseDetailsPageProps> = ({
onSubmit onSubmit
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const [displayCountry, setDisplayCountry] = useStateFromProps(""); const [displayCountry, setDisplayCountry] = useStateFromProps(
warehouse?.address?.country.country || ""
);
const { const {
errors: validationErrors, errors: validationErrors,