push method
Implementation
Future<RelevaResponse> push(PushRequest request) async {
if (!_config.enableTracking) {
// Return empty response if tracking is disabled
return RelevaResponse(recommenders: [], banners: []);
}
final storage = HiveStorageService.instance;
await SessionService.instance.initialize(npsManager: _npsManager);
final sessionId = await SessionService.instance.getSessionId();
final wishlistProducts = await storage.getWishlistData();
// Use cart from request if explicitly set (e.g., for checkout success),
// otherwise load from storage for regular screen views
final String? cartToSend;
if (request.cart != null) {
// Cart explicitly provided in request (checkout success case)
cartToSend = jsonEncode(request.cart!.toMap());
} else {
// Load from storage for regular tracking
cartToSend = await storage.getCartData();
}
final deviceId = await storage.getDeviceId();
if (deviceId == null) {
throw Exception(
'Please provide deviceId using client.setDeviceId() before using the client!',
);
}
// Load merge profile IDs from storage so all instances share the same merge state
final mergeProfileIds = await storage.getMergeProfileIds() ?? [];
if (mergeProfileIds.isNotEmpty) {
debugPrint('Releva: Sending merge profile IDs to API: $mergeProfileIds');
}
Map<String, dynamic> context = request.toMap();
// Build device context fields
final sessionCount = await storage.getDeviceSessionCount();
final firstSeenAt = await storage.getDeviceFirstSeenAt();
final views = await storage.getDeviceViewsCount() + 1;
await storage.setDeviceViewsCount(views);
String platform;
try {
platform = Platform.isIOS ? 'ios' : 'android';
} catch (_) {
platform = 'android';
}
context.addAll({
'deviceId': deviceId,
'deviceIdChanged': _deviceIdChanged,
'sessionId': sessionId,
'profile': {'id': await storage.getProfileId()},
'profileChanged': _profileChanged,
'cart': cartToSend == null ? null : jsonDecode(cartToSend),
'cartChanged': _cartChanged,
'wishlist': {
'products': wishlistProducts == null
? []
: wishlistProducts.map((p) => jsonDecode(p)).toList(),
},
'wishlistChanged': _wishlistChanged,
'mergeProfileIds': mergeProfileIds,
'device': {
'sessions': sessionCount,
'platform': platform,
if (_appVersion != null) 'version': _appVersion,
if (firstSeenAt != null) 'firstSeenAt': firstSeenAt,
'views': views,
'sdkVersion': version,
},
});
try {
final response = await http.post(
Uri.parse('${_getEndpoint()}/api/v0/push'),
headers: {
'content-type': 'application/json',
'authorization': 'Bearer $_accessToken',
},
body: jsonEncode({
'context': context,
'options': {
'client': {
'vendor': 'Releva',
'platform': 'flutter',
'version': version,
},
},
}),
);
if (response.statusCode != 200) {
throw Exception(
'Backend API error: ${response.statusCode} - ${response.body}',
);
}
_cartChanged = false;
_wishlistChanged = false;
_profileChanged = false;
_deviceIdChanged = false;
// Clear merge profile IDs from storage after successful push
await storage.clearMergeProfileIds();
final responseMap =
jsonDecode(utf8.decode(response.bodyBytes)) as Map<String, dynamic>;
final relevaResponse = RelevaResponse.fromMap(responseMap);
// Initialize NPS manager with the config from this response.
// The server has already evaluated app_open/session_count/screen_view
// triggers — if nps is non-null, a server-side trigger has fired.
_npsManager.initialize(relevaResponse.nps);
return relevaResponse;
} catch (e) {
rethrow;
}
}