Skip to content

Commit

Permalink
Migrate to js_interop (#407)
Browse files Browse the repository at this point in the history
  • Loading branch information
deepak786 authored Feb 20, 2024
1 parent 6af2a0c commit 63bdceb
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 89 deletions.
4 changes: 4 additions & 0 deletions intercom_flutter_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.1.0

* Migrated to js_interop to be compatible with WASM.

## 1.0.2

* Automatically Injected Intercom script, if it is not added.
Expand Down
170 changes: 83 additions & 87 deletions intercom_flutter_web/lib/intercom_flutter_web.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'dart:async';
import 'dart:convert';
import 'dart:html';
import 'dart:js' as js;
import 'dart:js_interop';
import 'dart:js_interop_unsafe';

import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:intercom_flutter_platform_interface/intercom_flutter_platform_interface.dart';
import 'package:intercom_flutter_platform_interface/intercom_status_callback.dart';
import 'package:uuid/uuid.dart';
import 'package:web/web.dart' as web;

/// export the enum [IntercomVisibility]
export 'package:intercom_flutter_platform_interface/intercom_flutter_platform_interface.dart'
Expand All @@ -28,12 +28,13 @@ class IntercomFlutterWeb extends IntercomFlutterPlatform {
StreamController<dynamic> _unreadController =
StreamController<dynamic>.broadcast();
_unreadController.onListen = () {
js.context.callMethod('Intercom', [
'onUnreadCountChange',
js.allowInterop((unreadCount) {
globalContext.callMethod(
'Intercom'.toJS,
'onUnreadCountChange'.toJS,
((JSAny unreadCount) {
_unreadController.add(unreadCount);
}),
]);
}).toJS,
);
};
return _unreadController.stream;
}
Expand All @@ -44,35 +45,36 @@ class IntercomFlutterWeb extends IntercomFlutterPlatform {
String? androidApiKey,
String? iosApiKey,
}) async {
if (js.context['Intercom'] == null) {
if (globalContext.getProperty('Intercom'.toJS) == null) {
// Intercom script is not added yet
// Inject it from here in the body
var script = ScriptElement();
web.HTMLScriptElement script =
web.document.createElement("script") as web.HTMLScriptElement;
script.text = """
window.intercomSettings = ${convertJsObjectToDartObject(updateIntercomSettings('app_id', "'$appId'"))};
window.intercomSettings = ${updateIntercomSettings('app_id', "'$appId'").dartify()};
(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',w.intercomSettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Intercom=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/' + '$appId';var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();
""";
if (document.body != null) {
document.body!.append(script);
if (web.document.body != null) {
web.document.body!.appendChild(script);
}
} else {
// boot the Intercom
await js.context.callMethod('Intercom', [
'boot',
convertJsObjectToDartObject(updateIntercomSettings('app_id', appId)),
]);
globalContext.callMethod(
'Intercom'.toJS,
'boot'.toJS,
updateIntercomSettings('app_id', appId),
);
}
print("initialized");
}

@override
Future<void> setUserHash(String userHash) async {
await js.context.callMethod('Intercom', [
'update',
js.JsObject.jsify({
'user_hash': userHash,
}),
]);
globalContext.callMethod(
'Intercom'.toJS,
'update'.toJS,
{'user_hash': userHash}.jsify(),
);
print("user hash added");
}

Expand All @@ -88,23 +90,21 @@ class IntercomFlutterWeb extends IntercomFlutterPlatform {
'The parameter `email` must be null if `userId` is provided.');
}
// register the user with userId
await js.context.callMethod('Intercom', [
'update',
js.JsObject.jsify({
'user_id': userId,
}),
]);
// send the success callback only as web doesnot support the statusCallback.
globalContext.callMethod(
'Intercom'.toJS,
'update'.toJS,
{'user_id': userId}.jsify(),
);
// send the success callback only as web does not support the statusCallback.
statusCallback?.onSuccess?.call();
} else if (email?.isNotEmpty ?? false) {
// register the user with email
await js.context.callMethod('Intercom', [
'update',
js.JsObject.jsify({
'email': email,
}),
]);
// send the success callback only as web doesnot support the statusCallback.
globalContext.callMethod(
'Intercom'.toJS,
'update'.toJS,
{'email': email}.jsify(),
);
// send the success callback only as web does not support the statusCallback.
statusCallback?.onSuccess?.call();
} else {
throw ArgumentError(
Expand All @@ -117,13 +117,12 @@ class IntercomFlutterWeb extends IntercomFlutterPlatform {
{IntercomStatusCallback? statusCallback}) async {
// to register an unidentified user, a unique id will be created using the package uuid
String userId = Uuid().v1();
await js.context.callMethod('Intercom', [
'update',
js.JsObject.jsify({
'user_id': userId,
}),
]);
// send the success callback only as web doesnot support the statusCallback.
globalContext.callMethod(
'Intercom'.toJS,
'update'.toJS,
{'user_id': userId}.jsify(),
);
// send the success callback only as web does not support the statusCallback.
statusCallback?.onSuccess?.call();
}

Expand Down Expand Up @@ -180,130 +179,127 @@ class IntercomFlutterWeb extends IntercomFlutterPlatform {
userAttributes['language_override'] = language;
}

await js.context.callMethod('Intercom', [
'update',
js.JsObject.jsify(userAttributes),
]);
// send the success callback only as web doesnot support the statusCallback.
globalContext.callMethod(
'Intercom'.toJS, 'update'.toJS, userAttributes.jsify());
// send the success callback only as web does not support the statusCallback.
statusCallback?.onSuccess?.call();
}

@override
Future<void> logEvent(String name, [Map<String, dynamic>? metaData]) async {
await js.context.callMethod('Intercom', [
'trackEvent',
name,
metaData != null ? js.JsObject.jsify(metaData) : null,
]);
globalContext.callMethod(
'Intercom'.toJS,
'trackEvent'.toJS,
name.toJS,
metaData != null ? metaData.jsify() : null,
);

print("Logged event");
}

@override
Future<void> setLauncherVisibility(IntercomVisibility visibility) async {
await js.context.callMethod('Intercom', [
'update',
convertJsObjectToDartObject(updateIntercomSettings(
globalContext.callMethod(
'Intercom'.toJS,
'update'.toJS,
updateIntercomSettings(
'hide_default_launcher',
visibility == IntercomVisibility.visible ? false : true,
)),
]);
),
);

print("Showing launcher: $visibility");
}

@override
Future<void> logout() async {
await js.context.callMethod('Intercom', ['shutdown']);
globalContext.callMethod('Intercom'.toJS, 'shutdown'.toJS);
print("logout");
}

@override
Future<void> displayMessenger() async {
await js.context.callMethod('Intercom', ['show']);
globalContext.callMethod('Intercom'.toJS, 'show'.toJS);
print("Launched");
}

@override
Future<void> hideMessenger() async {
await js.context.callMethod('Intercom', ['hide']);
globalContext.callMethod('Intercom'.toJS, 'hide'.toJS);
print("Hidden");
}

@override
Future<void> displayHelpCenter() async {
await js.context.callMethod('Intercom', ['showSpace', 'help']);
globalContext.callMethod('Intercom'.toJS, 'showSpace'.toJS, 'help'.toJS);
print("Launched the Help Center");
}

@override
Future<void> displayMessageComposer(String message) async {
await js.context.callMethod('Intercom', ['showNewMessage', message]);
globalContext.callMethod(
'Intercom'.toJS, 'showNewMessage'.toJS, message.toJS);
print("Message composer displayed");
}

@override
Future<void> displayMessages() async {
await js.context.callMethod('Intercom', ['showMessages']);
globalContext.callMethod('Intercom'.toJS, 'showMessages'.toJS);
print("Launched the Messenger with the message list");
}

@override
Future<void> setBottomPadding(int padding) async {
await js.context.callMethod('Intercom', [
'update',
convertJsObjectToDartObject(updateIntercomSettings(
globalContext.callMethod(
'Intercom'.toJS,
'update'.toJS,
updateIntercomSettings(
'vertical_padding',
padding,
))
]);
),
);

print("Bottom padding set");
}

@override
Future<void> displayArticle(String articleId) async {
await js.context.callMethod('Intercom', ['showArticle', articleId]);
globalContext.callMethod(
'Intercom'.toJS, 'showArticle'.toJS, articleId.toJS);
}

@override
Future<void> displaySurvey(String surveyId) async {
await js.context.callMethod('Intercom', ['startSurvey', surveyId]);
globalContext.callMethod(
'Intercom'.toJS, 'startSurvey'.toJS, surveyId.toJS);
}

@override
Future<void> displayConversation(String conversationId) async {
await js.context
.callMethod('Intercom', ['showConversation', conversationId]);
globalContext.callMethod(
'Intercom'.toJS, 'showConversation'.toJS, conversationId.toJS);
}

@override
Future<void> displayTickets() async {
await js.context.callMethod('Intercom', ['showSpace', 'tickets']);
globalContext.callMethod('Intercom'.toJS, 'showSpace'.toJS, 'tickets'.toJS);
print("Launched Tickets space");
}

/// get the [window.IntercomSettings]
js.JsObject getIntercomSettings() {
if (js.context.hasProperty('intercomSettings')) {
return js.JsObject.fromBrowserObject(js.context['intercomSettings']);
JSObject getIntercomSettings() {
if (globalContext.hasProperty('intercomSettings'.toJS).toDart) {
return globalContext.getProperty('intercomSettings'.toJS) as JSObject;
}

return js.JsObject.jsify({});
return JSObject();
}

/// add/update property to [window.IntercomSettings]
/// and returns the updated object
js.JsObject updateIntercomSettings(String key, dynamic value) {
JSObject updateIntercomSettings(String key, dynamic value) {
var intercomSettings = getIntercomSettings();
intercomSettings[key] = value;
return intercomSettings;
}

/// convert the [js.JsObject] to [Map]
Object convertJsObjectToDartObject(js.JsObject jsObject) {
return json.decode(js.context["JSON"].callMethod("stringify", [
jsObject,
]));
}
}
5 changes: 3 additions & 2 deletions intercom_flutter_web/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: intercom_flutter_web
description: Web platform implementation of intercom_flutter
version: 1.0.2
version: 1.1.0
homepage: https://github.com/v3rm0n/intercom_flutter

flutter:
Expand All @@ -17,12 +17,13 @@ dependencies:
sdk: flutter
intercom_flutter_platform_interface: ^2.0.0
uuid: ^4.2.1 # to get the random uuid for loginUnidentifiedUser in web
web: '>=0.3.0 <0.6.0'

dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.4.0

environment:
sdk: ">=3.0.0 <4.0.0"
sdk: ">=3.2.0 <4.0.0"
flutter: ">=3.10.0"

0 comments on commit 63bdceb

Please sign in to comment.