IntercomBridge.m update for Intercom Cordova Ionic

Recently I had to update the intercom bridge file manually because the cordova intercom plugin appears incompatible with the latest ios sdk. Here are the changes:

//IntercomBridge.m

#import "IntercomBridge.h"
#import "AppDelegate+IntercomPush.h"
#import "ICMHelpCenterCollection+DictionaryConversion.h"
#import "ICMHelpCenterArticleSearchResult+DictionaryConversion.h"
#import "ICMHelpCenterCollectionContent+DictionaryConversion.h"
#import 

@interface Intercom (Cordoava)
+ (void)setCordovaVersion:(NSString *)v;
@end

@implementation IntercomBridge : CDVPlugin

- (void)pluginInitialize {
    [Intercom setCordovaVersion:@"12.4.0"];
    #ifdef DEBUG
        [Intercom enableLogging];
    #endif

    //Get app credentials from config.xml or the info.plist if they can't be found
    NSString* apiKey = self.commandDelegate.settings[@"intercom-ios-api-key"] ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"IntercomApiKey"];
    NSString* appId = self.commandDelegate.settings[@"intercom-app-id"] ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"IntercomAppId"];

    [Intercom setApiKey:apiKey forAppId:appId];
}

- (void)registerIdentifiedUser:(CDVInvokedUrlCommand*)command {
    NSDictionary* options = command.arguments[0];
    NSString* userId      = options[@"userId"];
    NSString* userEmail   = options[@"email"];

    if ([userId isKindOfClass:[NSNumber class]]) {
        userId = [(NSNumber *)userId stringValue];
    }

    ICMUserAttributes *userAttributes = [ICMUserAttributes new];
    
    if (userId.length > 0 && userEmail.length > 0) {
        userAttributes.userId = userId;
        userAttributes.email = userEmail;
    } else if (userId.length > 0) {
        userAttributes.userId = userId;
    } else if (userEmail.length > 0) {
        userAttributes.email = userEmail;
    } else {
        NSLog(@"[Intercom-Cordova] ERROR - No user registered. You must supply an email, a userId or both");
        [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]
                                    callbackId:command.callbackId];
        return;
    }
    
    [Intercom loginUserWithUserAttributes:userAttributes success:nil failure:nil];
    [self sendSuccess:command];
}

- (void)registerUnidentifiedUser:(CDVInvokedUrlCommand*)command {
    [Intercom loginUnidentifiedUserWithSuccess:nil failure:nil];
    [self sendSuccess:command];
}

- (void)logout:(CDVInvokedUrlCommand*)command {
    [Intercom logout];
    [self sendSuccess:command];
}

- (void)setUserHash:(CDVInvokedUrlCommand*)command {
    NSString *hmac = command.arguments[0];

    [Intercom setUserHash:hmac];
    [self sendSuccess:command];
}

- (void)updateUser:(CDVInvokedUrlCommand*)command {
    NSDictionary* attributesDict = command.arguments[0];
    [Intercom updateUser:[self userAttributesForDictionary:attributesDict] success:nil failure:nil];
    [self sendSuccess:command];
}

- (void)logEvent:(CDVInvokedUrlCommand*)command {
    NSString *eventName = command.arguments[0];
    NSDictionary *metaData = command.arguments[1];

    if ([metaData isKindOfClass:[NSDictionary class]] && metaData.count > 0) {
        [Intercom logEventWithName:eventName metaData:metaData];
    } else {
        [Intercom logEventWithName:eventName];
    }
    [self sendSuccess:command];
}

- (void)unreadConversationCount:(CDVInvokedUrlCommand*)command {
    NSUInteger count = [Intercom unreadConversationCount];
    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsNSUInteger:count];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)displayMessenger:(CDVInvokedUrlCommand*)command {
    [Intercom presentIntercom];

    [self sendSuccess:command];
}

- (void)displayMessageComposer:(CDVInvokedUrlCommand*)command {
    [Intercom presentMessageComposer:nil];
    [self sendSuccess:command];
}

- (void)displayMessageComposerWithInitialMessage:(CDVInvokedUrlCommand*)command {
    NSString *initialMessage = command.arguments[0];
    [Intercom presentMessageComposer:initialMessage];
    [self sendSuccess:command];
}

