@faststore/api 1.10.33 → 1.11.4

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.
@@ -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
+ }
@@ -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')
@@ -62,6 +62,10 @@ type StoreProduct {
62
62
  Array of additional properties.
63
63
  """
64
64
  additionalProperty: [StorePropertyValue!]!
65
+ """
66
+ The product's release date. Formatted using https://en.wikipedia.org/wiki/ISO_8601
67
+ """
68
+ releaseDate: String!
65
69
  }
66
70
 
67
71
  """
@@ -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
+