@faststore/api 1.10.19 → 1.10.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/__generated__/schema.d.ts +94 -0
- package/dist/api.cjs.development.js +196 -9
- package/dist/api.cjs.development.js.map +1 -1
- package/dist/api.cjs.production.min.js +1 -1
- package/dist/api.cjs.production.min.js.map +1 -1
- package/dist/api.esm.js +196 -9
- package/dist/api.esm.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/platforms/vtex/index.d.ts +5 -0
- package/dist/platforms/vtex/resolvers/skuVariations.d.ts +6 -0
- package/dist/platforms/vtex/utils/skuVariants.d.ts +15 -0
- package/package.json +3 -3
- package/src/__generated__/schema.ts +99 -0
- package/src/platforms/vtex/index.ts +2 -0
- package/src/platforms/vtex/resolvers/collection.ts +4 -1
- package/src/platforms/vtex/resolvers/productGroup.ts +4 -3
- package/src/platforms/vtex/resolvers/skuVariations.ts +47 -0
- package/src/platforms/vtex/utils/skuVariants.ts +206 -0
- package/src/typeDefs/index.ts +3 -1
- package/src/typeDefs/productGroup.graphql +6 -0
- package/src/typeDefs/skuVariants.graphql +87 -0
package/dist/index.d.ts
CHANGED
|
@@ -71,6 +71,11 @@ export declare const getResolvers: (options: Options) => {
|
|
|
71
71
|
}, unknown, any>>;
|
|
72
72
|
StoreSearchResult: Record<string, import("./platforms/vtex").Resolver<Pick<import("./platforms/vtex/clients/search").SearchArgs, "sort" | "selectedFacets" | "hideUnavailableItems" | "query" | "page" | "count" | "fuzzy">, unknown, any>>;
|
|
73
73
|
StorePropertyValue: Record<string, import("./platforms/vtex").Resolver<import("./__generated__/schema").IStorePropertyValue, unknown, any>>;
|
|
74
|
+
SkuVariants: Record<string, import("./platforms/vtex").Resolver<import("./platforms/vtex/clients/search/types/ProductSearchResult").Item & {
|
|
75
|
+
isVariantOf: import("./platforms/vtex/clients/search/types/ProductSearchResult").Product;
|
|
76
|
+
} & {
|
|
77
|
+
attachmentsValues?: import("./platforms/vtex/clients/commerce/types/OrderForm").Attachment[] | undefined;
|
|
78
|
+
}, unknown, any>>;
|
|
74
79
|
ObjectOrString: import("graphql").GraphQLScalarType;
|
|
75
80
|
Query: {
|
|
76
81
|
product: (_: unknown, { locator }: import("./__generated__/schema").QueryProductArgs, ctx: import("./platforms/vtex").Context) => Promise<import("./platforms/vtex/utils/enhanceSku").EnhancedSku>;
|
|
@@ -101,6 +101,11 @@ export declare const getResolvers: (_: Options) => {
|
|
|
101
101
|
}, unknown, any>>;
|
|
102
102
|
StoreSearchResult: Record<string, Resolver<Pick<SearchArgs, "hideUnavailableItems" | "query" | "page" | "count" | "sort" | "selectedFacets" | "fuzzy">, unknown, any>>;
|
|
103
103
|
StorePropertyValue: Record<string, Resolver<import("../..").IStorePropertyValue, unknown, any>>;
|
|
104
|
+
SkuVariants: Record<string, Resolver<import("./clients/search/types/ProductSearchResult").Item & {
|
|
105
|
+
isVariantOf: import("./clients/search/types/ProductSearchResult").Product;
|
|
106
|
+
} & {
|
|
107
|
+
attachmentsValues?: import("./clients/commerce/types/OrderForm").Attachment[] | undefined;
|
|
108
|
+
}, unknown, any>>;
|
|
104
109
|
ObjectOrString: import("graphql").GraphQLScalarType;
|
|
105
110
|
Query: {
|
|
106
111
|
product: (_: unknown, { locator }: import("../..").QueryProductArgs, ctx: Context) => Promise<import("./utils/enhanceSku").EnhancedSku>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Resolver } from '..';
|
|
2
|
+
import type { PromiseType } from '../../../typings';
|
|
3
|
+
import type { StoreProduct } from './product';
|
|
4
|
+
declare type Root = PromiseType<ReturnType<typeof StoreProduct.isVariantOf>>;
|
|
5
|
+
export declare const SkuVariants: Record<string, Resolver<Root>>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StoreProduct as StoreProductType } from '../../..';
|
|
2
|
+
import type { Product, Item } from '../clients/search/types/ProductSearchResult';
|
|
3
|
+
export declare type SkuVariants = StoreProductType[];
|
|
4
|
+
export declare type SkuVariantsByName = Record<string, Array<FormattedSkuVariant>>;
|
|
5
|
+
declare type FormattedSkuVariant = {
|
|
6
|
+
alt: string;
|
|
7
|
+
src: string;
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function createSlugsMap(variants: Item[], dominantVariantName: string, baseSlug: string): Record<string, string>;
|
|
12
|
+
export declare function getActiveSkuVariations(variations: Item['variations']): Record<string, string>;
|
|
13
|
+
export declare function getVariantsByName(skuSpecifications: Product['skuSpecifications']): Record<string, string[]>;
|
|
14
|
+
export declare function getFormattedVariations(variants: Item[], dominantVariantName: string, dominantVariantValue: string): Record<string, FormattedSkuVariant[]>;
|
|
15
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/api",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.34",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"express-graphql": "^0.12.0",
|
|
38
38
|
"graphql": "^15.6.0",
|
|
39
39
|
"jest-transform-graphql": "^2.1.0",
|
|
40
|
-
"shared": "^1.10.
|
|
40
|
+
"shared": "^1.10.34",
|
|
41
41
|
"ts-jest": "25.5.1",
|
|
42
42
|
"tsdx": "^0.14.1",
|
|
43
43
|
"tslib": "^2.3.1",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"graphql": "^15.6.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "5d59e28c724e389b596e2bb13b1464314eab275f"
|
|
50
50
|
}
|
|
@@ -9,7 +9,69 @@ export type Scalars = {
|
|
|
9
9
|
Boolean: boolean;
|
|
10
10
|
Int: number;
|
|
11
11
|
Float: number;
|
|
12
|
+
/**
|
|
13
|
+
* Example:
|
|
14
|
+
*
|
|
15
|
+
* ```json
|
|
16
|
+
* {
|
|
17
|
+
* Color: 'Red', Size: '42'
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
ActiveVariations: any;
|
|
22
|
+
/**
|
|
23
|
+
* Example:
|
|
24
|
+
*
|
|
25
|
+
* ```json
|
|
26
|
+
* {
|
|
27
|
+
* Color: [
|
|
28
|
+
* {
|
|
29
|
+
* src: "https://storecomponents.vtexassets.com/...",
|
|
30
|
+
* alt: "...",
|
|
31
|
+
* label: "...",
|
|
32
|
+
* value: "..."
|
|
33
|
+
* },
|
|
34
|
+
* {
|
|
35
|
+
* src: "https://storecomponents.vtexassets.com/...",
|
|
36
|
+
* alt: "...",
|
|
37
|
+
* label: "...",
|
|
38
|
+
* value: "..."
|
|
39
|
+
* }
|
|
40
|
+
* ],
|
|
41
|
+
* Size: [
|
|
42
|
+
* {
|
|
43
|
+
* src: "https://storecomponents.vtexassets.com/...",
|
|
44
|
+
* alt: "...",
|
|
45
|
+
* label: "...",
|
|
46
|
+
* value: "..."
|
|
47
|
+
* }
|
|
48
|
+
* ]
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
FormattedVariants: any;
|
|
12
53
|
ObjectOrString: any;
|
|
54
|
+
/**
|
|
55
|
+
* Example:
|
|
56
|
+
*
|
|
57
|
+
* ```json
|
|
58
|
+
* {
|
|
59
|
+
* 'Color-Red-Size-40': 'classic-shoes-37'
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
SlugsMap: any;
|
|
64
|
+
/**
|
|
65
|
+
* Example:
|
|
66
|
+
*
|
|
67
|
+
* ```json
|
|
68
|
+
* {
|
|
69
|
+
* Color: [ "Red", "Blue", "Green" ],
|
|
70
|
+
* Size: [ "40", "41" ]
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
VariantsByName: any;
|
|
13
75
|
};
|
|
14
76
|
|
|
15
77
|
/** Person data input to the newsletter. */
|
|
@@ -206,6 +268,37 @@ export type QuerySearchArgs = {
|
|
|
206
268
|
term?: Maybe<Scalars['String']>;
|
|
207
269
|
};
|
|
208
270
|
|
|
271
|
+
export type SkuVariants = {
|
|
272
|
+
__typename?: 'SkuVariants';
|
|
273
|
+
/** SKU property values for the current SKU. */
|
|
274
|
+
activeVariations?: Maybe<Scalars['ActiveVariations']>;
|
|
275
|
+
/** All available options for each SKU variant property, indexed by their name. */
|
|
276
|
+
allVariantsByName?: Maybe<Scalars['VariantsByName']>;
|
|
277
|
+
/**
|
|
278
|
+
* Available options for each varying SKU property, taking into account the
|
|
279
|
+
* `dominantVariantName` property. Returns all available options for the
|
|
280
|
+
* dominant property, and only options that can be combined with its current
|
|
281
|
+
* value for other properties.
|
|
282
|
+
*/
|
|
283
|
+
availableVariations?: Maybe<Scalars['FormattedVariants']>;
|
|
284
|
+
/**
|
|
285
|
+
* Maps property value combinations to their respective SKU's slug. Enables
|
|
286
|
+
* us to retrieve the slug for the SKU that matches the currently selected
|
|
287
|
+
* variations in O(1) time.
|
|
288
|
+
*/
|
|
289
|
+
slugsMap?: Maybe<Scalars['SlugsMap']>;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
export type SkuVariantsAvailableVariationsArgs = {
|
|
294
|
+
dominantVariantName: Scalars['String'];
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
export type SkuVariantsSlugsMapArgs = {
|
|
299
|
+
dominantVariantName: Scalars['String'];
|
|
300
|
+
};
|
|
301
|
+
|
|
209
302
|
/** Aggregate offer information, for a given SKU that is available to be fulfilled by multiple sellers. */
|
|
210
303
|
export type StoreAggregateOffer = {
|
|
211
304
|
__typename?: 'StoreAggregateOffer';
|
|
@@ -556,6 +649,12 @@ export type StoreProductGroup = {
|
|
|
556
649
|
name: Scalars['String'];
|
|
557
650
|
/** Product group ID. */
|
|
558
651
|
productGroupID: Scalars['String'];
|
|
652
|
+
/**
|
|
653
|
+
* Object containing data structures to facilitate handling different SKU
|
|
654
|
+
* variant properties. Specially useful for implementing SKU selection
|
|
655
|
+
* components.
|
|
656
|
+
*/
|
|
657
|
+
skuVariants?: Maybe<SkuVariants>;
|
|
559
658
|
};
|
|
560
659
|
|
|
561
660
|
/** Properties that can be associated with products and products groups. */
|
|
@@ -20,6 +20,7 @@ import { Query } from './resolvers/query'
|
|
|
20
20
|
import { StoreReview } from './resolvers/review'
|
|
21
21
|
import { StoreSearchResult } from './resolvers/searchResult'
|
|
22
22
|
import { StoreSeo } from './resolvers/seo'
|
|
23
|
+
import { SkuVariants } from './resolvers/skuVariations'
|
|
23
24
|
import ChannelMarshal from './utils/channel'
|
|
24
25
|
import type { Loaders } from './loaders'
|
|
25
26
|
import type { Clients } from './clients'
|
|
@@ -80,6 +81,7 @@ const Resolvers = {
|
|
|
80
81
|
StoreProductGroup,
|
|
81
82
|
StoreSearchResult,
|
|
82
83
|
StorePropertyValue,
|
|
84
|
+
SkuVariants,
|
|
83
85
|
ObjectOrString,
|
|
84
86
|
Query,
|
|
85
87
|
Mutation,
|
|
@@ -11,8 +11,11 @@ const isBrand = (x: any): x is Brand | CollectionPageType =>
|
|
|
11
11
|
x.type === 'brand' ||
|
|
12
12
|
(isCollectionPageType(x) && x.pageType.toLowerCase() === 'brand')
|
|
13
13
|
|
|
14
|
+
const isCollection = (x: Root): x is CollectionPageType =>
|
|
15
|
+
isCollectionPageType(x) && x.pageType.toLowerCase() === 'collection'
|
|
16
|
+
|
|
14
17
|
const slugifyRoot = (root: Root) => {
|
|
15
|
-
if (isBrand(root)) {
|
|
18
|
+
if (isBrand(root) || isCollection(root)) {
|
|
16
19
|
return slugify(root.name)
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -12,15 +12,16 @@ export const StoreProductGroup: Record<string, Resolver<Root>> = {
|
|
|
12
12
|
hasVariant: (root) =>
|
|
13
13
|
root.isVariantOf.items.map((item) => enhanceSku(item, root.isVariantOf)),
|
|
14
14
|
productGroupID: ({ isVariantOf }) => isVariantOf.productId,
|
|
15
|
-
name: (
|
|
15
|
+
name: (root) => root.isVariantOf.productName,
|
|
16
|
+
skuVariants: (root) => root,
|
|
16
17
|
additionalProperty: ({ isVariantOf: { specificationGroups } }) =>
|
|
17
18
|
specificationGroups
|
|
18
|
-
//
|
|
19
|
+
// Filter sku specifications so we don't mix them with product specs.
|
|
19
20
|
.filter(
|
|
20
21
|
(specificationGroup) =>
|
|
21
22
|
!BLOCKED_SPECIFICATIONS.has(specificationGroup.name)
|
|
22
23
|
)
|
|
23
|
-
// Transform specs back into product specs
|
|
24
|
+
// Transform specs back into product specs.
|
|
24
25
|
.flatMap(({ specifications }) =>
|
|
25
26
|
specifications.flatMap(({ name, values }) =>
|
|
26
27
|
values.map((value) => ({
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Resolver } from '..'
|
|
2
|
+
import type { PromiseType } from '../../../typings'
|
|
3
|
+
import type { StoreProduct } from './product'
|
|
4
|
+
import {
|
|
5
|
+
createSlugsMap,
|
|
6
|
+
getActiveSkuVariations,
|
|
7
|
+
getFormattedVariations,
|
|
8
|
+
getVariantsByName,
|
|
9
|
+
} from '../utils/skuVariants'
|
|
10
|
+
|
|
11
|
+
type Root = PromiseType<ReturnType<typeof StoreProduct.isVariantOf>>
|
|
12
|
+
|
|
13
|
+
type SlugsMapArgs = {
|
|
14
|
+
dominantVariantName: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const SkuVariants: Record<string, Resolver<Root>> = {
|
|
18
|
+
activeVariations: (root) => getActiveSkuVariations(root.variations),
|
|
19
|
+
allVariantsByName: (root) =>
|
|
20
|
+
getVariantsByName(root.isVariantOf.skuSpecifications),
|
|
21
|
+
|
|
22
|
+
slugsMap: (root, args) =>
|
|
23
|
+
createSlugsMap(
|
|
24
|
+
root.isVariantOf.items,
|
|
25
|
+
// Since `dominantVariantProperty` is a required argument, we can safely
|
|
26
|
+
// access it.
|
|
27
|
+
(args as SlugsMapArgs).dominantVariantName,
|
|
28
|
+
root.isVariantOf.linkText
|
|
29
|
+
),
|
|
30
|
+
|
|
31
|
+
availableVariations: (root, args) => {
|
|
32
|
+
// Since `dominantVariantProperty` is a required argument, we can safely
|
|
33
|
+
// access it.
|
|
34
|
+
const dominantVariantName = (args as SlugsMapArgs).dominantVariantName
|
|
35
|
+
const activeVariations = getActiveSkuVariations(root.variations)
|
|
36
|
+
|
|
37
|
+
const activeDominantVariationValue = activeVariations[dominantVariantName]
|
|
38
|
+
|
|
39
|
+
const filteredFormattedVariations = getFormattedVariations(
|
|
40
|
+
root.isVariantOf.items,
|
|
41
|
+
dominantVariantName,
|
|
42
|
+
activeDominantVariationValue
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return filteredFormattedVariations
|
|
46
|
+
},
|
|
47
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { StoreProduct as StoreProductType } from '../../..'
|
|
2
|
+
import type { Product, Item } from '../clients/search/types/ProductSearchResult'
|
|
3
|
+
|
|
4
|
+
export type SkuVariants = StoreProductType[]
|
|
5
|
+
|
|
6
|
+
export type SkuVariantsByName = Record<string, Array<FormattedSkuVariant>>
|
|
7
|
+
|
|
8
|
+
type FormattedSkuVariant = {
|
|
9
|
+
alt: string
|
|
10
|
+
src: string
|
|
11
|
+
label: string
|
|
12
|
+
value: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function findSkuVariantImage(availableImages: Item['images']) {
|
|
16
|
+
return (
|
|
17
|
+
availableImages.find(
|
|
18
|
+
(imageProperties) => imageProperties.imageLabel === 'skuvariation'
|
|
19
|
+
) ?? availableImages[0]
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createSlugsMap(
|
|
24
|
+
variants: Item[],
|
|
25
|
+
dominantVariantName: string,
|
|
26
|
+
baseSlug: string
|
|
27
|
+
) {
|
|
28
|
+
/**
|
|
29
|
+
* Maps property value combinations to their respective SKU's slug. Enables
|
|
30
|
+
* us to retrieve the slug for the SKU that matches the currently selected
|
|
31
|
+
* variations in O(1) time.
|
|
32
|
+
*
|
|
33
|
+
* Example: `'Color-Red-Size-40': 'classic-shoes-37'`
|
|
34
|
+
*/
|
|
35
|
+
const slugsMap: Record<string, string> = {}
|
|
36
|
+
|
|
37
|
+
variants.forEach((variant) => {
|
|
38
|
+
const skuSpecificationProperties = variant.variations
|
|
39
|
+
|
|
40
|
+
if (skuSpecificationProperties.length === 0) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Make sure that the 'name-value' pair for the dominant variation
|
|
45
|
+
// is always the first one.
|
|
46
|
+
const dominantNameValue = `${dominantVariantName}-${
|
|
47
|
+
skuSpecificationProperties.find(
|
|
48
|
+
(variationDetails) => variationDetails.name === dominantVariantName
|
|
49
|
+
)?.values[0] ?? ''
|
|
50
|
+
}`
|
|
51
|
+
|
|
52
|
+
const skuVariantKey = skuSpecificationProperties.reduce((acc, property) => {
|
|
53
|
+
const shouldIgnore = property.name === dominantVariantName
|
|
54
|
+
|
|
55
|
+
if (shouldIgnore) {
|
|
56
|
+
return acc
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return acc + `-${property.name}-${property.values[0]}`
|
|
60
|
+
}, dominantNameValue)
|
|
61
|
+
|
|
62
|
+
slugsMap[skuVariantKey] = `${baseSlug}-${variant.itemId}`
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return slugsMap
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getActiveSkuVariations(variations: Item['variations']) {
|
|
69
|
+
const activeVariations: Record<string, string> = {}
|
|
70
|
+
|
|
71
|
+
variations.forEach((variation) => {
|
|
72
|
+
activeVariations[variation.name] = variation.values[0]
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return activeVariations
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getVariantsByName(
|
|
79
|
+
skuSpecifications: Product['skuSpecifications']
|
|
80
|
+
) {
|
|
81
|
+
const variants: Record<string, string[]> = {}
|
|
82
|
+
|
|
83
|
+
skuSpecifications?.forEach((specification) => {
|
|
84
|
+
variants[specification.field.originalName ?? specification.field.name] =
|
|
85
|
+
specification.values.map((value) => value.originalName ?? value.name)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return variants
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function compare(a: string, b: string) {
|
|
92
|
+
// Values are always represented as Strings, so we need to handle numbers
|
|
93
|
+
// in this special case.
|
|
94
|
+
if (!Number.isNaN(Number(a) - Number(b))) {
|
|
95
|
+
return Number(a) - Number(b)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (a < b) {
|
|
99
|
+
return -1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (a > b) {
|
|
103
|
+
return 1
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return 0
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function sortVariants(variantsByName: SkuVariantsByName) {
|
|
110
|
+
const sortedVariants = variantsByName
|
|
111
|
+
|
|
112
|
+
for (const variantProperty in variantsByName) {
|
|
113
|
+
variantsByName[variantProperty].sort((a, b) => compare(a.value, b.value))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return sortedVariants
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getFormattedVariations(
|
|
120
|
+
variants: Item[],
|
|
121
|
+
dominantVariantName: string,
|
|
122
|
+
dominantVariantValue: string
|
|
123
|
+
) {
|
|
124
|
+
/**
|
|
125
|
+
* SKU options already formatted and indexed by their property name.
|
|
126
|
+
*
|
|
127
|
+
* Ex: {
|
|
128
|
+
* `Size`: [
|
|
129
|
+
* { label: '42', value: '42' },
|
|
130
|
+
* { label: '41', value: '41' },
|
|
131
|
+
* { label: '39', value: '39' },
|
|
132
|
+
* ]
|
|
133
|
+
* }
|
|
134
|
+
*/
|
|
135
|
+
const variantsByName: SkuVariantsByName = {}
|
|
136
|
+
|
|
137
|
+
const previouslySeenPropertyValues = new Set<string>()
|
|
138
|
+
|
|
139
|
+
variants.forEach((variant) => {
|
|
140
|
+
if (variant.variations.length === 0) {
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const variantImageToUse = findSkuVariantImage(variant.images)
|
|
145
|
+
|
|
146
|
+
const dominantVariantEntry = variant.variations.find(
|
|
147
|
+
(variation) => variation.name === dominantVariantName
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
const matchesDominantVariant =
|
|
151
|
+
dominantVariantEntry?.values[0] === dominantVariantValue
|
|
152
|
+
|
|
153
|
+
if (!matchesDominantVariant) {
|
|
154
|
+
const nameValueIdentifier = `${dominantVariantName}-${dominantVariantEntry?.values[0]}`
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
!dominantVariantEntry ||
|
|
158
|
+
previouslySeenPropertyValues.has(nameValueIdentifier)
|
|
159
|
+
) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
previouslySeenPropertyValues.add(nameValueIdentifier)
|
|
164
|
+
|
|
165
|
+
const formattedVariant = {
|
|
166
|
+
src: variantImageToUse.imageUrl,
|
|
167
|
+
alt: variantImageToUse.imageLabel ?? '',
|
|
168
|
+
label: `${dominantVariantName}: ${dominantVariantEntry.values[0]}`,
|
|
169
|
+
value: dominantVariantEntry.values[0],
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (variantsByName[dominantVariantEntry.name]) {
|
|
173
|
+
variantsByName[dominantVariantEntry.name].push(formattedVariant)
|
|
174
|
+
} else {
|
|
175
|
+
variantsByName[dominantVariantEntry.name] = [formattedVariant]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
variant.variations.forEach((variationProperty) => {
|
|
182
|
+
const nameValueIdentifier = `${variationProperty.name}-${variationProperty.values[0]}`
|
|
183
|
+
|
|
184
|
+
if (previouslySeenPropertyValues.has(nameValueIdentifier)) {
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
previouslySeenPropertyValues.add(nameValueIdentifier)
|
|
189
|
+
|
|
190
|
+
const formattedVariant = {
|
|
191
|
+
src: variantImageToUse.imageUrl,
|
|
192
|
+
alt: variantImageToUse.imageLabel ?? '',
|
|
193
|
+
label: `${variationProperty.name}: ${variationProperty.values[0]}`,
|
|
194
|
+
value: variationProperty.values[0],
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (variantsByName[variationProperty.name]) {
|
|
198
|
+
variantsByName[variationProperty.name].push(formattedVariant)
|
|
199
|
+
} else {
|
|
200
|
+
variantsByName[variationProperty.name] = [formattedVariant]
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
return sortVariants(variantsByName)
|
|
206
|
+
}
|
package/src/typeDefs/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ import Person from './person.graphql'
|
|
|
25
25
|
import ObjectOrString from './objectOrString.graphql'
|
|
26
26
|
import Session from './session.graphql'
|
|
27
27
|
import Newsletter from './newsletter.graphql'
|
|
28
|
+
import SkuVariants from './skuVariants.graphql'
|
|
28
29
|
|
|
29
30
|
export const typeDefs = [
|
|
30
31
|
Query,
|
|
@@ -51,7 +52,8 @@ export const typeDefs = [
|
|
|
51
52
|
Person,
|
|
52
53
|
ObjectOrString,
|
|
53
54
|
Session,
|
|
54
|
-
Newsletter
|
|
55
|
+
Newsletter,
|
|
56
|
+
SkuVariants,
|
|
55
57
|
]
|
|
56
58
|
.map(print)
|
|
57
59
|
.join('\n')
|
|
@@ -18,4 +18,10 @@ type StoreProductGroup {
|
|
|
18
18
|
Array of additional properties.
|
|
19
19
|
"""
|
|
20
20
|
additionalProperty: [StorePropertyValue!]!
|
|
21
|
+
"""
|
|
22
|
+
Object containing data structures to facilitate handling different SKU
|
|
23
|
+
variant properties. Specially useful for implementing SKU selection
|
|
24
|
+
components.
|
|
25
|
+
"""
|
|
26
|
+
skuVariants: SkuVariants
|
|
21
27
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
type SkuVariants {
|
|
2
|
+
"""
|
|
3
|
+
SKU property values for the current SKU.
|
|
4
|
+
"""
|
|
5
|
+
activeVariations: ActiveVariations
|
|
6
|
+
"""
|
|
7
|
+
All available options for each SKU variant property, indexed by their name.
|
|
8
|
+
"""
|
|
9
|
+
allVariantsByName: VariantsByName
|
|
10
|
+
"""
|
|
11
|
+
Maps property value combinations to their respective SKU's slug. Enables
|
|
12
|
+
us to retrieve the slug for the SKU that matches the currently selected
|
|
13
|
+
variations in O(1) time.
|
|
14
|
+
"""
|
|
15
|
+
slugsMap(dominantVariantName: String!): SlugsMap
|
|
16
|
+
"""
|
|
17
|
+
Available options for each varying SKU property, taking into account the
|
|
18
|
+
`dominantVariantName` property. Returns all available options for the
|
|
19
|
+
dominant property, and only options that can be combined with its current
|
|
20
|
+
value for other properties.
|
|
21
|
+
"""
|
|
22
|
+
availableVariations(dominantVariantName: String!): FormattedVariants
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
Example:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
'Color-Red-Size-40': 'classic-shoes-37'
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
scalar SlugsMap
|
|
35
|
+
"""
|
|
36
|
+
Example:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
Color: 'Red', Size: '42'
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
"""
|
|
44
|
+
scalar ActiveVariations
|
|
45
|
+
"""
|
|
46
|
+
Example:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
Color: [ "Red", "Blue", "Green" ],
|
|
51
|
+
Size: [ "40", "41" ]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
"""
|
|
55
|
+
scalar VariantsByName
|
|
56
|
+
"""
|
|
57
|
+
Example:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
Color: [
|
|
62
|
+
{
|
|
63
|
+
src: "https://storecomponents.vtexassets.com/...",
|
|
64
|
+
alt: "...",
|
|
65
|
+
label: "...",
|
|
66
|
+
value: "..."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
src: "https://storecomponents.vtexassets.com/...",
|
|
70
|
+
alt: "...",
|
|
71
|
+
label: "...",
|
|
72
|
+
value: "..."
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
Size: [
|
|
76
|
+
{
|
|
77
|
+
src: "https://storecomponents.vtexassets.com/...",
|
|
78
|
+
alt: "...",
|
|
79
|
+
label: "...",
|
|
80
|
+
value: "..."
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
"""
|
|
86
|
+
scalar FormattedVariants
|
|
87
|
+
|