@sellwild/react-native-sdk 1.7.0 → 1.7.2
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/android/src/main/java/com/sellwild/rnsdk/SellwildBannerViewManager.kt +4 -0
- package/android/src/main/java/com/sellwild/rnsdk/SellwildFeedViewManager.kt +48 -0
- package/ios/SellwildFeedViewManager.m +1 -0
- package/ios/SellwildFeedViewManager.swift +22 -0
- package/package.json +1 -1
- package/src/SellwildFeed.tsx +16 -0
|
@@ -152,6 +152,10 @@ class SellwildBannerViewManager : SimpleViewManager<SellwildAdView>() {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
override fun onDropViewInstance(view: SellwildAdView) {
|
|
155
|
+
// Tear down the native ad view on unmount so its GMA / Prebid banners are
|
|
156
|
+
// released deterministically. Without this the views leak until GC (iOS
|
|
157
|
+
// RN gets this for free via ARC deinit). Mirrors SellwildFeedView cleanup.
|
|
158
|
+
view.destroy()
|
|
155
159
|
pending.remove(view)
|
|
156
160
|
super.onDropViewInstance(view)
|
|
157
161
|
}
|
|
@@ -11,6 +11,7 @@ import com.facebook.react.uimanager.annotations.ReactProp
|
|
|
11
11
|
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
12
12
|
import com.sellwild.sdk.SellwildConfig
|
|
13
13
|
import com.sellwild.sdk.SellwildFeedView
|
|
14
|
+
import com.sellwild.sdk.SellwildGrowthCodeConfig
|
|
14
15
|
import com.sellwild.sdk.SellwildListing
|
|
15
16
|
import com.sellwild.sdk.SellwildLocalizedListingsConfig
|
|
16
17
|
import com.sellwild.sdk.SellwildSDK
|
|
@@ -82,6 +83,11 @@ class SellwildFeedViewManager : SimpleViewManager<SellwildFeedView>() {
|
|
|
82
83
|
emit(reactContext, view, "onFeedLoaded", null)
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
override fun onFeedReady(listingCount: Int) {
|
|
87
|
+
val payload = Arguments.createMap().apply { putInt("listingCount", listingCount) }
|
|
88
|
+
emit(reactContext, view, "onFeedReady", payload)
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
override fun onError(message: String) {
|
|
86
92
|
val payload = Arguments.createMap().apply { putString("message", message) }
|
|
87
93
|
emit(reactContext, view, "onFeedError", payload)
|
|
@@ -131,6 +137,7 @@ class SellwildFeedViewManager : SimpleViewManager<SellwildFeedView>() {
|
|
|
131
137
|
override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
|
|
132
138
|
return MapBuilder.builder<String, Any>()
|
|
133
139
|
.put("onFeedLoaded", MapBuilder.of("registrationName", "onFeedLoaded"))
|
|
140
|
+
.put("onFeedReady", MapBuilder.of("registrationName", "onFeedReady"))
|
|
134
141
|
.put("onListingTap", MapBuilder.of("registrationName", "onListingTap"))
|
|
135
142
|
.put("onAdImpression", MapBuilder.of("registrationName", "onAdImpression"))
|
|
136
143
|
.put("onHouseAdImpression", MapBuilder.of("registrationName", "onHouseAdImpression"))
|
|
@@ -185,11 +192,52 @@ class SellwildFeedViewManager : SimpleViewManager<SellwildFeedView>() {
|
|
|
185
192
|
if (map.hasKey("adRefreshMax")) config = config.copy(adRefreshMax = map.getInt("adRefreshMax"))
|
|
186
193
|
if (map.hasKey("adRefreshMaxMobile")) config = config.copy(adRefreshMaxMobile = map.getInt("adRefreshMaxMobile"))
|
|
187
194
|
if (map.hasKey("adRefreshIntervalMs")) config = config.copy(adRefreshIntervalMs = map.getDouble("adRefreshIntervalMs").toLong())
|
|
195
|
+
|
|
196
|
+
// Flat identity/display/zone fields — mirror the iOS feed bridge so
|
|
197
|
+
// static buildConfig() and overrides land identically. SellwildSDK.apply
|
|
198
|
+
// (above) resolves these from `remote` when present; these overlay on top.
|
|
199
|
+
if (map.hasKey("slug")) config = config.copy(slug = map.getString("slug") ?: config.slug)
|
|
200
|
+
if (map.hasKey("listingsUrl")) config = config.copy(listingsUrl = map.getString("listingsUrl"))
|
|
201
|
+
if (map.hasKey("priceColor")) config = config.copy(priceColor = map.getString("priceColor") ?: config.priceColor)
|
|
202
|
+
if (map.hasKey("bannerZid")) config = config.copy(bannerZid = map.getString("bannerZid"))
|
|
203
|
+
if (map.hasKey("bottomBannerZid")) config = config.copy(bottomBannerZid = map.getString("bottomBannerZid"))
|
|
204
|
+
// mobileZids / mobileBannerZid are OS-suffix-resolved by SellwildSDK.apply
|
|
205
|
+
// when `remote` is present; only fall back to the flat (OS-agnostic) JS
|
|
206
|
+
// values when there was no remote payload to resolve from (parity w/ iOS).
|
|
207
|
+
if (!map.hasKey("remote") || map.isNull("remote")) {
|
|
208
|
+
if (map.hasKey("mobileBannerZid")) config = config.copy(mobileBannerZid = map.getString("mobileBannerZid"))
|
|
209
|
+
if (map.hasKey("mobileZids") && !map.isNull("mobileZids")) {
|
|
210
|
+
val arr = map.getArray("mobileZids")
|
|
211
|
+
if (arr != null) config = config.copy(mobileZids = (0 until arr.size()).mapNotNull { arr.getString(it) })
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
188
215
|
// Custom Prebid Server (S2S) config — mirror the iOS feed bridge.
|
|
189
216
|
if (map.hasKey("prebidServer") && !map.isNull("prebidServer")) {
|
|
190
217
|
config = config.copy(prebidServer = RnPrebidServer.fromMap(map.getMap("prebidServer")))
|
|
191
218
|
}
|
|
192
219
|
|
|
220
|
+
// Local GrowthCode override — parity with the banner bridge and the
|
|
221
|
+
// iOS feed bridge. Without it the feed's ad rows only see remote
|
|
222
|
+
// GROWTHCODE_* keys; a code-supplied partnerId never reaches the
|
|
223
|
+
// auction, so the identity sync never fires for feed ad rows.
|
|
224
|
+
if (map.hasKey("growthCode") && !map.isNull("growthCode")) {
|
|
225
|
+
val gc = map.getMap("growthCode")!!
|
|
226
|
+
fun bool(k: String): Boolean? = if (gc.hasKey(k) && !gc.isNull(k)) gc.getBoolean(k) else null
|
|
227
|
+
fun str(k: String): String? = if (gc.hasKey(k) && !gc.isNull(k)) gc.getString(k) else null
|
|
228
|
+
fun int(k: String): Int? = if (gc.hasKey(k) && !gc.isNull(k)) gc.getInt(k) else null
|
|
229
|
+
config = config.copy(
|
|
230
|
+
growthCode = SellwildGrowthCodeConfig(
|
|
231
|
+
enabled = bool("enabled"),
|
|
232
|
+
partnerId = str("partnerId"),
|
|
233
|
+
endpoint = str("endpoint"),
|
|
234
|
+
syncUrl = str("syncUrl"),
|
|
235
|
+
sendMaid = bool("sendMaid"),
|
|
236
|
+
ttlHours = int("ttlHours"),
|
|
237
|
+
),
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
193
241
|
// Local override for the localized (geo-based) secondary-listings
|
|
194
242
|
// integration; the remote LOCALIZED_LISTINGS object rides `remote`.
|
|
195
243
|
if (map.hasKey("localizedListings") && !map.isNull("localizedListings")) {
|
|
@@ -16,6 +16,7 @@ RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
|
|
|
16
16
|
|
|
17
17
|
// Direct events emitted to JS callbacks.
|
|
18
18
|
RCT_EXPORT_VIEW_PROPERTY(onFeedLoaded, RCTDirectEventBlock)
|
|
19
|
+
RCT_EXPORT_VIEW_PROPERTY(onFeedReady, RCTDirectEventBlock)
|
|
19
20
|
RCT_EXPORT_VIEW_PROPERTY(onListingTap, RCTDirectEventBlock)
|
|
20
21
|
RCT_EXPORT_VIEW_PROPERTY(onAdImpression, RCTDirectEventBlock)
|
|
21
22
|
RCT_EXPORT_VIEW_PROPERTY(onHouseAdImpression, RCTDirectEventBlock)
|
|
@@ -45,6 +45,9 @@ final class SellwildFeedHostView: UIView, SellwildFeedViewDelegate {
|
|
|
45
45
|
// MARK: RN events
|
|
46
46
|
|
|
47
47
|
@objc var onFeedLoaded: RCTDirectEventBlock?
|
|
48
|
+
/// Fires after a successful fetch with the bound listing count
|
|
49
|
+
/// (`listingCount == 0` ⇒ empty / header-only). Reliable "ready" signal.
|
|
50
|
+
@objc var onFeedReady: RCTDirectEventBlock?
|
|
48
51
|
@objc var onListingTap: RCTDirectEventBlock?
|
|
49
52
|
@objc var onAdImpression: RCTDirectEventBlock?
|
|
50
53
|
/// A house ad backfilled an empty feed slot (no-fill). Not a paid impression.
|
|
@@ -110,6 +113,10 @@ final class SellwildFeedHostView: UIView, SellwildFeedViewDelegate {
|
|
|
110
113
|
onFeedLoaded?([:])
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
func sellwildFeed(_ feed: SellwildFeedView, didBecomeReadyWithListingCount count: Int) {
|
|
117
|
+
onFeedReady?(["listingCount": count])
|
|
118
|
+
}
|
|
119
|
+
|
|
113
120
|
func sellwildFeed(_ feed: SellwildFeedView, didTapListing listing: SellwildListing) -> Bool {
|
|
114
121
|
// Forward the listing payload to JS as a plain dictionary. JS
|
|
115
122
|
// can't return a value back through a direct event block, so
|
|
@@ -207,6 +214,21 @@ final class SellwildFeedHostView: UIView, SellwildFeedViewDelegate {
|
|
|
207
214
|
)
|
|
208
215
|
}
|
|
209
216
|
|
|
217
|
+
// Local GrowthCode override — parity with the banner bridge. Without
|
|
218
|
+
// this the feed's ad rows only see remote GROWTHCODE_* keys (via
|
|
219
|
+
// remoteJSON); a code-supplied partnerId never reaches the auction, so
|
|
220
|
+
// the identity sync never fires and feed ad rows lose eids enrichment.
|
|
221
|
+
if let gc = map["growthCode"] as? NSDictionary {
|
|
222
|
+
cfg.growthCode = SellwildGrowthCodeConfig(
|
|
223
|
+
enabled: gc["enabled"] as? Bool,
|
|
224
|
+
partnerId: gc["partnerId"] as? String,
|
|
225
|
+
endpoint: gc["endpoint"] as? String,
|
|
226
|
+
syncUrl: gc["syncUrl"] as? String,
|
|
227
|
+
sendMaid: gc["sendMaid"] as? Bool,
|
|
228
|
+
ttlHours: gc["ttlHours"] as? Int
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
210
232
|
// Local override for the localized (geo-based) secondary-listings
|
|
211
233
|
// integration; remote LOCALIZED_LISTINGS rides `remote` verbatim.
|
|
212
234
|
if let ll = map["localizedListings"] as? NSDictionary {
|
package/package.json
CHANGED
package/src/SellwildFeed.tsx
CHANGED
|
@@ -32,6 +32,7 @@ interface NativeFeedProps {
|
|
|
32
32
|
scrollEnabled?: boolean
|
|
33
33
|
style?: StyleProp<ViewStyle>
|
|
34
34
|
onFeedLoaded?: (e: NativeSyntheticEvent<{}>) => void
|
|
35
|
+
onFeedReady?: (e: NativeSyntheticEvent<{ listingCount: number }>) => void
|
|
35
36
|
onListingTap?: (e: NativeSyntheticEvent<{ listing: SellwildListing }>) => void
|
|
36
37
|
onAdImpression?: (e: NativeSyntheticEvent<{ zoneId: string }>) => void
|
|
37
38
|
onHouseAdImpression?: (e: NativeSyntheticEvent<{ zoneId: string }>) => void
|
|
@@ -84,6 +85,14 @@ export interface SellwildFeedProps {
|
|
|
84
85
|
/** Fired once after the initial listings fetch resolves successfully. */
|
|
85
86
|
onLoad?: () => void
|
|
86
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Fired after a successful fetch with the number of listings bound to the
|
|
90
|
+
* feed. `listingCount === 0` means an empty / header-only render. Prefer this
|
|
91
|
+
* over `onLoad` when you need to know the feed is actually populated — `onLoad`
|
|
92
|
+
* also fires on an empty result.
|
|
93
|
+
*/
|
|
94
|
+
onFeedReady?: (listingCount: number) => void
|
|
95
|
+
|
|
87
96
|
/**
|
|
88
97
|
* Fired when a listing card is tapped. Return `true` to consume the
|
|
89
98
|
* event; return `false` (or omit) to let the SDK open `listing.url`
|
|
@@ -113,6 +122,7 @@ export function SellwildFeed({
|
|
|
113
122
|
scrollEnabled = true,
|
|
114
123
|
onContentSizeChange,
|
|
115
124
|
onLoad,
|
|
125
|
+
onFeedReady,
|
|
116
126
|
onListingTap,
|
|
117
127
|
onAdImpression,
|
|
118
128
|
onHouseAdImpression,
|
|
@@ -166,6 +176,9 @@ export function SellwildFeed({
|
|
|
166
176
|
prebidServer: config.prebidServer,
|
|
167
177
|
// Local localized-listings overrides (remote LOCALIZED_LISTINGS rides `remote`).
|
|
168
178
|
localizedListings: config.localizedListings,
|
|
179
|
+
// Local GrowthCode overrides (remote GROWTHCODE_* rides `remote`) — parity
|
|
180
|
+
// with SellwildBanner so the feed's native auctions honor local overrides too.
|
|
181
|
+
growthCode: config.growthCode,
|
|
169
182
|
remote: config.remote,
|
|
170
183
|
listingsUrl: config.listingsUrl,
|
|
171
184
|
priceColor: config.priceColor,
|
|
@@ -188,6 +201,9 @@ export function SellwildFeed({
|
|
|
188
201
|
onContentSizeChange?.({ width, height })
|
|
189
202
|
}}
|
|
190
203
|
onFeedLoaded={() => onLoad?.()}
|
|
204
|
+
onFeedReady={(e: NativeSyntheticEvent<{ listingCount: number }>) => {
|
|
205
|
+
onFeedReady?.(e.nativeEvent.listingCount)
|
|
206
|
+
}}
|
|
191
207
|
onListingTap={(e: NativeSyntheticEvent<{ listing: SellwildListing }>) => {
|
|
192
208
|
onListingTap?.(e.nativeEvent.listing)
|
|
193
209
|
}}
|