create-cartbase 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/template/app/docs/BUILD-A-STOREFRONT.md +6 -6
- package/template/app/docs/README.md +77 -76
- package/template/app/docs/auth.md +1 -1
- package/template/app/docs/carts.md +6 -6
- package/template/app/docs/categories.md +1 -1
- package/template/app/docs/checkout.md +127 -76
- package/template/app/docs/collections.md +1 -1
- package/template/app/docs/components.md +59 -60
- package/template/app/docs/consent.md +1 -1
- package/template/app/docs/content.md +1 -1
- package/template/app/docs/customers.md +1 -1
- package/template/app/docs/deploy.md +5 -5
- package/template/app/docs/gift-cards.md +1 -1
- package/template/app/docs/integrations.md +1 -1
- package/template/app/docs/menus.md +1 -1
- package/template/app/docs/metaobjects.md +1 -1
- package/template/app/docs/orders.md +1 -1
- package/template/app/docs/platform.md +126 -0
- package/template/app/docs/products.md +1 -1
- package/template/app/docs/redirects.md +1 -1
- package/template/app/docs/regions.md +5 -6
- package/template/app/docs/reviews.md +1 -1
- package/template/app/docs/search.md +1 -1
- package/template/app/docs/subscriptions.md +1 -1
- package/template/app/docs/variables.md +315 -0
- package/template/app/next-env.d.ts +6 -0
- package/template/app/next.config.ts +3 -3
- package/template/app/package.json +1 -1
- package/template/app/smoke.mjs +1 -1
- package/template/app/src/app/checkout/checkout-page-client.tsx +26 -10
- package/template/app/src/app/checkout/mypos-demo-tab.tsx +101 -0
- package/template/app/src/app/checkout/page.tsx +5 -6
- package/template/app/src/app/layout.tsx +113 -105
- package/template/app/src/app/order/[id]/confirmed/page.tsx +5 -4
- package/template/app/src/lib/cart-actions.ts +47 -43
- package/template/app/src/lib/config.ts +10 -5
- package/template/app/tsconfig.tsbuildinfo +1 -1
|
@@ -1,105 +1,113 @@
|
|
|
1
|
-
import type { Metadata } from "next"
|
|
2
|
-
import Link from "next/link"
|
|
3
|
-
import { cookies } from "next/headers"
|
|
4
|
-
import { retrieveCart, type Cart } from "@cartbase/storefront/api/carts"
|
|
5
|
-
import { getConsent } from "@cartbase/storefront/api/consent"
|
|
6
|
-
import { getMenu, type Menu } from "@cartbase/storefront/api/menus"
|
|
7
|
-
import { ConsentInit } from "@cartbase/storefront/tracking/consent-init"
|
|
8
|
-
import { CartButtonClient } from "@cartbase/storefront/common/cart-button-client"
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import "./
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{item.title}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import Link from "next/link"
|
|
3
|
+
import { cookies } from "next/headers"
|
|
4
|
+
import { retrieveCart, type Cart } from "@cartbase/storefront/api/carts"
|
|
5
|
+
import { getConsent } from "@cartbase/storefront/api/consent"
|
|
6
|
+
import { getMenu, type Menu } from "@cartbase/storefront/api/menus"
|
|
7
|
+
import { ConsentInit } from "@cartbase/storefront/tracking/consent-init"
|
|
8
|
+
import { CartButtonClient } from "@cartbase/storefront/common/cart-button-client"
|
|
9
|
+
import { createStorefrontMetadata, PlatformInit } from "@cartbase/storefront/platform"
|
|
10
|
+
import { BARTER_CLIENT_ID, readCartCookie } from "@/lib/config"
|
|
11
|
+
import { getServerClient } from "@/lib/server-client"
|
|
12
|
+
import { Providers } from "./providers"
|
|
13
|
+
import "./globals.css"
|
|
14
|
+
|
|
15
|
+
// createStorefrontMetadata (platform-fingerprints card) stamps
|
|
16
|
+
// `<meta name="generator" content="Cartbase" />` on every page — never
|
|
17
|
+
// hand-write `generator` here.
|
|
18
|
+
export const metadata: Metadata = createStorefrontMetadata({
|
|
19
|
+
title: "Barter Example Store",
|
|
20
|
+
description: "Reference storefront built on @cartbase/storefront",
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Runbook steps 3–4: bootstrap store config at layout level, then mount
|
|
25
|
+
* order inside <body>: ConsentInit FIRST (static, synchronous), then the
|
|
26
|
+
* consent-gated UI, then navigation. A store with no menus 404s every
|
|
27
|
+
* handle — render no nav, never crash (menus.md).
|
|
28
|
+
*/
|
|
29
|
+
async function fetchMenu(handle: string): Promise<Menu | null> {
|
|
30
|
+
const client = await getServerClient()
|
|
31
|
+
try {
|
|
32
|
+
const { menu } = await getMenu(client, handle)
|
|
33
|
+
return menu
|
|
34
|
+
} catch {
|
|
35
|
+
return null // unknown/deleted handle (404) → graceful "no nav"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function MenuNav({ menu }: { menu: Menu | null }) {
|
|
40
|
+
if (!menu || menu.items.length === 0) return null
|
|
41
|
+
return (
|
|
42
|
+
<nav className="flex items-center gap-4">
|
|
43
|
+
{menu.items.map((item) => (
|
|
44
|
+
<Link
|
|
45
|
+
key={`${item.title}-${item.url}`}
|
|
46
|
+
href={item.url}
|
|
47
|
+
className="text-sm text-muted-foreground hover:text-foreground"
|
|
48
|
+
>
|
|
49
|
+
{item.title}
|
|
50
|
+
</Link>
|
|
51
|
+
))}
|
|
52
|
+
</nav>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default async function RootLayout({
|
|
57
|
+
children,
|
|
58
|
+
}: {
|
|
59
|
+
children: React.ReactNode
|
|
60
|
+
}) {
|
|
61
|
+
const client = await getServerClient()
|
|
62
|
+
const jar = await cookies()
|
|
63
|
+
// Back-compat: prefer the new `_cartbase_cart` cookie, fall back to the
|
|
64
|
+
// legacy `_barter_cart_id` name so an existing visitor's cart survives
|
|
65
|
+
// the rename (platform-fingerprints card).
|
|
66
|
+
const cartId = readCartCookie((name) => jar.get(name)?.value) ?? null
|
|
67
|
+
|
|
68
|
+
const [consentRes, mainMenu, footerMenu, cart] = await Promise.all([
|
|
69
|
+
getConsent(client),
|
|
70
|
+
fetchMenu("main-menu"),
|
|
71
|
+
fetchMenu("footer"),
|
|
72
|
+
cartId
|
|
73
|
+
? retrieveCart(client, cartId)
|
|
74
|
+
.then((res): Cart | null => res.cart)
|
|
75
|
+
.catch(() => null) // stale cookie → empty cart state
|
|
76
|
+
: Promise.resolve(null),
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<html lang="en">
|
|
81
|
+
<body>
|
|
82
|
+
<ConsentInit />
|
|
83
|
+
<PlatformInit storeId={BARTER_CLIENT_ID} />
|
|
84
|
+
<Providers cart={cart} consent={consentRes.consent}>
|
|
85
|
+
<header className="border-b border-border">
|
|
86
|
+
<div className="max-w-7xl mx-auto px-4 h-16 flex items-center justify-between gap-6">
|
|
87
|
+
<Link href="/" className="font-semibold text-lg">
|
|
88
|
+
Barter Example Store
|
|
89
|
+
</Link>
|
|
90
|
+
<div className="flex items-center gap-6">
|
|
91
|
+
<MenuNav menu={mainMenu} />
|
|
92
|
+
<Link
|
|
93
|
+
href="/search"
|
|
94
|
+
className="text-sm text-muted-foreground hover:text-foreground"
|
|
95
|
+
>
|
|
96
|
+
Search
|
|
97
|
+
</Link>
|
|
98
|
+
<CartButtonClient cart={cart} />
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</header>
|
|
102
|
+
<main>{children}</main>
|
|
103
|
+
<footer className="border-t border-border mt-12">
|
|
104
|
+
<div className="max-w-7xl mx-auto px-4 py-8 text-sm text-muted-foreground flex items-center justify-between">
|
|
105
|
+
<span>Barter Example Store</span>
|
|
106
|
+
<MenuNav menu={footerMenu} />
|
|
107
|
+
</div>
|
|
108
|
+
</footer>
|
|
109
|
+
</Providers>
|
|
110
|
+
</body>
|
|
111
|
+
</html>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
@@ -67,10 +67,11 @@ export default function OrderConfirmedPage() {
|
|
|
67
67
|
order={orderForTemplate}
|
|
68
68
|
totals={totals}
|
|
69
69
|
items={cartItems.map(displayItemFromCartLine)}
|
|
70
|
-
// This reference store
|
|
71
|
-
//
|
|
72
|
-
// checkout state alongside
|
|
73
|
-
|
|
70
|
+
// This reference store checks out via one merchant method (pp_* kill:
|
|
71
|
+
// methods are merchant-named, provider-less); a multi-tender store
|
|
72
|
+
// should stash the chosen tender from its checkout state alongside
|
|
73
|
+
// the order.
|
|
74
|
+
paymentMethodName={"Cash on delivery"}
|
|
74
75
|
storeHref="/"
|
|
75
76
|
/>
|
|
76
77
|
)
|
|
@@ -1,43 +1,47 @@
|
|
|
1
|
-
"use server"
|
|
2
|
-
|
|
3
|
-
import { revalidatePath } from "next/cache"
|
|
4
|
-
import { cookies } from "next/headers"
|
|
5
|
-
import { addLineItem, createCart } from "@cartbase/storefront/api/carts"
|
|
6
|
-
import { CART_COOKIE, CART_COOKIE_MAX_AGE } from "./config"
|
|
7
|
-
import { getServerClient } from "./server-client"
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* PDP add-to-cart server action (carts.md: create the cart lazily on the
|
|
11
|
-
* first add — region falls back to the store default; persist `cart.id`
|
|
12
|
-
* in a cookie). Passed into `ProductTemplate`'s `addToCart` seam.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
import { revalidatePath } from "next/cache"
|
|
4
|
+
import { cookies } from "next/headers"
|
|
5
|
+
import { addLineItem, createCart } from "@cartbase/storefront/api/carts"
|
|
6
|
+
import { CART_COOKIE, CART_COOKIE_MAX_AGE, readCartCookie } from "./config"
|
|
7
|
+
import { getServerClient } from "./server-client"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* PDP add-to-cart server action (carts.md: create the cart lazily on the
|
|
11
|
+
* first add — region falls back to the store default; persist `cart.id`
|
|
12
|
+
* in a cookie). Passed into `ProductTemplate`'s `addToCart` seam.
|
|
13
|
+
*
|
|
14
|
+
* Reads via `readCartCookie` (new `_cartbase_cart` name, falls back to the
|
|
15
|
+
* legacy `_barter_cart_id` — platform-fingerprints card); every WRITE uses
|
|
16
|
+
* the new name only, so a visitor's cart survives the rename.
|
|
17
|
+
*/
|
|
18
|
+
export async function addToCartAction(input: {
|
|
19
|
+
variantId: string
|
|
20
|
+
quantity: number
|
|
21
|
+
}): Promise<void> {
|
|
22
|
+
const client = await getServerClient()
|
|
23
|
+
const jar = await cookies()
|
|
24
|
+
const cartId = readCartCookie((name) => jar.get(name)?.value)
|
|
25
|
+
|
|
26
|
+
if (cartId) {
|
|
27
|
+
await addLineItem(client, cartId, {
|
|
28
|
+
variant_id: input.variantId,
|
|
29
|
+
quantity: input.quantity,
|
|
30
|
+
})
|
|
31
|
+
} else {
|
|
32
|
+
const { cart } = await createCart(client, {
|
|
33
|
+
currency_code: "eur",
|
|
34
|
+
items: [{ variant_id: input.variantId, quantity: input.quantity }],
|
|
35
|
+
})
|
|
36
|
+
jar.set(CART_COOKIE, cart.id, {
|
|
37
|
+
path: "/",
|
|
38
|
+
sameSite: "lax",
|
|
39
|
+
httpOnly: false, // the browser-side drawer persists the same cookie
|
|
40
|
+
maxAge: CART_COOKIE_MAX_AGE,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Layout refetches the cart snapshot → CartDrawerProvider sees the new
|
|
45
|
+
// product-line count and auto-opens the drawer.
|
|
46
|
+
revalidatePath("/", "layout")
|
|
47
|
+
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/** Shared storefront configuration (BUILD-A-STOREFRONT.md — inputs table). */
|
|
2
2
|
|
|
3
|
-
export const BARTER_URL = process.env.
|
|
4
|
-
export const BARTER_CLIENT_ID = process.env.
|
|
3
|
+
export const BARTER_URL = process.env.NEXT_PUBLIC_CARTBASE_URL ?? ""
|
|
4
|
+
export const BARTER_CLIENT_ID = process.env.NEXT_PUBLIC_CARTBASE_CLIENT_ID ?? ""
|
|
5
5
|
export const BARTER_PUBLISHABLE_KEY =
|
|
6
|
-
process.env.
|
|
6
|
+
process.env.NEXT_PUBLIC_CARTBASE_PUBLISHABLE_KEY || undefined
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Cart-id cookie — owned by the app (the SDK never persists the cart);
|
|
10
|
+
* the NAME is owned by the library so every consumer emits the same wire
|
|
11
|
+
* fingerprint (platform-fingerprints card). `readCartCookie` is the
|
|
12
|
+
* backward-compat reader for the legacy `_barter_cart_id` name.
|
|
13
|
+
*/
|
|
14
|
+
export { CART_COOKIE, readCartCookie } from "@cartbase/storefront/lib/cookie-names"
|
|
10
15
|
export const CART_COOKIE_MAX_AGE = 60 * 60 * 24 * 30 // 30 days
|
|
11
16
|
|
|
12
17
|
/** Locale cookie read by the clients' `getLocale`. */
|