npm package: @fluid-app/react-widgets
Description: React components for the Fluid shopping experience with built-in attribution tracking.
Latest version: 1.0.12

# Fluid React Widgets

React components for the Fluid shopping experience with built-in attribution tracking.

## Installation

```bash
npm install @fluid-app/react-widgets
# or
yarn add @fluid-app/react-widgets
# or
pnpm add @fluid-app/react-widgets
```

## Quick Start

Here's a complete example to get up and running with the Cart Widget in a React application:

```jsx
import React from "react";

import { CartWidget, initializeFluid } from "@fluid-app/react-widgets";

// Initialize the Fluid SDK once in your app (typically in your main component or App.js)
function App() {
  React.useEffect(() => {
    // Initialize with your shop ID (server-side attribution)
    initializeFluid({
      fluidShop: "your-shop-id", // Replace with your actual shop ID
    });

    // Or with attribution override
    initializeFluid({
      fluidShop: "your-shop-id",
      attributionOverride: {
        share_guid: "your-affiliate-id",
      },
    });
  }, []);

  return (
    <div className="app">
      <h1>My Awesome Store</h1>

      {/* Add the cart widget to your app */}
      <CartWidget
        position="bottom-right"
        fluidShopDisplayName="My Awesome Store"
      />

      {/* Your other app content */}
      <main>{/* Your products, pages, etc. */}</main>
    </div>
  );
}

export default App;
```

## Customizing Widget Styles

The widgets can be customized to match your brand's color scheme using CSS variables. First, make sure to import the widget styles:

```jsx
// In your main CSS file or component
import "@fluid-app/react-widgets/dist/styles.css";
```

Or if you prefer using CSS imports:

```css
@import url("../node_modules/@fluid-app/react-widgets/dist/styles.css");
```

Then, you can customize the widget's appearance by setting CSS variables:

```css
/* In your CSS file */
:root {
  --company-color: #27522e; /* Replace with your brand color */
  --ff-body: "Your Custom Font", sans-serif; /* Your custom font */
}
```

Available customization variables:

- `--company-color`: Controls primary colors, accents, and highlights
- `--ff-body`: Sets the font family used throughout the widgets (falls back to system fonts if not specified)

This will apply your brand's color and typography to various elements of the Fluid widgets like buttons, text, borders, and accents.

## Setting Up Attribution

Attribution is built into the Fluid SDK and automatically works with the React widgets using **server-side attribution calculation**. No client-side configuration is needed:

```jsx
// For React applications with server-side attribution
import { initializeFluid } from "@fluid-app/react-widgets";

function FluidInitializer() {
  React.useEffect(() => {
    // Basic server-side attribution (recommended)
    initializeFluid({
      fluidShop: "your-shop-id",
    });

    // Or with attribution override for specific use cases
    // You can use any of these attribution data formats:

    // Attribution by email
    initializeFluid({
      fluidShop: "your-shop-id",
      attributionOverride: {
        email: "affiliate@example.com",
      },
    });

    // Attribution by username
    initializeFluid({
      fluidShop: "your-shop-id",
      attributionOverride: {
        username: "influencer-username",
      },
    });

    // Attribution by share GUID
    initializeFluid({
      fluidShop: "your-shop-id",
      attributionOverride: {
        share_guid: "abc123-def456-ghi789",
      },
    });

    // Attribution by Fluid rep ID
    initializeFluid({
      fluidShop: "your-shop-id",
      attributionOverride: {
        fluid_rep_id: 12345,
      },
    });

    // Attribution by external ID
    initializeFluid({
      fluidShop: "your-shop-id",
      attributionOverride: {
        external_id: "external-affiliate-id",
      },
    });
  }, []);

  return null; // This component doesn't render anything
}

// Add <FluidInitializer /> to your main App component
```

**🔄 Migration Note:** Client-side attribution patterns are deprecated. Attribution is now handled server-side automatically.

## Usage Examples

### Basic Cart Widget

```jsx
import { CartWidget } from "@fluid-app/react-widgets";

function MyComponent() {
  return (
    <div>
      <CartWidget
        position="bottom-right" // Options: top-left, top-right, bottom-left, bottom-right
        size={60} // Size in pixels
        zIndex={50} // Z-index for the widget
        xMargin={40} // Horizontal margin from edge in pixels
        yMargin={98} // Vertical margin from edge in pixels
        fluidShopDisplayName="My Store" // Name displayed in cart
      />
    </div>
  );
}
```

### Custom Cart Button with Hidden Widget

```jsx
import { CartWidget, openCart } from "@fluid-app/react-widgets";

function CustomCartButton() {
  return (
    <div>
      {/* Hide the default cart widget button */}
      <CartWidget hideWidget={true} />

      {/* Use your own custom button to control the cart */}
      <button className="custom-cart-button" onClick={openCart}>
        My Custom Cart Button
        <span className="cart-count">3</span>
      </button>
    </div>
  );
}
```

