npm package: @gaian-sdk/widgets
Description: Scan-to-Pay and Order History widgets for React (Rollup build)
Latest version: 0.2.2

# Gaian Widget SDK — Quick Integration Guide

This README walks you through integrating **@gaian-sdk/widgets** into a React app from zero to working screens:

1. Install the widget SDK
2. Reset CSS (or delete your global CSS)
3. Install Solana libraries
4. Wrap **Solana Provider** and **GaianProvider**
5. Set up the **Scan** button (`onScan`)
6. Add an **Order Page**
7. Add **Transaction History**

> **Prereqs**
>
> - Node 18+ / pnpm, npm or yarn
> - React 18+
> - Vite or Next.js (examples below use Vite-style entry)

---

## 1) Install @gaian-sdk/widgets

```bash
# with pnpm (recommended)
pnpm add @gaian-sdk/widgets

# or npm\ nnpm i @gaian-sdk/widgets

# or yarn
yarn add @gaian-sdk/widgets
```

If you’re using TypeScript, make sure you’re on TS 5.x+.

---

## 2) Reset CSS or delete your app CSS

The widget ships with its own styles. To avoid style clashes, **either**:

**Delete your global CSS**

- Remove `import './index.css'` (or `./App.css`) from your entry files (e.g., `main.tsx`, `index.tsx`).
- Delete the css file(s) if you don’t need them.

---

## 3) Install Solana libraries

```bash
pnpm add @solana/web3.js \
          @solana/wallet-adapter-base \
          @solana/wallet-adapter-wallets \
          @solana/wallet-adapter-react \
          @solana/wallet-adapter-react-ui \
          @solana/wallet-adapter-phantom
```

> The widget expects a Wallet Adapter context to be present. We’ll wire it next.

---

## 4) Wrap Solana Provider and GaianProvider

Create a small provider shell that sets up Solana (RPC + wallets) and the Gaian config.

```tsx
// src/providers/AppProviders.tsx
import React, { PropsWithChildren, useMemo } from "react";
import {
  ConnectionProvider,
  WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-phantom";
import "@solana/wallet-adapter-react-ui/styles.css";

import { GaianProvider } from "@gaian-sdk/widgets";

const RPC_DEVNET = "https://api.devnet.solana.com";
const RPC_MAINNET = "https://api.mainnet-beta.solana.com";

export function AppProviders({ children }: PropsWithChildren) {
  // switch envs however your app prefers
  const endpoint = RPC_DEVNET; // or RPC_MAINNET
  const wallets = useMemo(() => [new PhantomWalletAdapter()], []);

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
          <GaianProvider
            config={{
              partnerCode: "YOUR_PARTNER_CODE",
              mode: "dev", // 'dev' | 'prod'
            }}
          >
            {children}
          </GaianProvider>
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
}
```

---

## 5) Set up routes

Add React Router so your Scan button can navigate to the Order and History pages.

```bash
pnpm install react-router-dom
# or: npm i react-router-dom / yarn add react-router-dom
```

Create the router and wrap your app:

```tsx
// src/App.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import { router } from "./routes/";
import { AppProviders } from "./providers/AppProviders";

export default function App() {
  return (
    <AppProviders>
      <RouterProvider router={router} />
    </AppProviders>
  );
}
```

Define routes for Home, Order, and History:

```tsx
// src/routes/index.tsx
import { createBrowserRouter } from "react-router-dom";
import App from "./App";
import OrderPageRoute from "./pages/OrderPage";
import HistoryPage from "./pages/HistoryPage";

export const router = createBrowserRouter([
  { path: "/", element: <HomePage /> },
  { path: "/orders/:orderId", element: <OrderPageRoute /> },
  { path: "/history", element: <HistoryPage /> },
]);
```

---

## 6) Set up the Scan button (`onScan`)

Use the widget’s scan hook to get `onScan`, then wire it to any button.

