Skip to content

Commit

Permalink
feat: allow modifier quantity
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinlee11 committed Apr 4, 2024
1 parent fc181ee commit 2beb1bb
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 14 deletions.
29 changes: 24 additions & 5 deletions src/helpers/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,18 @@ export class Item {
let selectedValueCount = (<TextModifier>selectedModifier)?.textEntry?.length || 0;
if ((<ChoiceModifier>selectedModifier)?.choiceSelections?.length) {
// Invalid or sold out choices
const invalidChoice = (<ChoiceModifier>selectedModifier).choiceSelections.find(s => !modifierList.modifiers?.find(m => m.id === s));
const soldOutChoice = (<ChoiceModifier>selectedModifier).choiceSelections.find(s => modifierList.modifiers?.find(m => m.id === s)?.sold_out);
const invalidChoice = (<ChoiceModifier>selectedModifier).choiceSelections.find(s => !modifierList.modifiers?.find(m => {
if (typeof s === 'object') {
return m.id === s.id;
}
return m.id === s;
}));
const soldOutChoice = (<ChoiceModifier>selectedModifier).choiceSelections.find(s => modifierList.modifiers?.find(m => {
if (typeof s === 'object') {
return m.id === s.id;
}
return m.id === s;
})?.sold_out);
if (invalidChoice || soldOutChoice) {
return false;
}
Expand Down Expand Up @@ -322,9 +332,18 @@ export class Item {
const matchingModifierList = item.modifier_lists?.find(l => l.id === selectedModifier.id);
if (matchingModifierList) {
matchingModifierList.modifiers?.forEach(m => {
if (selectedModifier.choiceSelections.includes(m.id) && m.price_money) {
regularPrice += m.price_money.amount;
salePrice += m.price_money.amount;
let quantity = 1;
if (selectedModifier.choiceSelections.find(s => {
if (typeof s === 'object') {
if (m.id === s.id) {
quantity = s.quantity;
return true;
}
}
return m.id === s;
}) && m.price_money) {
regularPrice += m.price_money.amount * quantity;
salePrice += m.price_money.amount * quantity;
}
});
}
Expand Down
13 changes: 10 additions & 3 deletions src/types/api/cart/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export interface ChoiceModifier extends BaseModifier {
/** The modifier type. */
type: 'CHOICE';
/** Choice selections for modifier. */
choiceSelections: string[];
choiceSelections: Choice[];
}

export interface TextModifier extends BaseModifier {
Expand All @@ -106,7 +106,14 @@ export interface GiftWrapModifier extends BaseModifier {
/** The modifier type. */
type: 'GIFT_WRAP';
/** Choice selections for modifier. */
choiceSelections: string[];
choiceSelections: Choice[];
}

export type Choice = string | ChoiceSelection;

export interface ChoiceSelection {
id: string;
quantity: number;
}

export interface GiftMessageModifier extends BaseModifier {
Expand Down Expand Up @@ -387,4 +394,4 @@ export interface CartValidation {
export interface CartResponse extends CartBaseResponse {
/** The response from the Fetch API. */
response: Response;
}
}
91 changes: 87 additions & 4 deletions test/helpers.item.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ function createModifierSelection({
excludeText = false,
choiceSelectionsCount = 2,
textSelectionCount = 2,
invalidChoice = false
invalidChoice = false,
useChoiceSelectionObject = false,
useMultipleChoiceSelectionQuantity = false,
}: {
excludeGiftWrap?: boolean;
excludeChoice?: boolean;
Expand All @@ -429,13 +431,17 @@ function createModifierSelection({
choiceSelectionsCount?: number;
textSelectionCount?: number;
invalidChoice?: boolean;
useChoiceSelectionObject?: boolean;
useMultipleChoiceSelectionQuantity?: boolean;
}) {
const selectedModifiers: AddItemModifier[] = [];
if (!excludeGiftWrap) {
selectedModifiers.push({
id: 'modifierListGiftWrapId',
type: ModifierType.GIFT_WRAP,
choiceSelections: [
choiceSelections: useChoiceSelectionObject ? [
{ id: 'modifierGiftWrapId1', quantity: 1 }
] : [
'modifierGiftWrapId1'
]
});
Expand All @@ -444,7 +450,10 @@ function createModifierSelection({
const choiceModifier = {
id: 'modifierListChoiceId',
type: ModifierType.CHOICE,
choiceSelections: [
choiceSelections: useChoiceSelectionObject ? [
invalidChoice ? { id: 'invalidChoiceId1', quantity: 1 } : { id: 'modifierChoiceId1', quantity: useMultipleChoiceSelectionQuantity ? 2 : 1 },
{ id: 'modifierChoiceId2', quantity: 1 },
]: [
invalidChoice ? 'invalidChoiceId1' : 'modifierChoiceId1',
'modifierChoiceId2',
]
Expand All @@ -454,7 +463,8 @@ function createModifierSelection({
} else if (choiceSelectionsCount === 0) {
choiceModifier.choiceSelections = [];
} else if (choiceSelectionsCount === 3) {
choiceModifier.choiceSelections.push('modifierChoiceId3');
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
(<any>choiceModifier.choiceSelections).push(useChoiceSelectionObject ? { id: 'modifierChoiceId3', quantity: 1 } : 'modifierChoiceId3');
}
selectedModifiers.push(choiceModifier);
}
Expand Down Expand Up @@ -772,6 +782,19 @@ describe('Modifier list valid', () => {
expect(result4).toStrictEqual(true);
});

it('should return valid for all with valid modifiers selections using ChoiceSelection', () => {
const modifierSelections = createModifierSelection({useChoiceSelectionObject: true});

const result = sdk.helpers.item.isModifierListForSelectedModifiersValid(defaultItem.modifier_lists![0], modifierSelections);
expect(result).toStrictEqual(true);
const result2 = sdk.helpers.item.isModifierListForSelectedModifiersValid(defaultItem.modifier_lists![1], modifierSelections);
expect(result2).toStrictEqual(true);
const result3 = sdk.helpers.item.isModifierListForSelectedModifiersValid(defaultItem.modifier_lists![2], modifierSelections);
expect(result3).toStrictEqual(true);
const result4 = sdk.helpers.item.isModifierListForSelectedModifiersValid(defaultItem.modifier_lists![3], modifierSelections);
expect(result4).toStrictEqual(true);
});

it('should return false for invalid choice modifier selections', () => {
const modifierSelections = createModifierSelection({ invalidChoice: true });
const result = sdk.helpers.item.isModifierListForSelectedModifiersValid(defaultItem.modifier_lists![1], modifierSelections);
Expand All @@ -782,6 +805,16 @@ describe('Modifier list valid', () => {
expect(result2).toStrictEqual(false);
});

it('should return false for invalid choice modifier selections using ChoiceSelection', () => {
const modifierSelections = createModifierSelection({ invalidChoice: true, useChoiceSelectionObject: true });
const result = sdk.helpers.item.isModifierListForSelectedModifiersValid(defaultItem.modifier_lists![1], modifierSelections);
expect(result).toStrictEqual(false);
const modifierSelections2 = createModifierSelection({ choiceSelectionsCount: 1, useChoiceSelectionObject: true });
const zeroChoiceModifiersItem = createTestItem({ zeroChoiceModifiers: true });
const result2 = sdk.helpers.item.isModifierListForSelectedModifiersValid(zeroChoiceModifiersItem.modifier_lists![1], modifierSelections2);
expect(result2).toStrictEqual(false);
});

it('should return false for sold out choice modifier selections', () => {
const soldOutChoiceModifiersItem = createTestItem({ soldOutChoiceModifier: true });
const modifierSelections = createModifierSelection({ choiceSelectionsCount: 1 });
Expand All @@ -792,6 +825,16 @@ describe('Modifier list valid', () => {
expect(result2).toStrictEqual(false);
});

it('should return false for sold out choice modifier selections using ChoiceSelection', () => {
const soldOutChoiceModifiersItem = createTestItem({ soldOutChoiceModifier: true});
const modifierSelections = createModifierSelection({ choiceSelectionsCount: 1, useChoiceSelectionObject: true });
const result = sdk.helpers.item.isModifierListForSelectedModifiersValid(soldOutChoiceModifiersItem.modifier_lists![1], modifierSelections);
expect(result).toStrictEqual(true);
const modifierSelections2 = createModifierSelection({ useChoiceSelectionObject: true });
const result2 = sdk.helpers.item.isModifierListForSelectedModifiersValid(soldOutChoiceModifiersItem.modifier_lists![1], modifierSelections2);
expect(result2).toStrictEqual(false);
});

it('should verify choice modifier with same min/max 0', () => {
const sameChoiceMinMaxItem = createTestItem({ choiceModifierMin: 0, choiceModifierMax: 0 });

Expand Down Expand Up @@ -1406,6 +1449,25 @@ describe('Validate item', () => {
]);
}
});

it('should throw invalid or missing modifiers using ChoiceSelection', () => {
const singleVariationItem = createTestItem({ variationType: 'single' });
const invalidChoiceModifiers = createModifierSelection({ choiceSelectionsCount: 3, useChoiceSelectionObject: true });
const validateItemFn = () => sdk.helpers.item.validateItem({ item: singleVariationItem, selectedModifiers: invalidChoiceModifiers });
expect(validateItemFn).toThrowError();
try {
validateItemFn();
} catch (ex) {
expect((<ValidateItemError>ex).itemOptionIds).toBeUndefined();
expect((<ValidateItemError>ex).flatVariationSelectionMissing).toBeUndefined();
expect((<ValidateItemError>ex).variationId).toBeUndefined();
expect((<ValidateItemError>ex).modifierListIds).toStrictEqual([singleVariationItem.modifier_lists![1].id]);
}
const singleVariationItem2 = createTestItem({ variationType: 'single', choiceModifierMin: 1, choiceModifierMax: 1 });
const missingChoiceModifiers = createModifierSelection({ choiceSelectionsCount: 0, useChoiceSelectionObject: true });
const validateItemFn2 = () => sdk.helpers.item.validateItem({ item: singleVariationItem2, selectedModifiers: missingChoiceModifiers });
expect(validateItemFn2).toThrowError();
});
});

describe('Get item price', () => {
Expand Down Expand Up @@ -1482,6 +1544,27 @@ describe('Get item price', () => {
});
});

it('should return price on modifiers using ChoiceSelection', () => {
const singleVariationItem = createTestItem({ variationType: 'single' });
const modifierSelections = createModifierSelection({ useChoiceSelectionObject: true, useMultipleChoiceSelectionQuantity: true });
const modifierCost = singleVariationItem.modifier_lists![0].modifiers![0].price_money.amount
+ (singleVariationItem.modifier_lists![1].modifiers![0].price_money.amount * 2)
+ singleVariationItem.modifier_lists![1].modifiers![1].price_money.amount;
const result = sdk.helpers.item.getItemPrice({ item: singleVariationItem, selectedModifiers: modifierSelections });
expect(result).toStrictEqual({
regular: {
amount: singleVariationItem.variations[0].price.regular.amount + modifierCost,
formatted: '',
currency: singleVariationItem.variations[0].price.regular.currency
},
sale: {
amount: singleVariationItem.variations[0].price.sale.amount + modifierCost,
formatted: '',
currency: singleVariationItem.variations[0].price.sale.currency
}
});
});

it('should return price on flat variation', () => {
const flatItem = createTestItem({ variationType: 'flat' });
const selectedVariationId = flatItem.variations[3].id;
Expand Down
2 changes: 1 addition & 1 deletion typedocs/interfaces/types_api_cart.ChoiceModifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ ___

### choiceSelections

**choiceSelections**: `string`[]
**choiceSelections**: [`Choice`](../modules/types_api_cart.md#choice)[]

Choice selections for modifier.
24 changes: 24 additions & 0 deletions typedocs/interfaces/types_api_cart.ChoiceSelection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[@square/site-theme-sdk](../GettingStarted.md) / [Modules](../modules.md) / [types/api/cart](../modules/types_api_cart.md) / ChoiceSelection

# Interface: ChoiceSelection

[types/api/cart](../modules/types_api_cart.md).ChoiceSelection

## Table of contents

### Properties

- [id](types_api_cart.ChoiceSelection.md#id)
- [quantity](types_api_cart.ChoiceSelection.md#quantity)

## Properties

### id

**id**: `string`

___

### quantity

**quantity**: `number`
2 changes: 1 addition & 1 deletion typedocs/interfaces/types_api_cart.GiftWrapModifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ ___

### choiceSelections

**choiceSelections**: `string`[]
**choiceSelections**: [`Choice`](../modules/types_api_cart.md#choice)[]

Choice selections for modifier.
8 changes: 8 additions & 0 deletions typedocs/modules/types_api_cart.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [ChoiceModifier](../interfaces/types_api_cart.ChoiceModifier.md)
- [TextModifier](../interfaces/types_api_cart.TextModifier.md)
- [GiftWrapModifier](../interfaces/types_api_cart.GiftWrapModifier.md)
- [ChoiceSelection](../interfaces/types_api_cart.ChoiceSelection.md)
- [GiftMessageModifier](../interfaces/types_api_cart.GiftMessageModifier.md)
- [AddLineItem](../interfaces/types_api_cart.AddLineItem.md)
- [BuyNowSubscriptionLineItem](../interfaces/types_api_cart.BuyNowSubscriptionLineItem.md)
Expand All @@ -34,6 +35,7 @@
- [ScheduleTypeEnum](types_api_cart.md#scheduletypeenum)
- [ModifierTypeEnum](types_api_cart.md#modifiertypeenum)
- [CurrencyTypeEnum](types_api_cart.md#currencytypeenum)
- [Choice](types_api_cart.md#choice)
- [AddItemModifier](types_api_cart.md#additemmodifier)
- [BuyNowSubscriptionItemModifier](types_api_cart.md#buynowsubscriptionitemmodifier)

Expand Down Expand Up @@ -70,6 +72,12 @@ ___

___

### Choice

Ƭ **Choice**: `string` \| [`ChoiceSelection`](../interfaces/types_api_cart.ChoiceSelection.md)

___

### AddItemModifier

Ƭ **AddItemModifier**: [`ChoiceModifier`](../interfaces/types_api_cart.ChoiceModifier.md) \| [`TextModifier`](../interfaces/types_api_cart.TextModifier.md) \| [`GiftWrapModifier`](../interfaces/types_api_cart.GiftWrapModifier.md) \| [`GiftMessageModifier`](../interfaces/types_api_cart.GiftMessageModifier.md)
Expand Down

0 comments on commit 2beb1bb

Please sign in to comment.