diff --git a/app/product/[...handle]/page.tsx b/app/product/[...handle]/page.tsx
index 573fe475b..f1ae3aa18 100644
--- a/app/product/[...handle]/page.tsx
+++ b/app/product/[...handle]/page.tsx
@@ -2,12 +2,11 @@ import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { Suspense } from 'react';
+import { AddToCart } from 'components/cart/add-to-cart';
import Grid from 'components/grid';
import Footer from 'components/layout/footer';
import ProductGridItems from 'components/layout/product-grid-items';
-import { AddToCart } from 'components/cart/add-to-cart';
import { Gallery } from 'components/product/gallery';
-import { VariantSelector } from 'components/product/variant-selector';
import Prose from 'components/prose';
import { HIDDEN_PRODUCT_TAG } from 'lib/constants';
import { getProduct, getProductRecommendations } from 'lib/shopware';
@@ -98,13 +97,13 @@ export default async function ProductPage({ params }: { params: { handle: string
-
+ {/*
*/}
{product.descriptionHtml ? (
) : null}
-
+
diff --git a/components/cart/actions.ts b/components/cart/actions.ts
index 5e5f2b2ea..b5a187971 100644
--- a/components/cart/actions.ts
+++ b/components/cart/actions.ts
@@ -1,17 +1,21 @@
'use server';
-import { addToCart, removeFromCart, updateCart } from 'lib/shopify';
+import { requestAddToCart, requestCart } from 'lib/shopware/api';
import { cookies } from 'next/headers';
+export const fetchCart = async (cartId?: string) => {
+ await requestCart(cartId);
+};
export const addItem = async (variantId: string | undefined): Promise => {
- const cartId = cookies().get('cartId')?.value;
+ const cartId = cookies().get('sw-context-token')?.value || '';
- if (!cartId || !variantId) {
+ if (!variantId) {
return new Error('Missing cartId or variantId');
}
try {
- await addToCart(cartId, [{ merchandiseId: variantId, quantity: 1 }]);
+ await requestAddToCart(variantId, cartId);
} catch (e) {
+ console.error('eeeee', e);
return new Error('Error adding item', { cause: e });
}
};
@@ -23,7 +27,7 @@ export const removeItem = async (lineId: string): Promise =>
return new Error('Missing cartId');
}
try {
- await removeFromCart(cartId, [lineId]);
+ //await removeFromCart(cartId, [lineId]);
} catch (e) {
return new Error('Error removing item', { cause: e });
}
@@ -44,14 +48,15 @@ export const updateItemQuantity = async ({
return new Error('Missing cartId');
}
try {
- await updateCart(cartId, [
- {
- id: lineId,
- merchandiseId: variantId,
- quantity
- }
- ]);
+ // await updateCart(cartId, [
+ // {
+ // id: lineId,
+ // merchandiseId: variantId,
+ // quantity
+ // }
+ // ]);
} catch (e) {
return new Error('Error updating item quantity', { cause: e });
}
};
+
diff --git a/components/cart/add-to-cart.tsx b/components/cart/add-to-cart.tsx
index eecee848e..5362ff590 100644
--- a/components/cart/add-to-cart.tsx
+++ b/components/cart/add-to-cart.tsx
@@ -7,13 +7,16 @@ import { useEffect, useState, useTransition } from 'react';
import LoadingDots from 'components/loading-dots';
import { ProductVariant } from 'lib/shopify/types';
+import { Product } from 'lib/shopware/types';
export function AddToCart({
+ product,
variants,
- availableForSale
+ availableForSale,
}: {
variants: ProductVariant[];
availableForSale: boolean;
+ product: Product
}) {
const [selectedVariantId, setSelectedVariantId] = useState(variants[0]?.id);
const router = useRouter();
@@ -39,12 +42,12 @@ export function AddToCart({
onClick={() => {
if (!availableForSale) return;
startTransition(async () => {
- const error = await addItem(selectedVariantId);
+ const error = await addItem(product.id);
- if (error) {
- alert(error);
- return;
- }
+ if (error) {
+ console.error(error);
+ return;
+ }
router.refresh();
});
diff --git a/components/cart/index.tsx b/components/cart/index.tsx
index ab2372af1..6a68685ff 100644
--- a/components/cart/index.tsx
+++ b/components/cart/index.tsx
@@ -1,11 +1,13 @@
+import { fetchCart } from 'components/cart/actions';
import { getCart } from 'lib/shopware';
import { cookies } from 'next/headers';
import CartModal from './modal';
export default async function Cart() {
const cartId = cookies().get('sw-context-token')?.value;
- let cartIdUpdated = true;
- const cart = await getCart();
+ await fetchCart(cartId);
+ let cartIdUpdated = false;
+ const cart = await getCart(cartId);
if (cartId !== cart.id) {
cartIdUpdated = true;
diff --git a/components/cart/modal.tsx b/components/cart/modal.tsx
index bb14abf2a..71deaa6a4 100644
--- a/components/cart/modal.tsx
+++ b/components/cart/modal.tsx
@@ -21,7 +21,7 @@ type MerchandiseSearchParams = {
};
export default function CartModal({ cart, cartIdUpdated }: { cart: Cart; cartIdUpdated: boolean }) {
- const [, setCookie] = useCookies(['cartId']);
+ const [, setCookie] = useCookies(['sw-context-token']);
const [isOpen, setIsOpen] = useState(false);
const quantityRef = useRef(cart.totalQuantity);
const openCart = () => setIsOpen(true);
@@ -29,7 +29,7 @@ export default function CartModal({ cart, cartIdUpdated }: { cart: Cart; cartIdU
useEffect(() => {
if (cartIdUpdated) {
- setCookie('cartId', cart.id, {
+ setCookie('sw-context-token', cart.id, {
path: '/',
sameSite: 'strict',
secure: process.env.NODE_ENV === 'production'
@@ -39,6 +39,7 @@ export default function CartModal({ cart, cartIdUpdated }: { cart: Cart; cartIdU
}, [setCookie, cartIdUpdated, cart.id]);
useEffect(() => {
+ console.warn('cart modal', cart);
// Open cart modal when when quantity changes.
if (cart.totalQuantity !== quantityRef.current) {
// But only if it's not already open (quantity also changes when editing items in cart).
diff --git a/lib/shopware/api.ts b/lib/shopware/api.ts
index 89c666674..ed73ee8b4 100644
--- a/lib/shopware/api.ts
+++ b/lib/shopware/api.ts
@@ -1,5 +1,6 @@
import { createAPIClient, RequestReturnType } from '@shopware/api-client';
import { operations } from '@shopware/api-client/api-types';
+import { cookies } from 'next/headers';
import {
ExtendedCategory,
ExtendedCriteria,
@@ -19,11 +20,19 @@ import {
const domainSW = `https://${process.env.SHOPWARE_STORE_DOMAIN!}/${process.env.SHOPWARE_API_TYPE!}`;
const accessTokenSW = `${process.env.SHOPWARE_ACCESS_TOKEN}`;
-const apiInstance = createAPIClient({
- baseURL: domainSW,
- accessToken: accessTokenSW,
- apiType: 'store-api'
-});
+function getApiClient(cartId?: string) {
+ const apiInstance = createAPIClient({
+ baseURL: domainSW,
+ accessToken: accessTokenSW,
+ apiType: 'store-api',
+ contextToken: cartId,
+ onContextChanged(newContextToken: string) {
+ //cookies().set('sw-context-token', newContextToken);
+ }
+ });
+
+ return apiInstance;
+}
// reimport operations return types to use it in application
export type ApiReturnType = RequestReturnType<
@@ -35,7 +44,7 @@ export async function requestNavigation(
type: StoreNavigationTypeSW,
depth: number
): Promise {
- return await apiInstance.invoke(
+ return await getApiClient(cookies().get('sw-context-token')).invoke(
'readNavigation post /navigation/{activeId}/{rootId} sw-include-seo-urls',
{
activeId: type,
@@ -49,7 +58,7 @@ export async function requestCategory(
categoryId: string,
criteria?: Partial
): Promise {
- return await apiInstance.invoke('readCategory post /category/{navigationId}?slots', {
+ return await getApiClient().invoke('readCategory post /category/{navigationId}?slots', {
navigationId: categoryId,
criteria
});
@@ -58,20 +67,20 @@ export async function requestCategory(
export async function requestCategoryList(
criteria: Partial
): Promise {
- return await apiInstance.invoke('readCategoryList post /category', criteria);
+ return await getApiClient().invoke('readCategoryList post /category', criteria);
}
export async function requestProductsCollection(
criteria: Partial
): Promise {
- return await apiInstance.invoke('readProduct post /product', criteria);
+ return await getApiClient().invoke('readProduct post /product', criteria);
}
export async function requestCategoryProductsCollection(
categoryId: string,
criteria: Partial
): Promise {
- return await apiInstance.invoke('readProductListing post /product-listing/{categoryId}', {
+ return await getApiClient().invoke('readProductListing post /product-listing/{categoryId}', {
...criteria,
categoryId: categoryId
});
@@ -80,14 +89,14 @@ export async function requestCategoryProductsCollection(
export async function requestSearchCollectionProducts(
criteria?: Partial
): Promise {
- return await apiInstance.invoke('searchPage post /search', {
+ return await getApiClient().invoke('searchPage post /search', {
search: encodeURIComponent(criteria?.query || ''),
...criteria
});
}
export async function requestSeoUrls(routeName: RouteNames, page: number = 1, limit: number = 100) {
- return await apiInstance.invoke('readSeoUrl post /seo-url', {
+ return await getApiClient().invoke('readSeoUrl post /seo-url', {
page: page,
limit: limit,
filter: [
@@ -105,7 +114,7 @@ export async function requestSeoUrl(
page: number = 1,
limit: number = 1
): Promise {
- return await apiInstance.invoke('readSeoUrl post /seo-url', {
+ return await getApiClient().invoke('readSeoUrl post /seo-url', {
page: page,
limit: limit,
filter: [
@@ -134,7 +143,7 @@ export async function requestCrossSell(
productId: string,
criteria?: Partial
): Promise {
- return await apiInstance.invoke(
+ return await getApiClient().invoke(
'readProductCrossSellings post /product/{productId}/cross-selling',
{
productId: productId,
@@ -143,6 +152,26 @@ export async function requestCrossSell(
);
}
-export async function requestCart() {
- return apiInstance.invoke('readCart get /checkout/cart?name', {});
+export async function requestCart(cartId?: string) {
+ return getApiClient(cartId).invoke('readCart get /checkout/cart?name', {});
+}
+
+export async function requestContext(cartId?: string) {
+ return getApiClient(cartId).invoke('readCart get /checkout/cart?name', {});
+}
+
+export async function requestAddToCart(itemId: string, cartId: string) {
+ try {
+ return getApiClient(cartId).invoke('addLineItem post /checkout/cart/line-item', {
+ items: [
+ {
+ referencedId: itemId,
+ quantity: 1,
+ type: 'product'
+ }
+ ]
+ });
+ } catch (e) {
+ console.error('e', e);
+ }
}
\ No newline at end of file
diff --git a/lib/shopware/index.ts b/lib/shopware/index.ts
index b5938c8ed..a7a7fe1b4 100644
--- a/lib/shopware/index.ts
+++ b/lib/shopware/index.ts
@@ -217,8 +217,8 @@ export async function getProductRecommendations(productId: string): Promise {
- const cartData = await requestCart();
+export async function getCart(cartId?: string): Promise {
+ const cartData = await requestCart(cartId);
let cart: Cart = {
checkoutUrl: 'https://frontends-demo.vercel.app',
@@ -260,7 +260,10 @@ export async function getCart(): Promise {
title: lineItem.label
},
availableForSale: true,
- featuredImage: (lineItem as any).cover?.url,
+ featuredImage: {
+ altText: 'Cover image of ' + lineItem.label,
+ url: (lineItem as any).cover?.url
+ },
handle: '',
options: [],
variants: [],
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 169c48afc..dcd7e05f8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10,7 +10,7 @@ dependencies:
version: 1.7.15(react-dom@18.2.0)(react@18.2.0)
'@shopware/api-client':
specifier: 0.0.0-canary-20230706101754
- version: 0.0.0-canary-20230706101754
+ version: link:../../frontends/packages/api-client-next
'@vercel/og':
specifier: ^0.5.8
version: 0.5.8
@@ -379,12 +379,6 @@ packages:
resolution: {integrity: sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==}
dev: true
- /@shopware/api-client@0.0.0-canary-20230706101754:
- resolution: {integrity: sha512-h7nCTWVu6bLbxdKT8vEJcUVKVu/RveaZ3M1PxrQAMiP6b2nQeqRh5+QlqTEFGk+Middy11MINH70Wp6GMx+Y+A==}
- dependencies:
- ofetch: 1.1.1
- dev: false
-
/@shuding/opentype.js@1.4.0-beta.0:
resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
engines: {node: '>= 8.0.0'}
@@ -1046,10 +1040,6 @@ packages:
engines: {node: '>=6'}
dev: true
- /destr@2.0.0:
- resolution: {integrity: sha512-FJ9RDpf3GicEBvzI3jxc2XhHzbqD8p4ANw/1kPsFBfTvP1b7Gn/Lg1vO7R9J4IVgoMbyUmFrFGZafJ1hPZpvlg==}
- dev: false
-
/didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
dev: true
@@ -2383,10 +2373,6 @@ packages:
- babel-plugin-macros
dev: false
- /node-fetch-native@1.2.0:
- resolution: {integrity: sha512-5IAMBTl9p6PaAjYCnMv5FmqIF6GcZnawAVnzaCG0rX2aYZJ4CxEkZNtVPuTRug7fL7wyM5BQYTlAzcyMPi6oTQ==}
- dev: false
-
/node-releases@2.0.12:
resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==}
dev: true
@@ -2486,14 +2472,6 @@ packages:
es-abstract: 1.21.2
dev: true
- /ofetch@1.1.1:
- resolution: {integrity: sha512-SSMoktrp9SNLi20BWfB/BnnKcL0RDigXThD/mZBeQxkIRv1xrd9183MtLdsqRYLYSqW0eTr5t8w8MqjNhvoOQQ==}
- dependencies:
- destr: 2.0.0
- node-fetch-native: 1.2.0
- ufo: 1.1.2
- dev: false
-
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@@ -3457,10 +3435,6 @@ packages:
hasBin: true
dev: true
- /ufo@1.1.2:
- resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==}
- dev: false
-
/unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
dependencies: