Storeware Docs

App Bridge for React

A provider and hooks for App Bridge, so a React page in the admin can use its toasts, title bar, save bar, modals, confirm and resource picker.

@storeware/app-bridge-react ties App Bridge to React. Wrap the page the admin frames in AppBridgeProvider, then call the hooks from anything inside it. A title bar or a save bar goes when the component that set it does.

Early access

The CLI and the SDK are not on npm yet, so the commands below do not run for everyone. If you would like to build an app now, tell us.
npm install @storeware/app-bridge-react @storeware/app-ui

The provider

import { AppBridgeProvider } from '@storeware/app-bridge-react';

export function Root({ children }: { children: React.ReactNode }) {
  return <AppBridgeProvider hostOrigin="https://app.storeware.ai">{children}</AppBridgeProvider>;
}

It says hello when it mounts in the browser and renders its children at once. Hooks that need the admin's answer read null until it arrives. By default it writes the admin's --sw-* variables onto the page's root (applyTheme) and keeps the frame as tall as the page (autoResize). In Next.js the package is marked use client, so a server layout can render the provider.

Hooks

HookWhat it gives you
useWelcome()The admin's welcome: storeId, point, context, pickers, or null before it arrives
useAppBridge()The bridge itself, for anything the hooks do not cover
useSessionToken()A function that resolves to a session token for your server
useAuthenticatedFetch()fetch with the session token as a bearer token
useToast()A function that shows a toast
useLoading(on)The loading bar, while on is true
useTitleBar(bar)A title and buttons above the frame, each with its own handler
useSaveBar(options)The admin's save bar for your form
useModal()open a page of your home in a window, and close it from inside
useConfirm()A function that asks the merchant and resolves true or false
useResourcePicker()A function that opens the resource picker
useNavigate()navigate, appNavigate and redirect

A form with a save bar

import { useState } from 'react';
import {
  useAuthenticatedFetch,
  useSaveBar,
  useTitleBar,
  useToast,
} from '@storeware/app-bridge-react';

export function Settings({ saved }: { saved: string }) {
  const [greeting, setGreeting] = useState(saved);
  const authenticatedFetch = useAuthenticatedFetch();
  const toast = useToast();

  useTitleBar({ title: 'Greeting' });
  useSaveBar({
    dirty: greeting !== saved,
    onSave: async () => {
      const response = await authenticatedFetch('/api/settings', {
        method: 'POST',
        body: JSON.stringify({ greeting }),
      });
      if (!response.ok) throw new Error('The greeting could not be saved');
      toast('Saved');
    },
    onDiscard: () => setGreeting(saved),
  });

  return <input value={greeting} onChange={(event) => setGreeting(event.target.value)} />;
}

onSave resolves when the save worked. Throw to say it did not: the admin keeps the page unsaved and shows your error's message.

An action on the ticked rows

import { useModal, useWelcome } from '@storeware/app-bridge-react';

export function AskForReviews() {
  const welcome = useWelcome();
  const modal = useModal();
  const ids = (welcome?.context.selection as string[] | undefined) ?? [];

  return (
    <button
      onClick={async () => {
        await askFor(ids);
        modal.close({ asked: ids.length });
      }}
    >
      Ask {ids.length} customers for a review
    </button>
  );
}

On a list's action the page opens in a window, and context.selection holds the rows the merchant ticked.

Choosing records

import { useResourcePicker, useWelcome } from '@storeware/app-bridge-react';

export function ChooseProducts({ onChosen }: { onChosen: (ids: string[]) => void }) {
  const pick = useResourcePicker();
  const canPick = useWelcome()?.pickers.includes('products') ?? false;

  return (
    <button
      disabled={!canPick}
      onClick={async () => onChosen((await pick('products', { multiple: true })).map((p) => p.id))}
    >
      Choose products
    </button>
  );
}

Before the handshake

A function from a hook throws BridgeError with the code not_ready if it is called before the provider has mounted, which an event handler never is. The effect hooks, useLoading, useTitleBar and useSaveBar, wait for the bridge on their own.

On this page