[invites] Initial JS and Android invites functionality

This commit is contained in:
Chris Bianca
2018-03-22 12:46:37 +00:00
parent 26c3ed9a60
commit 53babb4cd9
16 changed files with 747 additions and 135 deletions

View File

@@ -19,6 +19,7 @@ import Crashlytics, {
import Database, { NAMESPACE as DatabaseNamespace } from '../database';
import Firestore, { NAMESPACE as FirestoreNamespace } from '../firestore';
import InstanceId, { NAMESPACE as InstanceIdNamespace } from '../instanceid';
import Invites, { NAMESPACE as InvitesNamespace } from '../invites';
import Links, { NAMESPACE as LinksNamespace } from '../links';
import Messaging, { NAMESPACE as MessagingNamespace } from '../messaging';
import Notifications, {
@@ -49,6 +50,7 @@ export default class App {
};
firestore: () => Firestore;
instanceid: () => InstanceId;
invites: () => Invites;
links: () => Links;
messaging: () => Messaging;
notifications: () => Notifications;
@@ -90,6 +92,7 @@ export default class App {
};
this.firestore = APPS.appModule(this, FirestoreNamespace, Firestore);
this.instanceid = APPS.appModule(this, InstanceIdNamespace, InstanceId);
this.invites = APPS.appModule(this, InvitesNamespace, Invites);
this.links = APPS.appModule(this, LinksNamespace, Links);
this.messaging = APPS.appModule(this, MessagingNamespace, Messaging);
this.notifications = APPS.appModule(

View File

@@ -42,6 +42,10 @@ import {
statics as InstanceIdStatics,
MODULE_NAME as InstanceIdModuleName,
} from '../instanceid';
import {
statics as InvitesStatics,
MODULE_NAME as InvitesModuleName,
} from '../invites';
import {
statics as LinksStatics,
MODULE_NAME as LinksModuleName,
@@ -78,6 +82,7 @@ import type {
FirebaseOptions,
FirestoreModule,
InstanceIdModule,
InvitesModule,
LinksModule,
MessagingModule,
NotificationsModule,
@@ -98,6 +103,7 @@ class Firebase {
fabric: FabricModule;
firestore: FirestoreModule;
instanceid: InstanceIdModule;
invites: InvitesModule;
links: LinksModule;
messaging: MessagingModule;
notifications: NotificationsModule;
@@ -147,6 +153,11 @@ class Firebase {
InstanceIdStatics,
InstanceIdModuleName
);
this.invites = APPS.moduleAndStatics(
'invites',
InvitesStatics,
InvitesModuleName
);
this.links = APPS.moduleAndStatics('links', LinksStatics, LinksModuleName);
this.messaging = APPS.moduleAndStatics(
'messaging',

View File

@@ -0,0 +1,69 @@
/**
* @flow
* AndroidInvitation representation wrapper
*/
import type Invitation from './Invitation';
import type { NativeAndroidInvitation } from './types';
export default class AndroidInvitation {
_additionalReferralParameters: { [string]: string } | void;
_emailHtmlContent: string | void;
_emailSubject: string | void;
_googleAnalyticsTrackingId: string | void;
_invitation: Invitation;
constructor(invitation: Invitation) {
this._invitation = invitation;
}
/**
*
* @param additionalReferralParameters
* @returns {Invitation}
*/
setAdditionalReferralParameters(additionalReferralParameters: {
[string]: string,
}): Invitation {
this._additionalReferralParameters = additionalReferralParameters;
return this._invitation;
}
/**
*
* @param emailHtmlContent
* @returns {Invitation}
*/
setEmailHtmlContent(emailHtmlContent: string): Invitation {
this._emailHtmlContent = emailHtmlContent;
return this._invitation;
}
/**
*
* @param emailSubject
* @returns {Invitation}
*/
setEmailSubject(emailSubject: string): Invitation {
this._emailSubject = emailSubject;
return this._invitation;
}
/**
*
* @param googleAnalyticsTrackingId
* @returns {Invitation}
*/
setGoogleAnalyticsTrackingId(googleAnalyticsTrackingId: string): Invitation {
this._googleAnalyticsTrackingId = googleAnalyticsTrackingId;
return this._invitation;
}
build(): NativeAndroidInvitation {
return {
additionalReferralParameters: this._additionalReferralParameters,
emailHtmlContent: this._emailHtmlContent,
emailSubject: this._emailSubject,
googleAnalyticsTrackingId: this._googleAnalyticsTrackingId,
};
}
}

View File

@@ -0,0 +1,106 @@
/**
* @flow
* Invitation representation wrapper
*/
import { Platform } from 'react-native';
import AndroidInvitation from './AndroidInvitation';
import type { NativeInvitation } from './types';
export default class Invitation {
_android: AndroidInvitation;
_androidClientId: string | void;
_androidMinimumVersionCode: number | void;
_callToActionText: string | void;
_customImage: string | void;
_deepLink: string | void;
_iosClientId: string | void;
_message: string;
_title: string;
constructor(title: string, message: string) {
this._android = new AndroidInvitation(this);
this._message = message;
this._title = title;
}
/**
*
* @param androidClientId
* @returns {Invitation}
*/
setAndroidClientId(androidClientId: string): Invitation {
this._androidClientId = androidClientId;
return this;
}
/**
*
* @param androidMinimumVersionCode
* @returns {Invitation}
*/
setAndroidMinimumVersionCode(androidMinimumVersionCode: number): Invitation {
this._androidMinimumVersionCode = androidMinimumVersionCode;
return this;
}
/**
*
* @param callToActionText
* @returns {Invitation}
*/
setCallToActionText(callToActionText: string): Invitation {
this._callToActionText = callToActionText;
return this;
}
/**
*
* @param customImage
* @returns {Invitation}
*/
setCustomImage(customImage: string): Invitation {
this._customImage = customImage;
return this;
}
/**
*
* @param deepLink
* @returns {Invitation}
*/
setDeepLink(deepLink: string): Invitation {
this._deepLink = deepLink;
return this;
}
/**
*
* @param iosClientId
* @returns {Invitation}
*/
setIOSClientId(iosClientId: string): Invitation {
this._iosClientId = iosClientId;
return this;
}
build(): NativeInvitation {
if (!this._message) {
throw new Error('Invitation: Missing required `message` property');
} else if (!this._title) {
throw new Error('Invitation: Missing required `title` property');
}
return {
android: Platform.OS === 'android' ? this._android.build() : undefined,
androidClientId: this._androidClientId,
androidMinimumVersionCode: this._androidMinimumVersionCode,
callToActionText: this._callToActionText,
customImage: this._customImage,
deepLink: this._deepLink,
iosClientId: this._iosClientId,
message: this._message,
title: this._title,
};
}
}

View File

@@ -0,0 +1,77 @@
/**
* @flow
* Invites representation wrapper
*/
import { SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import Invitation from './Invitation';
import type App from '../core/app';
export const MODULE_NAME = 'RNFirebaseInvites';
export const NAMESPACE = 'invites';
const NATIVE_EVENTS = ['invites_invitation_received'];
type InvitationOpen = {
deepLink: string,
invitationId: string,
};
export default class Invites extends ModuleBase {
constructor(app: App) {
super(app, {
events: NATIVE_EVENTS,
moduleName: MODULE_NAME,
multiApp: false,
namespace: NAMESPACE,
});
SharedEventEmitter.addListener(
// sub to internal native event - this fans out to
// public event name: onMessage
'invites_invitation_received',
(invitation: InvitationOpen) => {
SharedEventEmitter.emit('onInvitation', invitation);
}
);
}
/**
* Returns the invitation that triggered application open
* @returns {Promise.<Object>}
*/
getInitialInvitation(): Promise<string> {
return getNativeModule(this).getInitialInvitation();
}
/**
* Subscribe to invites
* @param listener
* @returns {Function}
*/
onInvitation(listener: InvitationOpen => any) {
getLogger(this).info('Creating onInvitation listener');
SharedEventEmitter.addListener('onInvitation', listener);
return () => {
getLogger(this).info('Removing onInvitation listener');
SharedEventEmitter.removeListener('onInvitation', listener);
};
}
sendInvitation(invitation: Invitation): Promise<string[]> {
if (!(invitation instanceof Invitation)) {
throw new Error(
`Invites:sendInvitation expects an 'Invitation' but got type ${typeof invitation}`
);
}
return getNativeModule(this).sendInvitation(invitation.build());
}
}
export const statics = {
Invitation,
};

View File

@@ -0,0 +1,21 @@
/**
* @flow
*/
export type NativeAndroidInvitation = {|
additionalReferralParameters?: { [string]: string },
emailHtmlContent?: string,
emailSubject?: string,
googleAnalyticsTrackingId?: string,
|};
export type NativeInvitation = {|
android?: NativeAndroidInvitation,
androidClientId?: string,
androidMinimumVersionCode?: number,
callToActionText?: string,
customImage?: string,
deepLink?: string,
iosClientId?: string,
message: string,
title: string,
|};

View File

@@ -3,6 +3,7 @@
* Dynamic Links representation wrapper
*/
import { SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import ModuleBase from '../../utils/ModuleBase';
import { areObjectKeysContainedInOther, isObject, isString } from '../../utils';
import { getNativeModule } from '../../utils/native';
@@ -10,7 +11,7 @@ import { getNativeModule } from '../../utils/native';
import type App from '../core/app';
const EVENT_TYPE = {
Link: 'dynamic_link_received',
Link: 'links_link_received',
};
const NATIVE_EVENTS = [EVENT_TYPE.Link];
@@ -82,33 +83,21 @@ export default class Links extends ModuleBase {
multiApp: false,
namespace: NAMESPACE,
});
SharedEventEmitter.addListener(
// sub to internal native event - this fans out to
// public event name: onMessage
'links_link_received',
(link: string) => {
SharedEventEmitter.emit('onLink', link);
}
);
}
get EVENT_TYPE(): Object {
return EVENT_TYPE;
}
/**
* Returns the link that triggered application open
* @returns {Promise.<String>}
*/
getInitialLink(): Promise<string> {
return getNativeModule(this).getInitialLink();
}
/**
* Subscribe to dynamic links
* @param listener
* @returns {Function}
*/
onLink(listener: Function): () => any {
const rnListener = SharedEventEmitter.addListener(
EVENT_TYPE.Link,
listener
);
return () => rnListener.remove();
}
/**
* Create long Dynamic Link from parameters
* @param parameters
@@ -138,6 +127,30 @@ export default class Links extends ModuleBase {
return Promise.reject(error);
}
}
/**
* Returns the link that triggered application open
* @returns {Promise.<String>}
*/
getInitialLink(): Promise<string> {
return getNativeModule(this).getInitialLink();
}
/**
* Subscribe to dynamic links
* @param listener
* @returns {Function}
*/
onLink(listener: string => any): () => any {
getLogger(this).info('Creating onLink listener');
SharedEventEmitter.addListener('onLink', listener);
return () => {
getLogger(this).info('Removing onLink listener');
SharedEventEmitter.removeListener('onLink', listener);
};
}
}
export const statics = {

View File

@@ -133,13 +133,13 @@ export default class RemoteMessage {
}
build(): NativeOutboundRemoteMessage {
if (!this.data) {
if (!this._data) {
throw new Error('RemoteMessage: Missing required `data` property');
} else if (!this.messageId) {
} else if (!this._messageId) {
throw new Error('RemoteMessage: Missing required `messageId` property');
} else if (!this.to) {
} else if (!this._to) {
throw new Error('RemoteMessage: Missing required `to` property');
} else if (!this.ttl) {
} else if (!this._ttl) {
throw new Error('RemoteMessage: Missing required `ttl` property');
}