- (void)displayConversationsList:(CDVInvokedUrlCommand*)command {
    NSLog(@"[Intercom-Cordova] WARNING - displayConversationsList is deprecated. Please use displayMessenger instead.");
    [Intercom presentIntercom];

    [self sendSuccess:command];
}

- (void)displayHelpCenter:(CDVInvokedUrlCommand*)command {
  //  [Intercom presentHelpCenter];

    [self sendSuccess:command];
}

- (void)displayHelpCenterCollections:(CDVInvokedUrlCommand*)command {
    NSDictionary *args = command.arguments[0];
    NSArray* collectionIds = args[@"collectionIds"];
  //  [Intercom presentHelpCenterCollections:collectionIds];
    [self sendSuccess:command];
}

- (void)fetchHelpCenterCollections:(CDVInvokedUrlCommand*)command {
    [Intercom fetchHelpCenterCollectionsWithCompletion:^(NSArray * _Nullable collections, NSError * _Nullable error) {
        if (error) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsNSInteger:error.code];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } else {
            NSMutableArray *array = [[NSMutableArray alloc] init];
            for (ICMHelpCenterCollection *collection in collections) {
                [array addObject:[collection toDictionary]];
            }
            NSString *jsonString = [self stringValueForDictionaries:(NSArray *)array];
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:jsonString];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)fetchHelpCenterCollection:(CDVInvokedUrlCommand*)command {
    NSString *collectionId = command.arguments[0];
    [Intercom fetchHelpCenterCollection:collectionId withCompletion:^(ICMHelpCenterCollectionContent * _Nullable collectionContent, NSError * _Nullable error) {
        if (error) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsNSInteger:error.code];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } else {
            NSString *jsonString = [self stringValueForDictionary:[collectionContent toDictionary]];
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:jsonString];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)searchHelpCenter:(CDVInvokedUrlCommand*)command {
    NSString *searchTerm = command.arguments[0];
    [Intercom searchHelpCenter:searchTerm withCompletion:^(NSArray * _Nullable articleSearchResults, NSError * _Nullable error) {
        if (error) {
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsNSInteger:error.code];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        } else {
            NSMutableArray *array = [[NSMutableArray alloc] init];
            for (ICMHelpCenterArticleSearchResult *articleSearchResult in articleSearchResults) {
                [array addObject:[articleSearchResult toDictionary]];
            }
            NSString *jsonString = [self stringValueForDictionaries:(NSArray *)array];
            CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:jsonString];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }
    }];
}

- (void)hideIntercom:(CDVInvokedUrlCommand*)command {
    [Intercom hideIntercom];
    [self sendSuccess:command];
}

- (void)setLauncherVisibility:(CDVInvokedUrlCommand*)command {
    NSString *visibilityString = command.arguments[0];
    BOOL visible = NO;
    if ([visibilityString isEqualToString:@"VISIBLE"]) {
        visible = YES;
    }
    [Intercom setLauncherVisible:visible];
    [self sendSuccess:command];
}

- (void)setInAppMessageVisibility:(CDVInvokedUrlCommand*)command {
    NSString *visibilityString = command.arguments[0];
    BOOL visible = NO;
    if ([visibilityString isEqualToString:@"VISIBLE"]) {
        visible = YES;
    }
    [Intercom setInAppMessagesVisible:visible];
    [self sendSuccess:command];
}

- (void)registerForPush:(CDVInvokedUrlCommand*)command {
    UIApplication *application = [UIApplication sharedApplication];
    [application registerUserNotificationSettings:[UIUserNotificationSettings
                                 settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)
                                       categories:nil]];
    [application registerForRemoteNotifications];
    [self sendSuccess:command];
}

- (void)sendPushTokenToIntercom:(CDVInvokedUrlCommand*)command {
  NSLog(@"[Intercom-Cordova] INFO - sendPushTokenToIntercom called");
}

- (void)displayCarousel:(CDVInvokedUrlCommand*)command {
  NSString *carouselId = command.arguments[0];
    [Intercom presentContent:[IntercomContent carouselWithId:carouselId]];
    [self sendSuccess:command];
}

- (void)displayArticle:(CDVInvokedUrlCommand*)command {
  NSString *articleId = command.arguments[0];
    [Intercom presentContent:[IntercomContent articleWithId:articleId]];
    [self sendSuccess:command];
}

