Skip to content

Composable gustavo #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: composable-demo
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27,575 changes: 27,575 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@
"pre-commit": "turbo run lint"
}
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"dependencies": {
"@moltin/sdk": "^10.1.0"
}
}
13 changes: 13 additions & 0 deletions site/components/algolia/ProductItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'

export function ProductItem({ hit, components }: any) {
return (
<a href={`/product/${hit.objectID}`} className="aa-ItemLink">
<div className="aa-ItemContent">
<div className="aa-ItemTitle">
<components.Highlight hit={hit} attribute="ep_name" />
</div>
</div>
</a>
)
}
78 changes: 78 additions & 0 deletions site/components/algolia/SearchGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react'
import algoliasearch from 'algoliasearch/lite'
import {
InstantSearch,
SearchBox,
Configure,
useHits,
} from 'react-instantsearch-hooks-web'
import 'instantsearch.css/themes/satellite.css'
import { ProductCard } from '@components/product'
import { parseToProductCell } from './helpers'

const searchClient = algoliasearch(
'3D5DQ7NIQP',
'476e5cbce98781b0ed3a8168558bc013'
)

interface Props {
title?: string
Collection: {
options: {
collection: string
}
}
}

function CustomHits(props: any) {
const { hits, results, sendEvent } = useHits(props)
return (
<div
style={{
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'row',
width: '100%',
flex: 1,
}}
>
{props.renderer(hits)}
</div>
)
}

export const AlgoliaSearchGrid = (props: Props) => {
return (
<div>
<InstantSearch
searchClient={searchClient}
indexName="Retail_Catalog_ea08671f"
>
{/* <SearchBox /> */}
<Configure hitsPerPage={20} page={0} />
<div
style={{ display: 'flex', flexWrap: 'wrap', flexDirection: 'row' }}
>
<CustomHits
{...props}
renderer={(hits: any) => {
// console.log('hits ', hits)
// todo: you can randomize the hits to make it cooler
return (
<div>
{hits.map((product: any) => (
<div key={product.objectID} style={{ width: 500 }}>
<ProductCard product={parseToProductCell(product)} />
</div>
))}
</div>
)
}}
/>
</div>
</InstantSearch>
</div>
)
}

export default AlgoliaSearchGrid
26 changes: 26 additions & 0 deletions site/components/algolia/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export function parseToProductCell(product: any) {
const newProduct = {
id: product.objectID,
name: product.ep_name,
description: product.ep_description,
descriptionHtml: product.ep_description,
sku: product.ep_sku,
slug: product.ep_slug,
path: product.ep_path,
images: [
{
url: product.ep_main_image_url,
alt: product.ep_name,
},
],
variants: [],
price: {
value: product.ep_price?.USD?.float_price,
retailPrice: product.ep_price?.USD?.float_price,
currencyCode: 'USD',
},
options: [],
vendor: 'Shopaholic',
}
return newProduct
}
4 changes: 4 additions & 0 deletions site/components/algolia/override.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.aa-Form {
border-radius: 1rem;
height: 36px;
}
10 changes: 10 additions & 0 deletions site/config/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ Builder.registerComponent(
image: 'https://tabler-icons.io/static/tabler-icons/icons-png/search.png',
}
)

Builder.registerComponent(
dynamic(() => import('../components/algolia/SearchGrid')),
{
name: 'Algolia SearchGrid',
image:
'https://cdn.builder.io/api/v1/image/assets%2F1fa6810c36c54e87bfe1a6cc0f0be906%2Ff30fd90c31634e5ebb716fad734185f4',
}
)

