[Fix] preorder fixes (#1477)

* Fix creating variant without preorder

* Fix creating simple product in preorder

* Proper stock display for variant in preorder

* Fix ending preorder for simple product

* CR response

* CR response

* Fix global threshold empty input
This commit is contained in:
JanChodorowski 2021-10-14 14:15:59 +03:00 committed by GitHub
parent 5bee739872
commit cbeed52a30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 131 additions and 49 deletions

View file

@ -6534,6 +6534,10 @@
"context": "button",
"string": "Create variants"
},
"src_dot_products_dot_components_dot_ProductVariants_dot_1819927358": {
"context": "product variant preorder threshold",
"string": "In preorder"
},
"src_dot_products_dot_components_dot_ProductVariants_dot_2153006789": {
"context": "section header",
"string": "Variants"
@ -6565,6 +6569,10 @@
"context": "product variant inventory",
"string": "Not stocked"
},
"src_dot_products_dot_components_dot_ProductVariants_dot_4232843317": {
"context": "product variant preorder threshold",
"string": "{globalThreshold} Global threshold"
},
"src_dot_products_dot_components_dot_ProductVariants_dot_693960049": {
"string": "SKU"
},

View file

@ -72,7 +72,7 @@ export interface ProductCreateFormData extends MetadataFormData {
taxCode: string;
trackInventory: boolean;
isPreorder: boolean;
globalThreshold: number;
globalThreshold: string;
globalSoldUnits: number;
hasPreorderEndDate: boolean;
preorderEndDateTime: string;
@ -185,7 +185,7 @@ function useProductCreateForm(
trackInventory: false,
weight: "",
globalSoldUnits: 0,
globalThreshold: 0,
globalThreshold: "",
isPreorder: false,
hasPreorderEndDate: false,
preorderEndDateTime: ""

View file

@ -57,7 +57,7 @@ export interface ProductStockFormData {
sku: string;
trackInventory: boolean;
isPreorder: boolean;
globalThreshold: number;
globalThreshold: string;
globalSoldUnits: number;
hasPreorderEndDate: boolean;
preorderEndDateTime?: string;
@ -201,7 +201,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
const intl = useIntl();
const anchor = React.useRef<HTMLDivElement>();
const [isExpanded, setExpansionState] = React.useState(false);
const unitsLeft = data.globalThreshold - data.globalSoldUnits;
const unitsLeft = parseInt(data.globalThreshold, 10) - data.globalSoldUnits;
const warehousesToAssign =
warehouses?.filter(

View file

@ -59,6 +59,7 @@ const props: ProductUpdatePageProps = {
onVariantReorder: () => undefined,
onVariantShow: () => undefined,
onVariantsAdd: () => undefined,
onVariantEndPreorderDialogOpen: () => undefined,
onWarehouseConfigure: () => undefined,
openChannelsModal: () => undefined,
placeholderImage,

View file

@ -113,6 +113,7 @@ export interface ProductUpdatePageProps extends ListActions, ChannelProps {
onVariantsAdd: () => void;
onVariantShow: (id: string) => () => void;
onVariantReorder: ReorderAction;
onVariantEndPreorderDialogOpen: () => void;
onImageDelete: (id: string) => () => void;
onSubmit: (data: ProductUpdatePageSubmitData) => SubmitPromise;
openChannelsModal: () => void;
@ -183,6 +184,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
onSetDefaultVariant,
onVariantShow,
onVariantReorder,
onVariantEndPreorderDialogOpen,
onWarehouseConfigure,
isChecked,
isMediaUrlModalVisible,
@ -385,6 +387,11 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
handlers.changeChannelPreorder
}
productVariantChannelListings={data.channelListings}
onEndPreorderTrigger={
!!variants?.[0]?.preorder
? () => onVariantEndPreorderDialogOpen()
: null
}
data={data}
disabled={disabled}
hasVariants={false}

View file

@ -81,7 +81,7 @@ export interface ProductUpdateFormData extends MetadataFormData {
taxCode: string;
trackInventory: boolean;
isPreorder: boolean;
globalThreshold: number;
globalThreshold: string;
globalSoldUnits: number;
hasPreorderEndDate: boolean;
preorderEndDateTime?: string;

View file

@ -34,7 +34,7 @@ export interface ProductVariantCreateFormData extends MetadataFormData {
trackInventory: boolean;
weight: string;
isPreorder: boolean;
globalThreshold: number;
globalThreshold: string;
globalSoldUnits: number;
hasPreorderEndDate: boolean;
preorderEndDateTime?: string;

View file

@ -56,7 +56,7 @@ export interface ProductVariantUpdateFormData extends MetadataFormData {
trackInventory: boolean;
weight: string;
isPreorder: boolean;
globalThreshold: number;
globalThreshold: string;
globalSoldUnits: number;
hasPreorderEndDate: boolean;
preorderEndDateTime?: string;
@ -161,7 +161,7 @@ function useProductVariantUpdateForm(
sku: variant?.sku || "",
trackInventory: variant?.trackInventory,
isPreorder: !!variant?.preorder || false,
globalThreshold: variant?.preorder?.globalThreshold || null,
globalThreshold: variant?.preorder?.globalThreshold?.toString() || null,
globalSoldUnits: variant?.preorder?.globalSoldUnits || 0,
hasPreorderEndDate: !!variant?.preorder?.endDate,
preorderEndDateTime: variant?.preorder?.endDate,

View file

@ -137,6 +137,25 @@ function getAvailabilityLabel(
variant: ProductDetails_product_variants,
numAvailable: number
): string {
if (variant.preorder) {
if (variant.preorder.globalThreshold) {
return intl.formatMessage(
{
defaultMessage: "{globalThreshold} Global threshold",
description: "product variant preorder threshold"
},
{
globalThreshold: variant.preorder.globalThreshold
}
);
}
return intl.formatMessage({
defaultMessage: "In preorder",
description: "product variant preorder threshold"
});
}
const variantStock = variant.stocks.find(s => s.warehouse.id === warehouse);
if (!!warehouse) {

View file

@ -227,7 +227,7 @@ export interface ProductUpdatePageFormData extends MetadataFormData {
trackInventory: boolean;
weight: string;
isPreorder: boolean;
globalThreshold: number;
globalThreshold: string;
globalSoldUnits: number;
hasPreorderEndDate: boolean;
preorderEndDateTime?: string;
@ -273,7 +273,7 @@ export function getProductUpdatePageFormData(
trackInventory: !!variant?.trackInventory,
weight: product?.weight?.value.toString() || "",
isPreorder: !!variant?.preorder || false,
globalThreshold: variant?.preorder?.globalThreshold || 0,
globalThreshold: variant?.preorder?.globalThreshold?.toString() || "",
globalSoldUnits: variant?.preorder?.globalSoldUnits || 0,
hasPreorderEndDate: !!variant?.preorder?.endDate,
preorderEndDateTime: variant?.preorder?.endDate

View file

@ -61,6 +61,14 @@ const getSimpleProductVariables = (
quantity: parseInt(stock.value, 10),
warehouse: stock.id
})),
preorder: formData.isPreorder
? {
globalThreshold: formData.globalThreshold
? parseInt(formData.globalThreshold, 10)
: null,
endDate: formData.preorderEndDateTime || null
}
: null,
trackInventory: formData.trackInventory
}
});

View file

@ -30,6 +30,7 @@ import useShop from "@saleor/hooks/useShop";
import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { commonMessages, errorMessages } from "@saleor/intl";
import ProductVariantCreateDialog from "@saleor/products/components/ProductVariantCreateDialog";
import ProductVariantEndPreorderDialog from "@saleor/products/components/ProductVariantEndPreorderDialog";
import {
useProductChannelListingUpdate,
useProductDeleteMutation,
@ -39,6 +40,7 @@ import {
useProductUpdateMutation,
useProductVariantBulkDeleteMutation,
useProductVariantChannelListingUpdate,
useProductVariantPreorderDeactivateMutation,
useProductVariantReorderMutation,
useSimpleProductUpdateMutation,
useVariantCreateMutation
@ -265,6 +267,11 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
ProductUrlQueryParams
>(navigate, params => productUrl(id, params), params);
const [
isEndPreorderModalOpened,
setIsEndPreorderModalOpened
] = React.useState(false);
const product = data?.product;
const allChannels: ChannelData[] = createChannelsDataWithPrice(
@ -406,6 +413,18 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
reorderProductVariants({ variables })
);
const handleDeactivatePreorder = async () => {
await handleDeactivateVariantPreorder(product.variants[0].id);
setIsEndPreorderModalOpened(false);
};
const [
deactivatePreorder,
deactivatePreoderOpts
] = useProductVariantPreorderDeactivateMutation({});
const handleDeactivateVariantPreorder = (id: string) =>
deactivatePreorder({ variables: { id } });
const handleAssignAttributeReferenceClick = (attribute: AttributeInput) =>
navigate(
productUrl(id, {
@ -424,6 +443,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
updateChannelsOpts.loading ||
updateVariantChannelsOpts.loading ||
productVariantCreateOpts.loading ||
deactivatePreoderOpts.loading ||
deleteAttributeValueOpts.loading ||
createProductMediaOpts.loading ||
loading;
@ -563,6 +583,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
onVariantShow={variantId => () =>
navigate(productVariantEditUrl(product.id, variantId))}
onVariantReorder={handleVariantReorder}
onVariantEndPreorderDialogOpen={() => setIsEndPreorderModalOpened(true)}
onImageUpload={handleImageUpload}
onImageEdit={handleImageEdit}
onImageDelete={handleImageDelete}
@ -647,6 +668,15 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
option === "multiple" ? handleVariantsAdd() : handleVariantAdd()
}
/>
{isSimpleProduct && !!product?.variants?.[0].preorder && (
<ProductVariantEndPreorderDialog
confirmButtonState={deactivatePreoderOpts.status}
onClose={() => setIsEndPreorderModalOpened(false)}
onConfirm={handleDeactivatePreorder}
open={isEndPreorderModalOpened}
variantGlobalSoldUnits={product.variants[0].preorder.globalSoldUnits}
/>
)}
</>
);
};

View file

@ -38,7 +38,9 @@ export const getSimpleProductVariables = (
sku: data.sku,
trackInventory: data.trackInventory,
preorder: {
globalThreshold: data.globalThreshold,
globalThreshold: data.globalThreshold
? parseInt(data.globalThreshold, 10)
: null,
endDate: data.preorderEndDateTime
}
},

View file

@ -205,7 +205,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
deactivatePreorder,
deactivatePreoderOpts
] = useProductVariantPreorderDeactivateMutation({});
const handleDeactivateVariantPreorder = async (id: string) =>
const handleDeactivateVariantPreorder = (id: string) =>
deactivatePreorder({ variables: { id } });
const [
@ -282,7 +282,9 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
trackInventory: data.trackInventory,
preorder: data.isPreorder
? {
globalThreshold: data.globalThreshold,
globalThreshold: data.globalThreshold
? parseInt(data.globalThreshold, 10)
: null,
endDate: data?.preorderEndDateTime || null
}
: null,

View file

@ -119,10 +119,14 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
})),
trackInventory: true,
weight: weight(formData.weight),
preorder: {
globalThreshold: formData.globalThreshold,
endDate: formData.preorderEndDateTime
}
preorder: formData.isPreorder
? {
globalThreshold: formData.globalThreshold
? parseInt(formData.globalThreshold, 10)
: null,
endDate: formData.preorderEndDateTime || null
}
: null
},
firstValues: 10
}

View file

@ -199117,7 +199117,7 @@ exports[`Storyshots Views / Products / Product edit form errors 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -199208,7 +199208,7 @@ exports[`Storyshots Views / Products / Product edit form errors 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -200878,7 +200878,7 @@ exports[`Storyshots Views / Products / Product edit limits reached 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -200969,7 +200969,7 @@ exports[`Storyshots Views / Products / Product edit limits reached 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -202584,7 +202584,7 @@ exports[`Storyshots Views / Products / Product edit no limits 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -202675,7 +202675,7 @@ exports[`Storyshots Views / Products / Product edit no limits 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -204032,7 +204032,7 @@ exports[`Storyshots Views / Products / Product edit no product attributes 1`] =
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -204123,7 +204123,7 @@ exports[`Storyshots Views / Products / Product edit no product attributes 1`] =
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -210478,7 +210478,7 @@ exports[`Storyshots Views / Products / Product edit when data is fully loaded 1`
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -210569,7 +210569,7 @@ exports[`Storyshots Views / Products / Product edit when data is fully loaded 1`
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -213164,7 +213164,7 @@ exports[`Storyshots Views / Products / Product edit when product has no images 1
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -213255,7 +213255,7 @@ exports[`Storyshots Views / Products / Product edit when product has no images 1
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -216450,7 +216450,7 @@ exports[`Storyshots Views / Products / Product edit with channels 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
3 available at 2 locations
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -216541,7 +216541,7 @@ exports[`Storyshots Views / Products / Product edit with channels 1`] = `
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colInventory-id"
data-test="inventory"
>
11 available at 1 location
In preorder
</td>
<td
class="MuiTableCell-root-id MuiTableCell-body-id ProductVariants-colActions-id"
@ -232546,8 +232546,8 @@ exports[`Storyshots Views / Products / Product variant details attribute errors
class="MuiFormControl-root-id MuiTextField-root-id ProductStocks-thresholdInput-id MuiFormControl-fullWidth-id"
>
<label
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-required-id MuiInputLabel-required-id"
data-shrink="false"
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id MuiFormLabel-filled-id MuiFormLabel-required-id MuiInputLabel-required-id"
data-shrink="true"
>
Global threshold
<span
@ -232567,14 +232567,14 @@ exports[`Storyshots Views / Products / Product variant details attribute errors
name="globalThreshold"
required=""
type="text"
value=""
value="0"
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-id MuiOutlinedInput-notchedOutline-id"
>
<legend
class="PrivateNotchedOutline-legendLabelled-id"
class="PrivateNotchedOutline-legendLabelled-id PrivateNotchedOutline-legendNotched-id"
>
<span>
Global threshold *
@ -232583,7 +232583,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors
</fieldset>
</div>
<p
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-required-id"
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-filled-id MuiFormHelperText-required-id"
>
Threshold that cannot be exceeded even if per channel thresholds are still available
</p>
@ -232591,7 +232591,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors
<div
class="MuiTypography-root-id ProductStocks-preorderItemsLeftCount-id MuiTypography-caption-id"
>
Unlimited
0 units left
</div>
</div>
</div>
@ -234418,8 +234418,8 @@ exports[`Storyshots Views / Products / Product variant details no warehouses 1`]
class="MuiFormControl-root-id MuiTextField-root-id ProductStocks-thresholdInput-id MuiFormControl-fullWidth-id"
>
<label
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-required-id MuiInputLabel-required-id"
data-shrink="false"
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id MuiFormLabel-filled-id MuiFormLabel-required-id MuiInputLabel-required-id"
data-shrink="true"
>
Global threshold
<span
@ -234439,14 +234439,14 @@ exports[`Storyshots Views / Products / Product variant details no warehouses 1`]
name="globalThreshold"
required=""
type="text"
value=""
value="0"
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-id MuiOutlinedInput-notchedOutline-id"
>
<legend
class="PrivateNotchedOutline-legendLabelled-id"
class="PrivateNotchedOutline-legendLabelled-id PrivateNotchedOutline-legendNotched-id"
>
<span>
Global threshold *
@ -234455,7 +234455,7 @@ exports[`Storyshots Views / Products / Product variant details no warehouses 1`]
</fieldset>
</div>
<p
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-required-id"
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-filled-id MuiFormHelperText-required-id"
>
Threshold that cannot be exceeded even if per channel thresholds are still available
</p>
@ -234463,7 +234463,7 @@ exports[`Storyshots Views / Products / Product variant details no warehouses 1`]
<div
class="MuiTypography-root-id ProductStocks-preorderItemsLeftCount-id MuiTypography-caption-id"
>
Unlimited
0 units left
</div>
</div>
</div>
@ -236290,8 +236290,8 @@ exports[`Storyshots Views / Products / Product variant details when loaded data
class="MuiFormControl-root-id MuiTextField-root-id ProductStocks-thresholdInput-id MuiFormControl-fullWidth-id"
>
<label
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-required-id MuiInputLabel-required-id"
data-shrink="false"
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id MuiFormLabel-filled-id MuiFormLabel-required-id MuiInputLabel-required-id"
data-shrink="true"
>
Global threshold
<span
@ -236311,14 +236311,14 @@ exports[`Storyshots Views / Products / Product variant details when loaded data
name="globalThreshold"
required=""
type="text"
value=""
value="0"
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-id MuiOutlinedInput-notchedOutline-id"
>
<legend
class="PrivateNotchedOutline-legendLabelled-id"
class="PrivateNotchedOutline-legendLabelled-id PrivateNotchedOutline-legendNotched-id"
>
<span>
Global threshold *
@ -236327,7 +236327,7 @@ exports[`Storyshots Views / Products / Product variant details when loaded data
</fieldset>
</div>
<p
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-required-id"
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-filled-id MuiFormHelperText-required-id"
>
Threshold that cannot be exceeded even if per channel thresholds are still available
</p>
@ -236335,7 +236335,7 @@ exports[`Storyshots Views / Products / Product variant details when loaded data
<div
class="MuiTypography-root-id ProductStocks-preorderItemsLeftCount-id MuiTypography-caption-id"
>
Unlimited
0 units left
</div>
</div>
</div>

View file

@ -69,6 +69,7 @@ const props: ProductUpdatePageProps = {
onVariantReorder: () => undefined,
onVariantShow: () => undefined,
onVariantsAdd: () => undefined,
onVariantEndPreorderDialogOpen: () => undefined,
onWarehouseConfigure: () => undefined,
openChannelsModal: () => undefined,
placeholderImage,