npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

avada-ui-bridge

v1.0.9

Published

Shared Cross App Banner components and hooks for Avada Shopify apps

Downloads

593

Readme

Avada UI Bridge

Shared components, hooks, and utilities for Avada Shopify apps.

Installation

npm install avada-ui-bridge

Peer Dependencies

  • @shopify/polaris >= 12.0.0
  • @shopify/react-i18n >= 7.0.0
  • react >= 16.8.0
  • react-dom >= 16.8.0
  • react-router-dom

Components

AgeVerificationBanner

Standalone age verification banner that fetches shop data and manages its own state via API.

import { AgeVerificationBanner } from "avada-ui-bridge";

function MyComponent() {
  return (
    <AgeVerificationBanner
      sourcePage="dashboard"
      fetchAuthenticatedApi={(uri, options) => fetch(uri, options)}
    />
  );
}

Props

| Prop | Type | Required | Default | Description | | ----------------------- | ------------------------------------ | -------- | ------------- | -------------------------------- | | sourcePage | string | No | "dashboard" | Page where banner is displayed | | fetchAuthenticatedApi | (uri: string, options: any) => any | Yes | - | Authenticated API fetch function |


BundleSaving

Displays a bundle saving promotion card that shows discount tiers based on how many Avada apps the merchant has installed. Fetches campaign data automatically from the Avada CRM API.

import { BundleSaving } from "avada-ui-bridge";
import "avada-ui-bridge/dist/styles.css";

<BundleSaving
  plans={plans}
  getMonthlyPricing={getMonthlyPricing}
  onSubscribe={(planId, options) => {
    store.dispatch(subscribeShopify(planId, options));
  }}
/>;

Props

| Prop | Type | Required | Default | Description | | ------------------- | ----------------------------------------------------- | -------- | ------------------- | ------------------------------------------------------------ | | shop | BundleSavingShop | No | window.activeShop | Shop data. Falls back to window.activeShop if not provided | | plans | PlanConfig[] | Yes | - | Available plan configurations | | getMonthlyPricing | (params: { shop, plan, interval }) => string | Yes | - | Function to calculate monthly pricing | | freePlanId | string | No | "free" | ID of the free plan | | subscriptionUrl | string | No | "/subscription" | URL for subscription management | | onSubscribe | (planId: string, options: SubscribeOptions) => void | Yes | - | Callback when user subscribes with bundle discount |

BundleSavingShop

interface BundleSavingShop {
  shopifyDomain: string;
  appName: string; // Used to detect current app ("accessibility", "cookie", "pdf"/"invoice")
  plan: string;
  subStartAt?: string;
}

SubscribeOptions

interface SubscribeOptions {
  interval: string;
  redirectUrl: string;
  discountCode?: string;
}

The component automatically detects the current app from shop.appName and shows other Avada apps (Accessibility, Cookie Bar, PDF Invoice) as bundle options. Discount tiers increase as more apps are installed. Navigation is handled internally via react-router-dom.


Hooks

useDisplayBanner

Manages banner visibility with localStorage persistence and shop-level dismissal tracking.

import {
  useDisplayBanner,
  TARGET_STORAGE_NEXT_DAY,
} from "avada-ui-bridge";

function MyBanner() {
  const { displayBanner, closeBanner } = useDisplayBanner({
    storageKey: "my-banner",
    shopKey: "my-banner-key",
    activeShop: shop,
    checkShop: true,
    disableCount: 3,
    targetDateType: TARGET_STORAGE_NEXT_DAY,
    checkStorage: true,
    onClose: () => console.log("Banner closed"),
    onDismiss: async (dismissedBanners) => {
      await updateShop({ dismissedBanners });
    },
  });

  if (!displayBanner) return null;

  return (
    <div>
      My Banner Content
      <button onClick={() => closeBanner()}>Close</button>
      <button onClick={() => closeBanner(true)}>Don't show again</button>
    </div>
  );
}

Options

