avada-crossapp-banner 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -0
- package/dist/components/CrossAppBanner/CrossAppBanner.d.ts +10 -0
- package/dist/components/CrossAppBanner/CrossAppBannerWithI18n.d.ts +10 -0
- package/dist/components/CrossAppBanner/index.d.ts +3 -0
- package/dist/components/icons/CrossAppIcon.d.ts +10 -0
- package/dist/components/icons/DownloadIcon.d.ts +7 -0
- package/dist/components/icons/index.d.ts +4 -0
- package/dist/constants/index.d.ts +116 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useDisplayBanner.d.ts +66 -0
- package/dist/index.d.ts +413 -0
- package/dist/index.esm.js +531 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +552 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +78 -0
- package/dist/types/index.d.ts +214 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# @avada/crossapp-banner
|
|
2
|
+
|
|
3
|
+
Shared CrossApp Banner components and hooks for Avada Shopify apps.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @avada/crossapp-banner
|
|
9
|
+
# or
|
|
10
|
+
yarn add @avada/crossapp-banner
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Peer Dependencies
|
|
14
|
+
|
|
15
|
+
This library requires the following peer dependencies:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"react": ">=16.8.0",
|
|
20
|
+
"react-dom": ">=16.8.0",
|
|
21
|
+
"@shopify/polaris": ">=12.0.0",
|
|
22
|
+
"@shopify/polaris-icons": ">=7.0.0",
|
|
23
|
+
"@shopify/react-i18n": ">=7.0.0"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Basic Usage
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import {
|
|
33
|
+
CrossAppBanner,
|
|
34
|
+
createCrossAppConfig,
|
|
35
|
+
getAgeVerificationAppData,
|
|
36
|
+
} from '@avada/crossapp-banner';
|
|
37
|
+
import '@avada/crossapp-banner/dist/styles.css';
|
|
38
|
+
|
|
39
|
+
// Create config for your app
|
|
40
|
+
const config = createCrossAppConfig({
|
|
41
|
+
appPrefix: 'cb', // 'cb' | 'ol' | 'ac' | 'av'
|
|
42
|
+
apiClient: fetchAuthenticatedApi, // Your API client
|
|
43
|
+
storeDispatch: (action) => store.dispatch(action), // Optional
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Get app data
|
|
47
|
+
const appData = getAgeVerificationAppData(shop, {
|
|
48
|
+
eventPrefix: 'cb',
|
|
49
|
+
utmSource: 'cookiebar',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function MyComponent() {
|
|
53
|
+
return (
|
|
54
|
+
<CrossAppBanner
|
|
55
|
+
config={config}
|
|
56
|
+
appData={appData}
|
|
57
|
+
sourcePage="dashboard"
|
|
58
|
+
shop={shop}
|
|
59
|
+
onClose={() => console.log('Banner closed')}
|
|
60
|
+
onShopUpdate={(data) => dispatch(setShop(data))}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### With i18n Support
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import {CrossAppBannerWithI18n} from '@avada/crossapp-banner';
|
|
70
|
+
|
|
71
|
+
// Requires @shopify/react-i18n context
|
|
72
|
+
function MyComponent() {
|
|
73
|
+
return (
|
|
74
|
+
<CrossAppBannerWithI18n
|
|
75
|
+
config={config}
|
|
76
|
+
appData={appData}
|
|
77
|
+
sourcePage="settings"
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Using the Display Banner Hook
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import {useDisplayBanner} from '@avada/crossapp-banner';
|
|
87
|
+
|
|
88
|
+
function MyBanner() {
|
|
89
|
+
const {shouldDisplay, hideBanner, handleCloseBanner} = useDisplayBanner({
|
|
90
|
+
storageKey: 'my-banner-key',
|
|
91
|
+
shopKey: 'banner_promotion',
|
|
92
|
+
shop: activeShop,
|
|
93
|
+
checkShop: true,
|
|
94
|
+
disableCount: 3,
|
|
95
|
+
targetDateType: '7_days_after',
|
|
96
|
+
apiClient: fetchAuthenticatedApi,
|
|
97
|
+
onShopUpdate: (data) => dispatch(setShop(data)),
|
|
98
|
+
onClose: () => console.log('Closed'),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!shouldDisplay) return null;
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div>
|
|
105
|
+
<button onClick={() => handleCloseBanner()}>Close</button>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API Reference
|
|
112
|
+
|
|
113
|
+
### Components
|
|
114
|
+
|
|
115
|
+
#### `CrossAppBanner`
|
|
116
|
+
Main banner component without i18n.
|
|
117
|
+
|
|
118
|
+
#### `CrossAppBannerWithI18n`
|
|
119
|
+
Banner component with `@shopify/react-i18n` support.
|
|
120
|
+
|
|
121
|
+
#### `CrossAppIcon`
|
|
122
|
+
Icon component for different apps.
|
|
123
|
+
|
|
124
|
+
#### `DownloadIcon`
|
|
125
|
+
Download icon SVG component.
|
|
126
|
+
|
|
127
|
+
### Hooks
|
|
128
|
+
|
|
129
|
+
#### `useDisplayBanner`
|
|
130
|
+
Hook to manage banner display state with localStorage persistence.
|
|
131
|
+
|
|
132
|
+
### Utilities
|
|
133
|
+
|
|
134
|
+
#### `createCrossAppConfig(config)`
|
|
135
|
+
Create a configuration object for the banner.
|
|
136
|
+
|
|
137
|
+
#### `getCookieBarAppData(shop, options?)`
|
|
138
|
+
Get app data for Cookie Bar promotion.
|
|
139
|
+
|
|
140
|
+
#### `getAgeVerificationAppData(shop, options?)`
|
|
141
|
+
Get app data for Age Verification promotion.
|
|
142
|
+
|
|
143
|
+
#### `getAccessibilityAppData(shop, options?)`
|
|
144
|
+
Get app data for Accessibility promotion.
|
|
145
|
+
|
|
146
|
+
#### `shouldExcludeShop(shop)`
|
|
147
|
+
Check if a shop should be excluded from cross-app promotions.
|
|
148
|
+
|
|
149
|
+
### Constants
|
|
150
|
+
|
|
151
|
+
- `APP_HANDLES` - App handle identifiers
|
|
152
|
+
- `APP_DOMAINS` - App domains
|
|
153
|
+
- `SHOPIFY_APP_HANDLES` - Shopify app handles
|
|
154
|
+
- `EXCLUDED_SHOPIFY_PLANS` - Plans to exclude
|
|
155
|
+
- `EXCLUDED_COUNTRIES` - Countries to exclude
|
|
156
|
+
- `TARGET_STORAGE_TYPES` - Storage type options
|
|
157
|
+
|
|
158
|
+
## Types
|
|
159
|
+
|
|
160
|
+
All types are exported and can be imported:
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import type {
|
|
164
|
+
AppHandle,
|
|
165
|
+
AppPrefix,
|
|
166
|
+
CrossAppConfig,
|
|
167
|
+
CrossAppData,
|
|
168
|
+
CrossAppBannerProps,
|
|
169
|
+
UseDisplayBannerConfig,
|
|
170
|
+
} from '@avada/crossapp-banner';
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Migration from Existing Code
|
|
174
|
+
|
|
175
|
+
### Before (duplicated code)
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
// order-limit/CrossApp.js
|
|
179
|
+
import {useStore} from '@assets/reducers/storeReducer';
|
|
180
|
+
import {setShop} from '@assets/actions/storeActions';
|
|
181
|
+
|
|
182
|
+
const CrossApp = ({appData}) => {
|
|
183
|
+
const {dispatch, state: {shop}} = useStore();
|
|
184
|
+
// ... 170+ lines of duplicated code
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### After (using library)
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
// order-limit/CrossApp.js
|
|
192
|
+
import {CrossAppBannerWithI18n, createCrossAppConfig} from '@avada/crossapp-banner';
|
|
193
|
+
import '@avada/crossapp-banner/dist/styles.css';
|
|
194
|
+
|
|
195
|
+
const config = createCrossAppConfig({
|
|
196
|
+
appPrefix: 'ol',
|
|
197
|
+
apiClient: fetchAuthenticatedApi,
|
|
198
|
+
storeDispatch: (action) => setShop(dispatch, action.payload),
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const CrossApp = ({appData}) => {
|
|
202
|
+
const {dispatch, state: {shop}} = useStore();
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<CrossAppBannerWithI18n
|
|
206
|
+
config={config}
|
|
207
|
+
appData={appData}
|
|
208
|
+
shop={shop}
|
|
209
|
+
onShopUpdate={(data) => setShop(dispatch, data)}
|
|
210
|
+
/>
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CrossAppBannerProps } from "../../types";
|
|
2
|
+
import "./CrossAppBanner.scss";
|
|
3
|
+
/**
|
|
4
|
+
* CrossApp Banner Component
|
|
5
|
+
*
|
|
6
|
+
* A reusable banner component for cross-promoting Avada apps.
|
|
7
|
+
* Supports configuration-based customization for different apps.
|
|
8
|
+
*/
|
|
9
|
+
export declare function CrossAppBanner({ config, appData, sourcePage, shop, onClose, onShopUpdate, }: CrossAppBannerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export default CrossAppBanner;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CrossAppBannerProps } from '../../types';
|
|
2
|
+
import './CrossAppBanner.scss';
|
|
3
|
+
/**
|
|
4
|
+
* CrossApp Banner Component with i18n support
|
|
5
|
+
*
|
|
6
|
+
* A reusable banner component for cross-promoting Avada apps.
|
|
7
|
+
* Uses @shopify/react-i18n for translations.
|
|
8
|
+
*/
|
|
9
|
+
export declare function CrossAppBannerWithI18n({ config, appData, sourcePage, shop, onClose, onShopUpdate, }: CrossAppBannerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export default CrossAppBannerWithI18n;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AppHandle } from '../../types';
|
|
2
|
+
export interface CrossAppIconProps {
|
|
3
|
+
app: AppHandle;
|
|
4
|
+
size?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* CrossApp icon component that renders the appropriate icon based on app handle
|
|
8
|
+
*/
|
|
9
|
+
export declare function CrossAppIcon({ app, size }: CrossAppIconProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default CrossAppIcon;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { AppHandle, CrossAppData, TargetStorageType } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* App handle constants
|
|
4
|
+
*/
|
|
5
|
+
export declare const APP_HANDLES: {
|
|
6
|
+
readonly ORDER_LIMIT: AppHandle;
|
|
7
|
+
readonly ACCESSIBILITY: AppHandle;
|
|
8
|
+
readonly COOKIE_BAR: AppHandle;
|
|
9
|
+
readonly AGE_VERIFICATION: AppHandle;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* App domains
|
|
13
|
+
*/
|
|
14
|
+
export declare const APP_DOMAINS: {
|
|
15
|
+
readonly COOKIE_BAR: "cookie.avada.io";
|
|
16
|
+
readonly AGE_VERIFICATION: "age-verification-b0fa4.firebaseapp.com";
|
|
17
|
+
readonly ACCESSIBILITY: "accessibility.avada.io";
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Shopify app handles
|
|
21
|
+
*/
|
|
22
|
+
export declare const SHOPIFY_APP_HANDLES: {
|
|
23
|
+
readonly COOKIE_BAR: "avada-cookie-bar";
|
|
24
|
+
readonly AGE_VERIFICATION: "sun-age-verification-popup";
|
|
25
|
+
readonly ACCESSIBILITY: "avada-accessibility";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Shopify plans to exclude from cross-app promotion
|
|
29
|
+
*/
|
|
30
|
+
export declare const EXCLUDED_SHOPIFY_PLANS: readonly ["partner_test", "affiliate", "staff", "frozen", "fraudulent", "cancelled", "paused"];
|
|
31
|
+
/**
|
|
32
|
+
* Countries to exclude from cross-app promotion
|
|
33
|
+
*/
|
|
34
|
+
export declare const EXCLUDED_COUNTRIES: readonly ["IN", "VN"];
|
|
35
|
+
/**
|
|
36
|
+
* Email suffixes to exclude
|
|
37
|
+
*/
|
|
38
|
+
export declare const EXCLUDED_EMAIL_SUFFIXES: readonly ["shopify.com"];
|
|
39
|
+
/**
|
|
40
|
+
* Avada email suffixes
|
|
41
|
+
*/
|
|
42
|
+
export declare const AVADA_EMAIL_SUFFIXES: readonly ["avadagroup.com", "avada.io"];
|
|
43
|
+
/**
|
|
44
|
+
* Target storage types for display banner
|
|
45
|
+
*/
|
|
46
|
+
export declare const TARGET_STORAGE_TYPES: Record<string, TargetStorageType>;
|
|
47
|
+
/**
|
|
48
|
+
* Default banner close key prefix
|
|
49
|
+
*/
|
|
50
|
+
export declare const BANNER_CLOSE_KEY_PREFIX = "bannerCloseCount_";
|
|
51
|
+
/**
|
|
52
|
+
* Get Shopify store name from domain
|
|
53
|
+
*/
|
|
54
|
+
export declare function getShopifyName(domain: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Check if shop should be excluded from cross-app promotion
|
|
57
|
+
*/
|
|
58
|
+
export declare function shouldExcludeShop(shop: {
|
|
59
|
+
shopifyPlan?: string;
|
|
60
|
+
country?: string;
|
|
61
|
+
email?: string;
|
|
62
|
+
}): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Get Cookie Bar app data for cross-app promotion
|
|
65
|
+
*/
|
|
66
|
+
export declare function getCookieBarAppData(shop: {
|
|
67
|
+
shopifyDomain: string;
|
|
68
|
+
cookieBarInstalled?: boolean;
|
|
69
|
+
}, options?: {
|
|
70
|
+
showPlanBtn?: boolean;
|
|
71
|
+
eventPrefix?: string;
|
|
72
|
+
}): CrossAppData;
|
|
73
|
+
/**
|
|
74
|
+
* Get Age Verification app data for cross-app promotion
|
|
75
|
+
*/
|
|
76
|
+
export declare function getAgeVerificationAppData(shop: {
|
|
77
|
+
shopifyDomain: string;
|
|
78
|
+
ageVerificationInstalled?: boolean;
|
|
79
|
+
hideVerificationBanner?: boolean;
|
|
80
|
+
}, options?: {
|
|
81
|
+
eventPrefix?: string;
|
|
82
|
+
utmSource?: string;
|
|
83
|
+
}): CrossAppData;
|
|
84
|
+
/**
|
|
85
|
+
* Get Accessibility app data for cross-app promotion
|
|
86
|
+
*/
|
|
87
|
+
export declare function getAccessibilityAppData(shop: {
|
|
88
|
+
shopifyDomain: string;
|
|
89
|
+
accessibilityInstalled?: boolean;
|
|
90
|
+
}, options?: {
|
|
91
|
+
eventPrefix?: string;
|
|
92
|
+
}): CrossAppData;
|
|
93
|
+
/**
|
|
94
|
+
* Create cross-app config helper
|
|
95
|
+
*/
|
|
96
|
+
export declare function createCrossAppConfig(config: {
|
|
97
|
+
appPrefix: 'cb' | 'av' | 'ac' | 'ol';
|
|
98
|
+
apiClient: (url: string, options?: {
|
|
99
|
+
method?: string;
|
|
100
|
+
body?: Record<string, unknown>;
|
|
101
|
+
}) => Promise<unknown>;
|
|
102
|
+
storeDispatch?: (action: unknown) => void;
|
|
103
|
+
closeIcon?: React.ReactNode;
|
|
104
|
+
bannerEventEndpoint?: string;
|
|
105
|
+
shopUpdateEndpoint?: string;
|
|
106
|
+
}): {
|
|
107
|
+
appPrefix: "cb" | "av" | "ac" | "ol";
|
|
108
|
+
apiClient: (url: string, options?: {
|
|
109
|
+
method?: string;
|
|
110
|
+
body?: Record<string, unknown>;
|
|
111
|
+
}) => Promise<unknown>;
|
|
112
|
+
storeDispatch: ((action: unknown) => void) | undefined;
|
|
113
|
+
closeIcon: import("react").ReactNode;
|
|
114
|
+
bannerEventEndpoint: string;
|
|
115
|
+
shopUpdateEndpoint: string;
|
|
116
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { UseDisplayBannerReturn, TargetStorageType } from '../types';
|
|
2
|
+
export interface UseDisplayBannerConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Storage key for tracking display state
|
|
5
|
+
*/
|
|
6
|
+
storageKey: string;
|
|
7
|
+
/**
|
|
8
|
+
* Shop key for tracking dismissed banners per shop
|
|
9
|
+
*/
|
|
10
|
+
shopKey?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Current shop data
|
|
13
|
+
*/
|
|
14
|
+
shop?: {
|
|
15
|
+
dismissedBanners?: string[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Whether to check shop dismissed banners
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
checkShop?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Number of closes before permanently dismissing
|
|
25
|
+
* @default 3
|
|
26
|
+
*/
|
|
27
|
+
disableCount?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Target storage type for next display
|
|
30
|
+
* @default 'next_day'
|
|
31
|
+
*/
|
|
32
|
+
targetDateType?: TargetStorageType;
|
|
33
|
+
/**
|
|
34
|
+
* API client function for making requests
|
|
35
|
+
*/
|
|
36
|
+
apiClient?: (url: string, options?: {
|
|
37
|
+
method?: string;
|
|
38
|
+
body?: Record<string, unknown>;
|
|
39
|
+
}) => Promise<{
|
|
40
|
+
success?: boolean;
|
|
41
|
+
data?: Record<string, unknown>;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Endpoint for updating shop data
|
|
45
|
+
* @default '/shops?type=banner'
|
|
46
|
+
*/
|
|
47
|
+
shopUpdateEndpoint?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Callback when shop data is updated
|
|
50
|
+
*/
|
|
51
|
+
onShopUpdate?: (shopData: Record<string, unknown>) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Callback when banner is closed
|
|
54
|
+
*/
|
|
55
|
+
onClose?: () => void;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to check storage for display state
|
|
58
|
+
* @default true
|
|
59
|
+
*/
|
|
60
|
+
checkStorage?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Hook to manage banner display state with localStorage persistence
|
|
64
|
+
*/
|
|
65
|
+
export declare function useDisplayBanner({ storageKey, shopKey, shop, checkShop, disableCount, targetDateType, apiClient, shopUpdateEndpoint, onShopUpdate, onClose, checkStorage, }: UseDisplayBannerConfig): UseDisplayBannerReturn;
|
|
66
|
+
export default useDisplayBanner;
|