- (void)displaySurvey:(CDVInvokedUrlCommand*)command {
  NSString *surveyId = command.arguments[0];
    [Intercom presentContent:[IntercomContent surveyWithId:surveyId]];
    [self sendSuccess:command];
}

- (void)setBottomPadding:(CDVInvokedUrlCommand*)command {
    double bottomPadding = [[command.arguments objectAtIndex:0] doubleValue];
    [Intercom setBottomPadding:bottomPadding];
    [self sendSuccess:command];
}

#pragma mark - User attributes

- (ICMUserAttributes *)userAttributesForDictionary:(NSDictionary *)attributesDict {
    ICMUserAttributes *attributes = [ICMUserAttributes new];
    if ([self stringValueForKey:@"email" inDictionary:attributesDict]) {
        attributes.email = [self stringValueForKey:@"email" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"user_id" inDictionary:attributesDict]) {
        attributes.userId = [self stringValueForKey:@"user_id" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"name" inDictionary:attributesDict]) {
        attributes.name = [self stringValueForKey:@"name" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"phone" inDictionary:attributesDict]) {
        attributes.phone = [self stringValueForKey:@"phone" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"language_override" inDictionary:attributesDict]) {
        attributes.languageOverride = [self stringValueForKey:@"language_override" inDictionary:attributesDict];
    }
    if ([self dateValueForKey:@"signed_up_at" inDictionary:attributesDict]) {
        attributes.signedUpAt = [self dateValueForKey:@"signed_up_at" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"unsubscribed_from_emails" inDictionary:attributesDict]) {
        attributes.unsubscribedFromEmails = [self stringValueForKey:@"unsubscribed_from_emails" inDictionary:attributesDict];
    }
    if (attributesDict[@"custom_attributes"]) {
        attributes.customAttributes = attributesDict[@"custom_attributes"];
    }
    if (attributesDict[@"companies"]) {
        NSMutableArray *companies = [NSMutableArray new];
        for (NSDictionary *companyDict in attributesDict[@"companies"]) {
            [companies addObject:[self companyForDictionary:companyDict]];
        }
        attributes.companies = companies;
    }
    return attributes;
}

- (ICMCompany *)companyForDictionary:(NSDictionary *)attributesDict {
    ICMCompany *company = [ICMCompany new];
    if ([self stringValueForKey:@"company_id" inDictionary:attributesDict]) {
        company.companyId = [self stringValueForKey:@"company_id" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"name" inDictionary:attributesDict]) {
        company.name = [self stringValueForKey:@"name" inDictionary:attributesDict];
    }
    if ([self dateValueForKey:@"created_at" inDictionary:attributesDict]) {
        company.createdAt = [self dateValueForKey:@"created_at" inDictionary:attributesDict];
    }
    if ([self numberValueForKey:@"monthly_spend" inDictionary:attributesDict]) {
        company.monthlySpend = [self numberValueForKey:@"monthly_spend" inDictionary:attributesDict];
    }
    if ([self stringValueForKey:@"plan" inDictionary:attributesDict]) {
        company.plan = [self stringValueForKey:@"plan" inDictionary:attributesDict];
    }
    if (attributesDict[@"custom_attributes"]) {
        company.customAttributes = attributesDict[@"custom_attributes"];
    }
    return company;
}

- (NSString *)stringValueForKey:(NSString *)key inDictionary:(NSDictionary *)dictionary {
    NSString *value = dictionary[key];
    if ([value isKindOfClass:[NSString class]]) {
        return value;
    }
    if ([value isKindOfClass:[NSNumber class]]) {
        return [NSString stringWithFormat:@"%@", value];
    }
    if ([value isKindOfClass:[NSNull class]]) {
        return [ICMUserAttributes nullStringAttribute];
    }
    return nil;
}

- (NSString *)stringValueForDictionaries:(NSArray *)dictionaries {
    NSError *error;
    NSString *jsonString;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionaries options:0 error:&error];
    if (!jsonData) {
        NSLog(@"Got an error: %@", error);
    } else {
        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    return jsonString;
}


