Skip to content

Commit

Permalink
Added example with salesforce commerce cloud (#41376)
Browse files Browse the repository at this point in the history
Adding a Next.js example with Salesforce Commerce Cloud

Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
  • Loading branch information
Nutlope and ijjk committed Oct 13, 2022
1 parent e1cb7f7 commit af739ed
Show file tree
Hide file tree
Showing 19 changed files with 429 additions and 0 deletions.
5 changes: 5 additions & 0 deletions examples/with-sfcc/.env.local.example
@@ -0,0 +1,5 @@
SFDC_CLIENT_ID=
SFDC_SECRET=
SFDC_ORGANIZATIONID=
SFDC_SHORTCODE=
SFDC_SITEID=
35 changes: 35 additions & 0 deletions examples/with-sfcc/.gitignore
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
31 changes: 31 additions & 0 deletions examples/with-sfcc/README.md
@@ -0,0 +1,31 @@
# Example Next.js app with Salesforce Commerce Cloud

This example shows how to create a headless ecommerce application using Next.js, [Salesforce commerce cloud](https://www.salesforce.com/products/commerce-cloud/overview/), and [Tailwind](https://tailwindcss.com).

## Deploy your own

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) or view the demo [here](https://salesforce-cloud-commerce.vercel.app/)

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-sfcc&project-name=with-sfcc&repository-name=with-sfcc&env=SFDC_CLIENT_ID,SFDC_SECRET,SFDC_ORGANIZATIONID,SFDC_SHORTCODE,SFDC_SITEID&envDescription=API%20Keys%20from%20SFCC%20needed%20to%20run%20this%20application.)

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/with-sfcc) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example::

```bash
npx create-next-app --example with-sfcc nextjs-sfcc-app
```

```bash
yarn create next-app --example with-sfcc nextjs-sfcc-app
```

```bash
pnpm create next-app --example with-sfcc nextjs-sfcc-app
```

## References

- SDK: https://github.com/SalesforceCommerceCloud/commerce-sdk
41 changes: 41 additions & 0 deletions examples/with-sfcc/components/Header.js
@@ -0,0 +1,41 @@
import Image from 'next/future/image'

export default function Header({ scrollHandler }) {
return (
<header className="relative">
<div className="absolute inset-x-0 bottom-0 h-1/2 bg-gray-100" />
<div className="mx-auto">
<div className="relative shadow-xl sm:overflow-hidden">
<div className="absolute inset-0">
<Image
priority
fill
className="h-full w-full object-cover"
src="/hero.jpg"
alt="Coffee grinder"
/>
<div className="absolute inset-0 bg-orange-100 mix-blend-multiply" />
</div>
<div className="relative px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8">
<p className="relative left-0 right-0 mx-auto mt-5 max-w-xl text-center text-xl font-semibold uppercase tracking-wide text-orange-600">
The Coffee House
</p>
<h1 className="mt-1 text-center font-bold uppercase text-gray-900 sm:text-5xl sm:tracking-tight lg:text-7xl">
<span className="block text-white">Life is better with</span>
<span className="block text-orange-500">coffee</span>
</h1>

<div className="mx-auto mt-10 max-w-xs sm:flex sm:max-w-none sm:justify-center">
<button
className="flex items-center justify-center rounded-md border border-transparent bg-white px-4 py-3 text-base font-medium text-orange-600 shadow-sm hover:bg-orange-100 sm:px-8"
onClick={scrollHandler}
>
Shop coffees
</button>
</div>
</div>
</div>
</div>
</header>
)
}
39 changes: 39 additions & 0 deletions examples/with-sfcc/components/ProductCard.js
@@ -0,0 +1,39 @@
import Image from 'next/future/image'
import Link from 'next/link'
import { useState } from 'react'

function cn(...classes) {
return classes.filter(Boolean).join(' ')
}

export default function ProductCard({ product }) {
const [isLoading, setLoading] = useState(true)

return (
<Link href={`/products/${product.id}`}>
<a className="group">
<div className="aspect-w-1 aspect-h-1 w-full overflow-hidden rounded-lg bg-gray-200 xl:aspect-w-7 xl:aspect-h-8">
<Image
alt=""
src={product.imageGroups[0].images[0].link}
fill
className={cn(
'object-cover duration-700 ease-in-out group-hover:opacity-75 ',
isLoading
? 'scale-110 blur-2xl grayscale'
: 'scale-100 blur-0 grayscale-0'
)}
onLoadingComplete={() => setLoading(false)}
/>
</div>
<div className="mt-4 flex items-center justify-between text-base font-medium text-gray-900">
<h3>{product.name}</h3>
<p>${product.price}</p>
</div>
<p className="mt-1 text-sm italic text-gray-500">
{product.shortDescription}
</p>
</a>
</Link>
)
}
17 changes: 17 additions & 0 deletions examples/with-sfcc/components/layout.js
@@ -0,0 +1,17 @@
export default function Layout({ children }) {
return (
<>
<main>{children}</main>
<footer className="center mt-5 flex justify-center space-x-4 bg-[#E7E8EF] p-4 text-xs">
<p>Powered by Next.js, Salesforce Commerce Cloud, and Vercel </p>
<span>|</span>
<a
href="https://github.com/vercel/next.js/tree/canary/examples/with-sfcc"
className="font-medium text-orange-600"
>
Source code
</a>
</footer>
</>
)
}
6 changes: 6 additions & 0 deletions examples/with-sfcc/next.config.js
@@ -0,0 +1,6 @@
module.exports = {
reactStrictMode: true,
images: {
domains: ['zzte-003.sandbox.us02.dx.commercecloud.salesforce.com'],
},
}
23 changes: 23 additions & 0 deletions examples/with-sfcc/package.json
@@ -0,0 +1,23 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"commerce-sdk": "^2.8.0",
"next": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@tailwindcss/aspect-ratio": "^0.4.0",
"@types/node": "17.0.4",
"@types/react": "17.0.38",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.5",
"tailwindcss": "^3.0.7",
"typescript": "4.5.4"
}
}
18 changes: 18 additions & 0 deletions examples/with-sfcc/pages/_app.js
@@ -0,0 +1,18 @@
import '../styles/globals.css'
import Layout from '../components/layout'
import Head from 'next/head'

function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<title>The Coffee House</title>
</Head>
<Layout>
<Component {...pageProps} />
</Layout>
</>
)
}

export default MyApp
23 changes: 23 additions & 0 deletions examples/with-sfcc/pages/_document.js
@@ -0,0 +1,23 @@
import { Head, Html, Main, NextScript } from 'next/document'

export default function Document() {
return (
<Html lang="en">
<Head>
<meta
name="description"
content="The premiere coffee delivery service."
/>
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet"
/>
</Head>

<body>
<Main />
<NextScript />
</body>
</Html>
)
}
50 changes: 50 additions & 0 deletions examples/with-sfcc/pages/index.js
@@ -0,0 +1,50 @@
import { useRef } from 'react'
import Header from '../components/Header'
import ProductCard from '../components/ProductCard'
import getProducts from '../sfcc.js'

export default function Gallery({ data }) {
let coffeeRef = useRef()

const scrollHandler = (e) => {
e.preventDefault()
coffeeRef.scrollIntoView({
behavior: 'smooth',
block: 'start',
})
}

return (
<>
<Header scrollHandler={scrollHandler} />
<div className="mx-auto max-w-2xl px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<div className="sm:py-15 mx-auto max-w-7xl py-16 px-4 sm:px-6 lg:px-8">
<div className="text-center">
<p
className="mt-1 text-4xl font-bold uppercase text-gray-900 sm:text-5xl sm:tracking-tight lg:text-5xl"
ref={(element) => (coffeeRef = element)}
>
Crafted by us, for you
</p>
</div>
</div>
<div className="grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
{data &&
data.map((product) => (
<ProductCard product={product} key={product.id} />
))}
</div>
</div>
</>
)
}

export async function getStaticProps() {
const searchResults = await getProducts('coffee')

return {
props: {
data: searchResults,
},
}
}
60 changes: 60 additions & 0 deletions examples/with-sfcc/pages/products/[slug].js
@@ -0,0 +1,60 @@
import Image from 'next/future/image'
import getProducts from '../../sfcc.js'

export default function Product({ product }) {
return (
<div className="flex h-screen flex-col justify-between">
<div className="mx-auto mt-16 max-w-2xl px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<div className="mx-auto flex flex-col sm:flex-row">
<Image
alt="coffee"
className="rounded-lg"
src={product.imageGroups[0].images[0].link}
width={560}
height={640}
/>
<div className="mt-10 flex flex-col sm:mt-0 sm:ml-10">
<h1 className="mt-1 text-4xl font-bold uppercase text-gray-900 sm:text-5xl sm:tracking-tight lg:text-5xl">
{product.name}
</h1>
<h1 className="mt-3 text-4xl font-bold text-gray-500 sm:text-3xl sm:tracking-tight lg:text-3xl">
${product.price}
</h1>
<div className="mt-10 mb-5 border-t border-gray-200 pt-10 font-bold">
Description
</div>
<p className="max-w-xl">{product.longDescription}</p>
</div>
</div>
</div>
</div>
)
}

export async function getStaticProps({ params }) {
const searchResults = await getProducts(params.slug)
console.log('search Results are: ', searchResults)

const coffeeProduct = searchResults[0]
return {
props: {
product: coffeeProduct,
},
}
}

export async function getStaticPaths() {
const searchResults = await getProducts('coffee')

let coffeeProducts = searchResults

let fullPaths = []
for (let product of coffeeProducts) {
fullPaths.push({ params: { slug: product.id } })
}

return {
paths: fullPaths,
fallback: 'blocking',
}
}
6 changes: 6 additions & 0 deletions examples/with-sfcc/postcss.config.js
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Binary file added examples/with-sfcc/public/favicon.ico
Binary file not shown.
Binary file added examples/with-sfcc/public/hero.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions examples/with-sfcc/public/vercel.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit af739ed

Please sign in to comment.