Support staff only voucher (#1174)

* Support staff only voucher

* Trigger CI

* Update messages

* Update changelog
This commit is contained in:
Dawid Tarasiuk 2021-06-21 11:02:17 +02:00 committed by GitHub
parent a0dce99b5d
commit 4056ac395b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 264 additions and 29 deletions

View file

@ -51,6 +51,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Paginate attribute values in filters - #1152 by @orzechdev - Paginate attribute values in filters - #1152 by @orzechdev
- Fix attribute values input display - #1156 by @orzechdev - Fix attribute values input display - #1156 by @orzechdev
- Fix product type translations - #1163 by @orzechdev - Fix product type translations - #1163 by @orzechdev
- Support staff only voucher - #1174 by @orzechdev
# 2.11.1 # 2.11.1

View file

@ -3019,21 +3019,26 @@
"context": "voucher code, button", "context": "voucher code, button",
"string": "Generate Code" "string": "Generate Code"
}, },
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_2215544659": { "src_dot_discounts_dot_components_dot_VoucherLimits_dot_applyOncePerCustomer": {
"string": "Limit number of times this discount can be used in total"
},
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_3459612469": {
"context": "limit voucher", "context": "limit voucher",
"string": "Limit to one use per customer" "string": "Limit to one use per customer"
}, },
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_3751756157": { "src_dot_discounts_dot_components_dot_VoucherLimits_dot_hasUsageLimit": {
"context": "limit voucher",
"string": "Limit number of times this discount can be used in total"
},
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_onlyForStaff": {
"context": "limit voucher",
"string": "Limit to staff only"
},
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_usageLimit": {
"context": "limit voucher",
"string": "Limit of Uses"
},
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_usageLimitsTitle": {
"context": "voucher usage limit, header", "context": "voucher usage limit, header",
"string": "Usage Limit" "string": "Usage Limit"
}, },
"src_dot_discounts_dot_components_dot_VoucherLimits_dot_557552777": {
"context": "voucher",
"string": "Limit of Uses"
},
"src_dot_discounts_dot_components_dot_VoucherListPage_dot_1112241061": { "src_dot_discounts_dot_components_dot_VoucherListPage_dot_1112241061": {
"context": "tab name", "context": "tab name",
"string": "All Vouchers" "string": "All Vouchers"

View file

@ -1914,6 +1914,7 @@ type ExportError {
} }
enum ExportErrorCode { enum ExportErrorCode {
GRAPHQL_ERROR
INVALID INVALID
NOT_FOUND NOT_FOUND
REQUIRED REQUIRED
@ -4106,7 +4107,7 @@ type Product implements Node & ObjectWithMetadata {
taxType: TaxType taxType: TaxType
attributes: [SelectedAttribute!]! attributes: [SelectedAttribute!]!
channelListings: [ProductChannelListing!] channelListings: [ProductChannelListing!]
mediaById(id: ID): ProductMedia! mediaById(id: ID): ProductMedia
imageById(id: ID): ProductImage @deprecated(reason: "Will be removed in Saleor 4.0. Use the `mediaById` field instead.") imageById(id: ID): ProductImage @deprecated(reason: "Will be removed in Saleor 4.0. Use the `mediaById` field instead.")
variants: [ProductVariant] variants: [ProductVariant]
media: [ProductMedia!] media: [ProductMedia!]
@ -5757,6 +5758,7 @@ type Voucher implements Node {
endDate: DateTime endDate: DateTime
applyOncePerOrder: Boolean! applyOncePerOrder: Boolean!
applyOncePerCustomer: Boolean! applyOncePerCustomer: Boolean!
onlyForStaff: Boolean!
discountValueType: DiscountValueTypeEnum! discountValueType: DiscountValueTypeEnum!
minCheckoutItemsQuantity: Int minCheckoutItemsQuantity: Int
categories(before: String, after: String, first: Int, last: Int): CategoryCountableConnection categories(before: String, after: String, first: Int, last: Int): CategoryCountableConnection
@ -5858,6 +5860,7 @@ input VoucherInput {
countries: [String] countries: [String]
applyOncePerOrder: Boolean applyOncePerOrder: Boolean
applyOncePerCustomer: Boolean applyOncePerCustomer: Boolean
onlyForStaff: Boolean
usageLimit: Int usageLimit: Int
} }

View file

@ -30,6 +30,7 @@ import VoucherValue from "../VoucherValue";
export interface FormData { export interface FormData {
applyOncePerCustomer: boolean; applyOncePerCustomer: boolean;
applyOncePerOrder: boolean; applyOncePerOrder: boolean;
onlyForStaff: boolean;
channelListings: ChannelVoucherData[]; channelListings: ChannelVoucherData[];
code: string; code: string;
discountType: DiscountTypeEnum; discountType: DiscountTypeEnum;
@ -76,6 +77,7 @@ const VoucherCreatePage: React.FC<VoucherCreatePageProps> = ({
const initialForm: FormData = { const initialForm: FormData = {
applyOncePerCustomer: false, applyOncePerCustomer: false,
applyOncePerOrder: false, applyOncePerOrder: false,
onlyForStaff: false,
channelListings, channelListings,
code: "", code: "",
discountType: DiscountTypeEnum.VALUE_FIXED, discountType: DiscountTypeEnum.VALUE_FIXED,

View file

@ -58,6 +58,7 @@ export function voucherDetailsPageTab(tab: string): VoucherDetailsPageTab {
export interface VoucherDetailsPageFormData { export interface VoucherDetailsPageFormData {
applyOncePerCustomer: boolean; applyOncePerCustomer: boolean;
applyOncePerOrder: boolean; applyOncePerOrder: boolean;
onlyForStaff: boolean;
channelListings: ChannelVoucherData[]; channelListings: ChannelVoucherData[];
code: string; code: string;
discountType: DiscountTypeEnum; discountType: DiscountTypeEnum;
@ -170,6 +171,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
const initialForm: VoucherDetailsPageFormData = { const initialForm: VoucherDetailsPageFormData = {
applyOncePerCustomer: voucher?.applyOncePerCustomer || false, applyOncePerCustomer: voucher?.applyOncePerCustomer || false,
applyOncePerOrder: voucher?.applyOncePerOrder || false, applyOncePerOrder: voucher?.applyOncePerOrder || false,
onlyForStaff: voucher?.onlyForStaff || false,
channelListings, channelListings,
code: voucher?.code || "", code: voucher?.code || "",
discountType, discountType,

View file

@ -8,6 +8,7 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { VoucherDetailsPageFormData } from "../VoucherDetailsPage"; import { VoucherDetailsPageFormData } from "../VoucherDetailsPage";
import messages from "./messages";
interface VoucherLimitsProps { interface VoucherLimitsProps {
data: VoucherDetailsPageFormData; data: VoucherDetailsPageFormData;
@ -28,19 +29,11 @@ const VoucherLimits = ({
return ( return (
<Card> <Card>
<CardTitle <CardTitle title={intl.formatMessage(messages.usageLimitsTitle)} />
title={intl.formatMessage({
defaultMessage: "Usage Limit",
description: "voucher usage limit, header"
})}
/>
<CardContent> <CardContent>
<ControlledCheckbox <ControlledCheckbox
checked={data.hasUsageLimit} checked={data.hasUsageLimit}
label={intl.formatMessage({ label={intl.formatMessage(messages.hasUsageLimit)}
defaultMessage:
"Limit number of times this discount can be used in total"
})}
name={"hasUsageLimit" as keyof VoucherDetailsPageFormData} name={"hasUsageLimit" as keyof VoucherDetailsPageFormData}
onChange={onChange} onChange={onChange}
/> />
@ -49,10 +42,7 @@ const VoucherLimits = ({
disabled={disabled} disabled={disabled}
error={!!formErrors.usageLimit} error={!!formErrors.usageLimit}
helperText={getDiscountErrorMessage(formErrors.usageLimit, intl)} helperText={getDiscountErrorMessage(formErrors.usageLimit, intl)}
label={intl.formatMessage({ label={intl.formatMessage(messages.usageLimit)}
defaultMessage: "Limit of Uses",
description: "voucher"
})}
name={"usageLimit" as keyof VoucherDetailsPageFormData} name={"usageLimit" as keyof VoucherDetailsPageFormData}
value={data.usageLimit} value={data.usageLimit}
onChange={onChange} onChange={onChange}
@ -65,13 +55,16 @@ const VoucherLimits = ({
)} )}
<ControlledCheckbox <ControlledCheckbox
checked={data.applyOncePerCustomer} checked={data.applyOncePerCustomer}
label={intl.formatMessage({ label={intl.formatMessage(messages.applyOncePerCustomer)}
defaultMessage: "Limit to one use per customer",
description: "limit voucher"
})}
name={"applyOncePerCustomer" as keyof VoucherDetailsPageFormData} name={"applyOncePerCustomer" as keyof VoucherDetailsPageFormData}
onChange={onChange} onChange={onChange}
/> />
<ControlledCheckbox
checked={data.onlyForStaff}
label={intl.formatMessage(messages.onlyForStaff)}
name={"onlyForStaff" as keyof VoucherDetailsPageFormData}
onChange={onChange}
/>
</CardContent> </CardContent>
</Card> </Card>
); );

View file

@ -0,0 +1,24 @@
import { defineMessages } from "react-intl";
export default defineMessages({
usageLimitsTitle: {
defaultMessage: "Usage Limit",
description: "voucher usage limit, header"
},
hasUsageLimit: {
defaultMessage: "Limit number of times this discount can be used in total",
description: "limit voucher"
},
usageLimit: {
defaultMessage: "Limit of Uses",
description: "limit voucher"
},
applyOncePerCustomer: {
defaultMessage: "Limit to one use per customer",
description: "limit voucher"
},
onlyForStaff: {
defaultMessage: "Limit to staff only",
description: "limit voucher"
}
});

View file

@ -416,6 +416,7 @@ export const voucherDetails: VoucherDetails_voucher = {
__typename: "Voucher", __typename: "Voucher",
applyOncePerCustomer: false, applyOncePerCustomer: false,
applyOncePerOrder: false, applyOncePerOrder: false,
onlyForStaff: false,
categories: { categories: {
__typename: "CategoryCountableConnection", __typename: "CategoryCountableConnection",
edges: [], edges: [],

View file

@ -180,6 +180,7 @@ export interface VoucherCataloguesAdd_voucherCataloguesAdd_voucher {
used: number; used: number;
applyOncePerOrder: boolean; applyOncePerOrder: boolean;
applyOncePerCustomer: boolean; applyOncePerCustomer: boolean;
onlyForStaff: boolean;
products: VoucherCataloguesAdd_voucherCataloguesAdd_voucher_products | null; products: VoucherCataloguesAdd_voucherCataloguesAdd_voucher_products | null;
collections: VoucherCataloguesAdd_voucherCataloguesAdd_voucher_collections | null; collections: VoucherCataloguesAdd_voucherCataloguesAdd_voucher_collections | null;
categories: VoucherCataloguesAdd_voucherCataloguesAdd_voucher_categories | null; categories: VoucherCataloguesAdd_voucherCataloguesAdd_voucher_categories | null;

View file

@ -180,6 +180,7 @@ export interface VoucherCataloguesRemove_voucherCataloguesRemove_voucher {
used: number; used: number;
applyOncePerOrder: boolean; applyOncePerOrder: boolean;
applyOncePerCustomer: boolean; applyOncePerCustomer: boolean;
onlyForStaff: boolean;
products: VoucherCataloguesRemove_voucherCataloguesRemove_voucher_products | null; products: VoucherCataloguesRemove_voucherCataloguesRemove_voucher_products | null;
collections: VoucherCataloguesRemove_voucherCataloguesRemove_voucher_collections | null; collections: VoucherCataloguesRemove_voucherCataloguesRemove_voucher_collections | null;
categories: VoucherCataloguesRemove_voucherCataloguesRemove_voucher_categories | null; categories: VoucherCataloguesRemove_voucherCataloguesRemove_voucher_categories | null;

View file

@ -173,6 +173,7 @@ export interface VoucherDetails_voucher {
used: number; used: number;
applyOncePerOrder: boolean; applyOncePerOrder: boolean;
applyOncePerCustomer: boolean; applyOncePerCustomer: boolean;
onlyForStaff: boolean;
products: VoucherDetails_voucher_products | null; products: VoucherDetails_voucher_products | null;
collections: VoucherDetails_voucher_collections | null; collections: VoucherDetails_voucher_collections | null;
categories: VoucherDetails_voucher_categories | null; categories: VoucherDetails_voucher_categories | null;

View file

@ -29,6 +29,7 @@ export function createHandler(
input: { input: {
applyOncePerCustomer: formData.applyOncePerCustomer, applyOncePerCustomer: formData.applyOncePerCustomer,
applyOncePerOrder: formData.applyOncePerOrder, applyOncePerOrder: formData.applyOncePerOrder,
onlyForStaff: formData.onlyForStaff,
code: formData.code, code: formData.code,
discountValueType: discountValueType:
formData.discountType === DiscountTypeEnum.VALUE_PERCENTAGE formData.discountType === DiscountTypeEnum.VALUE_PERCENTAGE

View file

@ -35,6 +35,7 @@ export function createUpdateHandler(
input: { input: {
applyOncePerCustomer: formData.applyOncePerCustomer, applyOncePerCustomer: formData.applyOncePerCustomer,
applyOncePerOrder: formData.applyOncePerOrder, applyOncePerOrder: formData.applyOncePerOrder,
onlyForStaff: formData.onlyForStaff,
discountValueType: discountValueType:
formData.discountType === DiscountTypeEnum.VALUE_PERCENTAGE formData.discountType === DiscountTypeEnum.VALUE_PERCENTAGE
? DiscountValueTypeEnum.PERCENTAGE ? DiscountValueTypeEnum.PERCENTAGE

View file

@ -126,6 +126,7 @@ export const voucherDetailsFragment = gql`
used used
applyOncePerOrder applyOncePerOrder
applyOncePerCustomer applyOncePerCustomer
onlyForStaff
products(after: $after, before: $before, first: $first, last: $last) { products(after: $after, before: $before, first: $first, last: $last) {
edges { edges {
node { node {

View file

@ -173,6 +173,7 @@ export interface VoucherDetailsFragment {
used: number; used: number;
applyOncePerOrder: boolean; applyOncePerOrder: boolean;
applyOncePerCustomer: boolean; applyOncePerCustomer: boolean;
onlyForStaff: boolean;
products: VoucherDetailsFragment_products | null; products: VoucherDetailsFragment_products | null;
collections: VoucherDetailsFragment_collections | null; collections: VoucherDetailsFragment_collections | null;
categories: VoucherDetailsFragment_categories | null; categories: VoucherDetailsFragment_categories | null;

View file

@ -31,7 +31,7 @@ export interface ProductMediaById_product {
__typename: "Product"; __typename: "Product";
id: string; id: string;
name: string; name: string;
mainImage: ProductMediaById_product_mainImage; mainImage: ProductMediaById_product_mainImage | null;
media: ProductMediaById_product_media[] | null; media: ProductMediaById_product_media[] | null;
} }

View file

@ -95798,6 +95798,45 @@ exports[`Storyshots Views / Discounts / Voucher create default 1`] = `
Limit to one use per customer Limit to one use per customer
</span> </span>
</label> </label>
<label
class="MuiFormControlLabel-root-id"
>
<span
aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id MuiIconButton-colorPrimary-id"
>
<span
class="MuiIconButton-label-id"
>
<input
class="PrivateSwitchBase-input-id"
data-indeterminate="false"
name="onlyForStaff"
type="checkbox"
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root-id"
focusable="false"
viewBox="0 0 24 24"
>
<rect
fill="none"
height="14"
stroke="currentColor"
width="14"
x="5"
y="5"
/>
</svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Limit to staff only
</span>
</label>
</div> </div>
</div> </div>
<div <div
@ -97225,6 +97264,45 @@ exports[`Storyshots Views / Discounts / Voucher create form errors 1`] = `
Limit to one use per customer Limit to one use per customer
</span> </span>
</label> </label>
<label
class="MuiFormControlLabel-root-id"
>
<span
aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id MuiIconButton-colorPrimary-id"
>
<span
class="MuiIconButton-label-id"
>
<input
class="PrivateSwitchBase-input-id"
data-indeterminate="false"
name="onlyForStaff"
type="checkbox"
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root-id"
focusable="false"
viewBox="0 0 24 24"
>
<rect
fill="none"
height="14"
stroke="currentColor"
width="14"
x="5"
y="5"
/>
</svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Limit to staff only
</span>
</label>
</div> </div>
</div> </div>
<div <div
@ -99285,6 +99363,45 @@ exports[`Storyshots Views / Discounts / Voucher details default 1`] = `
Limit to one use per customer Limit to one use per customer
</span> </span>
</label> </label>
<label
class="MuiFormControlLabel-root-id"
>
<span
aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id MuiIconButton-colorPrimary-id"
>
<span
class="MuiIconButton-label-id"
>
<input
class="PrivateSwitchBase-input-id"
data-indeterminate="false"
name="onlyForStaff"
type="checkbox"
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root-id"
focusable="false"
viewBox="0 0 24 24"
>
<rect
fill="none"
height="14"
stroke="currentColor"
width="14"
x="5"
y="5"
/>
</svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Limit to staff only
</span>
</label>
</div> </div>
</div> </div>
<div <div
@ -101495,6 +101612,45 @@ exports[`Storyshots Views / Discounts / Voucher details form errors 1`] = `
Limit to one use per customer Limit to one use per customer
</span> </span>
</label> </label>
<label
class="MuiFormControlLabel-root-id"
>
<span
aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id MuiIconButton-colorPrimary-id"
>
<span
class="MuiIconButton-label-id"
>
<input
class="PrivateSwitchBase-input-id"
data-indeterminate="false"
name="onlyForStaff"
type="checkbox"
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root-id"
focusable="false"
viewBox="0 0 24 24"
>
<rect
fill="none"
height="14"
stroke="currentColor"
width="14"
x="5"
y="5"
/>
</svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Limit to staff only
</span>
</label>
</div> </div>
</div> </div>
<div <div
@ -103268,6 +103424,45 @@ exports[`Storyshots Views / Discounts / Voucher details loading 1`] = `
Limit to one use per customer Limit to one use per customer
</span> </span>
</label> </label>
<label
class="MuiFormControlLabel-root-id"
>
<span
aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id MuiIconButton-colorPrimary-id"
>
<span
class="MuiIconButton-label-id"
>
<input
class="PrivateSwitchBase-input-id"
data-indeterminate="false"
name="onlyForStaff"
type="checkbox"
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root-id"
focusable="false"
viewBox="0 0 24 24"
>
<rect
fill="none"
height="14"
stroke="currentColor"
width="14"
x="5"
y="5"
/>
</svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Limit to staff only
</span>
</label>
</div> </div>
</div> </div>
<div <div

View file

@ -440,6 +440,7 @@ export enum DiscountValueTypeEnum {
} }
export enum ExportErrorCode { export enum ExportErrorCode {
GRAPHQL_ERROR = "GRAPHQL_ERROR",
INVALID = "INVALID", INVALID = "INVALID",
NOT_FOUND = "NOT_FOUND", NOT_FOUND = "NOT_FOUND",
REQUIRED = "REQUIRED", REQUIRED = "REQUIRED",
@ -1978,6 +1979,7 @@ export interface VoucherInput {
countries?: (string | null)[] | null; countries?: (string | null)[] | null;
applyOncePerOrder?: boolean | null; applyOncePerOrder?: boolean | null;
applyOncePerCustomer?: boolean | null; applyOncePerCustomer?: boolean | null;
onlyForStaff?: boolean | null;
usageLimit?: number | null; usageLimit?: number | null;
} }