Builder.registerComponent(
dynamic(() => import('../components/ui/Rating')),
{
Expand Down
1 change: 1 addition & 0 deletions site/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// Declarations for modules without types
declare module 'next-themes'
// declare module '@moltin/sdk'
3 changes: 3 additions & 0 deletions site/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ module.exports = withCommerceConfig({
locales: ['en-US', 'es'],
defaultLocale: 'en-US',
},
images: {
domains: ['files-na.epusercontent.com'],
},
rewrites() {
return [
(isBC || isShopify || isSwell || isVendure || isSaleor) && {
Expand Down
8 changes: 7 additions & 1 deletion site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
},
"sideEffects": false,
"dependencies": {
"@algolia/autocomplete-js": "^1.9.2",
"@algolia/autocomplete-theme-classic": "^1.9.2",
"@builder.io/personalization-utils": "^1.1.1",
"@builder.io/react": "^2.0.9",
"@builder.io/react": "^2.0.2-7",
"@builder.io/utils": "^1.1.3",
"@moltin/sdk": "^10.1.0",
"@netlify/plugin-nextjs": "^4.29.3",
"@radix-ui/react-dropdown-menu": "^0.1.6",
"@react-spring/web": "^9.4.1",
Expand All @@ -30,10 +33,12 @@
"@vercel/commerce-spree": "^0.0.1",
"@vercel/commerce-swell": "^0.0.1",
"@vercel/commerce-vendure": "^0.0.1",
"algoliasearch": "^4.17.0",
"autoprefixer": "^10.4.2",
"body-scroll-lock": "^4.0.0-beta.0",
"clsx": "^1.1.1",
"email-validator": "^2.0.4",
"instantsearch.css": "^8.0.0",
"js-cookie": "^3.0.1",
"keen-slider": "^6.6.3",
"lodash.random": "^3.2.0",
Expand All @@ -47,6 +52,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-fast-marquee": "^1.3.1",
"react-instantsearch-hooks-web": "^6.44.0",
"react-merge-refs": "^1.1.0",
"react-use-measure": "^2.1.1",
"tabbable": "^5.2.1",
Expand Down
7 changes: 5 additions & 2 deletions site/pages/[[...pages]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ export async function getStaticProps({
.get('page', {
apiKey: builderConfig.apiKey,
userAttributes: {
locale,
locale: useLocale,
...attributes,
},
cachebust: true,
locale,
locale: useLocale,
options: {
locale: useLocale,
},
})
.promise()) || null

Expand Down
3 changes: 2 additions & 1 deletion site/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FC, useEffect } from 'react'
import type { AppProps } from 'next/app'
import { Head } from '@components/common'
import { ManagedUIContext } from '@components/ui/context'
import '../components/algolia/override.css'

const Noop: FC = ({ children }) => <>{children}</>

Expand All @@ -16,7 +17,7 @@ export default function MyApp({ Component, pageProps }: AppProps) {
document.body.classList?.remove('loading')

addEventListener('visibilitychange', (event) => {
Cookies.set('personalization.returnVisitor', 'true', { expires: 365 })
// Cookies.set('personalization.returnVisitor', 'true', { expires: 365 })
})
}, [])

Expand Down
29 changes: 29 additions & 0 deletions site/services/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const config = {
clientId: 'Iip7rqkddgLXWqdoC7bH6NQ1aVFTlVqGHXWaaost7D',
clientSecret: 'sYgFoO2eq7JwVElX09yjDs4SOonfFiPmudUr8e7ZB5',
categoryPageSize: 52,
maxCompareProducts: 4,
// compareKeys: process.env.REACT_APP_COMPARE_KEYS
// ? splitCompareKeys(process.env.REACT_APP_COMPARE_KEYS)
// : [],
// endpointURL: "api.moltin.com",
endpointURL: 'useast.api.elasticpath.com',
b2b: process.env.REACT_APP_B2B_ENABLE || false,
supportedLocales: process.env.REACT_APP_SUPPORTED_LOCALES?.split(',').map(
(el) => JSON.parse(el)
) || [
{
key: 'en',
name: 'english',
},
],
defaultLanguage: process.env.REACT_APP_DEFAULT_LANGUAGE || 'en',
defaultCurrency: process.env.REACT_APP_DEFAULT_CURRENCY || 'USD',
searchProvider: process.env.REACT_APP_SEARCH_PROVIDER || 'algolia',
shippingFee: 20,
freeShipping: 200,
epContextTag: 'EPCC',
'X-MOLTIN-SDK-LANGUAGE': 'JS',
'X-MOLTIN-SDK-VERSION': '0.0.0-semantic-release',
autoplaySpeed: 5000, // heroBanner auto play speed
}
54 changes: 54 additions & 0 deletions site/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as moltin from '@moltin/sdk'
import { config } from './config'

export const MoltinGateway = moltin.gateway
export const moltinParam = {
host: config.endpointURL,
client_id: config.clientId,
client_secret: config.clientSecret,
}

const imageHrefCache: { [key: string]: string } = {}

const imageMimeTypes = [
'image/jpg',
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'image/jp2',
'image/jxr',
]

// Loads a file with a provided id and returns its url if it's mime type is an image or undefined otherwise
export async function loadImageHref(
imageId: string
): Promise<string | undefined> {
if (imageHrefCache[imageId]) {
return imageHrefCache[imageId]
}

const moltin = MoltinGateway(moltinParam)
const result = await moltin.Files.Get(imageId)

if (imageMimeTypes.indexOf(result.data.mime_type) === -1) {
return undefined
}

imageHrefCache[imageId] = result.data.link.href

return result.data.link.href
}

export async function getProductById(
productId: string
): Promise<moltin.PcmProduct> {
const moltin = MoltinGateway({
host: config.endpointURL,
client_id: config.clientId,
client_secret: config.clientSecret,
})
const result = await moltin.PCM.Get(productId)
const product = result.data
return product
}
Loading