Skip to content

Instantly share code, notes, and snippets.

@Bitaru
Last active August 21, 2019 11:47
Show Gist options
  • Save Bitaru/540927f6775488b1bc7d4b2892b36451 to your computer and use it in GitHub Desktop.
Save Bitaru/540927f6775488b1bc7d4b2892b36451 to your computer and use it in GitHub Desktop.
/** [1]: Import React hooks */
import React, { useState, useEffect } from 'react'
import classNames from 'classnames'
import Image from 'components/common/Image'
import Truncate from 'components/common/Truncate'
import Text from 'components/Text'
import Rating from 'components/Cards/Product/Rating';
import Price from 'components/Cards/Product/Price';
import template from 'helpers/template';
import { DiscountSticker, OutOfStockSticker } from 'components/Cards/Product/Stickers';
import { List } from 'immutable'
import { IProduct, MJSConfiguration, ThemedSFCProps } from 'types/index';
import BundleAction from 'components/Cards/Product/BundleAction';
import { withStateHandlers, compose, lifecycle } from 'recompose';
const Title: any = ({ text, theme, ...rest }) => (
<Text display-if={!!text} className={theme.title} {...rest}>{text}</Text>
);
const Description: any = ({ text, theme, ...rest }) => (
<p
display-if={!!text}
className={theme.description}
{...rest}
>
<Truncate>{text}</Truncate>
</p>
);
const enhancer = compose(
withStateHandlers(
({ item, config }) => ({
currentImage: item.get('image_url') || item.get('thumbnail_url'), //currentImage state will contain the default variant id, it might be 'item.get('selected_variant_id')', but by default it would be 'default'
shopifyImages: item.get('shopify_images')
}),
{
changeImage: ({ shopifyImages }) => (altText) => {
let colorName = altText.split('-')[0].trim().toLowerCase().replace(/\d/g,'');
let selectedImage = shopifyImages.filter((image: any) => {
let loopedAltText = image.get('alt').toLowerCase().replace(/\d/g,'');
if (loopedAltText.includes('swatch')) {
return false;
} else {
return loopedAltText.includes(colorName);
}
})
return {
currentImage: selectedImage.first().get('url')
}
}
}
)
);
const Swatches: any = ({images, changeImage, numberOfVariants}) => {
if (numberOfVariants > 1) {
let swatchImages = images.filter((image: any) => {
return image.get('alt').toLowerCase().includes("swatch");
})
return swatchImages.map((image: any) => {
return (
<img
style={{width: '20px', height: '20px'}}
src={image.get('url')}
alt={image.get('alt')}
onClick={() => changeImage(image.get('alt'))}
/>
)
})
} else {
return (
<div />
)
}
}
const fetchVariantMetaData: any = async (item: any) => {
return fetch(`${origin}${item.get('product_url')}`)
.then(function(response) {
return response.text()
})
.then(function(html) {
let parser = new DOMParser()
let doc = parser.parseFromString(html, "text/html")
let variantMetaData = Array.from(doc.querySelectorAll('.variant-meta-data')).map(function(element) {
return element.dataset
})
return variantMetaData;
})
}
/** [2]: Create React hook */
const getCurrentVariants = (item) => {
const [variants, setVariants] = useState([]);
useEffect(async () => {
let variantPageMetaData = await fetchVariantMetaData(item);
let validVariants = item.get('variants').reduce((accumulator: any, variant: any) => {
let variantPageData = variantPageMetaData.find((variantMetaData) => {
let variantMetaDataId = Number(variantMetaData.variantId)
let variantId = Number(variant.get('id'))
return variantMetaDataId === variantId;
})
if (variantPageData.variantAvailable === "true") {
accumulator.push(variant);
}
return accumulator;
}, []);
setVariants(variantPageMetaData);
}, [])
return variants;
}
export interface IProductCardProps extends ThemedSFCProps {
item: IProduct;
config: MJSConfiguration;
}
const ProductCardView: React.SFC<IProductCardProps> = async ({
item,
config,
theme,
currentImage,
changeImage
}: any) => {
/** [3]: Call hook to fetch data */
const validVariants = getCurrentVariants(item);
if (!validVariants.length) return null;
return (
<div
className={classNames(
theme.root,
config.get('simple') && theme.simple,
theme.productCard,
)}
>
<div className={classNames(theme.imageWrap)}>
<BundleAction display-if={config.get('bundle')} item={item} />
<Image
className={classNames(theme.image)}
aspectRatio={config.getIn(['product', 'image', 'aspectRatio'], 1)}
thumbnail={currentImage}
src={currentImage}
alt={item.get('title')}
/>
<div display-if={config.getIn(['product', 'stickers', 'display'])}>
<DiscountSticker
config={config}
className={theme.discountSticker}
discount={item.get('discount')}
display-if={
config.getIn(['stickers', 'discount']) &&
config.getIn(['product', 'stickers', 'display']) &&
item.get('discount', List()).size &&
item.getIn(['stickers', 'discount'])
} />
</div>
</div>
<div
display-if={
config.getIn(['product', 'reviews', 'display']) &&
(!!item.getIn(['reviews', 'count']) || !!item.getIn(['reviews', 'total_reviews']))
}
className={theme.rating}>
<Rating
value={item.getIn(['reviews', 'average_score'])}
count={item.getIn(['reviews', 'count']) || item.getIn(['reviews', 'total_reviews'])} />
</div>
<div
className={theme.variants}
display-if={
config.getIn(['product', 'variants', 'display']) &&
item.get('variants', List()).size > 1
}
>
{
template(config.getIn(['product', 'i18n', 'variants'], 'Available in %s variants'))(
item.get('variants', List()).size
)
}
</div>
<div className={theme.content}>
<Title
theme={theme}
display-if={config.getIn(['product', 'title', 'display'])}
text={item.get('title')}
config={config.getIn(['product', 'title'])} />
<Description
theme={theme}
display-if={config.getIn(['product', 'description', 'display'])}
text={item.get('description')}
config={config.getIn(['product', 'description'])} />
<Price
className={theme.priceWrapper}
display-if={config.getIn(['product', 'price', 'display'])}
price={item.get('price')}
oldPrice={item.get('compare_at')}
discount={item.get('discount')}
currency={config.get('currency_config').toJS()} />
<OutOfStockSticker
display-if={item.getIn(['stickers', 'out-of-stock'])}
config={config} />
</div>
<Swatches images={item.get('shopify_images')} changeImage={changeImage} numberOfVariants={item.get('variants', List()).size}/>
</div>
)
}
// export default ProductCardView;
export default enhancer(ProductCardView);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment