From db63db13318e0bb4a70d0d18944974a0396fda08 Mon Sep 17 00:00:00 2001 From: Kristian Arvidsson <124673544+arvidsson-geins@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:24:28 +0100 Subject: [PATCH] feat/add-geins-as-provider (#1) * feat: add geins as provider --- .env.example | 22 +- README.md | 95 +- app/[page]/opengraph-image.tsx | 2 +- app/[page]/page.tsx | 6 +- app/api/revalidate/route.ts | 2 +- app/layout.tsx | 2 +- app/product/[handle]/page.tsx | 12 +- app/search/[collection]/opengraph-image.tsx | 2 +- app/search/[collection]/page.tsx | 4 +- app/search/page.tsx | 2 +- app/sitemap.ts | 11 +- components/carousel.tsx | 4 +- components/cart/actions.ts | 4 +- components/cart/add-to-cart.tsx | 8 +- components/cart/cart-context.tsx | 31 +- components/cart/delete-item-button.tsx | 4 +- components/cart/edit-item-quantity-button.tsx | 4 +- components/grid/three-items.tsx | 6 +- components/icons/geins.tsx | 81 + components/layout/footer-menu.tsx | 8 +- components/layout/footer.tsx | 11 +- components/layout/navbar/index.tsx | 6 +- components/layout/navbar/mobile-menu.tsx | 6 +- components/layout/product-grid-items.tsx | 4 +- components/layout/search/collections.tsx | 2 +- components/price.tsx | 4 +- components/product/product-description.tsx | 4 +- components/product/variant-selector.tsx | 6 +- components/prose.tsx | 1 + components/welcome-toast.tsx | 2 +- lib/geins/cms.ts | 26 + lib/geins/constants.ts | 9 + lib/geins/index.ts | 214 ++ lib/geins/oms.ts | 102 + lib/geins/pim.ts | 151 + lib/geins/queries/fragments/campaign.ts | 7 + lib/geins/queries/fragments/cart.ts | 107 + lib/geins/queries/fragments/list-info.ts | 26 + lib/geins/queries/fragments/list-product.ts | 32 + lib/geins/queries/fragments/meta.ts | 7 + lib/geins/queries/fragments/price.ts | 16 + lib/geins/queries/fragments/sku.ts | 14 + lib/geins/queries/fragments/stock.ts | 10 + lib/geins/queries/fragments/variant.ts | 22 + lib/geins/queries/mutations/cart-add.ts | 22 + .../queries/mutations/cart-line-update.ts | 22 + lib/geins/queries/mutations/checkout.ts | 21 + lib/geins/queries/queries/cart-create.ts | 10 + lib/geins/queries/queries/cart-get.ts | 10 + lib/geins/queries/queries/categories.ts | 22 + lib/geins/queries/queries/listPageInfo.ts | 10 + lib/geins/queries/queries/product.ts | 92 + lib/geins/queries/queries/products-related.ts | 43 + lib/geins/queries/queries/products.ts | 38 + lib/geins/reshape.ts | 439 +++ lib/geins/types.ts | 184 ++ lib/shopify/fragments/cart.ts | 53 - lib/shopify/fragments/image.ts | 10 - lib/shopify/fragments/product.ts | 64 - lib/shopify/fragments/seo.ts | 8 - lib/shopify/index.ts | 455 --- lib/shopify/mutations/cart.ts | 45 - lib/shopify/queries/cart.ts | 10 - lib/shopify/queries/collection.ts | 56 - lib/shopify/queries/menu.ts | 10 - lib/shopify/queries/page.ts | 41 - lib/shopify/queries/product.ts | 32 - lib/shopify/types.ts | 272 -- next.config.ts | 9 +- package.json | 8 +- pnpm-lock.yaml | 991 ++++-- repopack-output.txt | 164 + yarn.lock | 2927 +++++++++++++++++ 73 files changed, 5702 insertions(+), 1465 deletions(-) create mode 100644 components/icons/geins.tsx create mode 100644 lib/geins/cms.ts create mode 100644 lib/geins/constants.ts create mode 100644 lib/geins/index.ts create mode 100644 lib/geins/oms.ts create mode 100644 lib/geins/pim.ts create mode 100644 lib/geins/queries/fragments/campaign.ts create mode 100644 lib/geins/queries/fragments/cart.ts create mode 100644 lib/geins/queries/fragments/list-info.ts create mode 100644 lib/geins/queries/fragments/list-product.ts create mode 100644 lib/geins/queries/fragments/meta.ts create mode 100644 lib/geins/queries/fragments/price.ts create mode 100644 lib/geins/queries/fragments/sku.ts create mode 100644 lib/geins/queries/fragments/stock.ts create mode 100644 lib/geins/queries/fragments/variant.ts create mode 100644 lib/geins/queries/mutations/cart-add.ts create mode 100644 lib/geins/queries/mutations/cart-line-update.ts create mode 100644 lib/geins/queries/mutations/checkout.ts create mode 100644 lib/geins/queries/queries/cart-create.ts create mode 100644 lib/geins/queries/queries/cart-get.ts create mode 100644 lib/geins/queries/queries/categories.ts create mode 100644 lib/geins/queries/queries/listPageInfo.ts create mode 100644 lib/geins/queries/queries/product.ts create mode 100644 lib/geins/queries/queries/products-related.ts create mode 100644 lib/geins/queries/queries/products.ts create mode 100644 lib/geins/reshape.ts create mode 100644 lib/geins/types.ts delete mode 100644 lib/shopify/fragments/cart.ts delete mode 100644 lib/shopify/fragments/image.ts delete mode 100644 lib/shopify/fragments/product.ts delete mode 100644 lib/shopify/fragments/seo.ts delete mode 100644 lib/shopify/index.ts delete mode 100644 lib/shopify/mutations/cart.ts delete mode 100644 lib/shopify/queries/cart.ts delete mode 100644 lib/shopify/queries/collection.ts delete mode 100644 lib/shopify/queries/menu.ts delete mode 100644 lib/shopify/queries/page.ts delete mode 100644 lib/shopify/queries/product.ts delete mode 100644 lib/shopify/types.ts create mode 100644 repopack-output.txt create mode 100644 yarn.lock diff --git a/.env.example b/.env.example index 9ff0463db..8d5d70b69 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,15 @@ -COMPANY_NAME="Vercel Inc." -TWITTER_CREATOR="@vercel" -TWITTER_SITE="https://nextjs.org/commerce" -SITE_NAME="Next.js Commerce" -SHOPIFY_REVALIDATION_SECRET="" -SHOPIFY_STOREFRONT_ACCESS_TOKEN="" -SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com" +COMPANY_NAME= # Company name for eg. Geins +SITE_NAME= # Site name for eg. Geins Store +GEINS_API_KEY= # API key from Geins for eg. XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX +GEINS_ACCOUNT_NAME= # Account name from geins for eg. acme +GEINS_CHANNEL= # Channel Id from Geins for eg. 1 +GEINS_TLD= # Top-level domain for eg. com +GEINS_LOCALE= # Locale for eg. en-US +GEINS_MARKET= # Market for eg. us +GEINS_ENVIRONMENT= # Environment for eg. qa, prod +GEINS_PRODUCT_DESCRIPTION_SHORT_TEXT= # Property for Product description from Geins for eg. text1, text2, text3 default is text2 +GEINS_CURRENCY_CODE= # Currency code for eg. USD +GEINS_PAYMENT_ID= # Payment ID from Geins for desired checkout for eg. 23 +GEINS_USE_CATEGORY_FOR_RECOMMENDATIONS_BACKUP= # Use category for recommendations backup on PDP true/false defalut is true +GEINS_SKU_DEFAULT_VARIATION= # Default variation for SKU for eg. Size +GEINS_REVALIDATION_SECRET= # Revalidation secret from your Geins webhook for eg. XYZ123-123-123 \ No newline at end of file diff --git a/README.md b/README.md index 6fcd72685..89cda3633 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,72 @@ -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&env=COMPANY_NAME,SHOPIFY_REVALIDATION_SECRET,SHOPIFY_STORE_DOMAIN,SHOPIFY_STOREFRONT_ACCESS_TOKEN,SITE_NAME,TWITTER_CREATOR,TWITTER_SITE) +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fgeins-io%2Fvercel-nextjs-commerce&env=GEINS_API_KEY,GEINS_ACCOUNT_NAME,GEINS_CHANNEL,GEINS_TLD,GEINS_LOCALE,GEINS_MARKET,GEINS_IMAGE_URL,GEINS_CURRENCY_CODE,GEINS_CHECKOUT_ID&envDescription=Read%20more%20about%20environment%20varibles%20in%20the%20example%20file&envLink=https%3A%2F%2Fgithub.com%2Fgeins-io%2Fvercel-nextjs-commerce%2Fblob%2Fmain%2F.env.example&project-name=geins-nextjs-commerce-starter&repository-name=geins-nextjs-commerce-starter&demo-title=Geins%20Next.js%20Commerce%20Starter&demo-description=Commerce%20website%20created%20with%20Next.js&demo-url=http%3A%2F%2Fgeins.io&demo-image=avatars.githubusercontent.com%2Fu%2F123540473) -# Next.js Commerce +# Next.js Commerce x Geins -A high-performance, server-rendered Next.js App Router ecommerce application. +A high-performance, server-rendered Next.js (15 RC) App Router ecommerce application. -This template uses React Server Components, Server Actions, `Suspense`, `useOptimistic`, and more. +This template showcases the integration of [Geins Commerce API](https://docs.geins.io) with [Next.js Commerce](https://github.com/vercel/commerce), leveraging the open-source [Geins SDK](https://github.com/geins-io/geins). -

+## Features -> Note: Looking for Next.js Commerce v1? View the [code](https://github.com/vercel/commerce/tree/v1), [demo](https://commerce-v1.vercel.store), and [release notes](https://github.com/vercel/commerce/releases/tag/v1). +- **React Server Components**: Build fast and scalable UIs with Next.js's server-first approach. +- **Server Actions**: Simplify backend logic and data fetching. +- **Modern React APIs**: Including `Suspense` and `useOptimistic`. +- **Integration with Geins**: Harness the power of Geins for exceptional ecommerce capabilities. -## Providers +## What is Geins? -Vercel will only be actively maintaining a Shopify version [as outlined in our vision and strategy for Next.js Commerce](https://github.com/vercel/commerce/pull/966). +[Geins](https://geins.io/) is the ultimate toolkit for modern commerce. With Geins, developers and agencies can craft unique, tailored shopping experiences using: -Vercel is happy to partner and work with any commerce provider to help them get a similar template up and running and listed below. Alternative providers should be able to fork this repository and swap out the `lib/shopify` file with their own implementation while leaving the rest of the template mostly unchanged. +- A hybrid model combining the reliability of a managed platform with open-source flexibility. +- A robust API-first approach enabling precise customization. +- Features for managing channels, content, CRM, events, and more. -- Shopify (this repository) -- [BigCommerce](https://github.com/bigcommerce/nextjs-commerce) ([Demo](https://next-commerce-v2.vercel.app/)) -- [Ecwid by Lightspeed](https://github.com/Ecwid/ecwid-nextjs-commerce/) ([Demo](https://ecwid-nextjs-commerce.vercel.app/)) -- [Medusa](https://github.com/medusajs/vercel-commerce) ([Demo](https://medusa-nextjs-commerce.vercel.app/)) -- [Saleor](https://github.com/saleor/nextjs-commerce) ([Demo](https://saleor-commerce.vercel.app/)) -- [Shopware](https://github.com/shopwareLabs/vercel-commerce) ([Demo](https://shopware-vercel-commerce-react.vercel.app/)) -- [Swell](https://github.com/swellstores/verswell-commerce) ([Demo](https://verswell-commerce.vercel.app/)) -- [Umbraco](https://github.com/umbraco/Umbraco.VercelCommerce.Demo) ([Demo](https://vercel-commerce-demo.umbraco.com/)) -- [Wix](https://github.com/wix/nextjs-commerce) ([Demo](https://wix-nextjs-commerce.vercel.app/)) -- [Fourthwall](https://github.com/FourthwallHQ/vercel-commerce) ([Demo](https://vercel-storefront.fourthwall.app/)) +Explore the [Geins Commerce API documentation](https://docs.geins.io) for detailed usage instructions and capabilities. -> Note: Providers, if you are looking to use similar products for your demo, you can [download these assets](https://drive.google.com/file/d/1q_bKerjrwZgHwCw0ovfUMW6He9VtepO_/view?usp=sharing). +## Getting Started -## Integrations +To run this application locally, follow these steps: -Integrations enable upgraded or additional functionality for Next.js Commerce +### Prerequisites -- [Orama](https://github.com/oramasearch/nextjs-commerce) ([Demo](https://vercel-commerce.oramasearch.com/)) +Ensure you have the following installed: - - Upgrades search to include typeahead with dynamic re-rendering, vector-based similarity search, and JS-based configuration. - - Search runs entirely in the browser for smaller catalogs or on a CDN for larger. +- [Node.js](https://nodejs.org/) (v20 or later) +- [Geins API-Key](https://geins.io/) -- [React Bricks](https://github.com/ReactBricks/nextjs-commerce-rb) ([Demo](https://nextjs-commerce.reactbricks.com/)) - - Edit pages, product details, and footer content visually using [React Bricks](https://www.reactbricks.com) visual headless CMS. +### Environment Variables -## Running locally +Set up your environment variables as defined in `.env.example`. It's recommended to use [Vercel's Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for secure storage. -You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js Commerce. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for this, but a `.env` file is all that is necessary. +> ⚠️ **Important**: Never commit your `.env` file to version control. -> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control your Shopify store. +### Steps to Run Locally -1. Install Vercel CLI: `npm i -g vercel` -2. Link local instance with Vercel and GitHub accounts (creates `.vercel` directory): `vercel link` -3. Download your environment variables: `vercel env pull` +1. Clone this repository: -```bash -pnpm install -pnpm dev -``` + ```bash + git clone https://github.com/geins-io/vercel-nextjs-commerce.git + cd + ``` -Your app should now be running on [localhost:3000](http://localhost:3000/). +2. Install dependencies: -
- Expand if you work at Vercel and want to run locally and / or contribute + ```bash + pnpm install + ``` -1. Run `vc link`. -1. Select the `Vercel Solutions` scope. -1. Connect to the existing `commerce-shopify` project. -1. Run `vc env pull` to get environment variables. -1. Run `pnpm dev` to ensure everything is working correctly. -
+3. Link your local instance with Vercel and pull environment variables: -## Vercel, Next.js Commerce, and Shopify Integration Guide + ```bash + npm i -g vercel + vercel link + vercel env pull + ``` -You can use this comprehensive [integration guide](https://vercel.com/docs/integrations/ecommerce/shopify) with step-by-step instructions on how to configure Shopify as a headless CMS using Next.js Commerce as your headless Shopify storefront on Vercel. +4. Start the development server: + + ```bash + pnpm dev + ``` + +5. Access the app on [http://localhost:3000](http://localhost:3000). diff --git a/app/[page]/opengraph-image.tsx b/app/[page]/opengraph-image.tsx index 2fd59281e..70e9a057e 100644 --- a/app/[page]/opengraph-image.tsx +++ b/app/[page]/opengraph-image.tsx @@ -1,5 +1,5 @@ import OpengraphImage from 'components/opengraph-image'; -import { getPage } from 'lib/shopify'; +import { getPage } from 'lib/geins'; export const runtime = 'edge'; diff --git a/app/[page]/page.tsx b/app/[page]/page.tsx index aa0c15603..7a2ef51ab 100644 --- a/app/[page]/page.tsx +++ b/app/[page]/page.tsx @@ -1,7 +1,6 @@ -import type { Metadata } from 'next'; - import Prose from 'components/prose'; -import { getPage } from 'lib/shopify'; +import { getPage } from 'lib/geins'; +import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; export async function generateMetadata(props: { @@ -33,6 +32,7 @@ export default async function Page(props: { params: Promise<{ page: string }> }) <>

{page.title}

+

{`This document was last updated on ${new Intl.DateTimeFormat(undefined, { year: 'numeric', diff --git a/app/api/revalidate/route.ts b/app/api/revalidate/route.ts index 4ecc0b45d..275bac9e1 100644 --- a/app/api/revalidate/route.ts +++ b/app/api/revalidate/route.ts @@ -1,4 +1,4 @@ -import { revalidate } from 'lib/shopify'; +import { revalidate } from 'lib/geins'; import { NextRequest, NextResponse } from 'next/server'; export async function POST(req: NextRequest): Promise { diff --git a/app/layout.tsx b/app/layout.tsx index 348adcecb..d71d08115 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,7 +2,7 @@ import { CartProvider } from 'components/cart/cart-context'; import { Navbar } from 'components/layout/navbar'; import { WelcomeToast } from 'components/welcome-toast'; import { GeistSans } from 'geist/font/sans'; -import { getCart } from 'lib/shopify'; +import { getCart } from 'lib/geins'; import { ensureStartsWith } from 'lib/utils'; import { cookies } from 'next/headers'; import { ReactNode } from 'react'; diff --git a/app/product/[handle]/page.tsx b/app/product/[handle]/page.tsx index 295b8b005..6d04987f9 100644 --- a/app/product/[handle]/page.tsx +++ b/app/product/[handle]/page.tsx @@ -7,8 +7,8 @@ import { Gallery } from 'components/product/gallery'; import { ProductProvider } from 'components/product/product-context'; import { ProductDescription } from 'components/product/product-description'; import { HIDDEN_PRODUCT_TAG } from 'lib/constants'; -import { getProduct, getProductRecommendations } from 'lib/shopify'; -import { Image } from 'lib/shopify/types'; +import { getProduct, getProductRecommendations } from 'lib/geins'; +import { ProductImageType, ProductType } from 'lib/geins/types'; import Link from 'next/link'; import { Suspense } from 'react'; @@ -89,7 +89,7 @@ export default async function ProductPage(props: { params: Promise<{ handle: str } > ({ + images={product.images.slice(0, 5).map((image: ProductImageType) => ({ src: image.url, altText: image.altText }))} @@ -103,15 +103,15 @@ export default async function ProductPage(props: { params: Promise<{ handle: str - +