| Option | Type | Required | Default | Description | | ---------------- | ----------------------------------------------- | -------- | ------------------------ | -------------------------------------------------- | | storageKey | string | Yes | - | LocalStorage key for persisting banner state | | shopKey | string | No | '' | Shop identifier for dismissal tracking | | activeShop | Shop | No | {} | Shop object with optional dismissedBanners array | | checkShop | boolean | No | false | Whether to check shop-level dismissal | | disableCount | number | No | 3 | Number of closures before permanently dismissing | | targetDateType | TargetStorageType | No | TARGET_STORAGE_NEXT_DAY| When to re-show the banner after closing | | checkStorage | boolean | No | true | Whether to check localStorage | | onClose | () => void | No | () => {} | Callback when banner is closed | | onDismiss | (dismissedBanners: string[]) => Promise<void> | No | - | Async callback to persist dismissal status |

Return

| Property | Type | Description | | --------------- | ------------------------------------ | ---------------------------------------------------- | | displayBanner | boolean | Whether the banner should be visible | | closeBanner | (isDismissShop?: boolean) => void | Close the banner. Pass true to permanently dismiss |


useBundleCampaign

Fetches bundle campaign data from the Avada CRM API. Used internally by BundleSaving but can be used standalone.

import { useBundleCampaign } from "avada-ui-bridge";

function MyComponent() {
  const { data, loading } = useBundleCampaign({
    shopifyDomain: "mystore.myshopify.com",
    appId: "cookieBar", // "cookieBar" | "seaAccessibility" | "pdfInvoice"
  });

  if (loading || !data) return null;

  return (
    <div>
      <h2>{data.copy.title}</h2>
      <p>Installed: {data.installedCount} / {data.totalApps}</p>
      {data.applicableDiscount && (
        <p>Discount: {data.applicableDiscount.percentOff}% off</p>
      )}
    </div>
  );
}

Return

interface UseBundleCampaignResult {
  data: BundleCampaignData | null;
  loading: boolean;
}

interface BundleCampaignData {
  copy: { title: string; subtitle: string; compareLabel: string; footerNote: string };
  discountRules: { minInstalled: number; percentOff: number }[];
  applicableDiscount: { percentOff: number; couponCode?: string } | null;
  installedCount: number;
  totalApps: number;
  apps: BundleApp[];
}

Utility Functions

CrossApp Config

import {
  getAgeVerification,
  getAccessibilityApp,
  getCookieBarApp,
  getAppData,
} from "avada-ui-bridge";

const ageVerificationConfig = getAgeVerification(shop, "dashboard");
const accessibilityConfig = getAccessibilityApp(shop);
const cookieBarConfig = getCookieBarApp(shop);

// Generic function
const appConfig = getAppData("ageVerification", shop, "dashboard");

Each function returns a CrossAppData object:

interface CrossAppData {
  appHandle: string;
  translationKey: string;
  targetUrl: string;
  showPlanBtn?: boolean;
  planUrl?: string;
  bgColor?: string;
  isHideBanner?: boolean;
  eventPrefix?: string;
  bannerCloseKey?: string;
  sourcePage?: string;
}

Storage Utilities

import {
  getStorageData,
  setStorageData,
  removeStorageData,
  isEmpty,
} from "avada-ui-bridge";

setStorageData("my-key", { count: 1, date: new Date() });
const data = getStorageData("my-key", { count: 0 });
removeStorageData("my-key");
isEmpty(data); // true if null, empty array, or empty object

Helpers

import { getShopifyName } from "avada-ui-bridge";

getShopifyName("mystore.myshopify.com"); // "mystore"

Constants

Grouped Constants

import {
  BANNER_SOURCE_PAGES,
  BANNER_ACTION_TYPES,
  BANNER_SOURCE_APP,
  BANNER_APP_HANDLE,
  BANNER_APP_DOMAIN,
  BANNER_SHOPIFY_APP_HANDLE,
  BANNER_PLAN,
} from "avada-ui-bridge";