### Controlling the Cart Programmatically

```jsx
import { closeCart, openCart, toggleCart } from "@fluid-app/react-widgets";

function ProductCard({ product }) {
  const handleAddToCart = async () => {
    // Add the product to cart
    // ...your add to cart logic

    // Then open the cart drawer
    openCart();
  };

  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <button onClick={handleAddToCart}>Add to Cart</button>

      {/* Additional cart control buttons if needed */}
      <div className="cart-controls">
        <button onClick={openCart}>Open Cart</button>
        <button onClick={closeCart}>Close Cart</button>
        <button onClick={toggleCart}>Toggle Cart</button>
      </div>
    </div>
  );
}
```

### Accessing Cart Count

You can access the current cart count using the `getCartItemCount` function from the `@fluid-app/fluid` package:

```jsx
import { useEffect, useState } from "react";

import { getCartItemCount, getLocalCart } from "@fluid-app/fluid";

function CartIndicator() {
  const [itemCount, setItemCount] = useState(0);

  useEffect(() => {
    // Initial cart count
    setItemCount(getCartItemCount());

    // Function to update the cart count
    const updateCartCount = () => {
      setItemCount(getCartItemCount());
    };

    // Listen for cart events
    window.addEventListener("ADD_TO_CART", updateCartCount);
    window.addEventListener("REMOVE_CART_ITEM", updateCartCount);
    window.addEventListener("UPDATE_CART_ITEM", updateCartCount);
    window.addEventListener("CREATE_CART", updateCartCount);

    return () => {
      // Clean up event listeners
      window.removeEventListener("ADD_TO_CART", updateCartCount);
      window.removeEventListener("REMOVE_CART_ITEM", updateCartCount);
      window.removeEventListener("UPDATE_CART_ITEM", updateCartCount);
      window.removeEventListener("CREATE_CART", updateCartCount);
    };
  }, []);

  return (
    <div className="cart-indicator">
      <i className="shopping-cart-icon" />
      <span className="cart-count">{itemCount}</span>
    </div>
  );
}
```

### HTML Cart Count Element

Alternatively, you can use an HTML element with the ID `fluid-cart-count` that will be automatically updated by the SDK:

```jsx
function CartIndicator() {
  return (
    <div className="cart-indicator">
      <i className="shopping-cart-icon" />
      <span id="fluid-cart-count">0</span>
    </div>
  );
}
```

### Cart Functions

The cart widget provides three functions to control it:

```jsx
import { closeCart, openCart, toggleCart } from "@fluid-app/react-widgets";

// Open the cart drawer
openCart();

// Close the cart drawer
closeCart();

// Toggle the cart drawer (open if closed, close if open)
toggleCart();
```

## Next.js App Router Integration

For Next.js with App Router, create a client component to initialize the SDK:

```jsx
// app/components/FluidInitializer.tsx
"use client";

import { useEffect, useState } from "react";

import { initializeFluid } from "@fluid-app/react-widgets";

export default function FluidInitializer() {
  const [isInitialized, setIsInitialized] = useState(false);

  useEffect(() => {
    if (isInitialized) return;

    try {
      initializeFluid({
        fluidShop: "your-shop-id",
      });

      setIsInitialized(true);
    } catch (error) {
      console.error("Error initializing Fluid SDK:", error);
    }
  }, [isInitialized]);

  return null;
}

// Then in your layout.tsx file:
// import FluidInitializer from './components/FluidInitializer';
// Add <FluidInitializer /> to your RootLayout component
```

## CartWidget Props

| Prop                 | Type                                                         | Default        | Description                                                                           |
| -------------------- | ------------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------------- |
| position             | 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | 'bottom-right' | The position of the cart widget                                                       |
| size                 | number                                                       | 60             | The size of the cart widget in pixels                                                 |
| zIndex               | number                                                       | 50             | The z-index of the cart widget                                                        |
| xMargin              | number                                                       | 40             | The horizontal margin from the edge of the screen in pixels                           |
| yMargin              | number                                                       | 98             | The vertical margin from the edge of the screen in pixels                             |
| onCheckout           | () => void                                                   | -              | Callback function when the checkout button is clicked                                 |
| fluidShopDisplayName | string                                                       | 'My Store'     | The display name of the shop shown in the cart header                                 |
| hideWidget           | boolean                                                      | false          | When true, hides the cart widget button but still allows the cart sheet functionality |

## Troubleshooting

1. **Attribution not tracking**: Attribution is now handled server-side automatically. Ensure your Fluid shop is properly configured.

2. **Cart widget not appearing**: Verify that the Fluid SDK is initialized before rendering the cart widget.

3. **Initialization issues**: Check the console for any errors during initialization. Ensure you're calling `initializeFluid` with the correct parameters.