feat: Add app-version to Chatwoot Contact Attributes (#2049)

Konstantin Ullrich committed Feb 24, 2025 at 23:01 UTC 465ff7e78ca493c6775ad51ee66f10f9aef80e61
4 files changed +50 -26
lib/di.dart
+2 -2
@@ -1256,7 +1256,7 @@ Future<void> setup({
1256 getIt.registerFactoryParam<OrderDetailsPage, Order, void>(
1257 (Order order, _) => OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));
1258
1259 - getIt.registerFactory(() => SupportViewModel());
1259 + getIt.registerFactory(() => SupportViewModel(getIt.get<SettingsStore>()));
1260
1261 getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
1262
@@ -1418,4 +1418,4 @@ Future<void> setup({
1418 getIt.registerFactory(() => SeedVerificationPage(getIt.get<WalletSeedViewModel>()));
1419
1420 _isSetupFinished = true;
1421 -}
\ No newline at end of file
1421 +}
lib/src/screens/support_chat/support_chat_page.dart
+4 -7
@@ -3,10 +3,8 @@ import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/src/screens/base_page.dart';
4 import 'package:cake_wallet/src/screens/support_chat/widgets/chatwoot_widget.dart';
5 import 'package:cake_wallet/view_model/support_view_model.dart';
6 -import 'package:cw_core/utils/print_verbose.dart';
6 import 'package:flutter/material.dart';
7
9 -
8 class SupportChatPage extends BasePage {
9 SupportChatPage(this.supportViewModel, {required this.secureStorage});
10
@@ -23,17 +21,16 @@ class SupportChatPage extends BasePage {
21 Widget body(BuildContext context) => FutureBuilder<String>(
22 future: getCookie(),
23 builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
26 - printV(snapshot.data);
24 if (snapshot.hasData)
25 return ChatwootWidget(
26 secureStorage,
30 - supportUrl: supportViewModel.fetchUrl(authToken: snapshot.data!)
27 + supportUrl: supportViewModel.fetchUrl(authToken: snapshot.data!),
28 + appVersion: supportViewModel.appVersion,
29 );
30 return Container();
31 },
32 );
33
36 - Future<String> getCookie() async {
37 - return await secureStorage.read(key: COOKIE_KEY) ?? "";
38 - }
34 + Future<String> getCookie() async =>
35 + await secureStorage.read(key: COOKIE_KEY) ?? "";
36 }
lib/src/screens/support_chat/widgets/chatwoot_widget.dart
+36 -15
@@ -1,46 +1,50 @@
1 import 'dart:convert';
2
3 import 'package:cake_wallet/core/secure_storage.dart';
4 -import 'package:cw_core/utils/print_verbose.dart';
4 import 'package:flutter/material.dart';
5 import 'package:flutter_inappwebview/flutter_inappwebview.dart';
6
7 const COOKIE_KEY = 'chatwootCookie';
8
9 class ChatwootWidget extends StatefulWidget {
11 - ChatwootWidget(this.secureStorage, {required this.supportUrl});
10 + const ChatwootWidget(
11 + this.secureStorage, {
12 + required this.supportUrl,
13 + required this.appVersion,
14 + });
15
16 final SecureStorage secureStorage;
17 final String supportUrl;
18 + final String appVersion;
19
20 @override
21 ChatwootWidgetState createState() => ChatwootWidgetState();
22 }
23
24 class ChatwootWidgetState extends State<ChatwootWidget> {
21 - final GlobalKey _webViewkey = GlobalKey();
25 + final GlobalKey _webViewKey = GlobalKey();
26
27 @override
28 Widget build(BuildContext context) => InAppWebView(
25 - key: _webViewkey,
26 - initialSettings: InAppWebViewSettings(
27 - transparentBackground: true,
28 - ),
29 + key: _webViewKey,
30 + initialSettings: InAppWebViewSettings(transparentBackground: true),
31 initialUrlRequest: URLRequest(url: WebUri(widget.supportUrl)),
32 onWebViewCreated: (InAppWebViewController controller) {
33 controller.addWebMessageListener(
34 WebMessageListener(
35 jsObjectName: 'ReactNativeWebView',
34 - onPostMessage: (WebMessage? message, WebUri? sourceOrigin, bool isMainFrame,
35 - PlatformJavaScriptReplyProxy replyProxy) {
36 + onPostMessage: (WebMessage? message, WebUri? sourceOrigin,
37 + bool isMainFrame, PlatformJavaScriptReplyProxy replyProxy) {
38 final shortenedMessage = message?.data.toString().substring(16);
37 - if (shortenedMessage != null && isJsonString(shortenedMessage)) {
39 + if (shortenedMessage != null &&
40 + _isJsonString(shortenedMessage)) {
41 final parsedMessage = jsonDecode(shortenedMessage);
42 final eventType = parsedMessage["event"];
43 if (eventType == 'loaded') {
44 final authToken = parsedMessage["config"]["authToken"];
42 - printV(authToken);
43 - storeCookie(authToken as String);
45 + _storeCookie(authToken as String);
46 + _setCustomAttributes(
47 + controller, {"app_version": widget.appVersion});
48 }
49 }
50 },
@@ -49,7 +53,7 @@ class ChatwootWidgetState extends State<ChatwootWidget> {
53 },
54 );
55
52 - bool isJsonString(String str) {
56 + bool _isJsonString(String str) {
57 try {
58 jsonDecode(str);
59 } catch (e) {
@@ -58,7 +62,24 @@ class ChatwootWidgetState extends State<ChatwootWidget> {
62 return true;
63 }
64
61 - Future<void> storeCookie(String value) async {
62 - await widget.secureStorage.write(key: COOKIE_KEY, value: value);
65 + /// Add additional contact attributes to the chatwoot chat.
66 + /// IMPORTANT: You have to add the attribute key in the chatwoot settings
67 + /// under: settings/custom-attributes
68 + Future<void> _setCustomAttributes(
69 + InAppWebViewController controller,
70 + Map<String, dynamic> customAttributes,
71 + ) {
72 + final attributeObject = {
73 + "event": "set-custom-attributes",
74 + "customAttributes": customAttributes,
75 + };
76 + return controller.postWebMessage(
77 + message: WebMessage(
78 + data: "chatwoot-widget:${jsonEncode(attributeObject)}",
79 + ),
80 + );
81 }
82 +
83 + Future<void> _storeCookie(String value) =>
84 + widget.secureStorage.write(key: COOKIE_KEY, value: value);
85 }
lib/view_model/support_view_model.dart
+8 -2
@@ -1,16 +1,19 @@
1 +import 'package:cake_wallet/.secrets.g.dart' as secrets;
2 import 'package:cake_wallet/generated/i18n.dart';
3 +import 'package:cake_wallet/store/settings_store.dart';
4 import 'package:cake_wallet/view_model/settings/link_list_item.dart';
5 import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
6 import 'package:cake_wallet/wallet_type_utils.dart';
7 import 'package:mobx/mobx.dart';
6 -import 'package:cake_wallet/.secrets.g.dart' as secrets;
8
9 part 'support_view_model.g.dart';
10
11 class SupportViewModel = SupportViewModelBase with _$SupportViewModel;
12
13 abstract class SupportViewModelBase with Store {
13 - SupportViewModelBase()
14 + final SettingsStore settingsStore;
15 +
16 + SupportViewModelBase(this.settingsStore)
17 : items = [
18 LinkListItem(
19 title: 'Email',
@@ -116,5 +119,8 @@ abstract class SupportViewModelBase with Store {
119 return supportUrl;
120 }
121
122 + String get appVersion =>
123 + "${isMoneroOnly ? "Monero.com" : "Cake Wallet"} - ${settingsStore.appVersion}";
124 +
125 List<SettingsListItem> items;
126 }