| Constant | Keys | Values | | ------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | BANNER_SOURCE_PAGES | DASHBOARD, SETTINGS, ORDERS, PRODUCTS, SCANNER, CONSENT_LOGS, BANNER_SETTINGS | "dashboard", "settings", "orders", "products", "scanner", "consentlogs", "bannersettings" | | BANNER_ACTION_TYPES | DISPLAY, ACCESS, CLOSE | "display", "access", "close" | | BANNER_SOURCE_APP | COOKIE_BAR, ORDER_LIMIT | "cb", "ol" | | BANNER_APP_HANDLE | COOKIE_BAR, ACCESSIBILITY, AGE_VERIFICATION | "cookieBar", "accessibility", "ageVerification" | | BANNER_APP_DOMAIN | COOKIE_BAR, ACCESSIBILITY, AGE_VERIFICATION | "cookie.avada.io", "sea-accessibility.firebaseapp.com", "age-verification-b0fa4.firebaseapp.com" | | BANNER_SHOPIFY_APP_HANDLE | COOKIE_BAR, ACCESSIBILITY, AGE_VERIFICATION | "avada-cookie-bar", "sea-accessibility-ada-wcag", "sun-age-verification-popup" | | BANNER_PLAN | ENTERPRISE | "enterprise" |

Storage Target Date Types

import {
  TARGET_STORAGE_NEXT_DAY,
  TARGET_STORAGE_NEXT_WEEK,
  TARGET_STORAGE_NEXT_MONDAY,
  TARGET_STORAGE_NEXT_MONDAY_AND_THURSDAY,
  TARGET_STORAGE_7_DAYS_AFTER,
} from "avada-ui-bridge";

Bundle Saving I18N Keys

import { BUNDLE_SAVING_I18N_KEYS } from "avada-ui-bridge";

Exports all required i18n translation keys for the BundleSaving component. Use this to ensure your app provides all necessary translations.

Backward Compatibility Aliases

import {
  AGE_VERIFICATION_HANDLE,    // = BANNER_APP_HANDLE.AGE_VERIFICATION
  ACCESSIBILITY_HANDLE,       // = BANNER_APP_HANDLE.ACCESSIBILITY
  COOKIE_BAR_HANDLE,          // = BANNER_APP_HANDLE.COOKIE_BAR
  AGE_VERIFICATION_DOMAIN,    // = BANNER_APP_DOMAIN.AGE_VERIFICATION
  ACCESSIBILITY_DOMAIN,       // = BANNER_APP_DOMAIN.ACCESSIBILITY
  COOKIE_BAR_DOMAIN,          // = BANNER_APP_DOMAIN.COOKIE_BAR
  AGE_VERIFICATION_APP_HANDLE, // = BANNER_SHOPIFY_APP_HANDLE.AGE_VERIFICATION
  ACCESSIBILITY_APP_HANDLE,   // = BANNER_SHOPIFY_APP_HANDLE.ACCESSIBILITY
  COOKIE_BAR_APP_HANDLE,      // = BANNER_SHOPIFY_APP_HANDLE.COOKIE_BAR
  ENTERPRISE,                 // = BANNER_PLAN.ENTERPRISE
} from "avada-ui-bridge";

TypeScript Types

import type {
  // AgeVerificationBanner
  AgeVerificationBannerProps,

  // useDisplayBanner
  UseDisplayBannerOptions,
  UseDisplayBannerResult,
  Shop,
  StorageData,
  TargetStorageType,

  // BundleSaving
  BundleSavingProps,
  BundleSavingShop,
  PlanConfig,
  SubscribeOptions,

  // CrossApp Config
  CrossAppData,
  ShopData,

  // Constants
  BannerActionType,
  BannerSourcePage,
  BannerSourceApp,
  BannerAppHandle,
  BannerAppDomain,
  BannerShopifyAppHandle,
  BannerPlan,
} from "avada-ui-bridge";

Translations

BundleSaving Component

