npm.io
0.7.2 • Published yesterday

@bildit-platform/nextjs

Licence
SEE LICENSE IN LICENSE
Version
0.7.2
Deps
4
Size
77 kB
Vulns
0
Weekly
0

@bildit-platform/nextjs

@bildit-platform/nextjs a library for integrating Bildit CMS with Next.js applications.

Installation

npm install @bildit-platform/nextjs

or

yarn add @bildit-platform/nextjs

Usage

Important: If you pass extraDependenciesConfig, The component that renders BilditProvider must be a Client Component. Ensure you include "use client" at the top of your file (or use a wrapper marked with "use client").

"use client"; // <-- required so extraDependenciesConfig works
import { BilditProvider, SlotPlaceholder } from '@bildit-platform/nextjs';

export default function MyPage({ banners }) {
  return (
    <BilditProvider banners={banners}>
      <main>
        <SlotPlaceholder slotId="hero-1" />
        <SlotPlaceholder slotId="features-1" />
      </main>
    </BilditProvider>
  );
}

API Reference

Components
BilditProvider

A context provider that processes and maps banners from Bildit CMS to their corresponding slots.

Note: Next.js doesn’t allow passing modules or functions from a Server Component into a Client Component. If you supply extraDependenciesConfig to BilditProvider, make sure the file starts with "use client" so it renders as a Client Component (or use a wrapper marked with "use client")

Props

Prop Type Default Required Description
children React.ReactNode Yes The content to be rendered within the BilditProvider context.
banners BannerType[] Yes An array of banners fetched from Bildit CMS used to generate dynamic slots.
extraDependenciesConfig Record<string, ExtraDependencyConfig> {} No A map of extra dependencies config, it should include module and the globalName
variantFilter (variant: Variant, banner: BannerType) => boolean - No Experimental: Client-side variant filtering function. May cause flickering.

Usage Example

import { BilditProvider } from '@bildit-platform/nextjs';

export default function App({ banners }) {
  return (
    <BilditProvider banners={banners}>
      <YourAppComponents />
    </BilditProvider>
  );
}

With external modules

'use client';
import { BilditProvider } from '@bildit-platform/nextjs';
import * as Axios from 'axios';
import * as _ from  'lodash';

export default function App({ banners }) {
  return (
    <BilditProvider 
      banners={banners} 
      extraDependenciesConfig={{ 
        axios: {module: Axios, globalName: 'axios'},
        lodash: {module: _, globalName: '_'},
      }}
    >
      <YourAppComponents />
    </BilditProvider>
  );
}

With client-side filtering (experimental)

'use client';
import { BilditProvider } from '@bildit-platform/nextjs';

export default function App({ banners }) {
  return (
    <BilditProvider 
      banners={banners}
      variantFilter={(variant, banner) => {
        // Filter by customer group
        if (variant.customerGroups && variant.customerGroups.length > 0) {
          return variant.customerGroups.includes('elite');
        }
        // Show variants with no customer groups defined
        return true;
      }}
    >
      <YourAppComponents />
    </BilditProvider>
  );
}
SlotPlaceholder

A component that renders dynamic content in a designated slot based on the provided slot identifier.

Prop Type Default Description
slotId string Unique identifier for the content slot to be rendered dynamically.
className string (Optional) Additional CSS classes to apply to the container element.
fallback React.ReactNode (Optional) Fallback UI to render when no components are available.
forceFallback boolean false Adds data-bildit-force-fallback="true" to the wrapper so admin tooling can skip the slot.

Usage Example

import { SlotPlaceholder } from '@bildit-platform/nextjs';
import DefaultLogo from './DefaultLogo';

export default function Page() {
  return (
    <div>
      <SlotPlaceholder slotId="hero-1" className="custom-class" />
      <SlotPlaceholder
        slotId="logo"
        fallback={<DefaultLogo />}
        forceFallback
      />
    </div>
  );
}
Hooks
useSlotComponent

A custom hook that retrieves a dynamic component mapped to a given slot identifier from the context.

Signature

const components = useSlotComponents(slotId: string): React.ReactNode[];

Parameters - slotId (string): The unique identifier for the desired content slot.

Returns - An array of React.ReactNode representing the dynamic components associated with the specified slot, or null if no components are found.

Usage

import { useSlotComponents } from '@bildit-platform/nextjs';

export default function CustomSlot({ slotId }) {
  const components = useSlotComponents(slotId);
  return <div>{components.map((component, index) => <div key={index}>{component ?? 'No content available'}</div>)}</div>;
}
Advanced Usage
Preview Date Feature

The preview date feature allows you to share website previews at a specific date/time without requiring any code changes in your application. This is useful for previewing scheduled content before it goes live.

How It Works

  1. URL Parameter Detection: Add ?bildit_preview_date=<ISO_DATE> to any URL
  2. Automatic Middleware Processing: The middleware detects the parameter and converts it to an epoch timestamp
  3. Header Forwarding: The preview date is forwarded to server components via headers
  4. API Integration: The date is automatically sent to the Bildit API to fetch scheduled content

Setup

Option 1: Using the Pre-built Middleware (Recommended)

The easiest way to add preview date support is to use the pre-built createBilditMiddleware function:

// middleware.ts
import { createBilditMiddleware } from '@bildit-platform/nextjs';

export const middleware = createBilditMiddleware();

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)'
  ]
};

With optional callback for custom logging or analytics:

// middleware.ts
import { createBilditMiddleware } from '@bildit-platform/nextjs';

