@cimplify/sdk 0.39.1 → 0.40.0
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/dispatcher.mjs +39 -5
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/templates/{storefront → storefront-bakery}/README.md +8 -1
- package/templates/{storefront → storefront-bakery}/package.json +1 -1
- package/templates/storefront-retail/.env.example +11 -0
- package/templates/storefront-retail/README.md +77 -0
- package/templates/storefront-retail/app/about/page.tsx +71 -0
- package/templates/storefront-retail/app/cart/page.tsx +9 -0
- package/templates/storefront-retail/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-retail/app/categories/[slug]/page.tsx +117 -0
- package/templates/storefront-retail/app/checkout/page.tsx +17 -0
- package/templates/storefront-retail/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-retail/app/collections/[slug]/page.tsx +117 -0
- package/templates/storefront-retail/app/faq/page.tsx +127 -0
- package/templates/storefront-retail/app/globals.css +47 -0
- package/templates/storefront-retail/app/layout.tsx +46 -0
- package/templates/storefront-retail/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-retail/app/page.tsx +97 -0
- package/templates/storefront-retail/app/privacy/page.tsx +101 -0
- package/templates/storefront-retail/app/shop/page.tsx +30 -0
- package/templates/storefront-retail/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-retail/app/terms/page.tsx +117 -0
- package/templates/storefront-retail/components/cart-pill.tsx +32 -0
- package/templates/storefront-retail/components/category-grid.tsx +28 -0
- package/templates/storefront-retail/components/collection-strip.tsx +45 -0
- package/templates/storefront-retail/components/footer.tsx +188 -0
- package/templates/storefront-retail/components/header.tsx +47 -0
- package/templates/storefront-retail/components/hero.tsx +28 -0
- package/templates/storefront-retail/components/nav-link.tsx +20 -0
- package/templates/storefront-retail/components/product-modal.tsx +105 -0
- package/templates/storefront-retail/components/providers.tsx +31 -0
- package/templates/storefront-retail/components/store-product-card.tsx +83 -0
- package/templates/storefront-retail/lib/cart.ts +27 -0
- package/templates/storefront-retail/next.config.ts +40 -0
- package/templates/storefront-retail/package.json +28 -0
- package/templates/storefront-retail/postcss.config.mjs +7 -0
- package/templates/storefront-retail/tsconfig.json +23 -0
- package/templates/storefront/lib/server-client.ts +0 -27
- /package/templates/{storefront → storefront-bakery}/.env.example +0 -0
- /package/templates/{storefront → storefront-bakery}/app/about/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/cart/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/categories/[slug]/listing-client.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/categories/[slug]/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/checkout/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/collections/[slug]/listing-client.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/collections/[slug]/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/faq/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/globals.css +0 -0
- /package/templates/{storefront → storefront-bakery}/app/layout.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/orders/[id]/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/privacy/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/shop/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/shop/shop-client.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/app/terms/page.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/cart-pill.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/category-grid.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/collection-strip.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/footer.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/header.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/hero.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/nav-link.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/product-modal.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/providers.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/components/store-product-card.tsx +0 -0
- /package/templates/{storefront → storefront-bakery}/lib/cart.ts +0 -0
- /package/templates/{storefront → storefront-bakery}/next.config.ts +0 -0
- /package/templates/{storefront → storefront-bakery}/postcss.config.mjs +0 -0
- /package/templates/{storefront → storefront-bakery}/tsconfig.json +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import {
|
|
5
|
+
CardVariant,
|
|
6
|
+
FoodProductCard,
|
|
7
|
+
RetailProductCard,
|
|
8
|
+
WholesaleProductCard,
|
|
9
|
+
DigitalProductCard,
|
|
10
|
+
BundleProductCard,
|
|
11
|
+
CompositeProductCard,
|
|
12
|
+
StandardServiceCard,
|
|
13
|
+
RentalServiceCard,
|
|
14
|
+
AccommodationCard,
|
|
15
|
+
LeaseServiceCard,
|
|
16
|
+
SubscriptionCard,
|
|
17
|
+
} from "@cimplify/sdk/react";
|
|
18
|
+
import type { CardLayoutProps } from "@cimplify/sdk/react";
|
|
19
|
+
import type { Product } from "@cimplify/sdk";
|
|
20
|
+
import { PRODUCT_TYPE, RENDER_HINT, DURATION_UNIT } from "@cimplify/sdk";
|
|
21
|
+
|
|
22
|
+
const RENTAL_UNITS = new Set<string>([DURATION_UNIT.Days, DURATION_UNIT.Hours]);
|
|
23
|
+
const LEASE_UNITS = new Set<string>([DURATION_UNIT.Weeks, DURATION_UNIT.Months, DURATION_UNIT.Years]);
|
|
24
|
+
|
|
25
|
+
const VARIANT_CARDS: Record<CardVariant, React.ComponentType<CardLayoutProps>> = {
|
|
26
|
+
[CardVariant.Food]: FoodProductCard,
|
|
27
|
+
[CardVariant.Retail]: RetailProductCard,
|
|
28
|
+
[CardVariant.Wholesale]: WholesaleProductCard,
|
|
29
|
+
[CardVariant.Digital]: DigitalProductCard,
|
|
30
|
+
[CardVariant.Bundle]: BundleProductCard,
|
|
31
|
+
[CardVariant.Composite]: CompositeProductCard,
|
|
32
|
+
[CardVariant.Standard]: StandardServiceCard,
|
|
33
|
+
[CardVariant.Rental]: RentalServiceCard,
|
|
34
|
+
[CardVariant.Accommodation]: AccommodationCard,
|
|
35
|
+
[CardVariant.Lease]: LeaseServiceCard,
|
|
36
|
+
[CardVariant.Subscription]: SubscriptionCard,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function resolveVariant(p: Product): CardVariant {
|
|
40
|
+
if (p.type === PRODUCT_TYPE.Bundle) return CardVariant.Bundle;
|
|
41
|
+
if (p.type === PRODUCT_TYPE.Composite) return CardVariant.Composite;
|
|
42
|
+
if (p.quantity_pricing && p.quantity_pricing.length > 1) return CardVariant.Wholesale;
|
|
43
|
+
if (p.type === PRODUCT_TYPE.Digital) return CardVariant.Digital;
|
|
44
|
+
if (p.type === PRODUCT_TYPE.Service) {
|
|
45
|
+
if (p.duration_unit && RENTAL_UNITS.has(p.duration_unit)) return CardVariant.Rental;
|
|
46
|
+
if (p.duration_unit === DURATION_UNIT.Nights) return CardVariant.Accommodation;
|
|
47
|
+
if (p.duration_unit && LEASE_UNITS.has(p.duration_unit)) return CardVariant.Lease;
|
|
48
|
+
if (p.billing_plans && p.billing_plans.length > 0 && !p.duration_minutes) return CardVariant.Subscription;
|
|
49
|
+
return CardVariant.Standard;
|
|
50
|
+
}
|
|
51
|
+
if (p.render_hint === RENDER_HINT.Food) return CardVariant.Food;
|
|
52
|
+
return CardVariant.Retail;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface Props {
|
|
56
|
+
product: Product;
|
|
57
|
+
/** Override the auto-detected card variant. */
|
|
58
|
+
variant?: CardVariant;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Variant-aware product card that opens the URL-driven product modal on
|
|
63
|
+
* click. Uses `next/link` with `?product=<slug>` so the link is statically
|
|
64
|
+
* pre-renderable — no `useSearchParams` dependency means cards don't
|
|
65
|
+
* become dynamic islands. The modal (which already reads `useSearchParams`
|
|
66
|
+
* inside a Suspense boundary in the root layout) handles the rest.
|
|
67
|
+
*/
|
|
68
|
+
export function StoreProductCard({ product, variant }: Props) {
|
|
69
|
+
const slug = product.slug || product.id;
|
|
70
|
+
const Card = VARIANT_CARDS[variant ?? resolveVariant(product)];
|
|
71
|
+
const href = `?product=${encodeURIComponent(slug)}`;
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Card
|
|
75
|
+
product={product}
|
|
76
|
+
renderLink={({ className, children }) => (
|
|
77
|
+
<Link href={href} scroll={false} prefetch={false} className={className}>
|
|
78
|
+
{children}
|
|
79
|
+
</Link>
|
|
80
|
+
)}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { useCimplifyClient } from "@cimplify/sdk/react";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tiny hook for the live cart-count pill in the header. Re-fetches on
|
|
8
|
+
* mount and exposes a refresh callback. The SDK's `useCart` hook is
|
|
9
|
+
* fine-grained but heavier — this is enough for a header badge.
|
|
10
|
+
*/
|
|
11
|
+
export function useCartCount(): { count: number; refresh: () => void } {
|
|
12
|
+
const { client } = useCimplifyClient();
|
|
13
|
+
const [count, setCount] = useState(0);
|
|
14
|
+
|
|
15
|
+
const refresh = () => {
|
|
16
|
+
void client.cart.getCount().then((r) => {
|
|
17
|
+
if (r.ok) setCount(r.value);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
refresh();
|
|
23
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
24
|
+
}, [client]);
|
|
25
|
+
|
|
26
|
+
return { count, refresh };
|
|
27
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const MOCK_URL = process.env.NEXT_PUBLIC_CIMPLIFY_API_URL?.trim() || "http://127.0.0.1:8787";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Same-origin proxy to the Cimplify mock so the browser never makes a
|
|
7
|
+
* cross-origin request in dev (no CORS preflights, no flaky `Origin`
|
|
8
|
+
* mismatches). The SDK's base URL stays empty/relative — requests go to
|
|
9
|
+
* `/api/v1/...` on the Next origin, then this rewrite forwards them to
|
|
10
|
+
* the mock at `127.0.0.1:8787`.
|
|
11
|
+
*
|
|
12
|
+
* In production, point `NEXT_PUBLIC_CIMPLIFY_API_URL` at your Cimplify
|
|
13
|
+
* host and the rewrite continues to work the same way (or remove it and
|
|
14
|
+
* pass the absolute URL through `<CimplifyProvider/>`).
|
|
15
|
+
*/
|
|
16
|
+
const nextConfig: NextConfig = {
|
|
17
|
+
// Enable Next 16's `cacheComponents` mode so we can use `'use cache'` +
|
|
18
|
+
// `cacheTag` / `cacheLife` for SSR caching. Cached chrome streams first,
|
|
19
|
+
// dynamic Suspense boundaries fill in when ready.
|
|
20
|
+
cacheComponents: true,
|
|
21
|
+
async rewrites() {
|
|
22
|
+
return [
|
|
23
|
+
{ source: "/api/v1/:path*", destination: `${MOCK_URL}/api/v1/:path*` },
|
|
24
|
+
{ source: "/img/:path*", destination: `${MOCK_URL}/img/:path*` },
|
|
25
|
+
{ source: "/elements/:path*", destination: `${MOCK_URL}/elements/:path*` },
|
|
26
|
+
{ source: "/_mock/:path*", destination: `${MOCK_URL}/_mock/:path*` },
|
|
27
|
+
];
|
|
28
|
+
},
|
|
29
|
+
images: {
|
|
30
|
+
remotePatterns: [
|
|
31
|
+
{ protocol: "http", hostname: "127.0.0.1", port: "8787", pathname: "/img/**" },
|
|
32
|
+
{ protocol: "http", hostname: "localhost", port: "8787", pathname: "/img/**" },
|
|
33
|
+
{ protocol: "http", hostname: "localhost", port: "3000", pathname: "/img/**" },
|
|
34
|
+
{ protocol: "https", hostname: "loremflickr.com", pathname: "/**" },
|
|
35
|
+
{ protocol: "https", hostname: "images.unsplash.com", pathname: "/**" },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default nextConfig;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__STOREFRONT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "concurrently -k -n mock,next -c blue,magenta \"bunx @cimplify/sdk --seed retail --quiet\" \"next dev\"",
|
|
7
|
+
"dev:storefront": "next dev",
|
|
8
|
+
"dev:mock": "bunx @cimplify/sdk --seed retail",
|
|
9
|
+
"build": "next build",
|
|
10
|
+
"start": "next start",
|
|
11
|
+
"lint": "next lint"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@cimplify/sdk": "^0.39.1",
|
|
15
|
+
"next": "^16.2.4",
|
|
16
|
+
"react": "^19.0.0",
|
|
17
|
+
"react-dom": "^19.0.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
21
|
+
"@types/node": "^22.10.0",
|
|
22
|
+
"@types/react": "^19.0.0",
|
|
23
|
+
"@types/react-dom": "^19.0.0",
|
|
24
|
+
"concurrently": "^9.0.0",
|
|
25
|
+
"tailwindcss": "^4.2.4",
|
|
26
|
+
"typescript": "^5.9.3"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": false,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [{ "name": "next" }],
|
|
17
|
+
"paths": {
|
|
18
|
+
"@/*": ["./*"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
|
|
22
|
+
"exclude": ["node_modules"]
|
|
23
|
+
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { createCimplifyClient, type CimplifyClient } from "@cimplify/sdk";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Server-side Cimplify client. Used by Server Components to fetch catalogue
|
|
5
|
-
* data during SSR/RSC for SEO-friendly product/category/collection pages.
|
|
6
|
-
*
|
|
7
|
-
* Cached per-request via React's cache mechanism — calling this multiple
|
|
8
|
-
* times within the same request returns the same client instance.
|
|
9
|
-
*
|
|
10
|
-
* Base-URL resolution:
|
|
11
|
-
* 1) NEXT_PUBLIC_CIMPLIFY_API_URL (matches the client-side default)
|
|
12
|
-
* 2) http://127.0.0.1:8787 — the local mock during dev
|
|
13
|
-
*/
|
|
14
|
-
let cached: CimplifyClient | undefined;
|
|
15
|
-
|
|
16
|
-
export function getServerClient(): CimplifyClient {
|
|
17
|
-
if (cached) return cached;
|
|
18
|
-
const baseUrl =
|
|
19
|
-
process.env.NEXT_PUBLIC_CIMPLIFY_API_URL?.trim() || "http://127.0.0.1:8787";
|
|
20
|
-
const publicKey = process.env.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY ?? "mock-dev";
|
|
21
|
-
cached = createCimplifyClient({
|
|
22
|
-
baseUrl,
|
|
23
|
-
publicKey,
|
|
24
|
-
suppressPublicKeyWarning: true,
|
|
25
|
-
});
|
|
26
|
-
return cached;
|
|
27
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/{storefront → storefront-bakery}/app/categories/[slug]/listing-client.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/{storefront → storefront-bakery}/app/collections/[slug]/listing-client.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|