Use BUNDLE_SAVING_I18N_KEYS to get the full list of required keys. Key categories:

  • OtherCompliance.bundle.copy.* - Header copy
  • OtherCompliance.bundle.progressBar.* - Progress bar labels
  • OtherCompliance.bundle.priceCards.* - Pricing card labels
  • OtherCompliance.bundle.appCards.* - App card action labels
  • OtherCompliance.cards.accessibility.* - Accessibility app card content
  • OtherCompliance.cards.dataProtection.* - Cookie Bar app card content
  • OtherCompliance.cards.eInvoice.* - PDF Invoice app card content

BundleSaving en.json

{
  "OtherCompliance": {
    "cards": {
      "eInvoice": {
        "title": "E-Invoice",
        "badge": "Required for EU, US, LATAM & APAC",
        "features": {
          "compliance": "Ensures legal invoicing compliance across global markets",
          "tax": "Simplifies tax reporting and accounting",
          "transparency": "Boosts transparency and customer trust",
          "automation": "Automates order invoicing (send, print, download)",
          "manualWork": "Reduces manual work and risk of legal penalties"
        },
        "appName": "PDF Invoice",
        "buttonText": "Install",
        "freePlan": "Free plan available"
      },
      "accessibility": {
        "title": "Accessibility (ADA, EAA, WCAG)",
        "badge": "Required for EU & US",
        "features": {
          "accessible": "Ensures that digital content is accessible to all customers",
          "experience": "Enhances user experience",
          "engagement": "Boosts customer engagement",
          "performance": "Improves your store's performance",
          "legal": "Reduces the risk of legal action and penalties"
        },
        "appName": "SEA Accessibility",
        "buttonText": "Install",
        "freePlan": "Free plan available"
      },
      "dataProtection": {
        "title": "Data protection (GDPR, CCPA)",
        "badge": "Required for EU & US",
        "features": {
          "privacy": "Protects personal data and privacy of customers",
          "trust": "Enhances customer trust",
          "engagement": "Boosts customer engagement",
          "reputation": "Protects brand reputation",
          "legal": "Reduces the risk of legal action and penalties"
        },
        "appName": "Avada GDPR Cookies Consent"
      }
    },
    "bundle": {
      "priceCards": {
        "currentPlan": "Current plan",
        "bestChoice": "Best choice",
        "perMonth": "/month",
        "downgradeTitle": "Downgrade to Free plan",
        "confirmDowngrade": "Confirm downgrade",
        "cancel": "Cancel",
        "downgradeMessage": "Are you sure you want to downgrade to the Free plan? You will lose access to premium features.",
        "planNames": {
          "cookieBar": {
            "free": "Free",
            "pro": "Professional",
            "advanced": "Advanced",
            "enterprise": "Enterprise"
          },
          "seaAccessibility": {
            "free": "Free",
            "starter": "Starter",
            "growth": "Growth",
            "scale": "Scale"
          },
          "pdfInvoice": {
            "free": "Free",
            "professional": "Professional",
            "ultimate": "Ultimate",
            "wholesale": "Wholesale"
          }
        }
      },
      "progressBar": {
        "awayFromDiscount": "You are {appsNeeded} app away from getting {percentOff}% off 🔥",
        "maxDiscount": "Amazing! You're saving {currentPercent}% — maximum discount reached!",
        "addOneMore": "Amazing! You're saving {currentPercent}% — add 1 more for max {percentOff}% off!",
        "savingGreat": "Great! You're saving {currentPercent}% — add {appsNeeded} more to save {percentOff}%",
        "savingAmazing": "Amazing! You're saving {currentPercent}% — add {appsNeeded} more for max {percentOff}% off!",
        "percentOff": "{percentOff}% off",
        "appInstalled": "{count} app installed",
        "appsInstalled": "{count} apps installed"
      },
      "appCards": {
        "subscribed": "Subscribed",
        "subscribe": "Subscribe",
        "install": "Install",
        "freePlanAvailable": "Free plan available"
      },
      "copy": {
        "title": "🎉 Stack your savings — the more apps you use, the more you save!",
        "subtitle": "Prices below reflect your bundle discount. Final price confirmed at checkout",
        "compareLabel": "Your discounted prices - active now!",
        "footerNote": "Discount applies automatically at checkout"
      }
    }
  }
}

License

MIT