export const middleware = createBilditMiddleware({
  onPreviewDate: (previewDate, request) => {
    console.log('[Preview] Date detected:', previewDate);
    // Add your custom logic here (analytics, logging, etc.)
  }
});

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)'
  ]
};

Option 2: Enhancing Existing Middleware

If you already have middleware, add BILDIT preview date support by wrapping it:

// middleware.ts
import { enhanceMiddlewareWithBildit } from '@bildit-platform/nextjs';
import { myExistingMiddleware } from './my-middleware';

export const middleware = enhanceMiddlewareWithBildit(myExistingMiddleware);

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)'
  ]
};

This will automatically add preview date detection while preserving your existing middleware logic.

Server Component Usage

Retrieve the preview date in your server components:

// app/layout.tsx
import { getPreviewDateFromHeaders } from '@bildit-platform/nextjs';
import { RemoteConnector } from '@bildit-platform/nextjs-api';
import { headers } from 'next/headers';

export const dynamic = 'force-dynamic';

const bilditConnector = new RemoteConnector({
  key: process.env.BILDIT_API_KEY || '',
  baseURL: process.env.BILDIT_API_URL || ''
});

async function getInitialData() {
  const headersList = await headers();
  const previewDate = getPreviewDateFromHeaders(headersList);

  const result = await bilditConnector.getWebBanners({
    source: 'live',
    location: '/',
    date: previewDate, // Pass the preview date to the API
    mode: 'csr',
    tomorrow: true
  });

  return result.data;
}

Example URLs

# Preview content scheduled for February 15, 2026
https://example.com/?bildit_preview_date=2026-02-15T00:00:00.000Z

# Preview content at a specific time
https://example.com/products?bildit_preview_date=2026-02-15T14:30:00.000Z

# Works on any page
https://example.com/blog/post-1?bildit_preview_date=2026-03-01T00:00:00.000Z

API Reference

getPreviewDateFromUrl(url: string): number | undefined

Extracts and converts the preview date from a URL to an epoch timestamp.

Parameters:

  • url (string): The full URL to check for the preview date parameter

Returns:

  • number: Epoch timestamp in milliseconds, or undefined if not found or invalid

Example:

const previewDate = getPreviewDateFromUrl(request.url);
// Returns: 1739577600000 (epoch timestamp)
getPreviewDateFromHeaders(headers: Headers): number | undefined

Extracts and converts the preview date from request headers to an epoch timestamp.

Parameters:

  • headers (Headers): Next.js request headers object

Returns:

  • number: Epoch timestamp in milliseconds, or undefined if not found or invalid

Example:

import { headers } from 'next/headers';

const headersList = await headers();
const previewDate = getPreviewDateFromHeaders(headersList);
// Returns: 1739577600000 (epoch timestamp)
convertToEpoch(dateInput: string | number): number | undefined

Converts an ISO date string or epoch timestamp to epoch milliseconds.

Parameters:

  • dateInput (string | number): ISO date string (e.g., "2026-02-15T0000.000Z"), epoch string (e.g., "1739577600000"), or epoch number

Returns:

  • number: Epoch timestamp in milliseconds, or undefined if invalid

Example:

const epoch1 = convertToEpoch('2026-02-15T00:00:00.000Z');
// Returns: 1739577600000

const epoch2 = convertToEpoch('1739577600000');
// Returns: 1739577600000

const epoch3 = convertToEpoch(1739577600000);
// Returns: 1739577600000
createPreviewHeaders(previewDate?: string | number): Record<string, string>

Creates headers object with preview date for API requests.

Parameters:

  • previewDate (string | number): ISO date string or epoch timestamp

Returns:

  • Object with X-Bildit-Preview-Date header set to epoch timestamp string, or empty object if invalid

Example:

const headers = createPreviewHeaders('2026-02-15T00:00:00.000Z');
// Returns: { 'X-Bildit-Preview-Date': '1739577600000' }

Notes:

  • Preview dates are converted to epoch timestamps (milliseconds) automatically
  • The middleware handles conversion from ISO dates to epoch format
  • The Bildit API expects epoch timestamps for date filtering
  • Preview dates work across all pages without code changes
Client-Side Filtering

Warning: Client-side filtering is experimental and may cause content flickering as banners are filtered after initial render. For better user experience, consider filtering banners on the server-side before passing them to BilditProvider.

The variantFilter prop allows you to filter banner variants on the client-side based on any criteria:

// Customer group filtering
<BilditProvider
  banners={banners}
  variantFilter={(variant) =>
    !variant.customerGroups ||
    variant.customerGroups.includes('elite')
  }
/>

// Location-based filtering
<BilditProvider
  banners={banners}
  variantFilter={(variant) =>
    variant.locations.includes('/') ||
    variant.locations.includes('/home')
  }
/>

// Category filtering
<BilditProvider
  banners={banners}
  variantFilter={(variant) =>
    variant.categories.some(cat => ['promo', 'sale'].includes(cat))
  }
/>

// Complex multi-criteria filtering
<BilditProvider
  banners={banners}
  variantFilter={(variant, banner) => {
    const hasValidCustomerGroup = !variant.customerGroups ||
      variant.customerGroups.includes(userCustomerGroup);
    const hasValidLocation = variant.locations.includes(userLocation);
    const isActivePromo = variant.categories.includes('active');

    return hasValidCustomerGroup && hasValidLocation && isActivePromo;
  }}
/>