- (NSString *)stringValueForDictionary:(NSDictionary *)dictionary {
    NSError *error;
    NSString *jsonString;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
    if (!jsonData) {
        NSLog(@"Got an error: %@", error);
    } else {
        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    return jsonString;
}

- (NSNumber *)numberValueForKey:(NSString *)key inDictionary:(NSDictionary *)dictionary {
    NSNumber *value = dictionary[key];
    if ([value isKindOfClass:[NSNumber class]]) {
        return value;
    }
    if ([value isKindOfClass:[NSNull class]]) {
        return [ICMUserAttributes nullNumberAttribute];
    }
    return nil;
}

- (NSDate *)dateValueForKey:(NSString *)key inDictionary:(NSDictionary *)dictionary {
    NSNumber *value = dictionary[key];
    if ([value isKindOfClass:[NSNumber class]]) {
        return [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
    }
    if ([value isKindOfClass:[NSNull class]]) {
        return [ICMUserAttributes nullDateAttribute];
    }
    return nil;
}


#pragma mark - Private methods

- (void)sendSuccess:(CDVInvokedUrlCommand*)command {
    CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

@end




How to convert div containing an image into a png in Ionic/Angular

You can do this by installing the html2canvas library via `npm i html2canvas`
But you have to remember to useCORS if your div includes an externally located image! very important.


html2canvas(this.screen.nativeElement, {
      useCORS: true, //By passing this option in function Cross origin images will be rendered properly in the downloaded version of the PDF
    }).then(canvas => {
      this.canvas.nativeElement.src = canvas.toDataURL();
      this.downloadLink.nativeElement.href = canvas.toDataURL('image/png');
      this.downloadLink.nativeElement.download = new Date() + '.png';
      this.downloadLink.nativeElement.click();
    });

How to fix ion-checkbox stealing clicks on ion-item elements

How to fix ion-checkbox stealing clicks on ion-item elements.

I found this annoying issue with Ionic 5 where clicking on ion-label inside ion-item can’t be clicked if there is also an ion-checkbox element.

You have to change the z-index on the element you want clickable.

// component css
ion-label{
   z-index: 3;
}

You can also disable button property on ion-item, check the docs here.

You can also apply this to any other element you want to use inside ion-item. Good luck!

Implement App Tracking Transparency for Ionic Angular and Cordova iOS app

How to use the https://github.com/chemerisuk/cordova-plugin-idfa plugin in Ionic v3.

I had some issues using the example provided so I had to call the exec directly:

// first install the plugin
// cordova plugin add cordova-plugin-idfa
// npm i cordova-plugin-idfa --save

// add permissions to config.xml under ios platform
<platform name="ios">
    <edit-config target="NSUserTrackingUsageDescription" file="*-Info.plist" mode="merge">
        <string> My tracking usage description </string>
    </edit-config>
</platform>

// has to be called after platform is ready
// this.platform.ready().then(() => {}

askTrackingPermission() {
    if (this.platform.is('cordova') && this.platform.is('ios')) {

      if (window.cordova) {
        console.log('trying to request permission ');
        window.cordova.exec(win, fail, 'idfa', "requestPermission", []);
      }
    }

    function win(res) {
      console.log('success ' + JSON.stringify(res));
    }
    function fail(res) {
      console.log('fail ' + JSON.stringify(res));
    }
  }

readTrackingPermission() {

    if (this.platform.is('cordova') && this.platform.is('ios')) {

      if (window.cordova) {
        window.cordova.exec(win, fail, 'idfa', "getInfo", []);
      }
    }

    function win(res) {
      console.log('success  ' + JSON.stringify(res));
    }
    function fail(res) {
      console.log('fail ' + JSON.stringify(res));
    }
  }

Also, you can only test this from the iOS simulator (or device) running 14.5.1+ iOS. In your iOS device settings check privacy->tracking (setting) it has to be allowed to ask. And you will only be able to ask the user once.

Good luck!

How To Create Downloadable CSV File in JS/Angular

 
import { SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
private sanitizer: DomSanitizer;

downloadCSV() {

  let blob = new Blob([yourdata], { type: 'text/csv' });
  let urlPath = this.sanitizer.sanitize(SecurityContext.URL,
this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(blob)));
    
  let tempLink = document.createElement('a');
  tempLink.href = urlPath;
  tempLink.setAttribute('download', 'download.csv');
  tempLink.click();
}