@prg/gatsby-source-something-whatever
Version:
something something whatever who gives a crap.
265 lines (229 loc) • 6.5 kB
JavaScript
import pluralize from 'pluralize';
import camelCase from 'lodash.camelcase';
import createNodeHelpers from 'gatsby-node-helpers';
import { formatMsg, convertId } from './util';
import {
TYPE_PREFIX,
IMAGE,
PRODUCT,
PRODUCT_VARIANT,
PRODUCT_OPTION,
PRODUCT_OPTION_VALUE,
} from './constants';
import {
IMAGES_QUERY,
PRODUCTS_QUERY,
PRODUCT_VARIANTS_QUERY,
PRODUCT_OPTIONS_QUERY,
PRODUCT_OPTION_VALUES_QUERY,
} from './queries';
const { createNodeFactory } = createNodeHelpers({
typePrefix: TYPE_PREFIX,
conflictFieldPrefix: 'platform',
});
const byPosition = ({ position: positionA }, { position: positionB }) => positionA - positionB;
const byId = TYPE => ({ id }) => convertId(id, TYPE);
const getSelectedOptions = variant =>
variant.selectedOptions.reduce((acc, { title, value }) => ({ ...acc, [title]: value }), {});
const productMiddleware = node => {
const {
id,
available,
title,
handle,
description,
type,
parent,
children,
internal,
} = node;
const foreignIds = node.shopifyProductIds.map(({ id }) => id);
const metadata = node.metadata === null ? {} : node.metadata;
const images = node.images.map(byId(IMAGE));
const options = node.options
.sort(byPosition)
.map(byId(PRODUCT_OPTION));
const optionValues = node.options.reduce((acc, { title, values }) => ({
...acc,
[title]: values
.sort(byPosition)
.map(value => value.title),
}), {});
const variants = node.variants
.sort((a, b) => {
try {
const A = getSelectedOptions(a);
const B = getSelectedOptions(b);
if (A.Color === B.Color && A.Size !== B.Size) {
return optionValues.Size.indexOf(A.Size) - optionValues.Size.indexOf(B.Size);
}
return optionValues.Color.indexOf(A.Color) - optionValues.Color.indexOf(B.Color);
} catch (error) {
return 0;
}
});
const featuredImage = (variants[0].images.length)
? convertId(variants[0].images[0].id, IMAGE)
: images[0]
return {
id,
available,
title,
handle,
description,
type,
foreignIds,
metadata,
featuredImage___NODE: featuredImage,
options___NODE: options,
images___NODE: images,
optionValues,
variants___NODE: variants.map(({ id }) => convertId(id, PRODUCT_VARIANT)),
parent,
children,
internal,
}
};
const productVariantMiddleware = node => {
const {
id,
title,
available,
inventory,
foreignId,
productForeignId,
foreignProductHandle,
foreignProductPublishedAt,
price,
compareAtPrice,
metadata,
parent,
children,
internal,
} = node;
const productId = convertId(node.productId, PRODUCT);
const product = productId;
const selectedOptions = getSelectedOptions(node);
const firstImage = node.images.find(({ position }) => position === 1);
const secondImage = node.images.find(({ position }) => position === 2);
const image = firstImage ? convertId(firstImage.id, IMAGE) : null;
const hoverImage = secondImage ? convertId(secondImage.id, IMAGE) : null;
const images = node.images.map(byId(IMAGE));
return {
id,
title,
available,
inventory,
foreignId,
productForeignId,
foreignProductHandle,
foreignProductPublishedAt,
price,
compareAtPrice,
product___NODE: product,
productId,
images___NODE: images,
image___NODE: image,
hoverImage___NODE: hoverImage,
selectedOptions,
metadata,
parent,
children,
internal,
}
};
const imageMiddleware = node => {
const { id, src, altText, parent, children, internal } = node;
if (node.variants && node.variants.length) {
const { variant: firstVariant } = node.variants && node.variants[0];
const match = firstVariant.images.find(({ id }) => id === node.platformId) || {};
const position = match.position || null;
const product = convertId(firstVariant.productId, PRODUCT);
const variants = node.variants
.map(({ id }) => convertId(id, PRODUCT_VARIANT));
return {
id,
src,
altText,
position,
product___NODE: product,
variants___NODE: variants,
parent,
children,
internal,
};
}
if (node.product) {
return {
id,
src,
altText,
position: node.product.position || null,
product___NODE: convertId(node.product.id, PRODUCT),
variants___NODE: [],
parent,
children,
internal,
};
}
return {
id,
src,
altText,
position: null,
product___NODE: null,
variants___NODE: [],
parent,
children,
internal,
};
};
const optionMiddleware = node => {
const productId = convertId(node.productId, PRODUCT);
const product = productId;
const values = node.values
.sort(byPosition)
.map(byId(PRODUCT_OPTION_VALUE))
return {
...node,
productId,
product___NODE: product,
values,
};
};
const types = [
{ name: IMAGE, query: IMAGES_QUERY, middleware: imageMiddleware },
{ name: PRODUCT, query: PRODUCTS_QUERY, middleware: productMiddleware },
{ name: PRODUCT_VARIANT, query: PRODUCT_VARIANTS_QUERY, middleware: productVariantMiddleware },
{ name: PRODUCT_OPTION, query: PRODUCT_OPTIONS_QUERY, middleware: optionMiddleware },
{ name: PRODUCT_OPTION_VALUE, query: PRODUCT_OPTION_VALUES_QUERY },
];
const getTypeData = async (types, client, shopId) => {
const queries = types.map(({ name, query, middleware = node => node }) => {
const factory = createNodeFactory(name, middleware);
const normalizedName = camelCase(pluralize(name));
return client.query({ query, variables: { shopId } })
.then(({ data }) => {
return ({
name,
nodes: data[normalizedName].map(item => factory(item))
})
});
});
const typeData = await Promise.all(queries);
return typeData
.reduce((acc, {name, nodes}) => ({ ...acc, [name]: nodes }), {});
};
export const createContentNodes = async (client, shopId, { actions: { createNode }}) => {
try {
const typeData = await getTypeData(types, client, shopId);
const createdNodes = Object.entries(typeData).map(([type, nodes]) => {
console.log(formatMsg(`Created ${nodes.length} ${TYPE_PREFIX}${type} nodes.`));
return nodes.map(node => createNode(node));
});
await Promise.all(createdNodes);
return typeData;
} catch (error) {
console.log('error', error);
}
};