@adtogether/web-sdk 0.1.12 → 0.1.14
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/CHANGELOG.md +13 -0
- package/README.md +8 -1
- package/dist/{chunk-7IJIBJD4.mjs → chunk-RW43ES42.mjs} +13 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -1
- package/dist/index.mjs +1 -1
- package/dist/react/index.d.mts +4 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +55 -3
- package/dist/react/index.mjs +43 -3
- package/package.json +2 -1
- package/src/core/AdTogether.ts +15 -1
- package/src/core/types.ts +1 -0
- package/src/react/AdTogetherBanner.tsx +47 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## 0.1.14
|
|
2
|
+
|
|
3
|
+
* **Feature**: Added `onAdClosed` callback support to banner components.
|
|
4
|
+
* **Feature**: Improved automatic `bundleId` detection across all platforms.
|
|
5
|
+
* **Security**: Hardened ad-serving logic to prevent payout fraud.
|
|
6
|
+
* **Sync**: Version parity across all AdTogether SDKs.
|
|
7
|
+
|
|
8
|
+
## 0.1.12
|
|
9
|
+
|
|
10
|
+
* **Feature**: Added `showCloseButton` to React components.
|
|
11
|
+
* **Standardization**: Support for `onAdLoaded` and `onAdFailedToLoad` across all platforms.
|
|
12
|
+
* **Layout**: Enhanced responsiveness and safety checks for ad rendering.
|
|
13
|
+
|
|
1
14
|
## 0.1.9
|
|
2
15
|
|
|
3
16
|
* **Feature**: Added `onAdLoaded` and `onAdFailedToLoad` callback support to React components.
|
package/README.md
CHANGED
|
@@ -45,7 +45,10 @@ Call `AdTogether.initialize()` before rendering any ad components. You can obtai
|
|
|
45
45
|
```typescript
|
|
46
46
|
import { AdTogether } from '@adtogether/web-sdk';
|
|
47
47
|
|
|
48
|
-
AdTogether.initialize({
|
|
48
|
+
AdTogether.initialize({
|
|
49
|
+
appId: 'YOUR_APP_ID',
|
|
50
|
+
// bundleId: 'com.example.app' // optional: automatically detected from window.location.hostname
|
|
51
|
+
});
|
|
49
52
|
```
|
|
50
53
|
|
|
51
54
|
## Usage
|
|
@@ -64,8 +67,10 @@ function MyApp() {
|
|
|
64
67
|
|
|
65
68
|
<AdTogetherBanner
|
|
66
69
|
adUnitId="home_bottom_banner"
|
|
70
|
+
showCloseButton={true}
|
|
67
71
|
onAdLoaded={() => console.log('Banner loaded!')}
|
|
68
72
|
onAdFailedToLoad={(error) => console.error('Banner error:', error)}
|
|
73
|
+
onAdClosed={() => console.log('Banner closed!')}
|
|
69
74
|
/>
|
|
70
75
|
</div>
|
|
71
76
|
);
|
|
@@ -77,6 +82,8 @@ function MyApp() {
|
|
|
77
82
|
| Prop | Type | Default | Description |
|
|
78
83
|
|--------------------|-------------------------|-----------|-------------|
|
|
79
84
|
| `adUnitId` | `string` | **required** | Unique identifier for this ad placement. |
|
|
85
|
+
| `showCloseButton` | `boolean` | `false` | Show a dismissable close button overlay. |
|
|
86
|
+
| `onAdClosed` | `() => void` | — | Called when the user closes the ad. |
|
|
80
87
|
| `width` | `number \| string` | `'100%'` | Width of the ad element. |
|
|
81
88
|
| `height` | `number \| string` | `'auto'` | Height of the ad element. |
|
|
82
89
|
| `theme` | `'dark' \| 'light' \| 'auto'` | `'auto'` | Color scheme. `'auto'` follows system preference. |
|
|
@@ -13,6 +13,11 @@ var AdTogether = class _AdTogether {
|
|
|
13
13
|
static initialize(options) {
|
|
14
14
|
const sdk = _AdTogether.shared;
|
|
15
15
|
sdk.appId = options.apiKey || options.appId;
|
|
16
|
+
if (options.bundleId) {
|
|
17
|
+
sdk.bundleId = options.bundleId;
|
|
18
|
+
} else if (typeof window !== "undefined") {
|
|
19
|
+
sdk.bundleId = window.location.hostname;
|
|
20
|
+
}
|
|
16
21
|
if (options.allowSelfAds !== void 0) {
|
|
17
22
|
sdk.allowSelfAds = options.allowSelfAds;
|
|
18
23
|
}
|
|
@@ -43,6 +48,9 @@ var AdTogether = class _AdTogether {
|
|
|
43
48
|
if (sdk.lastAdId) {
|
|
44
49
|
url += `&exclude=${sdk.lastAdId}`;
|
|
45
50
|
}
|
|
51
|
+
if (sdk.bundleId) {
|
|
52
|
+
url += `&bundleId=${sdk.bundleId}`;
|
|
53
|
+
}
|
|
46
54
|
url += `&allowSelfAds=${sdk.allowSelfAds}`;
|
|
47
55
|
if (typeof window !== "undefined") {
|
|
48
56
|
url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
|
|
@@ -74,7 +82,11 @@ var AdTogether = class _AdTogether {
|
|
|
74
82
|
body: JSON.stringify({
|
|
75
83
|
adId,
|
|
76
84
|
token,
|
|
77
|
-
apiKey: _AdTogether.shared.appId
|
|
85
|
+
apiKey: _AdTogether.shared.appId,
|
|
86
|
+
..._AdTogether.shared.bundleId ? { bundleId: _AdTogether.shared.bundleId } : {},
|
|
87
|
+
// Send platform and environment to match Flutter SDK
|
|
88
|
+
platform: "web",
|
|
89
|
+
environment: typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? "development" : "production"
|
|
78
90
|
})
|
|
79
91
|
}).catch(console.error);
|
|
80
92
|
}
|
package/dist/index.d.mts
CHANGED
|
@@ -12,6 +12,7 @@ interface AdTogetherOptions {
|
|
|
12
12
|
appId?: string;
|
|
13
13
|
apiKey?: string;
|
|
14
14
|
baseUrl?: string;
|
|
15
|
+
bundleId?: string;
|
|
15
16
|
/** Whether to show your own ads as fallback if no external ads are available. Defaults to true. */
|
|
16
17
|
allowSelfAds?: boolean;
|
|
17
18
|
}
|
|
@@ -19,6 +20,7 @@ interface AdTogetherOptions {
|
|
|
19
20
|
declare class AdTogether {
|
|
20
21
|
private static instance;
|
|
21
22
|
private appId?;
|
|
23
|
+
private bundleId?;
|
|
22
24
|
private allowSelfAds;
|
|
23
25
|
baseUrl: string;
|
|
24
26
|
private constructor();
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ interface AdTogetherOptions {
|
|
|
12
12
|
appId?: string;
|
|
13
13
|
apiKey?: string;
|
|
14
14
|
baseUrl?: string;
|
|
15
|
+
bundleId?: string;
|
|
15
16
|
/** Whether to show your own ads as fallback if no external ads are available. Defaults to true. */
|
|
16
17
|
allowSelfAds?: boolean;
|
|
17
18
|
}
|
|
@@ -19,6 +20,7 @@ interface AdTogetherOptions {
|
|
|
19
20
|
declare class AdTogether {
|
|
20
21
|
private static instance;
|
|
21
22
|
private appId?;
|
|
23
|
+
private bundleId?;
|
|
22
24
|
private allowSelfAds;
|
|
23
25
|
baseUrl: string;
|
|
24
26
|
private constructor();
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,11 @@ var AdTogether = class _AdTogether {
|
|
|
39
39
|
static initialize(options) {
|
|
40
40
|
const sdk = _AdTogether.shared;
|
|
41
41
|
sdk.appId = options.apiKey || options.appId;
|
|
42
|
+
if (options.bundleId) {
|
|
43
|
+
sdk.bundleId = options.bundleId;
|
|
44
|
+
} else if (typeof window !== "undefined") {
|
|
45
|
+
sdk.bundleId = window.location.hostname;
|
|
46
|
+
}
|
|
42
47
|
if (options.allowSelfAds !== void 0) {
|
|
43
48
|
sdk.allowSelfAds = options.allowSelfAds;
|
|
44
49
|
}
|
|
@@ -69,6 +74,9 @@ var AdTogether = class _AdTogether {
|
|
|
69
74
|
if (sdk.lastAdId) {
|
|
70
75
|
url += `&exclude=${sdk.lastAdId}`;
|
|
71
76
|
}
|
|
77
|
+
if (sdk.bundleId) {
|
|
78
|
+
url += `&bundleId=${sdk.bundleId}`;
|
|
79
|
+
}
|
|
72
80
|
url += `&allowSelfAds=${sdk.allowSelfAds}`;
|
|
73
81
|
if (typeof window !== "undefined") {
|
|
74
82
|
url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
|
|
@@ -100,7 +108,11 @@ var AdTogether = class _AdTogether {
|
|
|
100
108
|
body: JSON.stringify({
|
|
101
109
|
adId,
|
|
102
110
|
token,
|
|
103
|
-
apiKey: _AdTogether.shared.appId
|
|
111
|
+
apiKey: _AdTogether.shared.appId,
|
|
112
|
+
..._AdTogether.shared.bundleId ? { bundleId: _AdTogether.shared.bundleId } : {},
|
|
113
|
+
// Send platform and environment to match Flutter SDK
|
|
114
|
+
platform: "web",
|
|
115
|
+
environment: typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? "development" : "production"
|
|
104
116
|
})
|
|
105
117
|
}).catch(console.error);
|
|
106
118
|
}
|
package/dist/index.mjs
CHANGED
package/dist/react/index.d.mts
CHANGED
|
@@ -6,6 +6,10 @@ interface AdTogetherBannerProps {
|
|
|
6
6
|
style?: React.CSSProperties;
|
|
7
7
|
onAdLoaded?: () => void;
|
|
8
8
|
onAdFailedToLoad?: (error: Error) => void;
|
|
9
|
+
/** Whether to show a close button on the banner */
|
|
10
|
+
showCloseButton?: boolean;
|
|
11
|
+
/** Callback when the user closes the ad */
|
|
12
|
+
onAdClosed?: () => void;
|
|
9
13
|
/** Width of the ad element. Defaults to '100%' */
|
|
10
14
|
width?: number | string;
|
|
11
15
|
/** Height of the ad element. Defaults to 'auto' */
|
package/dist/react/index.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ interface AdTogetherBannerProps {
|
|
|
6
6
|
style?: React.CSSProperties;
|
|
7
7
|
onAdLoaded?: () => void;
|
|
8
8
|
onAdFailedToLoad?: (error: Error) => void;
|
|
9
|
+
/** Whether to show a close button on the banner */
|
|
10
|
+
showCloseButton?: boolean;
|
|
11
|
+
/** Callback when the user closes the ad */
|
|
12
|
+
onAdClosed?: () => void;
|
|
9
13
|
/** Width of the ad element. Defaults to '100%' */
|
|
10
14
|
width?: number | string;
|
|
11
15
|
/** Height of the ad element. Defaults to 'auto' */
|
package/dist/react/index.js
CHANGED
|
@@ -43,6 +43,11 @@ var AdTogether = class _AdTogether {
|
|
|
43
43
|
static initialize(options) {
|
|
44
44
|
const sdk = _AdTogether.shared;
|
|
45
45
|
sdk.appId = options.apiKey || options.appId;
|
|
46
|
+
if (options.bundleId) {
|
|
47
|
+
sdk.bundleId = options.bundleId;
|
|
48
|
+
} else if (typeof window !== "undefined") {
|
|
49
|
+
sdk.bundleId = window.location.hostname;
|
|
50
|
+
}
|
|
46
51
|
if (options.allowSelfAds !== void 0) {
|
|
47
52
|
sdk.allowSelfAds = options.allowSelfAds;
|
|
48
53
|
}
|
|
@@ -73,6 +78,9 @@ var AdTogether = class _AdTogether {
|
|
|
73
78
|
if (sdk.lastAdId) {
|
|
74
79
|
url += `&exclude=${sdk.lastAdId}`;
|
|
75
80
|
}
|
|
81
|
+
if (sdk.bundleId) {
|
|
82
|
+
url += `&bundleId=${sdk.bundleId}`;
|
|
83
|
+
}
|
|
76
84
|
url += `&allowSelfAds=${sdk.allowSelfAds}`;
|
|
77
85
|
if (typeof window !== "undefined") {
|
|
78
86
|
url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
|
|
@@ -104,7 +112,11 @@ var AdTogether = class _AdTogether {
|
|
|
104
112
|
body: JSON.stringify({
|
|
105
113
|
adId,
|
|
106
114
|
token,
|
|
107
|
-
apiKey: _AdTogether.shared.appId
|
|
115
|
+
apiKey: _AdTogether.shared.appId,
|
|
116
|
+
..._AdTogether.shared.bundleId ? { bundleId: _AdTogether.shared.bundleId } : {},
|
|
117
|
+
// Send platform and environment to match Flutter SDK
|
|
118
|
+
platform: "web",
|
|
119
|
+
environment: typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? "development" : "production"
|
|
108
120
|
})
|
|
109
121
|
}).catch(console.error);
|
|
110
122
|
}
|
|
@@ -118,6 +130,8 @@ var AdTogetherBanner = ({
|
|
|
118
130
|
style = {},
|
|
119
131
|
onAdLoaded,
|
|
120
132
|
onAdFailedToLoad,
|
|
133
|
+
showCloseButton = false,
|
|
134
|
+
onAdClosed,
|
|
121
135
|
width = "100%",
|
|
122
136
|
height = "auto",
|
|
123
137
|
theme = "auto"
|
|
@@ -125,6 +139,7 @@ var AdTogetherBanner = ({
|
|
|
125
139
|
const [adData, setAdData] = (0, import_react.useState)(null);
|
|
126
140
|
const [isLoading, setIsLoading] = (0, import_react.useState)(true);
|
|
127
141
|
const [hasError, setHasError] = (0, import_react.useState)(false);
|
|
142
|
+
const [isVisible, setIsVisible] = (0, import_react.useState)(true);
|
|
128
143
|
const [isDarkMode, setIsDarkMode] = (0, import_react.useState)(theme === "dark");
|
|
129
144
|
const containerRef = (0, import_react.useRef)(null);
|
|
130
145
|
const impressionTrackedRef = (0, import_react.useRef)(false);
|
|
@@ -141,7 +156,7 @@ var AdTogetherBanner = ({
|
|
|
141
156
|
}, [theme]);
|
|
142
157
|
(0, import_react.useEffect)(() => {
|
|
143
158
|
let isMounted = true;
|
|
144
|
-
AdTogether.fetchAd(adUnitId).then((ad) => {
|
|
159
|
+
AdTogether.fetchAd(adUnitId, "banner").then((ad) => {
|
|
145
160
|
if (isMounted) {
|
|
146
161
|
setAdData(ad);
|
|
147
162
|
setIsLoading(false);
|
|
@@ -183,6 +198,14 @@ var AdTogetherBanner = ({
|
|
|
183
198
|
window.open(adData.clickUrl, "_blank", "noopener,noreferrer");
|
|
184
199
|
}
|
|
185
200
|
};
|
|
201
|
+
const handleClose = (e) => {
|
|
202
|
+
e.stopPropagation();
|
|
203
|
+
setIsVisible(false);
|
|
204
|
+
onAdClosed?.();
|
|
205
|
+
};
|
|
206
|
+
if (!isVisible) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
186
209
|
if (isLoading) {
|
|
187
210
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
188
211
|
"div",
|
|
@@ -217,6 +240,7 @@ var AdTogetherBanner = ({
|
|
|
217
240
|
overflow: "hidden",
|
|
218
241
|
cursor: "pointer",
|
|
219
242
|
boxSizing: "border-box",
|
|
243
|
+
position: "relative",
|
|
220
244
|
...style
|
|
221
245
|
},
|
|
222
246
|
onMouseOver: (e) => {
|
|
@@ -249,7 +273,35 @@ var AdTogetherBanner = ({
|
|
|
249
273
|
}, children: "AD" })
|
|
250
274
|
] }),
|
|
251
275
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "12px", color: descColor, overflow: "hidden", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical" }, children: adData.description })
|
|
252
|
-
] })
|
|
276
|
+
] }),
|
|
277
|
+
showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
278
|
+
"button",
|
|
279
|
+
{
|
|
280
|
+
onClick: handleClose,
|
|
281
|
+
"aria-label": "Close ad",
|
|
282
|
+
style: {
|
|
283
|
+
position: "absolute",
|
|
284
|
+
top: "8px",
|
|
285
|
+
right: "8px",
|
|
286
|
+
width: "24px",
|
|
287
|
+
height: "24px",
|
|
288
|
+
borderRadius: "50%",
|
|
289
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
290
|
+
border: "none",
|
|
291
|
+
color: "#fff",
|
|
292
|
+
fontSize: "14px",
|
|
293
|
+
fontWeight: "bold",
|
|
294
|
+
cursor: "pointer",
|
|
295
|
+
display: "flex",
|
|
296
|
+
alignItems: "center",
|
|
297
|
+
justifyContent: "center",
|
|
298
|
+
padding: 0,
|
|
299
|
+
lineHeight: 1,
|
|
300
|
+
zIndex: 1
|
|
301
|
+
},
|
|
302
|
+
children: "\xD7"
|
|
303
|
+
}
|
|
304
|
+
)
|
|
253
305
|
]
|
|
254
306
|
}
|
|
255
307
|
);
|
package/dist/react/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AdTogether
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-RW43ES42.mjs";
|
|
4
4
|
|
|
5
5
|
// src/react/AdTogetherBanner.tsx
|
|
6
6
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -11,6 +11,8 @@ var AdTogetherBanner = ({
|
|
|
11
11
|
style = {},
|
|
12
12
|
onAdLoaded,
|
|
13
13
|
onAdFailedToLoad,
|
|
14
|
+
showCloseButton = false,
|
|
15
|
+
onAdClosed,
|
|
14
16
|
width = "100%",
|
|
15
17
|
height = "auto",
|
|
16
18
|
theme = "auto"
|
|
@@ -18,6 +20,7 @@ var AdTogetherBanner = ({
|
|
|
18
20
|
const [adData, setAdData] = useState(null);
|
|
19
21
|
const [isLoading, setIsLoading] = useState(true);
|
|
20
22
|
const [hasError, setHasError] = useState(false);
|
|
23
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
21
24
|
const [isDarkMode, setIsDarkMode] = useState(theme === "dark");
|
|
22
25
|
const containerRef = useRef(null);
|
|
23
26
|
const impressionTrackedRef = useRef(false);
|
|
@@ -34,7 +37,7 @@ var AdTogetherBanner = ({
|
|
|
34
37
|
}, [theme]);
|
|
35
38
|
useEffect(() => {
|
|
36
39
|
let isMounted = true;
|
|
37
|
-
AdTogether.fetchAd(adUnitId).then((ad) => {
|
|
40
|
+
AdTogether.fetchAd(adUnitId, "banner").then((ad) => {
|
|
38
41
|
if (isMounted) {
|
|
39
42
|
setAdData(ad);
|
|
40
43
|
setIsLoading(false);
|
|
@@ -76,6 +79,14 @@ var AdTogetherBanner = ({
|
|
|
76
79
|
window.open(adData.clickUrl, "_blank", "noopener,noreferrer");
|
|
77
80
|
}
|
|
78
81
|
};
|
|
82
|
+
const handleClose = (e) => {
|
|
83
|
+
e.stopPropagation();
|
|
84
|
+
setIsVisible(false);
|
|
85
|
+
onAdClosed?.();
|
|
86
|
+
};
|
|
87
|
+
if (!isVisible) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
79
90
|
if (isLoading) {
|
|
80
91
|
return /* @__PURE__ */ jsx(
|
|
81
92
|
"div",
|
|
@@ -110,6 +121,7 @@ var AdTogetherBanner = ({
|
|
|
110
121
|
overflow: "hidden",
|
|
111
122
|
cursor: "pointer",
|
|
112
123
|
boxSizing: "border-box",
|
|
124
|
+
position: "relative",
|
|
113
125
|
...style
|
|
114
126
|
},
|
|
115
127
|
onMouseOver: (e) => {
|
|
@@ -142,7 +154,35 @@ var AdTogetherBanner = ({
|
|
|
142
154
|
}, children: "AD" })
|
|
143
155
|
] }),
|
|
144
156
|
/* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: descColor, overflow: "hidden", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical" }, children: adData.description })
|
|
145
|
-
] })
|
|
157
|
+
] }),
|
|
158
|
+
showCloseButton && /* @__PURE__ */ jsx(
|
|
159
|
+
"button",
|
|
160
|
+
{
|
|
161
|
+
onClick: handleClose,
|
|
162
|
+
"aria-label": "Close ad",
|
|
163
|
+
style: {
|
|
164
|
+
position: "absolute",
|
|
165
|
+
top: "8px",
|
|
166
|
+
right: "8px",
|
|
167
|
+
width: "24px",
|
|
168
|
+
height: "24px",
|
|
169
|
+
borderRadius: "50%",
|
|
170
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
171
|
+
border: "none",
|
|
172
|
+
color: "#fff",
|
|
173
|
+
fontSize: "14px",
|
|
174
|
+
fontWeight: "bold",
|
|
175
|
+
cursor: "pointer",
|
|
176
|
+
display: "flex",
|
|
177
|
+
alignItems: "center",
|
|
178
|
+
justifyContent: "center",
|
|
179
|
+
padding: 0,
|
|
180
|
+
lineHeight: 1,
|
|
181
|
+
zIndex: 1
|
|
182
|
+
},
|
|
183
|
+
children: "\xD7"
|
|
184
|
+
}
|
|
185
|
+
)
|
|
146
186
|
]
|
|
147
187
|
}
|
|
148
188
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adtogether/web-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "The official AdTogether Web SDK — reciprocal ad exchange to increase conversions and grow your audience.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"react-dom": "^19.2.4"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
+
"@types/node": "^22.0.0",
|
|
53
54
|
"@types/react": "^19.2.14",
|
|
54
55
|
"@types/react-dom": "^19.2.3",
|
|
55
56
|
"tsup": "^8.5.1",
|
package/src/core/AdTogether.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { AdModel, AdType, AdTogetherOptions } from './types';
|
|
|
3
3
|
export class AdTogether {
|
|
4
4
|
private static instance: AdTogether;
|
|
5
5
|
private appId?: string;
|
|
6
|
+
private bundleId?: string;
|
|
6
7
|
private allowSelfAds: boolean = true;
|
|
7
8
|
public baseUrl: string = 'https://adtogether.relaxsoftwareapps.com';
|
|
8
9
|
|
|
@@ -19,6 +20,12 @@ export class AdTogether {
|
|
|
19
20
|
const sdk = AdTogether.shared;
|
|
20
21
|
sdk.appId = options.apiKey || options.appId;
|
|
21
22
|
|
|
23
|
+
if (options.bundleId) {
|
|
24
|
+
sdk.bundleId = options.bundleId;
|
|
25
|
+
} else if (typeof window !== 'undefined') {
|
|
26
|
+
sdk.bundleId = window.location.hostname;
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
if (options.allowSelfAds !== undefined) {
|
|
23
30
|
sdk.allowSelfAds = options.allowSelfAds;
|
|
24
31
|
}
|
|
@@ -57,6 +64,9 @@ export class AdTogether {
|
|
|
57
64
|
if (sdk.lastAdId) {
|
|
58
65
|
url += `&exclude=${sdk.lastAdId}`;
|
|
59
66
|
}
|
|
67
|
+
if (sdk.bundleId) {
|
|
68
|
+
url += `&bundleId=${sdk.bundleId}`;
|
|
69
|
+
}
|
|
60
70
|
|
|
61
71
|
// Pass allowSelfAds and source URL for smart serving
|
|
62
72
|
url += `&allowSelfAds=${sdk.allowSelfAds}`;
|
|
@@ -96,7 +106,11 @@ export class AdTogether {
|
|
|
96
106
|
body: JSON.stringify({
|
|
97
107
|
adId,
|
|
98
108
|
token,
|
|
99
|
-
apiKey: AdTogether.shared.appId
|
|
109
|
+
apiKey: AdTogether.shared.appId,
|
|
110
|
+
...(AdTogether.shared.bundleId ? { bundleId: AdTogether.shared.bundleId } : {}),
|
|
111
|
+
// Send platform and environment to match Flutter SDK
|
|
112
|
+
platform: 'web',
|
|
113
|
+
environment: typeof process !== 'undefined' && process.env?.NODE_ENV === 'development' ? 'development' : 'production',
|
|
100
114
|
}),
|
|
101
115
|
}).catch(console.error);
|
|
102
116
|
}
|
package/src/core/types.ts
CHANGED
|
@@ -8,6 +8,10 @@ export interface AdTogetherBannerProps {
|
|
|
8
8
|
style?: React.CSSProperties;
|
|
9
9
|
onAdLoaded?: () => void;
|
|
10
10
|
onAdFailedToLoad?: (error: Error) => void;
|
|
11
|
+
/** Whether to show a close button on the banner */
|
|
12
|
+
showCloseButton?: boolean;
|
|
13
|
+
/** Callback when the user closes the ad */
|
|
14
|
+
onAdClosed?: () => void;
|
|
11
15
|
/** Width of the ad element. Defaults to '100%' */
|
|
12
16
|
width?: number | string;
|
|
13
17
|
/** Height of the ad element. Defaults to 'auto' */
|
|
@@ -22,6 +26,8 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
|
|
|
22
26
|
style = {},
|
|
23
27
|
onAdLoaded,
|
|
24
28
|
onAdFailedToLoad,
|
|
29
|
+
showCloseButton = false,
|
|
30
|
+
onAdClosed,
|
|
25
31
|
width = '100%',
|
|
26
32
|
height = 'auto',
|
|
27
33
|
theme = 'auto',
|
|
@@ -29,6 +35,7 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
|
|
|
29
35
|
const [adData, setAdData] = useState<AdModel | null>(null);
|
|
30
36
|
const [isLoading, setIsLoading] = useState(true);
|
|
31
37
|
const [hasError, setHasError] = useState(false);
|
|
38
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
32
39
|
const [isDarkMode, setIsDarkMode] = useState(theme === 'dark');
|
|
33
40
|
|
|
34
41
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
@@ -52,7 +59,7 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
|
|
|
52
59
|
useEffect(() => {
|
|
53
60
|
let isMounted = true;
|
|
54
61
|
|
|
55
|
-
AdTogether.fetchAd(adUnitId)
|
|
62
|
+
AdTogether.fetchAd(adUnitId, 'banner')
|
|
56
63
|
.then((ad) => {
|
|
57
64
|
if (isMounted) {
|
|
58
65
|
setAdData(ad);
|
|
@@ -104,6 +111,16 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
|
|
|
104
111
|
}
|
|
105
112
|
};
|
|
106
113
|
|
|
114
|
+
const handleClose = (e: React.MouseEvent) => {
|
|
115
|
+
e.stopPropagation(); // Prevent triggering the ad click
|
|
116
|
+
setIsVisible(false);
|
|
117
|
+
onAdClosed?.();
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (!isVisible) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
107
124
|
if (isLoading) {
|
|
108
125
|
return (
|
|
109
126
|
<div
|
|
@@ -139,6 +156,7 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
|
|
|
139
156
|
overflow: 'hidden',
|
|
140
157
|
cursor: 'pointer',
|
|
141
158
|
boxSizing: 'border-box',
|
|
159
|
+
position: 'relative',
|
|
142
160
|
...style,
|
|
143
161
|
}}
|
|
144
162
|
onMouseOver={(e) => {
|
|
@@ -179,6 +197,34 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
|
|
|
179
197
|
{adData.description}
|
|
180
198
|
</span>
|
|
181
199
|
</div>
|
|
200
|
+
{showCloseButton && (
|
|
201
|
+
<button
|
|
202
|
+
onClick={handleClose}
|
|
203
|
+
aria-label="Close ad"
|
|
204
|
+
style={{
|
|
205
|
+
position: 'absolute',
|
|
206
|
+
top: '8px',
|
|
207
|
+
right: '8px',
|
|
208
|
+
width: '24px',
|
|
209
|
+
height: '24px',
|
|
210
|
+
borderRadius: '50%',
|
|
211
|
+
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
212
|
+
border: 'none',
|
|
213
|
+
color: '#fff',
|
|
214
|
+
fontSize: '14px',
|
|
215
|
+
fontWeight: 'bold',
|
|
216
|
+
cursor: 'pointer',
|
|
217
|
+
display: 'flex',
|
|
218
|
+
alignItems: 'center',
|
|
219
|
+
justifyContent: 'center',
|
|
220
|
+
padding: 0,
|
|
221
|
+
lineHeight: 1,
|
|
222
|
+
zIndex: 1,
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
×
|
|
226
|
+
</button>
|
|
227
|
+
)}
|
|
182
228
|
</div>
|
|
183
229
|
);
|
|
184
230
|
};
|