Skip to content

Commit a8ebfa2

Browse files
authored
Add support for Theme Mode & update iOS SDK version to 19.1.2 (#313)
* Update Intercom SDK version to 19.1.2 * add support for theme modes
1 parent 8e5ba12 commit a8ebfa2

File tree

8 files changed

+182
-44
lines changed

8 files changed

+182
-44
lines changed

android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,5 @@ dependencies {
7070
implementation "com.facebook.react:react-native:+" // From node_modules
7171
implementation "com.google.firebase:firebase-messaging:${safeExtGet('firebaseMessagingVersion', '20.2.+')}"
7272
implementation 'io.intercom.android:intercom-sdk:17.1.0'
73+
implementation 'io.intercom.android:intercom-sdk-ui:17.1.0'
7374
}

android/src/main/java/com/intercom/reactnative/IntercomErrorCodes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class IntercomErrorCodes {
1717
public static final String HIDE_INTERCOM = "206";
1818
public static final String SET_LAUNCHER_VISIBILITY = "208";
1919
public static final String SET_BOTTOM_PADDING = "209";
20+
public static final String SET_THEME_MODE = "210";
2021
public static final String HANDLE_PUSH_MESSAGE = "301";
2122
public static final String SEND_TOKEN_TO_INTERCOM = "302";
2223
public static final String FETCH_HELP_CENTER_COLLECTIONS = "901";

android/src/main/java/com/intercom/reactnative/IntercomModule.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import io.intercom.android.sdk.helpcenter.sections.HelpCenterCollectionContent;
3939
import io.intercom.android.sdk.identity.Registration;
4040
import io.intercom.android.sdk.push.IntercomPushClient;
41+
import io.intercom.android.sdk.ui.theme.ThemeMode;
4142
import android.app.TaskStackBuilder;
4243

4344
@ReactModule(name = IntercomModule.NAME)
@@ -530,6 +531,42 @@ public void setBottomPadding(int paddingBottom, Promise promise) {
530531
}
531532
}
532533

534+
@ReactMethod
535+
public void setThemeMode(String themeMode, Promise promise) {
536+
try {
537+
ThemeMode themeModeEnum = null;
538+
539+
if (themeMode == null || themeMode.trim().isEmpty()) {
540+
promise.reject(IntercomErrorCodes.SET_THEME_MODE,
541+
"Theme mode cannot be null or empty. Use 'LIGHT', 'DARK', or 'SYSTEM'.");
542+
return;
543+
}
544+
545+
switch (themeMode) {
546+
case "SYSTEM":
547+
themeModeEnum = ThemeMode.SYSTEM;
548+
break;
549+
case "LIGHT":
550+
themeModeEnum = ThemeMode.LIGHT;
551+
break;
552+
case "DARK":
553+
themeModeEnum = ThemeMode.DARK;
554+
break;
555+
default:
556+
promise.reject(IntercomErrorCodes.SET_THEME_MODE,
557+
"Invalid theme mode: '" + themeMode + "'. Use 'LIGHT', 'DARK', or 'SYSTEM'.");
558+
return;
559+
}
560+
561+
Intercom.client().setThemeMode(themeModeEnum);
562+
promise.resolve(true);
563+
} catch (Exception err) {
564+
Log.e(NAME, "setThemeMode error:");
565+
Log.e(NAME, err.toString());
566+
promise.reject(IntercomErrorCodes.SET_THEME_MODE, "Error in setThemeMode: " + err.toString());
567+
}
568+
}
569+
533570
@ReactMethod
534571
public void setUserJwt(String jwt, Promise promise) {
535572
try {

example/ios/Podfile.lock

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ PODS:
44
- FBLazyVector (0.74.0)
55
- fmt (9.1.0)
66
- glog (0.3.5)
7-
- Intercom (18.7.3)
8-
- intercom-react-native (8.5.0):
9-
- Intercom (~> 18.7.3)
7+
- Intercom (19.1.2)
8+
- intercom-react-native (8.8.0):
9+
- Intercom (~> 19.1.2)
1010
- React-Core
1111
- RCT-Folly (2024.01.01.00):
1212
- boost
@@ -911,9 +911,9 @@ PODS:
911911
- React-Mapbuffer (0.74.0):
912912
- glog
913913
- React-debug
914-
- react-native-config (1.5.5):
915-
- react-native-config/App (= 1.5.5)
916-
- react-native-config/App (1.5.5):
914+
- react-native-config (1.5.7):
915+
- react-native-config/App (= 1.5.7)
916+
- react-native-config/App (1.5.7):
917917
- React-Core
918918
- React-nativeconfig (0.74.0)
919919
- React-NativeModulesApple (0.74.0):
@@ -1313,56 +1313,56 @@ SPEC CHECKSUMS:
13131313
FBLazyVector: 026c8f4ae67b06e088ae01baa2271ef8a26c0e8c
13141314
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
13151315
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
1316-
Intercom: 93c6f5d9815b34bf2a7e5f03bcf7b6e08c1a4788
1317-
intercom-react-native: 985eb561fd1eb0765f86a3332a89a4f31ce3dfaa
1318-
RCT-Folly: 045d6ecaa59d826c5736dfba0b2f4083ff8d79df
1316+
Intercom: 0643528ea72515fb47096ad38fe455780441881b
1317+
intercom-react-native: 15a322d6032f91058563a02e049f4d7246aad1a0
1318+
RCT-Folly: 5f972de9f7d384c7d0e7380dd7da506228e568f5
13191319
RCTDeprecation: 3ca8b6c36bfb302e1895b72cfe7db0de0c92cd47
13201320
RCTRequired: 9fc183af555fd0c89a366c34c1ae70b7e03b1dc5
13211321
RCTTypeSafety: db1dd5ad1081a5e160d30bb29ef922693d5ac4b1
13221322
React: 8650d592d90b99097504b8dcfebab883972aed71
13231323
React-callinvoker: 6bb8b399ab8cec59e52458c3a592aa1fca130b68
1324-
React-Codegen: 0c5fb82424bc21119c79da38b93ab8a62bcf5f9f
1325-
React-Core: 6dc6cccf86dd6eb53e5f689211ceb2037d65d3a6
1326-
React-CoreModules: 087c24b785afc79d29d23bffe7b02f79bb00cf76
1327-
React-cxxreact: 8b5a860f8c673ba4f98a3e30b41d4a2ae20f3a31
1324+
React-Codegen: fbad87d0dc7c5bc1536b25bc5cf2f19a1449e438
1325+
React-Core: ab1b60c382b7b79c374b68918f856826ec7f02a9
1326+
React-CoreModules: c5791800e490979b15b819e13ceaee42aa4a2672
1327+
React-cxxreact: 7a5de9c31527a3a36b02caa3540ab55080a6448a
13281328
React-debug: 41175f3e30dfa8af6eab2631261e1eac26307f9f
1329-
React-Fabric: 109d6c97fb4856f3edd848d5d896b71dedeaa361
1330-
React-FabricImage: de46a64a0ca4b0409a0acfb2f5ccdf1195f2d8e2
1329+
React-Fabric: c96fe05717ffb9ab37f7533e9697e68932a621d4
1330+
React-FabricImage: 837a4d681f01084888c7ed55df848eb3611c5691
13311331
React-featureflags: 5e7e78c607661fe7f72bc38c6f03736e0876753a
1332-
React-graphics: 354adf8693bf849e696bf5096abc8cdc22c78ab4
1333-
React-ImageManager: 74e0898e24b12c45c40019b8558a1310d0b2a47c
1332+
React-graphics: ea6e3c3f77683565552986548ba6a2938cb83251
1333+
React-ImageManager: 49a461cd14ed15749fe7371afb1924e8a72aecc1
13341334
React-jsc: 8c066d00deacb809aba74cbe3fc94b76d5ae6b7e
1335-
React-jserrorhandler: 33cb327f5c6e1571b362f1a9c762ff839a5adb15
1336-
React-jsi: 9ab5aa12ce6d9238a150e81f43c99b97e53a48a7
1337-
React-jsiexecutor: c30f9dda4147c7339cffc64d6ad596c6faddddb9
1338-
React-jsinspector: 50cfdab96549beab8d6554e39f3d36ed2ba23078
1339-
React-jsitracing: 36a2bbc272300313653d980de5ab700ec86c534a
1340-
React-logger: 03f2f7b955cfe24593a2b8c9705c23e142d1ad24
1341-
React-Mapbuffer: 5e05d78fe6505f4a054b86f415733d4ad02dd314
1342-
react-native-config: 3367df9c1f25bb96197007ec531c7087ed4554c3
1335+
React-jserrorhandler: bccc0691bf5195f4da1292a4d2fbaa13fa895f89
1336+
React-jsi: 20c796a75f92a22b083ebe78005b50fecfe025bd
1337+
React-jsiexecutor: 2ac1b518e12547c6389d6b314f4d17b283feab7a
1338+
React-jsinspector: 1cdd1dbae4aa9c455da2fec9ecda2381dda54695
1339+
React-jsitracing: d30048b056e8c9673dfbe67813bdb874c03558a5
1340+
React-logger: 5ae0978955199c132e71e8cf7797f619a6d17164
1341+
React-Mapbuffer: 3b85b3778e447cd1f06d353b8e967af50f272829
1342+
react-native-config: 963b5efabc864cf69412e54b5de49b6a23e4af03
13431343
React-nativeconfig: 951ec32f632e81cbd7d40aebb3211313251c092e
1344-
React-NativeModulesApple: add06f130d91f3ca13b92d35861fdd6fdb9157e6
1344+
React-NativeModulesApple: 612f931b1e79736f2d59353979042a424fb314c8
13451345
React-perflogger: 271f1111779fef70f9502d1d38da5132e5585230
13461346
React-RCTActionSheet: 5d6fb9adb11ab1bfbce6695a2b785767e4658c53
1347-
React-RCTAnimation: 86ace32c56e69b3822e7e5184ea83a79d47fc7b9
1348-
React-RCTAppDelegate: 6379a11a49fd0be615dc2e23da0c8a84c52ec65c
1349-
React-RCTBlob: 558daf7c11715ef24d97a0be5ccc3b209753682c
1350-
React-RCTFabric: eb4b1fc3718040717f17114b7782a519987bd7c4
1351-
React-RCTImage: b482f07cfdbe8e413edbf9d85953cecdb569472c
1352-
React-RCTLinking: fbd73a66cab34df69b2389c17f200e4722890fd9
1353-
React-RCTNetwork: fbdd716fbd6e53feb6d8e00eeb85e8184ad42ac8
1354-
React-RCTSettings: 11c3051b965593988298a3f5fb39e23bf6f7df9f
1355-
React-RCTText: f240b4d39c36c295204d29e7634a2fac450b6d29
1356-
React-RCTVibration: 1750f80b39e1ad9b4f509f4fdf19a803f7ab0d38
1357-
React-rendererdebug: a89ffa25c7670de8f22e0b322dfdd8333bc0d126
1347+
React-RCTAnimation: 0d11291f869c8a15cff4fd21dca031a83f9e8527
1348+
React-RCTAppDelegate: 77a7b9a27f10aa55da5a44132be281a15cc0848c
1349+
React-RCTBlob: 72759b7acf86de079c87a1562a440612c57da1b0
1350+
React-RCTFabric: a0345a090221724893e0ea20ffab73324f4b6520
1351+
React-RCTImage: 80ba9b23ecf87536b14c5eb38bd76f9d2b842c8a
1352+
React-RCTLinking: afd22b0854eba28eb277baad45c37ada5ef77bc3
1353+
React-RCTNetwork: ffe5a1021f5a0bcbdf7944665dc44856493ab5bd
1354+
React-RCTSettings: f8472ee7998de8d186c198e820c40fcaf9ce4571
1355+
React-RCTText: f556484bf1ba49a7c9b1ce1138608657d80e0bcb
1356+
React-RCTVibration: 236755b4231073ebac6cabc3864edb4cd6308d89
1357+
React-rendererdebug: c1dac9f04b12f05929b6113a50aec5fcd5132b94
13581358
React-rncore: a3ab9e7271a5c692918e2a483beb900ff0a51169
1359-
React-RuntimeApple: dbaeec3eb503510c93e91d49e92fc39c0ccf7e3a
1360-
React-RuntimeCore: 67e737df40b8815f65671fbaf8f75440e7fba96e
1359+
React-RuntimeApple: 7fae2c2c7aa890e78830465f5ca7bd13b91939ed
1360+
React-RuntimeCore: 38f46aedbab24c4887cf763b8d0c676a059f95e6
13611361
React-runtimeexecutor: 4471221991b6e518466a0422fbeb2158c07c36e1
1362-
React-runtimescheduler: 203e25504974651c4472ad00e035658d32002305
1363-
React-utils: 67c666fd04996cdb6bba26590586753d3e8ff7ed
1364-
ReactCommon: 53dbd9a55e29188ded016078708d1da8de2db19d
1365-
RNCAsyncStorage: ec53e44dc3e75b44aa2a9f37618a49c3bc080a7a
1362+
React-runtimescheduler: 1b7a5ce47ba798252278727248a3f50e991e2631
1363+
React-utils: 5eded69fc2a3be3f1823a64c6aa7b202e8e5dd94
1364+
ReactCommon: 649ff2cbfc22342f119b43af78ee85bad61e8919
1365+
RNCAsyncStorage: b6410dead2732b5c72a7fdb1ecb5651bbcf4674b
13661366
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
13671367
Yoga: 56f906bf6c11c931588191dde1229fd3e4e3d557
13681368

example/src/App.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Intercom, {
1818
type UserAttributes,
1919
Visibility,
2020
IntercomContent,
21+
ThemeMode,
2122
} from '@intercom/intercom-react-native';
2223

2324
import {
@@ -48,6 +49,7 @@ export default function App() {
4849
useState<boolean>(true);
4950
const [launcherVisibility, setLauncherVisibility] = useState<boolean>(false);
5051
const [user, setUser] = useState<UserAttributes>({ email: '' });
52+
const [currentTheme, setCurrentTheme] = useState<ThemeMode>(ThemeMode.SYSTEM);
5153

5254
const [conversationId, setConversationId] = useState<string | undefined>(
5355
CONVERSATION_ID
@@ -582,6 +584,54 @@ export default function App() {
582584
resetAttributes();
583585
}}
584586
/>
587+
<Button
588+
intercom_accessibilityLabel="set-theme-light"
589+
intercom_title={`Set Theme: Light ${
590+
currentTheme === 'LIGHT' ? '✓' : ''
591+
}`}
592+
intercom_onPress={() => {
593+
Intercom.setThemeMode(ThemeMode.LIGHT)
594+
.then(() => {
595+
setCurrentTheme(ThemeMode.LIGHT);
596+
})
597+
.catch((e) => {
598+
showErrorAlert(e);
599+
console.error(e);
600+
});
601+
}}
602+
/>
603+
<Button
604+
intercom_accessibilityLabel="set-theme-dark"
605+
intercom_title={`Set Theme: Dark ${
606+
currentTheme === 'DARK' ? '✓' : ''
607+
}`}
608+
intercom_onPress={() => {
609+
Intercom.setThemeMode(ThemeMode.DARK)
610+
.then(() => {
611+
setCurrentTheme(ThemeMode.DARK);
612+
})
613+
.catch((e) => {
614+
showErrorAlert(e);
615+
console.error(e);
616+
});
617+
}}
618+
/>
619+
<Button
620+
intercom_accessibilityLabel="set-theme-system"
621+
intercom_title={`Set Theme: System ${
622+
currentTheme === 'SYSTEM' ? '✓' : ''
623+
}`}
624+
intercom_onPress={() => {
625+
Intercom.setThemeMode(ThemeMode.SYSTEM)
626+
.then(() => {
627+
setCurrentTheme(ThemeMode.SYSTEM);
628+
})
629+
.catch((e) => {
630+
showErrorAlert(e);
631+
console.error(e);
632+
});
633+
}}
634+
/>
585635
<Button
586636
intercom_accessibilityLabel="logout"
587637
intercom_disabled={!loggedUser}

intercom-react-native.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ Pod::Spec.new do |s|
2020
s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
2121

2222
s.dependency "React-Core"
23-
s.dependency "Intercom", '~> 18.7.3'
23+
s.dependency "Intercom", '~> 19.1.2'
2424
end

ios/IntercomModule.m

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,35 @@ - (NSData *)dataFromHexString:(NSString *)string {
365365
resolve(@(YES));
366366
};
367367

368+
RCT_EXPORT_METHOD(setThemeMode:(NSString *)themeMode
369+
resolver:(RCTPromiseResolveBlock)resolve
370+
rejecter:(RCTPromiseRejectBlock)reject) {
371+
@try {
372+
if (themeMode == nil || [themeMode isKindOfClass:[NSNull class]] || [themeMode length] == 0) {
373+
reject(@"SET_THEME_MODE", @"Theme mode cannot be null or empty. Use 'LIGHT', 'DARK', or 'SYSTEM'.", nil);
374+
return;
375+
}
376+
377+
ICMThemeOverride themeOverride;
378+
379+
if ([themeMode isEqualToString:@"LIGHT"]) {
380+
themeOverride = ICMThemeOverrideLight;
381+
} else if ([themeMode isEqualToString:@"DARK"]) {
382+
themeOverride = ICMThemeOverrideDark;
383+
} else if ([themeMode isEqualToString:@"SYSTEM"]) {
384+
themeOverride = ICMThemeOverrideSystem;
385+
} else {
386+
reject(@"SET_THEME_MODE", [NSString stringWithFormat:@"Invalid theme mode: '%@'. Use 'LIGHT', 'DARK', or 'SYSTEM'.", themeMode], nil);
387+
return;
388+
}
389+
390+
[Intercom setThemeOverride:themeOverride];
391+
resolve(@(YES));
392+
} @catch (NSException *exception) {
393+
reject(@"SET_THEME_MODE", @"Error in setThemeMode", [self exceptionToError:exception :@"SET_THEME_MODE" :@"setThemeMode"]);
394+
}
395+
};
396+
368397
- (NSError *)exceptionToError:(NSException *)exception :(NSString *)code :(NSString *)domain {
369398
NSMutableDictionary *info = [NSMutableDictionary dictionary];
370399
[info setValue:exception.name forKey:@"ExceptionName"];

src/index.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ export enum LogLevel {
2626

2727
type LogLevelType = keyof typeof LogLevel;
2828

29+
export enum ThemeMode {
30+
LIGHT = 'LIGHT',
31+
DARK = 'DARK',
32+
SYSTEM = 'SYSTEM',
33+
}
34+
35+
type ThemeModeType = keyof typeof ThemeMode;
36+
2937
export const IntercomEvents = {
3038
IntercomUnreadCountDidChange:
3139
IntercomEventEmitter.UNREAD_COUNT_CHANGE_NOTIFICATION,
@@ -290,6 +298,17 @@ export type IntercomType = {
290298
*/
291299
setLogLevel(logLevel: LogLevelType): Promise<boolean>;
292300

301+
/**
302+
* Sets the theme mode for the Intercom SDK.
303+
*
304+
* This allows you to override the server-provided theme setting for the current session only.
305+
* The theme mode controls whether the SDK displays in light mode, dark mode, or follows the system theme.
306+
* The theme selection will be reset when the app restarts.
307+
*
308+
* @param themeMode The theme mode to set (LIGHT, DARK, or SYSTEM).
309+
*/
310+
setThemeMode(themeMode: ThemeModeType): Promise<boolean>;
311+
293312
/**
294313
Sets a JWT token for the user, necessary for using the Messenger
295314
when Messenger Security is enforced. This is an improvement to Identity Verification.
@@ -358,6 +377,7 @@ const Intercom: IntercomType = {
358377

359378
sendTokenToIntercom: (token) => IntercomModule.sendTokenToIntercom(token),
360379
setLogLevel: (logLevel) => IntercomModule.setLogLevel(logLevel),
380+
setThemeMode: (themeMode) => IntercomModule.setThemeMode(themeMode),
361381
setUserJwt: (jwt) => IntercomModule.setUserJwt(jwt),
362382
addEventListener: (event, callback) => {
363383
event === IntercomEvents.IntercomUnreadCountDidChange &&

0 commit comments

Comments
 (0)