```tsx
// src/components/ScanToPayButton.tsx
import React from "react";
import { useScanQr } from "@gaian-sdk/widgets";

export function ScanToPayButton() {
  const { onScan } = useScanQr({
    userEmail: "tvugiang@gmail.com",
    onSuccess(data) {
      console.log("Data response:", data);
      window.location.href = `/order/${data.orderId}`;
    },
    onError(error) {
      console.log(error);
    },
  });

  return (
    <div>
      <button onClick={onScan}>Scan</button>
    </div>
  );
}
```

Use it anywhere:

```tsx
// src/pages/HomePage.tsx
import React from "react";
import { ScanToPayButton } from "./components/ScanToPayButton";

export default function App() {
  return (
    <main style={{ padding: 24 }}>
      <h1>Gaian Widget Demo</h1>
      <ScanToPayButton />
    </main>
  );
}
```

---

## 7) Set up `OrderPage`

Drop-in page to display order status and payment progress.

```tsx
// src/pages/OrderPage.tsx
import React from "react";
import { OrderPage } from "@gaian-sdk/widgets";
import { useParams } from "react-router-dom";

export default function OrderPageRoute() {
  const { orderId } = useParams();
  if (!orderId) return <p>Missing orderId</p>;
  return <OrderPage orderId={orderId} />;
}
```

> `OrderPage` fetches by `orderId` and renders real-time status updates.

---

## 8) Set up `TransactionHistory`

Embed a history list for the current user. You can filter by wallet or user profile depending on your integration.

```tsx
// src/pages/HistoryPage.tsx
import React from "react";
import { TransactionHistory } from "@gaian-sdk/widgets";

export default function HistoryPage() {
  return (
    <section style={{ padding: 24 }}>
      <h2>Transaction History</h2>
      <TransactionHistory />
    </section>
  );
}
```

---

## Environment & Config Notes

- `GaianProvider` requires:

  - `partnerCode` — issued by Gaian
  - `mode` — `'dev' | 'prod'`

- Solana **RPC**: use **Devnet** for development, switch to **Mainnet** for production.
- Wallets: start with **Phantom**; add more by pushing adapters into the `wallets` array.

---

## Minimal working example (all-in-one)

```tsx
// main.tsx (Vite)
import React from "react";
import ReactDOM from "react-dom/client";
import "modern-normalize/modern-normalize.css";
import {
  ConnectionProvider,
  WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-phantom";
import "@solana/wallet-adapter-react-ui/styles.css";
import { GaianProviderBYO, useScanQr } from "@gaian-sdk/widgets";

function ScanBtn() {
  const { onScan } = useScanQr({
    userEmail: "tvugiang@gmail.com",
    onSuccess(data) {
      console.log("Data response:", data);
      window.location.href = `/order/${data.orderId}`;
    },
    onError(error) {
      console.log(error);
    },
  });
  return <button onClick={onScan}>Scan & Pay</button>;
}

function App() {
  return (
    <main style={{ padding: 24 }}>
      <h1>Gaian + Solana</h1>
      <ScanBtn />
    </main>
  );
}

const endpoint = "https://api.devnet.solana.com";
const wallets = [new PhantomWalletAdapter()];

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
          <GaianProvider
            config={{ partnerCode: "YOUR_PARTNER_CODE", mode: "dev" }}
          >
            <App />
          </GaianProvider>
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  </React.StrictMode>
);
```

---

## Troubleshooting

- **No wallet found**: ensure Phantom (or another wallet) is installed and your `wallets` array includes its adapter.
- **Styles look off**: remove your global CSS or import a reset before anything else. Avoid overwriting the widget’s class names.
- **Callbacks not firing**: if you supplied `onSuccess`/`onError`, check they’re passed to `useScanQr({ ... })` and that you’re not catching/swallowing errors elsewhere.
- **Order page shows nothing**: confirm the `orderId` is present in the route and accessible via `useParams()`.