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-bannerPeer Dependencies
@shopify/polaris >= 12.0.0@shopify/react-i18n >= 7.0.0react >= 16.8.0react-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 objectHelpers
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
