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-crossapp-banner

v1.1.1

Published

Shared CrossApp Banner components and hooks for Avada Shopify apps

Readme

Avada CrossApp Banner

Shared CrossApp Banner components and hooks for Avada Shopify apps.

Installation

npm install avada-crossapp-banner

Peer Dependencies

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

Components

CrossApp

Displays cross-app promotional banners with built-in icons.

import { CrossApp, AGE_VERIFICATION_HANDLE } from "avada-crossapp-banner";
import "avada-crossapp-banner/dist/styles.css";

function MyComponent() {
  const shop = {
    shopifyDomain: "mystore.myshopify.com",
    plan: "professional",
    ageVerificationInstalled: false,
    hideVerificationBanner: false,
  };

  return (
    <CrossApp
      shop={shop}
      appHandle={AGE_VERIFICATION_HANDLE}
      sourceApp="cb"
      sourcePage="dashboard"
      onLogEvent={async (eventName, properties, isClosePermanently) => {
        await trackEvent(eventName, properties);
      }}
      onUpdateShop={(updates) => {
        updateShop({ ...shop, ...updates });
      }}
    />
  );
}

Props

| Prop | Type | Required | Default | Description | | -------------- | ------------------------------------------------------------------------------------------------------ | -------- | ------------- | --------------------------------------------------------------------------------------- | | shop | ShopData | Yes | - | Shop data object | | appHandle | string | Yes | - | App identifier (AGE_VERIFICATION_HANDLE, ACCESSIBILITY_HANDLE, COOKIE_BAR_HANDLE) | | sourceApp | string | Yes | - | Source app identifier for event tracking ("cb", "ol") | | sourcePage | BannerSourcePage | No | "dashboard" | Page where banner is displayed | | onLogEvent | (eventName: string, properties?: Record<string, any>, isClosePermanently?: boolean) => Promise<void> | No | - | Callback for tracking banner events | | onUpdateShop | (updates: Partial<ShopData>) => void | No | - | Callback to update shop state on permanent dismissal |

ShopData

interface ShopData {
  shopifyDomain: string;
  plan?: string;
  accessibilityInstalled?: boolean;
  cookieBarInstalled?: boolean;
  ageVerificationInstalled?: boolean;
  hideVerificationBanner?: boolean;
  [key: string]: any;
}

Icons are built-in. The component automatically displays the correct icon based on appHandle.


AgeVerificationBanner

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

import { AgeVerificationBanner } from "avada-crossapp-banner";

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 |


Hooks

useDisplayBanner

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

import {
  useDisplayBanner,
  TARGET_STORAGE_NEXT_DAY,
} from "avada-crossapp-banner";

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 |


Utility Functions

CrossApp Config

import {
  getAgeVerification,
  getAccessibilityApp,
  getCookieBarApp,
  getAppData,
} from "avada-crossapp-banner";

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-crossapp-banner";

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-crossapp-banner";

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-crossapp-banner";

| 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-crossapp-banner";

Backward Compatibility Aliases

import {
  // App handles
  AGE_VERIFICATION_HANDLE, // = BANNER_APP_HANDLE.AGE_VERIFICATION
  ACCESSIBILITY_HANDLE, // = BANNER_APP_HANDLE.ACCESSIBILITY
  COOKIE_BAR_HANDLE, // = BANNER_APP_HANDLE.COOKIE_BAR

  // App domains
  AGE_VERIFICATION_DOMAIN, // = BANNER_APP_DOMAIN.AGE_VERIFICATION
  ACCESSIBILITY_DOMAIN, // = BANNER_APP_DOMAIN.ACCESSIBILITY
  COOKIE_BAR_DOMAIN, // = BANNER_APP_DOMAIN.COOKIE_BAR

  // Shopify app handles
  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

  // Plan
  ENTERPRISE, // = BANNER_PLAN.ENTERPRISE
} from "avada-crossapp-banner";

TypeScript Types

import type {
  // Component props
  CrossAppProps,
  CrossAppData,
  ShopData,

  // Hook types
  UseDisplayBannerOptions,
  UseDisplayBannerResult,
  Shop,

  // Storage types
  StorageData,
  TargetStorageType,

  // Constant value types
  BannerActionType,
  BannerSourcePage,
  BannerSourceApp,
  BannerAppHandle,
  BannerAppDomain,
  BannerShopifyAppHandle,
  BannerPlan,
} from "avada-crossapp-banner";

Translations

The CrossApp component uses i18n translations from the consuming app. Add these keys to your translation files:

{
  "CrossApp": {
    "cookieApp": {
      "title": "Get Avada Cookie Consent for FREE",
      "btnClaim": "Claim FREE app",
      "description1": "Unlock full cookie consent compliance at no extra cost!",
      "description2": "If you're on the Accessibility Scale plan...",
      "btnViewPlan": "View our plan"
    },
    "ageVerification": {
      "title": "Get SUN Age Verification Popup for FREE",
      "btnClaim": "Try for FREE",
      "description1": "Protect your business from compliance risks without decreasing sales",
      "description2": "Selling to underage customers can hurt revenue...",
      "btnViewPlan": ""
    },
    "accessibilityApp": {
      "title": "Get Avada Accessibility App for FREE",
      "btnClaim": "Claim FREE app",
      "description1": "Make your store accessible to everyone at no extra cost!",
      "description2": "Ensure ADA and WCAG compliance...",
      "btnViewPlan": "View our plan"
    }
  }
}

License

MIT