Skip to content

Commit 06dd4a6

Browse files
committed
fix: use product model, add offer jsonld
1 parent ecc5886 commit 06dd4a6

File tree

6 files changed

+286
-103
lines changed

6 files changed

+286
-103
lines changed

src/index.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// @ts-check
1313

1414
import { errorResponse, errorWithResponse, makeContext } from './util.js';
15-
import getProductQueryCS from './queries/cs-product.js';
15+
import getProductQueryCS, { adapter } from './queries/cs-product.js';
1616
import getProductQueryCore from './queries/core-product.js';
1717
import HTML_TEMPLATE from './templates/html.js';
1818
import { resolveConfig } from './config.js';
@@ -40,10 +40,11 @@ async function fetchProductCS(sku, config) {
4040

4141
const json = await resp.json();
4242
try {
43-
const [product] = json.data.products;
44-
if (!product) {
43+
const [productData] = json.data.products;
44+
if (!productData) {
4545
throw errorWithResponse(404, 'could not find product', json.errors);
4646
}
47+
const product = adapter(productData);
4748
return product;
4849
} catch (e) {
4950
console.error('failed to parse product: ', e);

src/queries/cs-product.js

+104-31
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,85 @@
1212

1313
import { gql } from '../util.js';
1414

15+
/**
16+
* @param {any} productData
17+
* @returns {Product}
18+
*/
19+
export const adapter = (productData) => {
20+
const minPrice = productData.priceRange?.minimum ?? productData.price;
21+
const maxPrice = productData.priceRange?.maximum ?? productData.price;
22+
23+
/** @type {Product} */
24+
const product = {
25+
sku: productData.sku,
26+
name: productData.name,
27+
metaTitle: productData.metaTitle,
28+
metaDescription: productData.metaDescription,
29+
metaKeyword: productData.metaKeyword,
30+
description: productData.description,
31+
url: productData.url,
32+
urlKey: productData.urlKey,
33+
shortDescription: productData.shortDescription,
34+
addToCartAllowed: productData.addToCartAllowed,
35+
inStock: productData.inStock,
36+
externalId: productData.externalId,
37+
images: productData.images ?? [],
38+
attributes: productData.attributes ?? [],
39+
options: (productData.options ?? []).map((option) => ({
40+
id: option.id,
41+
label: option.title,
42+
// eslint-disable-next-line no-underscore-dangle
43+
typename: option.values?.[0]?.__typename,
44+
required: option.required,
45+
multiple: option.multi,
46+
items: (option.values ?? []).map((value) => ({
47+
id: value.id,
48+
label: value.title,
49+
inStock: value.inStock,
50+
type: value.type,
51+
product: value.product
52+
? {
53+
sku: value.product.sku,
54+
name: value.product.name,
55+
prices: value.product.price ? {
56+
regular: value.product.price.regular,
57+
final: value.product.price.final,
58+
visible: value.product.price.roles?.includes('visible'),
59+
} : undefined,
60+
}
61+
: undefined,
62+
quantity: value.quantity,
63+
isDefault: value.isDefault,
64+
})),
65+
})),
66+
prices: {
67+
regular: {
68+
// TODO: determine whether to use min or max
69+
amount: minPrice.regular.amount.value,
70+
currency: minPrice.regular.amount.currency,
71+
maximumAmount: maxPrice.regular.amount.value,
72+
minimumAmount: minPrice.regular.amount.value,
73+
// TODO: add variant?
74+
},
75+
final: {
76+
// TODO: determine whether to use min or max
77+
amount: minPrice.final.amount.value,
78+
currency: minPrice.final.amount.currency,
79+
maximumAmount: maxPrice.final.amount.value,
80+
minimumAmount: minPrice.final.amount.value,
81+
// TODO: add variant?
82+
},
83+
visible: minPrice.roles?.includes('visible'),
84+
},
85+
};
86+
87+
return product;
88+
};
89+
1590
export default ({ sku }) => gql`{
1691
products(
1792
skus: ["${sku}"]
1893
) {
19-
__typename
2094
id
2195
sku
2296
name
@@ -30,111 +104,110 @@ export default ({ sku }) => gql`{
30104
url
31105
addToCartAllowed
32106
inStock
107+
externalId
33108
images(roles: []) {
34109
url
35110
label
36-
roles
37-
__typename
38111
}
39112
attributes(roles: []) {
40113
name
41114
label
42115
value
43-
roles
44-
__typename
45116
}
46117
... on SimpleProductView {
47118
price {
48119
final {
49120
amount {
50121
value
51122
currency
52-
__typename
53123
}
54-
__typename
55124
}
56125
regular {
57126
amount {
58127
value
59128
currency
60-
__typename
61129
}
62-
__typename
63130
}
64131
roles
65-
__typename
66132
}
67-
__typename
68133
}
69134
... on ComplexProductView {
70135
options {
136+
__typename
71137
id
72138
title
73139
required
140+
multi
74141
values {
75142
id
76143
title
77-
... on ProductViewOptionValueProduct {
78-
product {
79-
sku
80-
name
81-
__typename
82-
}
144+
inStock
145+
...on ProductViewOptionValueConfiguration {
83146
__typename
84147
}
85148
... on ProductViewOptionValueSwatch {
149+
__typename
86150
type
87151
value
152+
}
153+
... on ProductViewOptionValueProduct {
88154
__typename
155+
quantity
156+
isDefault
157+
product {
158+
sku
159+
name
160+
price {
161+
regular {
162+
amount {
163+
value
164+
currency
165+
}
166+
}
167+
final {
168+
amount {
169+
value
170+
currency
171+
}
172+
}
173+
roles
174+
}
175+
}
89176
}
90-
__typename
91177
}
92-
__typename
93178
}
94179
priceRange {
95180
maximum {
96181
final {
97182
amount {
98183
value
99184
currency
100-
__typename
101185
}
102-
__typename
103186
}
104187
regular {
105188
amount {
106189
value
107190
currency
108-
__typename
109191
}
110-
__typename
111192
}
112193
roles
113-
__typename
114194
}
115195
minimum {
116196
final {
117197
amount {
118198
value
119199
currency
120-
__typename
121200
}
122-
__typename
123201
}
124202
regular {
125203
amount {
126204
value
127205
currency
128-
__typename
129206
}
130-
__typename
131207
}
132208
roles
133-
__typename
134209
}
135-
__typename
136210
}
137-
__typename
138211
}
139212
}
140213
}`;

src/templates/html.js

+33-18
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,33 @@
1313

1414
import JSON_LD_TEMPLATE from './json-ld.js';
1515

16+
/**
17+
* @param {string} name
18+
* @param {string|boolean|number|undefined|null} [content]
19+
* @returns {string}
20+
*/
21+
const metaContent = (name, content) => (content ? `<meta name="${name}" content="${content}">` : '');
22+
23+
/**
24+
* @param {Product} product
25+
*/
1626
export default (product) => {
1727
const {
1828
sku,
1929
name,
30+
urlKey,
2031
metaTitle,
2132
metaDescription,
2233
description,
2334
images,
2435
attributes,
2536
options,
37+
addToCartAllowed,
38+
inStock,
39+
metaKeyword,
40+
externalId,
2641
} = product;
2742

28-
const jsonLd = JSON_LD_TEMPLATE({
29-
sku,
30-
description: description ?? metaDescription,
31-
image: images[0].url,
32-
name,
33-
// TODO: add following...
34-
url: '',
35-
brandName: '',
36-
reviewCount: 0,
37-
ratingValue: 0,
38-
});
39-
4043
return /* html */`\
4144
<!DOCTYPE html>
4245
<html>
@@ -50,21 +53,26 @@ export default (product) => {
5053
<meta name="twitter:card" content="summary_large_image">
5154
<meta name="twitter:title" content="${metaTitle || name}">
5255
<meta name="twitter:image" content="${images[0].url}">
56+
<meta name="keywords" content="${metaKeyword}">
5357
<meta name="sku" content="${sku}">
58+
<meta name="urlKey" content="${urlKey}">
59+
${metaContent('externalId', externalId)}
60+
${metaContent('addToCartAllowed', addToCartAllowed)}
61+
${metaContent('inStock', inStock)}
5462
<meta name="viewport" content="width=device-width, initial-scale=1">
5563
<script src="/scripts/aem.js" type="module"></script>
5664
<script src="/scripts/scripts.js" type="module"></script>
5765
<link rel="stylesheet" href="/styles/styles.css">
5866
<script type="application/ld+json">
59-
${jsonLd}
67+
${JSON_LD_TEMPLATE(product)}
6068
</script>
6169
</head>
6270
<body>
6371
<header></header>
6472
<main>
6573
<div>
6674
<h1>${name}</h1>
67-
<div class="product-gallery">
75+
<div class="product-images">
6876
<div>
6977
${images.map((img) => `
7078
<div>
@@ -89,13 +97,20 @@ export default (product) => {
8997
${options.map((opt) => `
9098
<div>
9199
<div>${opt.id}</div>
92-
<div>${opt.title}</div>
100+
<div>${opt.label}</div>
101+
<div>${opt.typename}</div>
102+
<div>${opt.type ?? ''}</div>
103+
<div>${opt.multiple ? 'multiple' : ''}</div>
93104
<div>${opt.required === true ? 'required' : ''}</div>
94105
</div>
95-
${opt.values.map((val) => `
106+
${opt.items.map((item) => `
96107
<div>
97-
<div>${val.id}</div>
98-
<div>${val.title}</div>
108+
<div>option</div>
109+
<div>${item.id}</div>
110+
<div>${item.label}</div>
111+
<div>${item.value ?? ''}</div>
112+
<div>${item.selected ? 'selected' : ''}</div>
113+
<div>${item.inStock ? 'inStock' : ''}</div>
99114
</div>`).join('\n')}`).join('\n')}
100115
</div>
101116
</div>

0 commit comments

Comments
 (0)